UNPKG

siesta-lite

Version:

Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers

610 lines (415 loc) 21.5 kB
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>The source code</title> <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="../resources/prettify/prettify.js"></script> <style type="text/css"> .highlight { display: block; background-color: #ddd; } </style> <script type="text/javascript"> function highlight() { document.getElementById(location.hash.replace(/#/, "")).className = "highlight"; } </script> </head> <body onload="prettyPrint(); highlight();"> <pre class="prettyprint lang-js">/* Siesta 5.6.1 Copyright(c) 2009-2022 Bryntum AB https://bryntum.com/contact https://bryntum.com/products/siesta/license */ Role(&#39;Scope.Provider.Role.WithDOM&#39;, { requires : [ &#39;getDocument&#39;, &#39;create&#39;, &#39;getPreload&#39;, &#39;isAlreadySetUp&#39;, &#39;setViewportSize&#39; ], has : { useStrictMode : true, sourceURL : null, crossOriginFailed : false, innerHtmlHead : null, innerHtmlBody : null, minViewportSize : null, parentWindow : function () { return window }, scopeId : function () { return Math.round(Math.random() * 1e10) }, failOnResourceLoadError : false, failOnPromiseRejection : true, // init function attachToOnError : function () { // returns the value of the attribute // the &quot;handler&quot; argument is no longer used, its now being taken from the __ONERROR__ handler every time return function (window, scopeId, handler, preventDefault, failOnResourceLoadError, failOnPromiseRejection) { handler = (window.opener || window.parent).Scope.Provider.__ONERROR__[ scopeId ] if (failOnResourceLoadError &amp;&amp; (&quot;ErrorEvent&quot; in window)) { // if (window.ErrorEvent.__SIESTA_HOOK_INSTALLED__) return // http://stackoverflow.com/questions/8504673/how-to-detect-on-page-404-errors-using-javascript window.addEventListener(&#39;error&#39;, handler, true) // window.ErrorEvent.__SIESTA_HOOK_INSTALLED__ = true } else { var prevHandler = window.onerror if (prevHandler &amp;&amp; prevHandler.__SP_MANAGED__) return // this, &quot;managed&quot; handler is basically a wrapper around the current value in the &quot;__ONERROR__&quot; hash window.onerror = function (message, url, lineNumber) { // prevent recursive calls if other authors politely has not overwrite the handler and call it if (handler.__CALLING__) return handler.__CALLING__ = true prevHandler &amp;&amp; prevHandler.apply(this, arguments) handler.apply(this, arguments) handler.__CALLING__ = false // in FF/IE need to return `true` to prevent default action if (preventDefault !== false) return window.WebKitPoint ? false : true } window.onerror.__SP_MANAGED__ = true } if (failOnPromiseRejection &amp;&amp; window.Promise &amp;&amp; (&#39;onunhandledrejection&#39; in window)) { window.addEventListener(&#39;unhandledrejection&#39;, function (e) { handler.apply(this, [ null, null, null, null, null, e ]) }, true) } } }, // this is a &quot;cached&quot; onerror handler - a handler which was provided before the scope // has started the creation process - should be installed ASAP in the creation process // to allow catching of the exceptions in the scope with `sourceURL` cachedOnError : null }, override : { cleanup : function () { var onErrorHandler = this.cachedOnError this.cachedOnError = null // can throw exceptions for cross-domain case try { var scope = this.scope if (scope.ErrorEvent /*&amp;&amp; scope.ErrorEvent.__SIESTA_HOOK_INSTALLED__*/) scope.removeEventListener(&#39;error&#39;, onErrorHandler) scope.onerror = null } catch (e) { } this.SUPERARG(arguments) this.scope = null } }, methods : { cleanupHandlers : function () { var scopeProvider = this.parentWindow.Scope.Provider var scopeId = this.scopeId delete scopeProvider.__ONLOAD__[ scopeId ] delete scopeProvider.__ONERROR__[ scopeId ] delete scopeProvider.__FAILED_PRELOAD__[ scopeId ] }, getHead : function () { return this.getDocument().getElementsByTagName(&#39;head&#39;)[ 0 ] }, installOnErrorHandler : function (handler) { if (this.crossOriginFailed) return if (!this.isAlreadySetUp()) throw &quot;Scope should be already set up&quot; this.attachToOnError(this.scope, this.scopeId, handler, false, this.failOnResourceLoadError, this.failOnPromiseRejection) }, addOnErrorHandler : function (handler, preventDefault) { if (this.crossOriginFailed) return handler.__SP_MANAGED__ = true this.cachedOnError = handler var scopeId = this.scopeId this.parentWindow.Scope.Provider.__ONERROR__[ scopeId ] = handler var attachToOnError = &#39;;(&#39; + this.attachToOnError.toString() + &#39;)(window, &#39; + scopeId + &#39;, (window.opener || window.parent).Scope.Provider.__ONERROR__[ &#39; + scopeId + &#39; ], &#39; + preventDefault + &#39;, &#39; + this.failOnResourceLoadError + &#39;, &#39; + this.failOnPromiseRejection + &#39;);&#39; if (this.isAlreadySetUp()) this.runCode(attachToOnError) else { // this is a fallback - run the &quot;attachToOnError&quot; from inside of scope this.getPreload().unshift({ type : &#39;js&#39;, content : attachToOnError, unordered : true }) } }, addSeedingToPreload : function () { var preload = this.getPreload() if (this.seedingCode) preload.unshift({ type : &#39;js&#39;, content : this.seedingCode }) if (this.seedingScript) preload.push({ type : &#39;js&#39;, url : this.seedingScript, isEcmaModule : this.seedingScriptIsEcmaModule }) }, setup : function (callback) { var isIE = &#39;v&#39; == &#39;\v&#39; || Boolean(this.parentWindow.msWriteProfilerMark) // var isOpera = Object.prototype.toString.call(this.parentWindow.opera) == &#39;[object Opera]&#39; var hasInlineScript = false Joose.A.each(this.getPreload(), function (preloadDesc) { // IE will execute the inline scripts ASAP, this might be not what we want (inline script might be need executed only after some url script) // its however ok in some cases (like adding `onerror` handler // such inline scripts should be marked with `unordered` - true if (preloadDesc.type == &#39;js&#39; &amp;&amp; preloadDesc.content &amp;&amp; !preloadDesc.unordered) { hasInlineScript = true return false } }) var me = this var cont = function (e) { callback &amp;&amp; callback(me, me.parentWindow.Scope.Provider.__FAILED_PRELOAD__[ me.scopeId ], e) } this.parentWindow.Scope.Provider.__FAILED_PRELOAD__[ this.scopeId ] = {} if (this.sourceURL || isIE &amp;&amp; hasInlineScript) { this.addSeedingToPreload() this.setupIncrementally(cont) } else { // for sane browsers just add the seeding code and seeding script to preloads if (!isIE) this.addSeedingToPreload() // seeding scripts are included only for sane browsers (not IE) this.setupWithDocWrite(cont, isIE) } }, setupWithDocWrite : function (callback, needToSeed) { var html = [] var me = this Joose.A.each(this.getPreload(), function (preloadDesc) { if (preloadDesc.type == &#39;js&#39;) html.push( me.getScriptTagString(preloadDesc.url, preloadDesc.content, preloadDesc.isEcmaModule) ) else if (preloadDesc.type == &#39;css&#39;) html.push( me.getLinkTagString(preloadDesc.url, preloadDesc.content) ) else throw &quot;Incorrect preload descriptor &quot; + preloadDesc }) // no need to wait for DOM ready - we&#39;ll overwrite it anyway this.create() var scopeId = this.scopeId this.parentWindow.Scope.Provider.__ONLOAD__[ scopeId ] = function () { var cont = function () { callback &amp;&amp; callback() } // sane browsers - seeding code and script has been already added if (!needToSeed) { cont(); return } // our beloved IE - manually seeding the scope if (me.seedingCode) me.runCode(me.seedingCode, null) if (me.seedingScript) me.runScript(me.seedingScript, cont, me.seedingScriptIsEcmaModule) else cont() } var doc = this.getDocument() doc.open() doc.write([ this.useStrictMode ? &#39;&lt;!DOCTYPE html&gt;&#39; : &#39;&#39;, &#39;&lt;html style=&quot;width: 100%; height: 100%; margin : 0; padding : 0;&quot;&gt;&#39;, &#39;&lt;head&gt;&#39;, this.innerHtmlHead || &#39;&#39;, html.join(&#39;&#39;), &#39;&lt;/head&gt;&#39;, // delay here is for IE9 - the &quot;onerror&quot; handlers of the &lt;script&gt; tags are fired _after_ &lt;body&gt; onload otherwise &#39;&lt;body style=&quot;margin : 0; padding : 0; width: 100%; height: 100%&quot; onload=&quot;setTimeout(function () { (window.opener || window.parent).Scope.Provider.__ONLOAD__[&#39; + scopeId + &#39;]() }, 0)&quot;&gt;&#39;, this.innerHtmlBody || &#39;&#39;, &#39;&lt;/body&gt;&#39;, &#39;&lt;/html&gt;&#39; ].join(&#39;&#39;)) doc.close() // Chrome (Webkit?) will clear the `onerror` after &quot;doc.open()/.close()&quot; so need to re-install it if (me.cachedOnError) me.installOnErrorHandler(me.cachedOnError) }, setupIncrementally : function (callback) { // here the &quot;onerror&quot; should be included early in the &quot;preloads&quot; this.create(function (me, e) { if (e) { callback &amp;&amp; callback(e) return } if (!me.sourceURL) { var doc = me.getDocument() if (me.innerHtmlHead) { var head = me.getHead() // IE9 throws exception when accessing innerHTML of the &lt;head&gt; - its read only try { head.innerHTML = me.innerHtmlHead } catch (e) { var div = doc.createElement(&#39;div&#39;) div.innerHTML = me.innerHtmlHead for (var i = 0; i &lt; div.children.length; i++) head.appendChild(div.children[ i ]) } } if (me.innerHtmlBody) doc.body.innerHTML = me.innerHtmlBody } var loadScripts = function (preloads, callback) { var cont = function () { // cleanup can happen in the middle of setup if (me.scope) loadScripts(preloads, callback) } if (!preloads.length) callback &amp;&amp; callback() else { var preloadDesc = preloads.shift() if (preloadDesc.url) me.runScript(preloadDesc.url, cont, preloadDesc.isEcmaModule) else if (preloadDesc.type == &#39;js&#39;) me.runCode(preloadDesc.content, cont, preloadDesc.isEcmaModule) else { me.addStyleTag(preloadDesc.content) cont() } } } // cleanup can happen in the middle of setup if (me.scope) loadScripts(me.getPreload().slice(), callback) }) }, getScriptTagString : function (url, text, isEcmaModule) { var type = isEcmaModule ? &#39;module&#39; : &#39;text/javascript&#39;, res = &#39;&lt;script type=&quot;&#39; + type + &#39;&quot;&#39; + (isEcmaModule ? &#39; crossorigin=&quot;anonymous&quot;&#39; : &#39;&#39;) var onerror = &#39;(window.opener || window.parent).Scope.Provider.__FAILED_PRELOAD__[ scopeId ][ url ] = true&#39; onerror = onerror.replace(/scopeId/, &quot;&#39;&quot; + this.scopeId + &quot;&#39;&quot;).replace(/url/, &quot;&#39;&quot; + url + &quot;&#39;&quot;) if (url) res += &#39; src=&quot;&#39; + url + &#39;&quot; onerror=&quot;&#39; + onerror + &#39;&quot;&gt;&lt;/script&gt;&#39; else res += &#39;&gt;&#39; + text.replace(/&lt;\/script&gt;/gi, &#39;\\x3C/script&gt;&#39;) + &#39;&lt;/script&gt;&#39; return res }, getLinkTagString : function (url, text) { if (url) return &#39;&lt;link href=&quot;&#39; + url + &#39;&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;&#39; if (text) return &#39;&lt;style&gt;&#39; + text + &#39;&lt;/style&gt;&#39; }, loadCSS : function (url, callback) { var doc = this.getDocument() var link = doc.createElement(&#39;link&#39;) link.type = &#39;text/css&#39; link.rel = &#39;stylesheet&#39; link.href = url var hasOnLoad = false if (&#39;onload&#39; in link) { hasOnLoad = true link.onload = function () { link.onload = null if (callback) callback() callback = null link = null } } this.getHead().appendChild(link) if (!hasOnLoad) { var hasContinued = false var cont = function () { // just in case some crazy JS engine calls `onerror` even after node removal if (hasContinued) return hasContinued = true clearTimeout(forcedTimeout) if (callback) callback() doc.body.removeChild(img) } var forcedTimeout = setTimeout(cont, 30000) var img = doc.createElement(&#39;img&#39;) img.onerror = cont doc.body.appendChild(img) img.src = url } }, runCode : function (text, callback, isEcmaModule) { if (this.crossOriginFailed) { callback &amp;&amp; callback() return } this.getHead().appendChild(this.createScriptTag(text, null, null, null, isEcmaModule)) callback &amp;&amp; callback() }, runScript : function (url, callback, isEcmaModule) { if (this.crossOriginFailed) { callback &amp;&amp; callback() return } var scopeId = this.scopeId if (this.isCSS(url)) this.loadCSS(url, callback) else { var onerror = function () { this.onerror = null var doc = this.ownerDocument var win = doc.defaultView || doc.parentWindow ;(win.opener || win.parent).Scope.Provider.__FAILED_PRELOAD__[ scopeId ][ url ] = true callback() } this.getHead().appendChild(this.createScriptTag(null, url, callback, onerror, isEcmaModule)) } }, createScriptTag : function (text, url, callback, errback, isEcmaModule) { var node = this.getDocument().createElement(&quot;script&quot;) node.setAttribute(&quot;type&quot;, isEcmaModule ? &#39;module&#39; : &#39;text/javascript&#39;) isEcmaModule &amp;&amp; node.setAttribute(&quot;crossorigin&quot;, &quot;anonymous&quot;) if (url) node.setAttribute(&quot;src&quot;, url) if (text) node.text = text if (callback) node.onload = node.onreadystatechange = function () { if (!node.readyState || node.readyState == &quot;loaded&quot; || node.readyState == &quot;complete&quot; || node.readyState == 4 &amp;&amp; node.status == 200) { node.onload = node.onreadystatechange = null //surely for IE6.. if (&#39;v&#39; == &#39;\v&#39;) setTimeout(callback, 0) else callback() } } if (errback) node.onerror = errback return node }, addStyleTag : function (text) { var document = this.getDocument() var node = document.createElement(&#39;style&#39;) node.setAttribute(&quot;type&quot;, &quot;text/css&quot;) var head = document.getElementsByTagName(&#39;head&#39;)[0] head.appendChild(node) if (node.styleSheet) { // IE node.styleSheet.cssText = text } else { // the world node.appendChild(document.createTextNode(text)) } } } }) <span id='global-property-'>/** </span> Name ==== Scope.Provider.Role.WithDOM - role for scope provider, which uses `script` tag for running the code. SYNOPSIS ======== Class(&#39;Scope.Provider.IFrame&#39;, { isa : Scope.Provider, does : Scope.Provider.Role.WithDOM, ... }) DESCRIPTION =========== `Scope.Provider.Role.WithDOM` requires the implementation of the `getDocument` method, which should return the document into which the `script` tags will be created. In return, this role provides the implementation of `runCode` and `runScript`. GETTING HELP ============ This extension is supported via github issues tracker: &lt;http://github.com/SamuraiJack/Scope-Provider/issues&gt; For general Joose questions you can also visit [#joose](http://webchat.freenode.net/?randomnick=1&amp;channels=joose&amp;prompt=1) on irc.freenode.org or the forum at: &lt;http://joose.it/forum&gt; SEE ALSO ======== Web page of this module: &lt;http://github.com/SamuraiJack/Scope-Provider/&gt; General documentation for Joose: &lt;http://joose.github.com/Joose&gt; BUGS ==== All complex software has bugs lurking in it, and this module is no exception. Please report any bugs through the web interface at &lt;http://github.com/SamuraiJack/Scope-Provider/issues&gt; AUTHORS ======= Nickolay Platonov &lt;nplatonov@cpan.org&gt; COPYRIGHT AND LICENSE ===================== This software is Copyright (c) 2010 by Nickolay Platonov &lt;nplatonov@cpan.org&gt;. This is free software, licensed under: The GNU Lesser General Public License, Version 3, June 2007 */ </pre> </body> </html>