How to use inlineScript method in wpt

Best JavaScript code snippet using wpt

inline-script.ts

Source:inline-script.ts Github

copy

Full Screen

...210};211/**212 * Will initiate everything automatically213 */214function inlineScript() {215 if (compiledInlineScript) return;216 compiledInlineScript = true;217 const inlineScript = new InlineScriptInstance();218 [document.head, document.body].forEach((element) => inlineScript.scan(element));219 ScopedCss.scopeAllStyles();220 ISPR.finish();221}222/**223 * This variable will be true if the 'inlineScript' function will get called.224 * It also prevents the 'inlineScript' function to be called twice.225 */226var compiledInlineScript = false;227/**228 * The inline script pre renderer. This variable will get replaced by another229 * object that has all of the properties of the inline script renderer.230 */231var ISPR: any = {232 /**233 * Keeps track of asynchronous tasks.234 *235 * When an asynchronous task starts this number should increase by one in an synchronous process.236 * When an asynchronous task resolves or rejects this number should decrease by on in an async process.237 *238 * This results in a complete pre rendering where no asynchronous tasks got ignored.239 */240 tasks: 0,241 addElement() {},242 finish() {},243};244/**245 * Imitating the state variable.246 */247const state = {248 render() {249 Array.from(document.body.children).forEach((element: any) => {250 if (element.render !== undefined) element.render();251 });252 },253};254//#endregion255//#region CSS256/**257 * This will add some additional css rules that are necessary for inline script to behave properly.258 */259const inlineScriptCss = document.createElement('style');260document.head.appendChild(inlineScriptCss);261inlineScriptCss.innerHTML += `function, preload { display: none !important; }`;262//#region Scoped CSS263const ScopedCss = {264 //#region Class names265 /**266 * This is the prefix of unique class names for scoped css.267 */268 SCOPED_CSS_PREFIX: 'scoped-css-id-',269 /**270 * The counter for unique scoped css class names.271 * This variable will increase by one every time a new class name gets generated.272 */273 scopedCSSId: 0,274 //#endregion275 /**276 * A regex that is used the remove all comments in a css file.277 */278 cssCommentsRegex: /\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*\/+/gm,279 /**280 * This will remove all comments in a css.281 *282 * @param css the css as string with comments.283 * @returns the inputted css without comments.284 */285 removeAllCssComments(css: string): string {286 return css.replace(ScopedCss.cssCommentsRegex, '');287 },288 /**289 * Scopes the css.290 *291 * When a selector starts with '#this', it will get replaced by the scope.292 *293 * @param scope the scope that will get appended before every selector.294 * @param css the css that will get scoped.295 *296 * @returns the css inputted but scoped.297 */298 scope(scope: string, css: string): string {299 css = ScopedCss.removeAllCssComments(css);300 const regex = /([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g;301 let m: RegExpMatchArray;302 while ((m = regex.exec(css)) !== null) {303 if (m.index === regex.lastIndex) regex.lastIndex++;304 let match = m[0].trim();305 const index = m.index;306 if (307 !match.startsWith('@') &&308 !match.startsWith('from') &&309 !match.startsWith('to') &&310 !/[\d]/.test(match.substr(0, 1))311 ) {312 let end = css.substr(index).trim();313 if (end.startsWith('#this')) end = end.substr(6);314 css = css.substring(0, index) + scope + ' ' + end;315 regex.lastIndex += scope.length + 1;316 }317 }318 return css;319 },320 /**321 * @returns a unique class name for scoping css322 */323 getUniqueStyleClassName() {324 return ScopedCss.SCOPED_CSS_PREFIX + ScopedCss.scopedCSSId++;325 },326 /**327 * This will query all style elements with a scoped attribute over an element.328 *329 * @returns an array of elements that matches the query.330 */331 getScopedStyleElements(parent: HTMLElement): Array<HTMLElement> {332 return Array.from(parent.querySelectorAll('style[scoped]'));333 },334 /**335 * This will execute everything necessary in order to scope an style element.336 *337 * @param element the style element.338 */339 scopeStyle(element: HTMLElement) {340 const uniqueStyleClassName = ScopedCss.getUniqueStyleClassName();341 // sets a unique class name to the element's parent342 element.parentElement.classList.add(uniqueStyleClassName);343 element.innerHTML = ScopedCss.scope('.' + uniqueStyleClassName, element.innerHTML);344 element.removeAttribute('scoped');345 },346 /**347 * This will search for scoped style tags on the element 'parent' and automatically scope them.348 */349 scopeStyles(parent: HTMLElement) {350 let styles = ScopedCss.getScopedStyleElements(parent);351 styles.forEach(ScopedCss.scopeStyle);352 styles = Array.from(parent.querySelectorAll('style[scope]'));353 },354 /**355 * Calls the 'scopedStyles' function with the html element as parameter.356 */357 scopeAllStyles() {358 ScopedCss.scopeStyles(document.querySelector('html'));359 },360};361//#endregion362//#endregion363//#region Inline script364/**365 * This is an object containing global variables and function.366 * The reason these variables and functions are not included in the inlineScriptInstance class is simply367 * that in order for inlineScript to use variables and create a new scope for them, it must re-instantiate368 * the whole class every time when e.g. an html object gets returned from an inline script syntax.369 * So to keep the class as little as possible is key to improve performance.370 */371const InlineScript = {372 //#region Common functions373 /**374 * Queries using xpath.375 *376 * @param xpath the xpath query377 * @param parent the parent node. It defaults to document.378 *379 * @returns an array of nodes of the query380 */381 $x(xpath: string, parent: any): Array<Node> {382 let results: Array<Node> = [];383 parent = parent || document;384 let query = document.evaluate(xpath, parent, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);385 for (let i = 0, length = query.snapshotLength; i < length; ++i) {386 results.push(query.snapshotItem(i));387 }388 return results;389 },390 /**391 * This is a list of regex that define which parts of html (as string) should be reverse sanitized.392 * Every regex gets the attributes 'global' and 'multiline'.393 */394 reverseSanitationReplaceList: {395 '\\&gt;': '>',396 '\\&lt;': '<',397 },398 /**399 * Reverses the sanitation of an element.400 *401 * @param html the 'innerHTML' or content of an element.402 * @returns the content of an element reversed sanitized.403 */404 reverseSanitation(html: string): string {405 for (const [regex, replacement] of Object.entries(InlineScript.reverseSanitationReplaceList))406 html = html.replace(new RegExp(regex, 'gm'), replacement);407 return html;408 },409 /**410 * Escapes all special characters from a string.411 *412 * @param string the unescaped string.413 * @returns the script inputted but escaped.414 */415 escapeAll(string: string): string {416 return string417 .replace(/\\/gm, '\\\\')418 .replace(/\$/gm, '\\$')419 .replace(/'/gm, "\\'")420 .replace(/"/gm, '\\"')421 .replace(/`/gm, '\\`');422 },423 /**424 * Takes a string and return an collection of html elements.425 *426 * @param stringElement a string with valid html syntax427 * @returns a collection of all elements in the string as HTMLCollection428 */429 createElements(stringElement: string): HTMLCollection {430 const parent = document.createElement('div');431 parent.innerHTML = '<div>' + stringElement + '</div>';432 return (parent.firstChild as HTMLElement).children;433 },434 /**435 * Sets src attributes to all script tags in an HTMLCollection.436 */437 sanitizeScriptElements(collection: HTMLCollection) {438 for (const element of collection) {439 if (element.tagName === 'SCRIPT') {440 element.setAttribute('src', '');441 }442 }443 },444 /**445 * Converts a NamedNodeMap to an object.446 *447 * @returns an object of the attributes in 'element'.448 */449 getAttributesFromElementsAsObject(element: HTMLElement): Record<string, string> {450 let output = {};451 Array.from(element.attributes).forEach(({ name, value }) => {452 output[name] = value;453 });454 return output;455 },456 /**457 * Sets the attributes of an element to an object.458 */459 setAttributesFromObject(element: HTMLElement, attributes: Record<string, string>) {460 Object.entries(attributes).forEach(([name, value]) => {461 element.setAttribute(name, value);462 });463 },464 /**465 * Does the same as 'String.prototype.substr' but throws an error when the output string is empty.466 *467 * @returns the substring of a string.468 */469 substringThrow(string: string, start: number, length: number = undefined): string {470 const res = string.substr(start, length);471 if (res === '') throw 'substring is out of bounce.';472 return res;473 },474 /**475 * Will initiate a new instance of InlineScript and call the scan function on the element476 *477 * This is useful if you have variables in your scope that you want to get rid of.478 *479 * @param element the element that will get scanned in a new instance of InlineScript480 */481 newInlineScript(element: HTMLElement) {482 new InlineScriptInstance().scan(element);483 },484 //#endregion485 //#region Fetching and caching486 /**487 * Stores cached fetch request.488 */489 srcCache: {},490 /**491 * Fetches a url using xml http492 * @param url the url that should get fetched.493 * @return the content of the url.494 */495 async fetch(url: string): Promise<string> {496 var xmlHttp = new XMLHttpRequest();497 xmlHttp.open('GET', url, true);498 xmlHttp.send(null);499 return new Promise((resolve, reject) => {500 xmlHttp.onload = () => {501 resolve(xmlHttp.responseText);502 };503 setTimeout(() => {504 reject();505 }, 1000);506 });507 },508 /**509 * Fetches a url using xml http synced.510 * @param url the url that should get fetched.511 * @return the content of the url.512 */513 fetchSync(url: string): string {514 var xmlHttp = new XMLHttpRequest();515 xmlHttp.open('GET', url, false);516 xmlHttp.send(null);517 return xmlHttp.responseText;518 },519 /**520 * This will fetch an url and caches it in the variable 'srcCache'.521 * If the request already got cached it will return the cache.522 *523 * @param url the url / path.524 * @param forceFetch if set true, it won't return the cache but rather fetch the file again.525 *526 * @returns a promise of the content of the request as string.527 */528 async loadFromUrl(url: string, forceFetch: boolean = false): Promise<string> {529 let res: string;530 if (InlineScript.srcCache[url] === undefined || forceFetch) res = await InlineScript.fetch(url);531 else res = InlineScript.srcCache[url];532 ISPR.tasks--;533 InlineScript.srcCache[url] = res;534 return res;535 },536 /**537 * This will fetch an url synced and caches it in the variable 'srcCache'.538 * If the request already got cached it will return the cache.539 *540 * @param url the url / path.541 * @param forceFetch if set true, it won't return the cache but rather fetch the file again.542 *543 * @returns the content of the request as string.544 */545 loadFromUrlSync(url: string, forceFetch: boolean = false): string {546 let res: string;547 if (InlineScript.srcCache[url] === undefined || forceFetch) res = InlineScript.fetchSync(url);548 else res = InlineScript.srcCache[url];549 ISPR.tasks--;550 InlineScript.srcCache[url] = res;551 return res;552 },553 /**554 * Removes an entry in the 'srcCache'.555 *556 * @param url the url that got cached.557 */558 removeFromCache(url: string) {559 InlineScript.srcCache[url] = undefined;560 },561 //#endregion562 //#region Class names563 /**564 * This is the prefix of the unique attribute name (isid) for inline script.565 */566 ISID_ATTRIBUTE_NAME: 'isid',567 /**568 * The counter for unique inline script class names.569 * This variable will increase by one every time a new class name gets generated.570 */571 isid: 0,572 //#endregion573 //#region HTML Syntax574 /**575 * will generate some additional javascript code that should get executed before a new instance576 * of the 'InlineScriptInstance' gets created in a new scope.577 *578 * @param parentElement the parent element579 */580 /**581 * Inserts the lexing result into the string582 *583 * @param string the initial string584 * @param lexingResult the result of the lexing process. Note that the content of the lexing result is used.585 *586 * @returns the string with the content of the result inserted.587 */588 insertLexingResult(string: string, lexingResult: LexingResult): string {589 return (590 string.substr(0, lexingResult.index) +591 lexingResult.content +592 string.substr(lexingResult.index + lexingResult.length)593 );594 },595 /**596 * @returns default eval code that all eval calls to create new InlineScriptInstances use.597 */598 generateEvalPreCode(parentElement: HTMLElement): string {599 let evalCode = '';600 evalCode +=601 "let parent=document.querySelector('[" + InlineScript.ISID_ATTRIBUTE_NAME + '="' + parentElement.isid + '"]\');';602 evalCode += 'let scope=parent,__parent=parent;';603 evalCode += 'let state={render(){Array.from(parent.children).forEach(_=>_.render&&_.render())}};';604 return evalCode;605 },606 /**607 * Removes spaces and new lines from a string.608 */609 removeEmptySpace(string: string): string {610 return string.replace(/\n|\s/gm, '');611 },612 /**613 * Converts the LexingResult's content for html syntax.614 */615 convertHTMLSyntaxResultContent(content: string, element: HTMLElement): string {616 return (617 'eval(InlineScriptInstance+`' +618 InlineScript.generateEvalPreCode(element) +619 'new InlineScriptInstance().fromString(element,\\`' +620 content.substring(1, content.length - 1) +621 '\\`)`)'622 );623 },624 /**625 * Finds a html syntax and returns the index, length and content of it.626 *627 * @param string the html that gets lexed.628 * @param startIndex the index the scanner starts.629 *630 * @returns the start, length and content of the lexed result.631 */632 scanHTMLSyntax(string: string, startIndex: number): LexingResult {633 let result: LexingResult = {634 index: null,635 length: null,636 content: null,637 };638 try {639 let depth = 0;640 for (let i = startIndex; i < string.length; i++) {641 const c = InlineScript.substringThrow(string, i, 1);642 const cc = InlineScript.substringThrow(string, i, 2);643 /**644 * Handle quotes645 */646 if (['"', "'", '¸'].includes(c)) {647 const quote = c;648 i++;649 while (650 InlineScript.substringThrow(string, i, 1) !== quote ||651 InlineScript.substringThrow(string, i - 1, 1) === '\\'652 )653 i++;654 }655 /**656 * Handle comments657 */658 if (cc === '//') while (InlineScript.substringThrow(string, i, 1) !== '\n') i++;659 if (InlineScript.substringThrow(string, i, 4) === '<!--')660 while (InlineScript.substringThrow(string, i, 1) !== '\n') i++;661 if (cc === '/*') while (InlineScript.substringThrow(string, i, 2) !== '*/') i++;662 /**663 * Find opening bracket664 */665 while (InlineScript.substringThrow(string, i, 1) === '(') {666 const bracketIndex = i;667 i++;668 while (/\s|\r/.test(InlineScript.substringThrow(string, i, 1))) i++;669 if (InlineScript.substringThrow(string, i, 1) === '<') {670 depth++;671 if (depth === 1) result.index = bracketIndex;672 }673 }674 /**675 * Find closing bracket676 */677 while (InlineScript.substringThrow(string, i, 1) === '>' && depth > 0) {678 i++;679 while (/\s|\r/.test(InlineScript.substringThrow(string, i, 1))) i++;680 if (InlineScript.substringThrow(string, i, 1) === ')') {681 depth--;682 if (depth === 0) {683 result.length = i + 1 - result.index;684 result.content = string.substr(result.index, result.length);685 result.content = InlineScript.escapeAll(InlineScript.escapeAll(result.content));686 return result;687 }688 }689 }690 }691 } catch {}692 return null;693 },694 /**695 * Compiles the html syntax in an inline script code.696 *697 * @param inlineScript the inline script of an element.698 * @param element the element that has the inline script code.699 *700 * @returns the compiled inline script code.701 */702 compileHTMLSyntax(inlineScript: string, element: HTMLElement): string {703 inlineScript = InlineScript.reverseSanitation(inlineScript);704 let lexingResult: LexingResult,705 lastIndex: number = 0;706 while ((lexingResult = InlineScript.scanHTMLSyntax(inlineScript, lastIndex))) {707 lexingResult.content = InlineScript.convertHTMLSyntaxResultContent(lexingResult.content, element);708 inlineScript = InlineScript.insertLexingResult(inlineScript, lexingResult);709 lastIndex = lexingResult.index + lexingResult.content.length;710 }711 return inlineScript;712 },713 //#endregion714 //#region Rendering715 /**716 * @returns if an element generates child-elements.717 */718 generatesChildElements(element: HTMLElement): boolean {719 return element.functionName !== undefined || element.inlineScriptSrc !== undefined;720 },721 //#endregion722 //#region Handlers723 //#region Handle inline script eval result724 evalResultHandler: {725 handleEvalResultUndefined(element: HTMLElement, result: any): boolean {726 return result === undefined;727 },728 handleEvalResultHTMLCollection(element: HTMLElement, result: HTMLCollection): boolean {729 if (!(result instanceof HTMLCollection)) return;730 Array.from(result).forEach((child) => element.append(child));731 ScopedCss.scopeStyles(element);732 return true;733 },734 handleEvalResultHTMLElement(element: HTMLElement, result: HTMLElement): boolean {735 if (!(result instanceof HTMLElement)) return;736 element.append(result);737 ScopedCss.scopeStyles(element);738 return true;739 },740 handleEvalResultArray(element: HTMLElement, result: Array<any>): boolean {741 if (!(result instanceof Array)) return;742 result.forEach((child: any) => {743 InlineScript.handleEvalResult(element, child);744 });745 return true;746 },747 handleEvalResultPromise(element: HTMLElement, result: Promise<any>): boolean {748 if (!(result instanceof Promise)) return;749 ISPR.tasks++;750 result751 .then((res: any) => {752 ISPR.tasks--;753 InlineScript.handleEvalResult(element, res);754 })755 .catch((res) => {756 ISPR.tasks--;757 InlineScript.handleExceptionResult(element, res);758 });759 return true;760 },761 },762 /**763 * Checks the type of the result and applies it on the element.764 *765 * @param element the element that will get the result value.766 * @param result the result which type is unknown.767 * @param clear if the elements innerHTML should get reset automatically.768 */769 handleEvalResult(element: HTMLElement, result: any, clear: boolean = false) {770 if (clear) element.innerHTML = '';771 for (const [functionName, functionValue] of Object.entries(this.evalResultHandler)) {772 if ((functionValue as any)(element, result)) return;773 }774 element.innerHTML += result.toString();775 return;776 },777 //#endregion778 /**779 * @returns the result nicely parsed to string.780 */781 handleResult(result: any): string {782 if (result === undefined) return '';783 if (typeof result === 'string') return result;784 if (typeof result === 'number') return result.toString();785 if (result instanceof Array) return result.join('');786 return JSON.stringify(result);787 },788 /**789 * Handles errors while executing the eval.790 * It will print the error in the console as well as display the error791 * on the element directly.792 */793 handleExceptionResult(element: HTMLElement, error: any) {794 console.error(error);795 element.style.background = 'red';796 element.style.color = 'yellow';797 element.style.fontSize = '20px';798 element.innerHTML = error;799 },800 //#endregion801 //#region Attributes802 //#region General803 /**804 * Searches for attributes that use the inline script syntax and saves them.805 */806 scanAttributes(element: HTMLElement) {807 const attributes = Array.from(element.attributes);808 const inlineScriptAttributes = [];809 attributes.forEach((attribute) => {810 if (attribute.value.trim().startsWith('{')) {811 inlineScriptAttributes.push({ name: attribute.name, value: attribute.value });812 }813 });814 if (inlineScriptAttributes.length === 0) return;815 element.setIsid();816 element.setInlineScriptAttributes(inlineScriptAttributes);817 },818 /**819 * Reads the first attribute of an element820 *821 * @returns the first attribute of the element or an empty string822 */823 getFirstAttributeName(element: HTMLElement): string {824 const attributes = element.attributes;825 if (attributes.length === 0) return '';826 return attributes[0].name;827 },828 //#endregion829 //#region Reaction830 /**831 * @returns if the element has the 'reacts' attribute.832 */833 hasReaction(element: HTMLElement): boolean {834 return element.hasAttribute('reacts');835 },836 //#endregion837 //#region Src attribute838 /**839 * Tag names that occupy the attribute 'src' by html standards.840 */841 tagNamesUsingSrcAttribute: ['AUDIO', 'EMBED', 'IFRAME', 'IMG', 'INPUT', 'SCRIPT', 'SOURCE', 'TRACK', 'VIDEO'],842 /**843 * @returns if the element's tag name uses a 'src' tag by html standards.844 */845 tagNameUsesSrcAttribute(element: HTMLElement): boolean {846 return InlineScript.tagNamesUsingSrcAttribute.includes(element.tagName);847 },848 /**849 * Checks if the element has a src attribute and ignores tag names that850 * already use this attribute for other purposes.851 */852 hasValidSrcAttribute(element: HTMLElement): boolean {853 return element.hasAttribute('src') && !InlineScript.tagNameUsesSrcAttribute(element);854 },855 /**856 * Sets the property 'inlineScriptSrc' on the element,857 */858 handleSrcAttribute(element: HTMLElement) {859 const src = element.getAttribute('src');860 element.inlineScriptSrc = src;861 element.setIsid();862 },863 //#endregion864 //#region Event attribute865 /**866 * @returns true if the element has an event attribute.867 * Event attributes are e.g.: 'onclick', 'onmousedown', ...868 */869 hasEventAttribute(element: HTMLElement): boolean {870 return Array.from(element.attributes).findIndex((attribute) => attribute.name.startsWith('on')) !== -1;871 },872 //#endregion873 //#region Inner html attribute874 /**875 * @returns true if the element has an 'innerhtml' attribute.876 */877 hasInnerHTMLAttribute(element: HTMLElement): boolean {878 return element.hasAttribute('innerhtml');879 },880 /**881 * Will set the inner html of the object to the innerhtml attribute or an empty string.882 */883 handleInnerHTMLAttribute(element: HTMLElement) {884 if (this.hasInnerHTMLAttribute(element)) element.innerHTML = element.getAttribute('innerhtml');885 else element.innerHTML = '';886 },887 //#endregion888 //#endregion889 //#region Inline script890 /**891 * @returns if an elements has a valid inline script syntax.892 */893 hasInlineScript(element: HTMLElement): boolean {894 return element.innerHTML.trim().startsWith('{');895 },896 /**897 * Checks if the element has a valid inline script syntax and then apply all necessary configurations898 * on the element.899 */900 checksInlineScript(element: HTMLElement) {901 if (!InlineScript.hasInlineScript(element)) return;902 element.setIsid();903 element.setInlineScript(InlineScript.compileHTMLSyntax(element.innerHTML, element));904 },905 //#endregion906 //#region Scan907 //#region Tag name908 //#region Function909 /**910 * Keeps track of all the function defined.911 */912 functions: {},913 /**914 * @returns true if the tagName of the element if 'function'915 */916 isFunction(element: HTMLElement): boolean {917 return element.tagName === 'FUNCTION';918 },919 /**920 * Pushes a function from the element in functions array.921 */922 compileFunction(element: HTMLElement): boolean {923 if (element.attributes.length < 1) return true;924 const name = element.attributes[0].name;925 InlineScript.functions[name.toUpperCase()] = element.innerHTML;926 return true;927 },928 /**929 * @returns true if the element is calling a function.930 */931 callsFunction(element: HTMLElement): boolean {932 return Object.keys(InlineScript.functions).includes(element.tagName);933 },934 /**935 * Sets everything necessary for the element to be identified to call a function.936 */937 handleCallsFunction(element: HTMLElement): any {938 element.functionName = element.tagName;939 },940 //#endregion941 //#region Preload942 /**943 * @returns true if the tagName of the element is 'preload'.944 */945 isPreLoad(element: HTMLElement): boolean {946 return element.tagName === 'PRELOAD';947 },948 /**949 * Pre loads the url in the src attribute of an element.950 */951 preLoad(element: HTMLElement): boolean {952 if (!element.hasAttribute('src')) return true;953 const src = element.getAttribute('src');954 const sync = element.hasAttribute('sync');955 if (sync) {956 InlineScript.loadFromUrlSync(src);957 return true;958 }959 ISPR.tasks++;960 InlineScript.loadFromUrl(src);961 return true;962 },963 //#endregion964 /**965 * Tag names that will get skipped during the scanning process.966 */967 ignoredTagNameList: ['SCRIPT', 'STYLE', 'LINK', 'META'],968 /**969 * Filters all tagNames that inlineScript should ignore e.g. script, style, ...970 */971 ignoreDueToTagName(element: HTMLElement): boolean {972 return InlineScript.ignoredTagNameList.includes(element.tagName);973 },974 /**975 * Scans the tagName of an element and handles it.976 *977 * @returns true, if the scan process should stop.978 */979 scanTagName(element: HTMLElement): boolean {980 if (InlineScript.ignoreDueToTagName(element)) return true;981 if (InlineScript.isFunction(element)) return InlineScript.compileFunction(element);982 if (InlineScript.callsFunction(element)) return InlineScript.handleCallsFunction(element);983 if (InlineScript.isPreLoad(element)) return InlineScript.preLoad(element);984 },985 //#endregion986 //#region General scan987 /**988 * Tells if the scan script should scan the children of an element.989 */990 shouldScanChildren(element: HTMLElement): boolean {991 return !element.hasInlineScript() && element.inlineScriptSrc === undefined && !element.callsFunction();992 },993 /**994 * A list of invalid parent tags for the script element to get executed using inline script.995 */996 invalidScriptParent: ['HEAD', 'BODY'],997 /**998 * @returns if an element is a script element and is not a children an invalid parent.999 */1000 isValidScriptTag(element: HTMLElement): boolean {1001 return element.tagName === 'SCRIPT' && !InlineScript.invalidScriptParent.includes(element.parentElement.tagName);1002 },1003 /**1004 * Filters from the HTMLCollection all elements that have a valid script tag.1005 *1006 * @param elements an HTMLCollection of elements that will get filtered.1007 *1008 * @returns an array of HTMLElements that has a valid script tag.1009 */1010 filterScripts(elements: HTMLCollection): Array<HTMLElement> {1011 const scriptElements = [];1012 for (const element of elements)1013 if (InlineScript.isValidScriptTag(element as HTMLElement)) scriptElements.push(element);1014 return scriptElements;1015 },1016 /**1017 * @returns true if the element or the parent element has the attribute static.1018 */1019 isStatic(element: HTMLElement): boolean {1020 return element.hasAttribute('static') || element.parentElement?.hasAttribute('static');1021 },1022 //#endregion1023 //#endregion1024 //#region Reaction1025 /**1026 * The refresh time of the reaction interval in milliseconds1027 */1028 REACTION_INTERVAL_TIME: 50,1029 //#endregion1030};1031//#endregion1032//#region Inline script instance1033/**1034 * This class is a recursively self-containing class.1035 * That means that the class will create multiple instances of it self and evaluate it.1036 * This is why defining variables in a new scope works.1037 */1038class InlineScriptInstance {1039 //#region Constructor1040 /**1041 * It will setup the reaction interval.1042 */1043 constructor() {1044 this.setupReaction();1045 }1046 //#endregion1047 //#region Reaction1048 reactiveElements: Record<string, Array<HTMLElement>> = {};1049 oldValues: Record<string, any> = {};1050 /**1051 * Sets up an interval that calls the reaction function.1052 *1053 * This function will get called automatically by the constructor.1054 */1055 setupReaction() {1056 setInterval(() => {1057 this.reaction();1058 }, InlineScript.REACTION_INTERVAL_TIME);1059 }1060 /**1061 * Checks for variable changes and re-renders all reacting elements.1062 */1063 reaction() {1064 for (const [varName, reactiveElements] of Object.entries(this.reactiveElements)) {1065 const varValue = eval(varName);1066 if (this.oldValues[varName] !== varValue) {1067 this.oldValues[varName] = varValue;1068 for (const reactiveElement of reactiveElements) {1069 function remove() {1070 reactiveElements[varName] = reactiveElements.filter((element: HTMLElement) => element === reactiveElement);1071 }1072 if (reactiveElement.parentElement === null) remove();1073 reactiveElement.render(false);1074 }1075 }1076 }1077 }1078 //#endregion1079 //#region Rendering1080 /**1081 * Looks up whats necessary for the rendering process of the element and applies that.1082 */1083 setRenderFunction(element: HTMLElement) {1084 const that = this;1085 element.setIsid();1086 let newVars: Record<string, any> = {};1087 element.render = function (calledAutomatically: boolean = false) {1088 /**1089 * If the element is static then don't execute the render function.1090 */1091 if (element.static) return;1092 /**1093 * Render the attributes.1094 */1095 element.inlineScriptAttributes?.forEach(({ name, value }) => {1096 try {1097 const res = InlineScript.handleResult(eval(value));1098 element.setAttribute(name, res);1099 } catch (err) {}1100 });1101 if (InlineScript.isFunction(element)) return;1102 /**1103 * If the element has a fixed 'innerHTML' then apply that and return1104 */1105 if (element.fixedHTML) return InlineScript.handleInnerHTMLAttribute(element);1106 /**1107 * If the element generates child-elements then generate the following variables:1108 *1109 * innerHTML: the innerHTML after the element gets rendered.1110 * args: the attributes of the element as object.1111 */1112 if (InlineScript.generatesChildElements(element)) {1113 /**1114 * Sets the innerHTML1115 */1116 const virtualElement = document.createElement('div');1117 virtualElement.innerHTML = element.innerHTML;1118 that.scan(virtualElement);1119 newVars.innerHTML = virtualElement.innerHTML;1120 /**1121 * Sets the attributes1122 */1123 newVars.args = InlineScript.getAttributesFromElementsAsObject(this);1124 }1125 /**1126 * If the element calls a function1127 */1128 if (element.callsFunction()) {1129 /**1130 * These variables may get used inside the eval function.1131 */1132 const { innerHTML, args } = newVars;1133 element.innerHTML = InlineScript.functions[element.functionName];1134 eval(1135 InlineScriptInstance +1136 InlineScript.generateEvalPreCode(element) +1137 'new InlineScriptInstance().scanAll(element.children)'1138 );1139 return;1140 }1141 /**1142 * If the code has inline script1143 */1144 if (element.hasInlineScript()) {1145 try {1146 InlineScript.handleEvalResult(element, eval(element.inlineScript), true);1147 } catch (err) {1148 InlineScript.handleExceptionResult(element, err);1149 }1150 return;1151 }1152 /**1153 * If the element contains a valid 'src' attribute.1154 */1155 if (element.inlineScriptSrc !== undefined) {1156 ISPR.tasks++;1157 return InlineScript.loadFromUrl(element.inlineScriptSrc).then((content: string) => {1158 /**1159 * These variables may get used inside the eval function.1160 */1161 const { innerHTML, args } = newVars;1162 InlineScript.handleEvalResult(1163 element,1164 eval(1165 InlineScriptInstance +1166 InlineScript.generateEvalPreCode(element) +1167 'new InlineScriptInstance().fromString(element,`' +1168 InlineScript.escapeAll(content) +1169 '`);'1170 ),1171 true1172 );1173 });1174 }1175 /**1176 * If the function got called manually then scan it.1177 */1178 if (!calledAutomatically) that.scan(element);1179 };1180 }1181 //#endregion1182 //#region Attributes1183 /**1184 * Handles diverse attribute events:1185 * - Reactions1186 * - Src attributes1187 * - Event attributes1188 * - Inner html attributes1189 *1190 * This script is in InlineScriptInstance and not in InlineScript because it need variables1191 * that are inside the InlineScriptInstance class as well as it defines functions that should1192 * be in the same scope as the render function.1193 */1194 handleAttributes(element: HTMLElement) {1195 if (InlineScript.hasReaction(element)) this.addReaction(element);1196 if (InlineScript.hasValidSrcAttribute(element)) InlineScript.handleSrcAttribute(element);1197 if (InlineScript.hasEventAttribute(element)) this.handleEventAttributes(element);1198 if (InlineScript.hasInnerHTMLAttribute(element)) element.fixedHTML = true;1199 }1200 /**1201 * Adds an element to a reaction list.1202 *1203 * @param element the element that should react to a variable change.1204 */1205 addReaction(element: HTMLElement) {1206 const varName = element.getAttribute('reacts');1207 if (this.reactiveElements[varName] === undefined) this.reactiveElements[varName] = [];1208 this.reactiveElements[varName].push(element);1209 }1210 /**1211 * Gets all event attributes and rewrites them using the 'setAttribute' function.1212 * This will put the event in a scope so it can use outer variables.1213 * If an event is declared but it has no content then the content of the inline script1214 * will get executed whenever the event gets called but not automatically.1215 * In the scenario you can use the attribute 'innerHTML' to set the content of your element.1216 * If you need both to be written in the inline script syntax consider writing:1217 * this.onclick = function() { ... }1218 * in the inline script syntax.1219 */1220 handleEventAttributes(element: HTMLElement) {1221 const attributes = Array.from(element.attributes).filter((attribute) => attribute.name.startsWith('on'));1222 attributes.forEach((attribute) => {1223 let value = attribute.value;1224 if (!value) {1225 value = element.inlineScript;1226 element.fixedHTML = true;1227 }1228 if (value === '/**/') return;1229 element.setAttribute(attribute.name, '/**/');1230 element[attribute.name] = function (event: Event) {1231 eval(value);1232 };1233 });1234 }1235 //#endregion1236 //#region Scan1237 /**1238 * Scans a html element.1239 *1240 * @param element the element that will get scanned.1241 * @param recursive if true the child elements will get scanned as well.1242 */1243 scan(element: HTMLElement, recursive: boolean = true) {1244 if (element === undefined) return;1245 if (InlineScript.scanTagName(element)) return;1246 InlineScript.scanAttributes(element);1247 InlineScript.checksInlineScript(element);1248 this.setRenderFunction(element);1249 this.handleAttributes(element);1250 /**1251 * If the element should be static then apply the static attribute on the element.1252 * This is important because if this element generates child elements they will try1253 * to figure out if their parent element (this element) has the static attribute.1254 */1255 if (InlineScript.isStatic(element)) element.setAttribute('static', 'true');1256 /**1257 * Render the element and set the argument 'renderedAutomatically' to true so that the1258 * element will not scan itself again and overflow the maximum call stack size.1259 */1260 element.render(true);1261 /**1262 * Add the element to the pre renderer script.1263 */1264 ISPR.addElement(element);1265 /**1266 * If the element is static apply the static property so that the element will not get1267 * rendered again.1268 */1269 if (element.hasAttribute('static')) element.static = true;1270 if (recursive && InlineScript.shouldScanChildren(element)) this.scanAll(element.children);1271 }1272 /**1273 * Runs the scan function on all html elements1274 */1275 scanAll(elements: HTMLCollection) {1276 const scriptElements = InlineScript.filterScripts(elements);1277 const parentElement = elements[0]?.parentElement;1278 parentElement?.setIsid();1279 if (scriptElements.length !== 0) {1280 const elementsLeft = Array.from(elements).filter((element: HTMLElement) => !scriptElements.includes(element));1281 (function () {1282 eval(1283 scriptElements.map((scriptElement) => scriptElement.innerHTML + ';\n').join('') +1284 InlineScriptInstance +1285 'new InlineScriptInstance().scanAll(elementsLeft)'1286 );1287 }.call(parentElement));1288 return;1289 }1290 for (const element of elements) {1291 if (element.hasAttribute('dynamic')) {1292 InlineScript.newInlineScript(element as HTMLElement);1293 } else {1294 this.scan(element as HTMLElement);1295 }1296 }1297 }1298 /**1299 * Creates elements from a string and scans them.1300 *1301 * @param stringElement the elements as string.1302 */1303 fromString(parent: HTMLElement, stringElement: string) {1304 const elements = InlineScript.createElements(stringElement);1305 InlineScript.sanitizeScriptElements(elements);1306 /**1307 * Sets the elements to static if the parent element is static.1308 */1309 if (parent.hasAttribute('static')) {1310 for (const element of elements) {1311 element.setAttribute('static', 'true');1312 }1313 }1314 this.scanAll(elements);1315 return elements;1316 }1317 //#endregion1318}1319//#endregion1320//#region Call inline script1321window.addEventListener('load', () => {1322 if (inlineScriptGotPreRendered !== true) inlineScript();1323});1324//#endregion...

Full Screen

Full Screen

inline-script.js

Source:inline-script.js Github

copy

Full Screen

...75 InlineScript.removeFromCache(url);76 this.inlineScriptSrc = url;77 this.render(true);78};79function inlineScript() {80 if (compiledInlineScript)81 return;82 compiledInlineScript = true;83 const inlineScript = new InlineScriptInstance();84 [document.head, document.body].forEach((element) => inlineScript.scan(element));85 ScopedCss.scopeAllStyles();86 ISPR.finish();87}88var compiledInlineScript = false;89var ISPR = {90 tasks: 0,91 addElement() { },92 finish() { },93};94const state = {95 render() {96 Array.from(document.body.children).forEach((element) => {97 if (element.render !== undefined)98 element.render();99 });100 },101};102const inlineScriptCss = document.createElement('style');103document.head.appendChild(inlineScriptCss);104inlineScriptCss.innerHTML += `function, preload { display: none !important; }`;105const ScopedCss = {106 SCOPED_CSS_PREFIX: 'scoped-css-id-',107 scopedCSSId: 0,108 cssCommentsRegex: /\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*\/+/gm,109 removeAllCssComments(css) {110 return css.replace(ScopedCss.cssCommentsRegex, '');111 },112 scope(scope, css) {113 css = ScopedCss.removeAllCssComments(css);114 const regex = /([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g;115 let m;116 while ((m = regex.exec(css)) !== null) {117 if (m.index === regex.lastIndex)118 regex.lastIndex++;119 let match = m[0].trim();120 const index = m.index;121 if (!match.startsWith('@') &&122 !match.startsWith('from') &&123 !match.startsWith('to') &&124 !/[\d]/.test(match.substr(0, 1))) {125 let end = css.substr(index).trim();126 if (end.startsWith('#this'))127 end = end.substr(6);128 css = css.substring(0, index) + scope + ' ' + end;129 regex.lastIndex += scope.length + 1;130 }131 }132 return css;133 },134 getUniqueStyleClassName() {135 return ScopedCss.SCOPED_CSS_PREFIX + ScopedCss.scopedCSSId++;136 },137 getScopedStyleElements(parent) {138 return Array.from(parent.querySelectorAll('style[scoped]'));139 },140 scopeStyle(element) {141 const uniqueStyleClassName = ScopedCss.getUniqueStyleClassName();142 element.parentElement.classList.add(uniqueStyleClassName);143 element.innerHTML = ScopedCss.scope('.' + uniqueStyleClassName, element.innerHTML);144 element.removeAttribute('scoped');145 },146 scopeStyles(parent) {147 let styles = ScopedCss.getScopedStyleElements(parent);148 styles.forEach(ScopedCss.scopeStyle);149 styles = Array.from(parent.querySelectorAll('style[scope]'));150 },151 scopeAllStyles() {152 ScopedCss.scopeStyles(document.querySelector('html'));153 },154};155const InlineScript = {156 $x(xpath, parent) {157 let results = [];158 parent = parent || document;159 let query = document.evaluate(xpath, parent, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);160 for (let i = 0, length = query.snapshotLength; i < length; ++i) {161 results.push(query.snapshotItem(i));162 }163 return results;164 },165 reverseSanitationReplaceList: {166 '\\&gt;': '>',167 '\\&lt;': '<',168 },169 reverseSanitation(html) {170 for (const [regex, replacement] of Object.entries(InlineScript.reverseSanitationReplaceList))171 html = html.replace(new RegExp(regex, 'gm'), replacement);172 return html;173 },174 escapeAll(string) {175 return string176 .replace(/\\/gm, '\\\\')177 .replace(/\$/gm, '\\$')178 .replace(/'/gm, "\\'")179 .replace(/"/gm, '\\"')180 .replace(/`/gm, '\\`');181 },182 createElements(stringElement) {183 const parent = document.createElement('div');184 parent.innerHTML = '<div>' + stringElement + '</div>';185 return parent.firstChild.children;186 },187 sanitizeScriptElements(collection) {188 for (const element of collection) {189 if (element.tagName === 'SCRIPT') {190 element.setAttribute('src', '');191 }192 }193 },194 getAttributesFromElementsAsObject(element) {195 let output = {};196 Array.from(element.attributes).forEach(({ name, value }) => {197 output[name] = value;198 });199 return output;200 },201 setAttributesFromObject(element, attributes) {202 Object.entries(attributes).forEach(([name, value]) => {203 element.setAttribute(name, value);204 });205 },206 substringThrow(string, start, length = undefined) {207 const res = string.substr(start, length);208 if (res === '')209 throw 'substring is out of bounce.';210 return res;211 },212 newInlineScript(element) {213 new InlineScriptInstance().scan(element);214 },215 srcCache: {},216 fetch(url) {217 return __awaiter(this, void 0, void 0, function* () {218 var xmlHttp = new XMLHttpRequest();219 xmlHttp.open('GET', url, true);220 xmlHttp.send(null);221 return new Promise((resolve, reject) => {222 xmlHttp.onload = () => {223 resolve(xmlHttp.responseText);224 };225 setTimeout(() => {226 reject();227 }, 1000);228 });229 });230 },231 fetchSync(url) {232 var xmlHttp = new XMLHttpRequest();233 xmlHttp.open('GET', url, false);234 xmlHttp.send(null);235 return xmlHttp.responseText;236 },237 loadFromUrl(url, forceFetch = false) {238 return __awaiter(this, void 0, void 0, function* () {239 let res;240 if (InlineScript.srcCache[url] === undefined || forceFetch)241 res = yield InlineScript.fetch(url);242 else243 res = InlineScript.srcCache[url];244 ISPR.tasks--;245 InlineScript.srcCache[url] = res;246 return res;247 });248 },249 loadFromUrlSync(url, forceFetch = false) {250 let res;251 if (InlineScript.srcCache[url] === undefined || forceFetch)252 res = InlineScript.fetchSync(url);253 else254 res = InlineScript.srcCache[url];255 ISPR.tasks--;256 InlineScript.srcCache[url] = res;257 return res;258 },259 removeFromCache(url) {260 InlineScript.srcCache[url] = undefined;261 },262 ISID_ATTRIBUTE_NAME: 'isid',263 isid: 0,264 insertLexingResult(string, lexingResult) {265 return (string.substr(0, lexingResult.index) +266 lexingResult.content +267 string.substr(lexingResult.index + lexingResult.length));268 },269 generateEvalPreCode(parentElement) {270 let evalCode = '';271 evalCode +=272 "let parent=document.querySelector('[" + InlineScript.ISID_ATTRIBUTE_NAME + '="' + parentElement.isid + '"]\');';273 evalCode += 'let scope=parent,__parent=parent;';274 evalCode += 'let state={render(){Array.from(parent.children).forEach(_=>_.render&&_.render())}};';275 return evalCode;276 },277 removeEmptySpace(string) {278 return string.replace(/\n|\s/gm, '');279 },280 convertHTMLSyntaxResultContent(content, element) {281 return ('eval(InlineScriptInstance+`' +282 InlineScript.generateEvalPreCode(element) +283 'new InlineScriptInstance().fromString(element,\\`' +284 content.substring(1, content.length - 1) +285 '\\`)`)');286 },287 scanHTMLSyntax(string, startIndex) {288 let result = {289 index: null,290 length: null,291 content: null,292 };293 try {294 let depth = 0;295 for (let i = startIndex; i < string.length; i++) {296 const c = InlineScript.substringThrow(string, i, 1);297 const cc = InlineScript.substringThrow(string, i, 2);298 if (['"', "'", '¸'].includes(c)) {299 const quote = c;300 i++;301 while (InlineScript.substringThrow(string, i, 1) !== quote ||302 InlineScript.substringThrow(string, i - 1, 1) === '\\')303 i++;304 }305 if (cc === '//')306 while (InlineScript.substringThrow(string, i, 1) !== '\n')307 i++;308 if (InlineScript.substringThrow(string, i, 4) === '<!--')309 while (InlineScript.substringThrow(string, i, 1) !== '\n')310 i++;311 if (cc === '/*')312 while (InlineScript.substringThrow(string, i, 2) !== '*/')313 i++;314 while (InlineScript.substringThrow(string, i, 1) === '(') {315 const bracketIndex = i;316 i++;317 while (/\s|\r/.test(InlineScript.substringThrow(string, i, 1)))318 i++;319 if (InlineScript.substringThrow(string, i, 1) === '<') {320 depth++;321 if (depth === 1)322 result.index = bracketIndex;323 }324 }325 while (InlineScript.substringThrow(string, i, 1) === '>' && depth > 0) {326 i++;327 while (/\s|\r/.test(InlineScript.substringThrow(string, i, 1)))328 i++;329 if (InlineScript.substringThrow(string, i, 1) === ')') {330 depth--;331 if (depth === 0) {332 result.length = i + 1 - result.index;333 result.content = string.substr(result.index, result.length);334 result.content = InlineScript.escapeAll(InlineScript.escapeAll(result.content));335 return result;336 }337 }338 }339 }340 }341 catch (_a) { }342 return null;343 },344 compileHTMLSyntax(inlineScript, element) {345 inlineScript = InlineScript.reverseSanitation(inlineScript);346 let lexingResult, lastIndex = 0;347 while ((lexingResult = InlineScript.scanHTMLSyntax(inlineScript, lastIndex))) {348 lexingResult.content = InlineScript.convertHTMLSyntaxResultContent(lexingResult.content, element);349 inlineScript = InlineScript.insertLexingResult(inlineScript, lexingResult);350 lastIndex = lexingResult.index + lexingResult.content.length;351 }352 return inlineScript;353 },354 generatesChildElements(element) {355 return element.functionName !== undefined || element.inlineScriptSrc !== undefined;356 },357 evalResultHandler: {358 handleEvalResultUndefined(element, result) {359 return result === undefined;360 },361 handleEvalResultHTMLCollection(element, result) {362 if (!(result instanceof HTMLCollection))363 return;364 Array.from(result).forEach((child) => element.append(child));365 ScopedCss.scopeStyles(element);366 return true;367 },368 handleEvalResultHTMLElement(element, result) {369 if (!(result instanceof HTMLElement))370 return;371 element.append(result);372 ScopedCss.scopeStyles(element);373 return true;374 },375 handleEvalResultArray(element, result) {376 if (!(result instanceof Array))377 return;378 result.forEach((child) => {379 InlineScript.handleEvalResult(element, child);380 });381 return true;382 },383 handleEvalResultPromise(element, result) {384 if (!(result instanceof Promise))385 return;386 ISPR.tasks++;387 result388 .then((res) => {389 ISPR.tasks--;390 InlineScript.handleEvalResult(element, res);391 })392 .catch((res) => {393 ISPR.tasks--;394 InlineScript.handleExceptionResult(element, res);395 });396 return true;397 },398 },399 handleEvalResult(element, result, clear = false) {400 if (clear)401 element.innerHTML = '';402 for (const [functionName, functionValue] of Object.entries(this.evalResultHandler)) {403 if (functionValue(element, result))404 return;405 }406 element.innerHTML += result.toString();407 return;408 },409 handleResult(result) {410 if (result === undefined)411 return '';412 if (typeof result === 'string')413 return result;414 if (typeof result === 'number')415 return result.toString();416 if (result instanceof Array)417 return result.join('');418 return JSON.stringify(result);419 },420 handleExceptionResult(element, error) {421 console.error(error);422 element.style.background = 'red';423 element.style.color = 'yellow';424 element.style.fontSize = '20px';425 element.innerHTML = error;426 },427 scanAttributes(element) {428 const attributes = Array.from(element.attributes);429 const inlineScriptAttributes = [];430 attributes.forEach((attribute) => {431 if (attribute.value.trim().startsWith('{')) {432 inlineScriptAttributes.push({ name: attribute.name, value: attribute.value });433 }434 });435 if (inlineScriptAttributes.length === 0)436 return;437 element.setIsid();438 element.setInlineScriptAttributes(inlineScriptAttributes);439 },440 getFirstAttributeName(element) {441 const attributes = element.attributes;442 if (attributes.length === 0)443 return '';444 return attributes[0].name;445 },446 hasReaction(element) {447 return element.hasAttribute('reacts');448 },449 tagNamesUsingSrcAttribute: ['AUDIO', 'EMBED', 'IFRAME', 'IMG', 'INPUT', 'SCRIPT', 'SOURCE', 'TRACK', 'VIDEO'],450 tagNameUsesSrcAttribute(element) {451 return InlineScript.tagNamesUsingSrcAttribute.includes(element.tagName);452 },453 hasValidSrcAttribute(element) {454 return element.hasAttribute('src') && !InlineScript.tagNameUsesSrcAttribute(element);455 },456 handleSrcAttribute(element) {457 const src = element.getAttribute('src');458 element.inlineScriptSrc = src;459 element.setIsid();460 },461 hasEventAttribute(element) {462 return Array.from(element.attributes).findIndex((attribute) => attribute.name.startsWith('on')) !== -1;463 },464 hasInnerHTMLAttribute(element) {465 return element.hasAttribute('innerhtml');466 },467 handleInnerHTMLAttribute(element) {468 if (this.hasInnerHTMLAttribute(element))469 element.innerHTML = element.getAttribute('innerhtml');470 else471 element.innerHTML = '';472 },473 hasInlineScript(element) {474 return element.innerHTML.trim().startsWith('{');475 },476 checksInlineScript(element) {477 if (!InlineScript.hasInlineScript(element))478 return;479 element.setIsid();480 element.setInlineScript(InlineScript.compileHTMLSyntax(element.innerHTML, element));481 },482 functions: {},483 isFunction(element) {484 return element.tagName === 'FUNCTION';485 },486 compileFunction(element) {487 if (element.attributes.length < 1)488 return true;489 const name = element.attributes[0].name;490 InlineScript.functions[name.toUpperCase()] = element.innerHTML;491 return true;492 },493 callsFunction(element) {494 return Object.keys(InlineScript.functions).includes(element.tagName);495 },496 handleCallsFunction(element) {497 element.functionName = element.tagName;498 },499 isPreLoad(element) {500 return element.tagName === 'PRELOAD';501 },502 preLoad(element) {503 if (!element.hasAttribute('src'))504 return true;505 const src = element.getAttribute('src');506 const sync = element.hasAttribute('sync');507 if (sync) {508 InlineScript.loadFromUrlSync(src);509 return true;510 }511 ISPR.tasks++;512 InlineScript.loadFromUrl(src);513 return true;514 },515 ignoredTagNameList: ['SCRIPT', 'STYLE', 'LINK', 'META'],516 ignoreDueToTagName(element) {517 return InlineScript.ignoredTagNameList.includes(element.tagName);518 },519 scanTagName(element) {520 if (InlineScript.ignoreDueToTagName(element))521 return true;522 if (InlineScript.isFunction(element))523 return InlineScript.compileFunction(element);524 if (InlineScript.callsFunction(element))525 return InlineScript.handleCallsFunction(element);526 if (InlineScript.isPreLoad(element))527 return InlineScript.preLoad(element);528 },529 shouldScanChildren(element) {530 return !element.hasInlineScript() && element.inlineScriptSrc === undefined && !element.callsFunction();531 },532 invalidScriptParent: ['HEAD', 'BODY'],533 isValidScriptTag(element) {534 return element.tagName === 'SCRIPT' && !InlineScript.invalidScriptParent.includes(element.parentElement.tagName);535 },536 filterScripts(elements) {537 const scriptElements = [];538 for (const element of elements)539 if (InlineScript.isValidScriptTag(element))540 scriptElements.push(element);541 return scriptElements;542 },543 isStatic(element) {544 var _a;545 return element.hasAttribute('static') || ((_a = element.parentElement) === null || _a === void 0 ? void 0 : _a.hasAttribute('static'));546 },547 REACTION_INTERVAL_TIME: 50,548};549class InlineScriptInstance {550 constructor() {551 this.reactiveElements = {};552 this.oldValues = {};553 this.setupReaction();554 }555 setupReaction() {556 setInterval(() => {557 this.reaction();558 }, InlineScript.REACTION_INTERVAL_TIME);559 }560 reaction() {561 for (const [varName, reactiveElements] of Object.entries(this.reactiveElements)) {562 const varValue = eval(varName);563 if (this.oldValues[varName] !== varValue) {564 this.oldValues[varName] = varValue;565 for (const reactiveElement of reactiveElements) {566 function remove() {567 reactiveElements[varName] = reactiveElements.filter((element) => element === reactiveElement);568 }569 if (reactiveElement.parentElement === null)570 remove();571 reactiveElement.render(false);572 }573 }574 }575 }576 setRenderFunction(element) {577 const that = this;578 element.setIsid();579 let newVars = {};580 element.render = function (calledAutomatically = false) {581 var _a;582 if (element.static)583 return;584 (_a = element.inlineScriptAttributes) === null || _a === void 0 ? void 0 : _a.forEach(({ name, value }) => {585 try {586 const res = InlineScript.handleResult(eval(value));587 element.setAttribute(name, res);588 }589 catch (err) { }590 });591 if (InlineScript.isFunction(element))592 return;593 if (element.fixedHTML)594 return InlineScript.handleInnerHTMLAttribute(element);595 if (InlineScript.generatesChildElements(element)) {596 const virtualElement = document.createElement('div');597 virtualElement.innerHTML = element.innerHTML;598 that.scan(virtualElement);599 newVars.innerHTML = virtualElement.innerHTML;600 newVars.args = InlineScript.getAttributesFromElementsAsObject(this);601 }602 if (element.callsFunction()) {603 const { innerHTML, args } = newVars;604 element.innerHTML = InlineScript.functions[element.functionName];605 eval(InlineScriptInstance +606 InlineScript.generateEvalPreCode(element) +607 'new InlineScriptInstance().scanAll(element.children)');608 return;609 }610 if (element.hasInlineScript()) {611 try {612 InlineScript.handleEvalResult(element, eval(element.inlineScript), true);613 }614 catch (err) {615 InlineScript.handleExceptionResult(element, err);616 }617 return;618 }619 if (element.inlineScriptSrc !== undefined) {620 ISPR.tasks++;621 return InlineScript.loadFromUrl(element.inlineScriptSrc).then((content) => {622 const { innerHTML, args } = newVars;623 InlineScript.handleEvalResult(element, eval(InlineScriptInstance +624 InlineScript.generateEvalPreCode(element) +625 'new InlineScriptInstance().fromString(element,`' +626 InlineScript.escapeAll(content) +627 '`);'), true);628 });629 }630 if (!calledAutomatically)631 that.scan(element);632 };633 }634 handleAttributes(element) {635 if (InlineScript.hasReaction(element))636 this.addReaction(element);637 if (InlineScript.hasValidSrcAttribute(element))638 InlineScript.handleSrcAttribute(element);639 if (InlineScript.hasEventAttribute(element))640 this.handleEventAttributes(element);641 if (InlineScript.hasInnerHTMLAttribute(element))642 element.fixedHTML = true;643 }644 addReaction(element) {645 const varName = element.getAttribute('reacts');646 if (this.reactiveElements[varName] === undefined)647 this.reactiveElements[varName] = [];648 this.reactiveElements[varName].push(element);649 }650 handleEventAttributes(element) {651 const attributes = Array.from(element.attributes).filter((attribute) => attribute.name.startsWith('on'));652 attributes.forEach((attribute) => {653 let value = attribute.value;654 if (!value) {655 value = element.inlineScript;656 element.fixedHTML = true;657 }658 if (value === '/**/')659 return;660 element.setAttribute(attribute.name, '/**/');661 element[attribute.name] = function (event) {662 eval(value);663 };664 });665 }666 scan(element, recursive = true) {667 if (element === undefined)668 return;669 if (InlineScript.scanTagName(element))670 return;671 InlineScript.scanAttributes(element);672 InlineScript.checksInlineScript(element);673 this.setRenderFunction(element);674 this.handleAttributes(element);675 if (InlineScript.isStatic(element))676 element.setAttribute('static', 'true');677 element.render(true);678 ISPR.addElement(element);679 if (element.hasAttribute('static'))680 element.static = true;681 if (recursive && InlineScript.shouldScanChildren(element))682 this.scanAll(element.children);683 }684 scanAll(elements) {685 var _a;686 const scriptElements = InlineScript.filterScripts(elements);687 const parentElement = (_a = elements[0]) === null || _a === void 0 ? void 0 : _a.parentElement;688 parentElement === null || parentElement === void 0 ? void 0 : parentElement.setIsid();689 if (scriptElements.length !== 0) {690 const elementsLeft = Array.from(elements).filter((element) => !scriptElements.includes(element));691 (function () {692 eval(scriptElements.map((scriptElement) => scriptElement.innerHTML + ';\n').join('') +693 InlineScriptInstance +694 'new InlineScriptInstance().scanAll(elementsLeft)');695 }.call(parentElement));696 return;697 }698 for (const element of elements) {699 if (element.hasAttribute('dynamic')) {700 InlineScript.newInlineScript(element);701 }702 else {703 this.scan(element);704 }705 }706 }707 fromString(parent, stringElement) {708 const elements = InlineScript.createElements(stringElement);709 InlineScript.sanitizeScriptElements(elements);710 if (parent.hasAttribute('static')) {711 for (const element of elements) {712 element.setAttribute('static', 'true');713 }714 }715 this.scanAll(elements);716 return elements;717 }718}719window.addEventListener('load', () => {720 if (inlineScriptGotPreRendered !== true)721 inlineScript();...

Full Screen

Full Screen

INLINE_SCRIPT.ts

Source:INLINE_SCRIPT.ts Github

copy

Full Screen

1import {2 CODE,3 Range,4 STATE,5 StateDefinition,6 Meta,7 matchesCloseCurlyBrace,8} from "../internal";9interface ScriptletMeta extends Meta {10 block: boolean;11 value: Range;12}13export const INLINE_SCRIPT: StateDefinition<ScriptletMeta> = {14 name: "INLINE_SCRIPT",15 enter(parent, start) {16 this.endText();17 return {18 state: INLINE_SCRIPT as StateDefinition,19 parent,20 start,21 end: start,22 block: false,23 value: {24 start,25 end: start,26 },27 };28 },29 exit(inlineScript) {30 this.options.onScriptlet?.({31 start: inlineScript.start,32 end: inlineScript.end,33 block: inlineScript.block,34 value: {35 start: inlineScript.value.start,36 end: inlineScript.value.end,37 },38 });39 },40 eol() {},41 eof() {},42 char(code, inlineScript) {43 this.forward = 0;44 if (code === CODE.OPEN_CURLY_BRACE) {45 inlineScript.block = true;46 this.pos++; // skip {47 this.enterState(STATE.EXPRESSION).shouldTerminate =48 matchesCloseCurlyBrace;49 } else {50 const expr = this.enterState(STATE.EXPRESSION);51 expr.operators = true;52 expr.terminatedByEOL = true;53 }54 },55 return(child, inlineScript) {56 if (inlineScript.block) this.pos++; // skip }57 inlineScript.value.start = child.start;58 inlineScript.value.end = child.end;59 this.exitState();60 },...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('webpagetest');2var wpt = new WebPageTest('www.webpagetest.org');3var options = {4};5wpt.runTest(url, options, function (err, data) {6 if (err) {7 console.log('Error: ' + err);8 } else {9 console.log('Test Results: ' + JSON.stringify(data));10 }11});12var wpt = require('webpagetest');13var wpt = new WebPageTest('www.webpagetest.org');14var options = {15};16wpt.runTest(url, options, function (err, data) {17 if (err) {18 console.log('Error: ' + err);19 } else {20 console.log('Test Results: ' + JSON.stringify(data));21 }22});23var wpt = require('webpagetest');24var wpt = new WebPageTest('www.webpagetest.org');25var options = {26};27wpt.runTest(url, options, function (err, data) {28 if (err) {29 console.log('Error: ' + err);30 } else {31 console.log('Test Results: ' + JSON.stringify(data));32 }33});34var wpt = require('

Full Screen

Using AI Code Generation

copy

Full Screen

1wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');2wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');3wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');4wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');5wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');6wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');7wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');8wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');9wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');10wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');11wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');12wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');13wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');14wptHook.inlineScript('document.getElementById("test").innerHTML = "Hello World";');

Full Screen

Using AI Code Generation

copy

Full Screen

1var wptdriver = require('./wptdriver.js');2wptdriver.inlineScript('window.alert("Hello World");');3var wptdriver = require('./wptdriver.js');4wptdriver.runScript('test.js', 'window.alert("Hello World");');5var wptdriver = require('./wptdriver.js');6wptdriver.runScript('test.js', 'window.alert("Hello World");');7var wptdriver = require('./wptdriver.js');8wptdriver.runScript('test.js', 'window.alert("Hello World");');9var wptdriver = require('./wptdriver.js');10wptdriver.runScript('test.js', 'window.alert("Hello World");');11var wptdriver = require('./wptdriver.js');12wptdriver.runScript('test.js', 'window.alert("Hello World");');13var wptdriver = require('./wptdriver.js');14wptdriver.runScript('test.js', 'window.alert("Hello World");');15var wptdriver = require('./wptdriver.js');16wptdriver.runScript('test.js', 'window.alert("Hello World");');17var wptdriver = require('./wptdriver.js');18wptdriver.runScript('test.js', 'window.alert("Hello World");');19var wptdriver = require('./wptdriver.js');20wptdriver.runScript('test.js', 'window.alert("Hello World");');21var wptdriver = require('./wptdriver.js');22wptdriver.runScript('test.js

Full Screen

Using AI Code Generation

copy

Full Screen

1var wpt = require('wptdriver');2wpt.inlineScript('alert("hello world");');3 if (err) {4 console.log(err);5 } else {6 console.log(data);7 }8});9var wpt = require('wptdriver');10wpt.inlineScript('alert("hello world");');11 if (err) {12 console.log(err);13 } else {14 console.log(data);15 }16});17var wpt = require('wptdriver');18wpt.inlineScript('alert("hello world");');19 if (err) {20 console.log(err);21 } else {22 console.log(data);23 }24});25var wpt = require('wptdriver');26wpt.inlineScript('alert("hello world");');27 if (err) {28 console.log(err);29 } else {30 console.log(data);31 }32});33var wpt = require('wptdriver');34wpt.inlineScript('alert("hello world");');35 if (err) {36 console.log(err);37 } else {38 console.log(data);39 }40});41var wpt = require('wptdriver');42wpt.inlineScript('alert("hello world");');43 if (err) {44 console.log(err);45 } else {46 console.log(data);47 }48});

Full Screen

Using AI Code Generation

copy

Full Screen

1wpt.inlineScript('var a = 1;');2wpt.inlineScript('var a = 1;');3wpt.inlineScript('var a = 1;');4wpt.inlineScript('var a = 1;');5wpt.inlineScript('var a = 1;');6wpt.inlineScript('var a = 1;');7wpt.inlineScript('var a = 1;');8wpt.inlineScript('var a = 1;');9wpt.inlineScript('var a = 1;');10wpt.inlineScript('var a = 1;');11wpt.inlineScript('var a = 1;');12wpt.inlineScript('var a = 1;');

Full Screen

Using AI Code Generation

copy

Full Screen

1var driver = require('wptdriver');2test.run(function () {3 driver.inlineScript('inlineScript.js');4});5console.log('hello from inlineScript.js');6var driver = require('wptdriver');7test.run(function () {8});9test.run(function () {10});11test.run(function () {12 driver.inlineScript('myScript.js');13});14test.run(function () {15 driver.inlineScript('myScript.js', { param1: 'value1', param2: 'value2' });16});17test.run(function () {18 driver.inlineScript('myScript.js', { param1: 'value1', param2: 'value2' }, function (result) {19 console.log(result);20 });21});22test.run(function () {23 driver.inlineScript('myScript.js', { param1: 'value1', param2: 'value2' }, function (result) {24 console.log(result);25 });26});

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run wpt automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful