123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732 |
- /*
- *+------------------------------------------------------------------------+
- *| Licensed Materials - Property of IBM
- *| IBM Cognos Products: Viewer
- *| (C) Copyright IBM Corp. 2001, 2020
- *|
- *| US Government Users Restricted Rights - Use, duplication or
- *| disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
- *|
- *+------------------------------------------------------------------------+
- */
- /**
- Loads dynamically CSS and JavaScript files and execute inline scripts found in HTML code in the response outputs.
- @constructor
- */
- function CScriptLoader(sWebContentRoot)
- {
- /**
- Array of files to load.
- @type array
- @private
- */
- this.m_oFiles = {};
- /**
- Array of inline script to execute.
- @type array
- @private
- */
- this.m_aScripts = [];
- /**
- Array of document.writes/document.writeln to execute.
- @type array
- @private
- */
- this.m_aDocumentWriters = [];
- this.m_ajaxWarnings = [];
- this.m_bIgnoreAjaxWarnings = false;
-
- this.m_bHandleStylesheetLimit = false;
-
- /**
- Length of the interval (in Milliseconds) to check if files are done loading and that we can execute the inline scripts.
- @type integer
- @private
- */
- this.m_iInterval = 20;
- /**
- Regular expression to retrieve CSS file paths.
- @type RegularExpression
- @private
- */
- this.m_reFindCssPath = new RegExp('<link[^>]*href="([^"]*)"', "i");
- /**
- Regular expression to retrieve CSS inline code.
- @type RegularExpression
- @private
- */
- this.m_reFindInlineStyle = /<style\b(\s|.)*?<\/style>/gi;
- /**
- Regular expression to test if a CSS (<link> tag) is present.
- @type RegularExpression
- @private
- */
- this.m_reHasCss = /<link .*?>/gi;
- /**
- Regular expression to test if a file name has a CSS extension.
- @type RegularExpression
- @private
- */
- this.m_reIsCss = /\.css$/i;
- /**
- Regular expression to test if a file name has a JS extension.
- @type RegularExpression
- @private
- */
- this.m_reIsJavascript = /\.js$/i;
- /**
- Regular expression to test if a file name is a Prompting Toolkit Locale JS file.
- If there are changes to Prmt localization file names this may have to be revisited.
- @type RegularExpression
- @private
- */
- this.m_reIsPromptingLocaleJavascript = /prompting.res.[promptingStrings|promptLocale].*\.js$/i;
- /**
- Regular expression to match closing <script> tags.
- @type RegularExpression
- @private
- */
- this.m_reScriptTagClose = /\s*<\/script>.*?$/i;
- /**
- Regular expression to match opening <script> tags.
- @type RegularExpression
- @private
- */
- this.m_reScriptTagOpen = /^.*?<script[^>]*>\s*/i;
- /**
- Regular expression to match closing <style> tags.
- @type RegularExpression
- @private
- */
- this.m_reStyleTagClose = /(-|>|\s)*<\/style>\s*$/gi;
- /**
- Regular expression to match opening <style> tags.
- @type RegularExpression
- @private
- */
- this.m_reStyleTagOpen = /^\s*<style[^>]*>(\s|<|!|-)*/gi;
- /**
- Regular expression to match any escaped backslashes,
- quotes or double quotes.
- @type RegularExpression
- @private
- */
- this.m_reEscapedCharacters = /\\[\\"']/g;
- /**
- Regular expression to match any strings, assuming no
- escaped characters.
- @type RegularExpression
- @private
- */
- this.m_reStringLiterals = /("|')[\s\S]*?\1/g;
- /**
- String that represents the web content root
- @type String
- @private
- */
- this.m_sWebContentRoot = sWebContentRoot;
- /**
- Flag to signal that loaded scripts have completed execution
- @type Boolean
- @private
- */
- this.m_bHasCompletedExecution = false;
- /**
- Array of scripts to be loaded (in order) by inserting them into the DOM
- @type Array
- @private
- */
- this.m_aScriptLoadQueue = [];
- /**
- Flag to signal that a script is currently being downloaded and executed. When set
- to true, other scripts will be placed in the queue until the script has been loaded.
- @type Boolean
- @private
- */
- this.m_bBlockScriptLoading = false;
- /**
- Flag to signal that script load order should be enforced. This is currently only necessary
- with Internet Exlporer. See: http://www.stevesouders.com/blog/2009/04/27/loading-scripts-without-blocking/.
- @type Boolean
- @private
- */
- // this flag is set to false to fix bugs: COGCQ00247831 and COGCQ00249348
- this.m_bUseScriptBlocking = false;
-
- /**
- Flag to signal that a Prompting Locale script is currently being downloaded and executed. When set
- to true, other Prompting Locale scripts will be placed in the queue.
- @type Boolean
- @private
- */
- this.m_bBlockPromptingLocaleScripts = false;
-
- /**
- Array of scripts to be loaded (in order - synchronously) by inserting them into the DOM
- @type Array
- @private
- */
- this.m_aBlockedPromptingLocaleFileQueue = [];
- }
- /**
- Return whether or not the loaded scripts have completed execution
- @public
- */
- CScriptLoader.prototype.hasCompletedExecution = function()
- {
- return this.m_bHasCompletedExecution;
- };
- CScriptLoader.prototype.setHandlerStylesheetLimit = function(handleLimit) {
- this.m_bHandleStylesheetLimit = handleLimit;
- };
- /**
- Helper function to execute all inline javascript from a page, after all javascript files were loading and processed.
- @private
- */
- CScriptLoader.prototype.executeScripts = function(callback, sNamespaceId)
- {
- if (this.isReadyToExecute())
- {
- for (var idxScript = 0; idxScript < this.m_aScripts.length; idxScript++)
- {
- if (this.m_aScripts[idxScript])
- {
- var oScript = document.createElement('script');
- oScript.setAttribute("language", "javascript");
- oScript.setAttribute("type", "text/javascript");
- this.addNamespaceAttribute(oScript, sNamespaceId);
- oScript.text = this.m_aScripts[idxScript];
- document.getElementsByTagName("head").item(0).appendChild(oScript);
- }
- }
- this.m_aScripts = [];
- for(var idx = 0; idx < this.m_aDocumentWriters.length; ++idx)
- {
- var documentWriter = this.m_aDocumentWriters[idx];
- documentWriter.execute();
- }
- this.m_aDocumentWriters = [];
- if (!this.m_aScripts.length && !this.m_aDocumentWriters.length)
- {
- if (typeof callback == "function") {
- callback();
- }
- this.m_bHasCompletedExecution = true;
- }
- else
- {
- setTimeout(function(){window.gScriptLoader.executeScripts(callback, sNamespaceId);}, this.m_iInterval);
- }
- }
- else
- {
- setTimeout(function(){window.gScriptLoader.executeScripts(callback, sNamespaceId);}, this.m_iInterval);
- }
- };
- /**
- Helper function.
- @type bool
- @private
- @return true if all files in {m_oFiles} are set to 'complete'. false otherwise.
- */
- CScriptLoader.prototype.isReadyToExecute = function()
- {
- for (var idxFile in this.m_oFiles)
- {
- if (this.m_oFiles[idxFile] != "complete")
- {
- return false;
- }
- }
- if (this.m_aScriptLoadQueue.length > 0) {
- return false;
- }
- return true;
- };
- /**
- Load and process a CSS file from HTML code [received from an ajax response].
- @private
- @param {string} sHTML HTML code with a <link> tag.
- @param {object} oReportDiv The report div.
- */
- CScriptLoader.prototype.loadCSS = function(sHTML, oReportDiv, bUseNamespacedGRS, sNamespaceId)
- {
- var aM = sHTML.match(this.m_reHasCss);
- if (aM)
- {
- for (var i = 0; i < aM.length; i++)
- {
- if (aM[i].match(this.m_reFindCssPath))
- {
- var linkRef = RegExp.$1;
- if(linkRef.indexOf("GlobalReportStyles") != -1)
- {
- this.validateGlobalReportStyles(linkRef);
- if (bUseNamespacedGRS)
- {
- // only time we're using the namespaced stylesheet is when we're in BUX,
- // so make sure we bring in the new styles
- if (linkRef.indexOf("GlobalReportStyles.css") != -1) {
- linkRef = linkRef.replace("GlobalReportStyles.css", "GlobalReportStyles_10.css");
- }
- var sClassPrefix = this.getGlobalReportStylesClassPrefix(linkRef);
- linkRef = linkRef.replace(".css", "_NS.css");
- if (oReportDiv) {
- oReportDiv.className = "buxReport " + sClassPrefix;
- }
- }
- }
- this.loadObject(linkRef, sNamespaceId);
- }
- // remove the link tag from the html block
- sHTML = sHTML.replace(aM[i], "");
- }
- }
- return sHTML;
- };
- /**
- * @private
- * @param (String)
- */
- CScriptLoader.prototype.getGlobalReportStylesClassPrefix = function(globalReportStyleLinkRef)
- {
- var sClassPrefix = null;
- if (globalReportStyleLinkRef.indexOf("GlobalReportStyles_11.4.css") != -1)
- {
- sClassPrefix = "v114";
- }
- if (globalReportStyleLinkRef.indexOf("GlobalReportStyles_11.css") != -1)
- {
- sClassPrefix = "v11";
- }
- if (globalReportStyleLinkRef.indexOf("GlobalReportStyles_10.css") != -1)
- {
- sClassPrefix = "v10";
- }
- else if (globalReportStyleLinkRef.indexOf("GlobalReportStyles_1.css") != -1)
- {
- sClassPrefix = "v1";
- }
- else if (globalReportStyleLinkRef.indexOf("GlobalReportStyles_none.css") != -1)
- {
- sClassPrefix = "vnone";
- }
- else if (globalReportStyleLinkRef.indexOf("GlobalReportStyles.css") != -1)
- {
- sClassPrefix = "v8";
- }
- return sClassPrefix;
- };
- /**
- * @private
- * @param (String)
- */
- CScriptLoader.prototype.validateGlobalReportStyles = function(globalReportStyleLinkRef)
- {
- var linkNodes = document.getElementsByTagName("link");
- for(var i = 0; i < linkNodes.length; ++i)
- {
- var linkNode = linkNodes[i];
- if(linkNode.getAttribute("href").indexOf("GlobalReportStyles") != -1)
- {
- if(linkNode.getAttribute("href").toLowerCase() != globalReportStyleLinkRef.toLowerCase())
- {
- //COGCQ00654064: only compares the file names
- var existingGRSRef = globalReportStyleLinkRef.split("/");
- var newGRSRef = linkNode.getAttribute("href").split("/");
- if(existingGRSRef[existingGRSRef.length -1] != newGRSRef[newGRSRef.length-1])
- {
- this.m_ajaxWarnings.push("Ajax response contains different versions of the GlobalReportStyles.css.");
- }
- }
- break;
- }
- }
- };
- /**
- Load a file synchronously and return the content.
- @param {string} sURL URL to fetch
- @param {string} sParams parameter string to add to the file
- @param {string} sType POST or GET
- @type string
- @return The content of the file
- @private
- */
- CScriptLoader.prototype.loadFile = function(sURL_param, sContent_param, sType_param)
- {
- var sURL = "";
- if (sURL_param) {
- sURL = sURL_param;
- }
- var sContent = null;
- if (typeof sContent_param == "string") {
- sContent = sContent_param;
- }
- var sType = "POST";
- if (sType_param == "GET") {
- sType = "GET";
- }
- var oHTTPRequest = null;
- if (typeof ActiveXObject != "undefined")
- {
- oHTTPRequest = new ActiveXObject("Msxml2.XMLHTTP");
- }
- else
- {
- oHTTPRequest = new XMLHttpRequest();
- }
- oHTTPRequest.open(sType, sURL, false);
- oHTTPRequest.send(sContent);
- return oHTTPRequest.responseText;
- };
- /**
- Helper Function. Event called when a file status is changed (ie. when it's done loading).
- @private
- */
- function CScriptLoader_onReadyStateChange() {
- if (typeof this.readyState == "undefined") {
- // Mozilla-based browser are using onload event, so we are here when the file is done loading.
- this.readyState = "complete";
- }
- if (this.readyState == "loaded" || this.readyState == "complete") {
- var path = this.sFilePath;
- // if we don't have path check for the href attribute - this is for CSS files.
- if (!path && this.getAttribute) {
- path = this.getAttribute("href");
- }
- window.gScriptLoader.setFileState(path, "complete");
- window.gScriptLoader.m_bBlockScriptLoading = false;
-
- // If we were loading a prompting locale file and the one that just finished is a prompting locale file, check to
- // see if we were blocking another one from loading and load it if we were.
- if (this.sFilePath && window.gScriptLoader.m_bBlockPromptingLocaleScripts &&
- this.sFilePath.match(window.gScriptLoader.m_reIsPromptingLocaleJavascript)) {
- window.gScriptLoader.m_bBlockPromptingLocaleScripts = false;
- if (window.gScriptLoader.m_aBlockedPromptingLocaleFileQueue.length > 0) {
- var sQueueObject = window.gScriptLoader.m_aBlockedPromptingLocaleFileQueue.shift();
- window.gScriptLoader.loadObject(sQueueObject.sName, sQueueObject.sNamespaceId);
- }
- }
-
- if (window.gScriptLoader.m_aScriptLoadQueue.length > 0) {
- window.gScriptLoader.loadObject();
- }
- }
- }
- /**
- * Used to move links from the body to the head
- */
- CScriptLoader.prototype.moveLinks = function(node) {
- if (!node) {
- return;
- }
-
- var sName = node.getAttribute("href");
-
- if (!sName || this.m_oFiles[sName]) {
- return;
- }
-
- this.m_oFiles[sName] = "complete";
-
- document.getElementsByTagName("head").item(0).appendChild(node);
- };
- /**
- Helper function to load and process file (CSS or Javascript) from HTML code received from an ajax response.
- @private
- @param {string} sName
- */
- CScriptLoader.prototype.loadObject = function(sName, sNamespaceId) {
- var oFile = null;
- if (typeof sName === "undefined") {
- if (this.m_aScriptLoadQueue.length > 0) {
- var sQueueObject = this.m_aScriptLoadQueue.shift();
- sName = sQueueObject.name;
- sNamespaceId = sQueueObject.namespaceId;
- } else {
- return;
- }
- }
- if (this.m_oFiles[sName]) {
- return;
- }
- if (this.m_bBlockScriptLoading) {
- this.m_aScriptLoadQueue.push({
- "name": sName,
- "namespaceId": sNamespaceId
- });
- } else {
- if (sName.match(this.m_reIsCss))
- {
- // Add a <link> tag in the document. This let the browser deals with the cache.
- oFile = document.createElement('link');
- oFile.setAttribute("rel", "stylesheet");
- oFile.setAttribute("type", "text/css");
- oFile.setAttribute("href", sName);
- // In IE the css files aren't always loaded before we insert the HTML. Wait for
- // the onreadystatechange event that lets us know the css file has been loaded.
- if (window.isIE && window.isIE()) {
- oFile.onreadystatechange = CScriptLoader_onReadyStateChange;
- oFile.onload = CScriptLoader_onReadyStateChange;
- oFile.onerror = CScriptLoader_onReadyStateChange;
- this.m_oFiles[sName] = "new";
- }
- else {
- this.m_oFiles[sName] = "complete";
- }
- }
- else if (sName.match(this.m_reIsJavascript))
- {
- // Need to handle prompt locale files differently. We need to make sure we're only loading one at a time.
- if (sName.match(this.m_reIsPromptingLocaleJavascript)) {
- // If we're already loading a prompt locale file, block this one for now.
- if (this.m_bBlockPromptingLocaleScripts) {
- this.m_aBlockedPromptingLocaleFileQueue.push ({
- 'sName' : sName,
- 'sNamespaceId' : sNamespaceId
- });
- return;
- }
- this.m_bBlockPromptingLocaleScripts = true;
- }
-
- this.m_bBlockScriptLoading = this.m_bUseScriptBlocking;
- oFile = document.createElement('script');
- oFile.setAttribute("language", "javascript");
- oFile.setAttribute("type", "text/javascript");
- oFile.setAttribute("src", sName);
- oFile.sFilePath = sName;
- oFile.onreadystatechange = CScriptLoader_onReadyStateChange;
- oFile.onload = CScriptLoader_onReadyStateChange;
- oFile.onerror = CScriptLoader_onReadyStateChange;
- this.addNamespaceAttribute(oFile, sNamespaceId);
- this.m_oFiles[sName] = "new";
- }
- if (oFile)
- {
- document.getElementsByTagName("head").item(0).appendChild(oFile);
- }
- }
- };
- /**
- * Finds script tags under a provided element, examines the scripts, makes any
- * necessary substitutions (e.g. _THIS_ is replaced with the namespace), sets
- * the scripts up for later execution, and removes the script tags from the
- * actual document body.
- */
- CScriptLoader.prototype.loadScriptsFromDOM = function(domElement, sNamespaceId, bProcessDocumentWrite)
- {
- if (!domElement)
- {
- return;
- }
- var scriptElements = domElement.getElementsByTagName("script");
- while(scriptElements.length > 0)
- {
- var scriptElement = scriptElements[0];
- if (scriptElement.getAttribute("src") != null && scriptElement.getAttribute("src").length > 0)
- {
- this.loadObject(scriptElement.getAttribute("src"), sNamespaceId);
- }
- else
- {
- var sScript = scriptElement.innerHTML;
- var hasDocumentWrite = false;
- if(sScript.indexOf("document.write")!= -1) {
- //document.write may be included in a string, not in the script itself,
- //particularly in the report description. The report description is
- //included in the same script tag as initialization code which must be
- //executed through m_aScripts, not m_aDocumentWriters, as the order
- //of code execution is relevant (the script node which contains the report
- //description is also the node which contains viewer initialization code,
- //and so this node must be loaded before all others). For this reason,
- //check that the document.write is indeed in the script by deleting
- //strings enclosed in quotes and checking for it after:
- //Remove \\s, \"s and 's, then "..."s and '...'s
- var stripQuotes = sScript.replace(this.m_reEscapedCharacters, "").replace(this.m_reStringLiterals, "");
- hasDocumentWrite = (stripQuotes.indexOf("document.write") != -1);
- }
- if(hasDocumentWrite) {
- if (bProcessDocumentWrite) {
- var sId = "CVScriptFromDOMPlaceHolder" + scriptElements.length + sNamespaceId;
- var spanElement = scriptElement.ownerDocument.createElement("span");
- spanElement.setAttribute("id", sId);
- scriptElement.parentNode.insertBefore(spanElement, scriptElement);
- this.m_aDocumentWriters.push(new CDocumentWriter(sId, sScript));
- }
- } else if (sScript.length > 0) {
- this.m_aScripts.push(sScript);
- }
- }
- scriptElement.parentNode.removeChild(scriptElement);
- }
- };
- /**
- Move the style elemnts from the HTML body to the head so they'll get evaluated
- @private
- @param {string} sHTML HTML code with a <style> tag.
- */
- CScriptLoader.prototype.loadStyles = function(domElement, sNamespaceId)
- {
- if (!domElement || !domElement.parentNode)
- {
- return;
- }
- var styleElements = domElement.parentNode.getElementsByTagName("style");
- while(styleElements.length > 0) {
- var styleElement = styleElements[0];
- if (sNamespaceId) {
- this.addNamespaceAttribute(styleElement, sNamespaceId);
- }
-
- if (window.isIE && window.isIE() && window.getNavVer() < 10) {
- // IE has a limit of 31 stylesheets. If ever we reach the limit, then re-submit the request in "page" mode.
- // fix for trakker 564899 and 615224
- if ((document.getElementsByTagName("style").length + document.getElementsByTagName("link").length) >= 30) {
- if (this.m_bHandleStylesheetLimit) {
-
- // Loops through all the Viewers and ask any that are currently hidden to remove their styles from the head
- if( typeof window.gaRV_INSTANCES != "undefined") {
- for (var i=0; i < window.gaRV_INSTANCES.length; i++) {
- window.gaRV_INSTANCES[i].cleanupStyles();
- }
- }
- }
-
- // Last try to see if there's now room for the style
- if ((document.getElementsByTagName("style").length + document.getElementsByTagName("link").length) >= 30) {
- if (typeof console != "undefined" && console && console.log) {
- console.log("Stylesheet limit reached.");
- }
-
- this.m_ajaxWarnings.push("Stylesheet limit reached.");
- return;
- }
- }
- }
- document.getElementsByTagName("head").item(0).appendChild(styleElement);
- }
- };
- CScriptLoader.prototype.loadAll = function(oReportDiv, callback, sNamespaceId, bProcessDocumentWrite)
- {
- this.m_bScriptLoaderCalled = true;
-
- this.m_bHasCompletedExecution = false;
- this.loadScriptsFromDOM(oReportDiv, sNamespaceId, bProcessDocumentWrite);
- if(this.containsAjaxWarnings())
- {
- return false;
- }
- // need to load the css and styles after we've replaced the innerHTML of the div
- // since IE would end up removing the styles from the head when the html in the div got replaces
- // bug 573581
- this.loadStyles(oReportDiv, sNamespaceId);
- if(this.containsAjaxWarnings())
- {
- return false;
- }
- this.executeScripts(callback, sNamespaceId);
- return true;
- };
- /**
- Setter for the loading state of a file.
- @private
- @param {string} sFile Path of the file to load.
- @param {string} sState State of the current file. Can be 'new' or 'complete'.
- */
- CScriptLoader.prototype.setFileState = function(sFile, sState)
- {
- this.m_oFiles[sFile] = sState;
- };
- CScriptLoader.prototype.containsAjaxWarnings = function(){
- if (this.m_bIgnoreAjaxWarnings) {
- return false;
- }
- else {
- return (this.m_ajaxWarnings.length > 0);
- }
- };
- CScriptLoader.prototype.addNamespaceAttribute = function(oItem, sNamespaceId)
- {
- if (typeof sNamespaceId === "string") {
- oItem.setAttribute("namespaceId", sNamespaceId);
- }
- };
- // Declare a global instance of CScriptLoader if none exists. We just need one instance per page.
- if (typeof window.gScriptLoader == "undefined")
- {
- window.gScriptLoader = new CScriptLoader();
- }
|