/* IBM Confidential OCO Source Materials IBM Cognos Products: authoring (C) Copyright IBM Corp. 2015, 2022 The source code for this program is not published or otherwise divested of its trade secrets, irrespective of what has been deposited with the U.S. Copyright Office. */ define( [ 'bi/glass/app/ContentView', 'jquery', 'q', 'bi/classicviewer/nls/StringResource', 'bi/commons/utils/Utils', 'bi/authoring/utils/pat/rsLaunchParameters', 'bi/authoring/utils/pat/rsPromptParameters', 'bi/authoring/utils/rsPerformance', 'bi/authoring/utils/rsCommon', 'bi/authoring/utils/rsOpenHelper', 'bi/authoring/utils/rsShareHelper', 'bi/authoring/utils/rsPromptHandler', 'bi/admin/common/utils/parameters/ParameterValues'], function(ContentView, $, Q, StringResource, Utils, rsLaunchParameters, rsPromptParameters, rsPerformance, rsCommon, rsOpenHelper, rsShareHelper, rsPromptHandler, ParameterValues) { 'use strict'; var classicViewerGatewaySuffix = "v1/disp"; var promptPageEndpoint = "/rds/promptPage/report/"; var cvFormFields = [ "cv.navlinks", "cv.header", "cv.toolbar", "cv.selection", "cv.drill", "cv.contextInfo", "cv.contextmenu", "cv.id", "cv.responseFormat", "cv.rsProfile", "cv.showFaultPage", "cv.useAjax", "cv.reuseConversation", "cv.promptForDownload", "cv.gateway", "cv.webcontent", "cv.keepWindowOpen", "ui.action", "ui.cafcontextid", "ui.conversation", "ui.spec", "ui.errURL", "ui.routingServerGroup", "ui.name", "ui.object", "run.outputFormat", "run.outputLocale", "run.outputPageDefinition", "run.outputPageOrientation", "run.verticalElements", "run.horizontalElements", "run.prompt", "run.xslURL", "run.data", "specification.editSpecification", "modelPath", "m_tracking", "parameterValues", "reuseResults", "keepIterators", "rs_aliases", "authenticitytoken", "specificationType", "system.http://developer.cognos.com/ceba/constants/systemOptionEnum#accessibilityFeatures", "biDirectional.http://developer.cognos.com/ceba/constants/biDirectionalOptionEnum#biDirectionalFeaturesEnabled", "generic.anyURI.runOptionEnum#globalParameters", "isTitan", "IncludePerformance" ]; // Pattern to extract search path from defaultOutput method var g_reDefaultOutput = /^defaultOutput\((.*),\s*'[^']*'\s*,\s*'[^']*'\s*\)/; var cvContentView = ContentView.extend({ init: function(options, appView) { rsCommon.decodeAndMoveCMProperties(options); rsCommon.convertStringQSToValues(options, options.glassContext); rsCommon.decodeAndMoveRSOptions(options); // After the following call, every member of options is now a member of this cvContentView.inherited('init', this, arguments); this.m_sTitle = StringResource.get('classicviewer_welcome'); this.m_oAppView = appView; try { // to open a report passed on the URL and pass parameters, we need access to the // launch parameters stored in the calling window's Application object var v_oLaunchParameters = rsLaunchParameters.Retrieve(this.launchParametersKey); if (!v_oLaunchParameters && window.opener && !window.opener.closed && window.opener.RSParameters) { var v_sLaunchParametersKey = window.opener.RSParameters.launchParametersKey; var v_oLaunchParameters = rsLaunchParameters.Retrieve(v_sLaunchParametersKey); } else if (window.parent && options.launchParametersRef && window.parent[options.launchParametersRef]) { this.m_oPromptContext = window.parent[options.launchParametersRef].promptContext; } if (v_oLaunchParameters) { // merge options with the values pointed to by the key // the options from the object pointed to by the key take precedence $.extend(true, this, v_oLaunchParameters); } } catch(e) { console.log("cvContentView.init() - Call to window.opener failed, assume it doesn't exist"); } // console.log("end: cvContentView.init" ); this.m_bFullyInitialized = false; // Name of the classic viewer creation callback method this.m_sCreateCallback = "cvCreateCallback" + Date.now(); }, _postInit: function() { if (this.m_bFullyInitialized) { return; } this.m_bFullyInitialized = true; var options = this; if (options.type == 'output' && options.cmProperties && options.cmProperties.parent && options.cmProperties.parent[0] && options.cmProperties.parent[0].parent) { // If processing an output object and we have ancestor information, generate the saved output name. var v_sReportName = options.cmProperties.parent[0].parent[0].defaultName; this.m_sTitle = v_sReportName + " - " + options.cmProperties.modificationTime.substring(0, 10)+ " - " + options.cmProperties.format; } else if (options.cmProperties && options.cmProperties.defaultName) { this.m_sTitle = options.cmProperties.defaultName; } else if (options.defaultName) { this.m_sTitle = options.defaultName; } if (options.rsFinalRunOptions) { if (typeof options.rsFinalRunOptions.format != 'undefined') { options.format = options.rsFinalRunOptions.format; } if (typeof options.rsFinalRunOptions.locale != 'undefined') { // test how used options.locale = options.rsFinalRunOptions.locale; } if ( typeof options.rsFinalRunOptions.prompt !== 'undefined') { options.prompt = options.rsFinalRunOptions.prompt; } if (typeof options.rsFinalRunOptions.a11y != 'undefined') { options.a11y = options.rsFinalRunOptions.a11y; } if (typeof options.rsFinalRunOptions.bidi != 'undefined') { options.bidi = options.rsFinalRunOptions.bidi; } if (typeof options.rsFinalRunOptions.editSpecification != 'undefined') { options.editSpecification = options.rsFinalRunOptions.editSpecification; } delete options.rsFinalRunOptions; } // let create a form to submit to the classicviewer // TODO....change m_oRVFormParamters to something more meaningful like m_oClassicViewerForm? this.m_oRVFormParameters = {}; // Transfer all options.xxx fields where xxx is a recognised form field name to m_oRVFormParameters cvFormFields.forEach(function(v_sFormField){ if (typeof options[v_sFormField] != 'undefined') { this.m_oRVFormParameters[v_sFormField] = options[v_sFormField]; } }, this); if (options.format && !this.m_oRVFormParameters['run.outputFormat']) { this.m_oRVFormParameters['run.outputFormat'] = options.format; } if (options.contentLocale) { this.m_oRVFormParameters['run.outputLocale'] = options.contentLocale; } if (typeof options.prompt != 'undefined') { this.m_oRVFormParameters['run.prompt'] = (typeof options.prompt === "string") ? (options.prompt == "true") : !!options.prompt; } else { // for classical report running from RS, we treated undefined as true this.m_oRVFormParameters['run.prompt'] = true; } if (typeof options.a11y != 'undefined') { this.m_oRVFormParameters["system.http://developer.cognos.com/ceba/constants/systemOptionEnum#accessibilityFeatures"] = !!(options.a11y); } if (typeof options.bidi != 'undefined') { this.m_oRVFormParameters["biDirectional.http://developer.cognos.com/ceba/constants/biDirectionalOptionEnum#biDirectionalFeaturesEnabled"] = !!(options.bidi); } if (typeof options.editSpecification != 'undefined') { // This option is an XML string so only set it if we actually have something this.m_oRVFormParameters["specification.editSpecification"] = options.editSpecification; } // Ensure viewer renders the client side viewer in the response. // By default, PDF with accessibility enabled produces a page with PDF only and no viewer this.m_oRVFormParameters["ui.reuseWindow"] = true; this.m_oRVFormParameters["cv.createCallback"] = this.m_sCreateCallback; if (options.parameterValuesJSON) { this.m_oRVFormParameters["parameterValues"] = rsPromptParameters.rsBuildPromptParameters(null, options.parameterValuesJSON); } else if (options.parameterValuesXML) { this.m_oRVFormParameters["parameterValues"] = options.parameterValuesXML; } //Prompt parameters simple format this.m_aPromptParameters = []; for(var v_sKey in options) { if (options.hasOwnProperty(v_sKey) && v_sKey.indexOf('p_') == 0 && options[v_sKey]) { this.m_aPromptParameters.push({name: v_sKey, value: options[v_sKey]}); } } //Prompt parameters defined in json this.m_aPromptParametersComplex = []; if (options["promptParameters"]) { this.m_aPromptParametersComplex = Array.isArray(options["promptParameters"]) ? options["promptParameters"] : [options["promptParameters"]]; } var v_sSearchPath = this.getSearchPath(); var v_sStoreId = this.cmProperties && this.cmProperties.id; // Prefer search path over store ID since external lineage expects a standard search path var v_sReportSearchPath = v_sSearchPath || (v_sStoreId ? 'storeID("' + v_sStoreId + '")': ""); this.m_oRVFormParameters['ui.object'] = v_sReportSearchPath; if (!this.m_oRVFormParameters['ui.object']) { this.m_oRVFormParameters['cv.id'] = 'RS'; // this.m_oRVFormParameters['ui.errURL'] = 'javascript:window.close()'; } if (this.type == 'output') { this.m_oRVFormParameters['ui.action'] = 'view'; // Remove "run." parameters since we are viewing // Some of these override the ui.action=view and cause a run instead which is not what we want. for (var v_sProp in this.m_oRVFormParameters) { if (v_sProp.substring(0, 4) == "run.") { delete this.m_oRVFormParameters[v_sProp]; } } } else { // deletions are to ensure empty form fields are // not passed to viewer to avoid CAF rejecting them. if (this.m_oRVFormParameters['ui.object']) { this.m_oRVFormParameters['ui.action'] = 'run'; delete this.m_oRVFormParameters['ui.spec']; } else if (this.m_oRVFormParameters['ui.spec']) { this.m_oRVFormParameters['ui.action'] = 'runSpecification'; delete this.m_oRVFormParameters['ui.object']; } else { delete this.m_oRVFormParameters['ui.action']; delete this.m_oRVFormParameters['ui.spec']; delete this.m_oRVFormParameters['ui.object']; this.glassContext.showToast(StringResource.get('invalid_refresh'), {type:'error'}); } } // We want to explicitly turn off the header (which says Cognos Viewer) as well as the toolbars this.m_oRVFormParameters["cv.header"] = false; this.m_oRVFormParameters["cv.toolbar"] = false; this.m_oRVFormParameters["cv.keepWindowOpen"]=true; this.m_oRVFormParameters["isTitan"] = true; if (this.glassContext && this.glassContext.services && this.glassContext.services.userProfile && this.glassContext.services.userProfile.userProfileSettings && this.glassContext.services.userProfile.userProfileSettings.parameter_values) { this.m_oRVFormParameters["generic.anyURI.runOptionEnum#globalParameters"] = ParameterValues.toXML(this.glassContext.services.userProfile.userProfileSettings.parameter_values); } }, showWaitIndicator: function() { this.m_elDivViewerContainer.style.visibility = "hidden"; this.m_elDivStartUp.style.visibility = "visible"; }, hideWaitIndicator: function() { this.m_elDivStartUp.style.visibility = "hidden"; this.m_elDivViewerContainer.style.visibility = "visible"; }, _getNameFromViewer: function () { var v_oViewer = this.getCognosViewer(); return v_oViewer && v_oViewer.envParams && v_oViewer.envParams['ui.name']; }, getTitle: function() { // console.log("In cvContentView.getTitle\n"); return this.m_sTitle; }, getIcon: function() { //console.log("In cvContentView.getIcon\n"); return 'common-report'; }, getIconTooltip: function() { //console.log("In cvContentView.getIconTooltip\n"); return StringResource.get('classicviewer_welcome'); }, /** * Get the store ID of the underlying report object */ getReportStoreId: function() { if (rsCommon.isObjectOfType(this.cmProperties, 'output')) { return this.cmProperties.parent[0].parent[0].id; } return this.cmProperties && this.cmProperties.id; }, /** * Get the search path of the underlying report object */ getSearchPath: function() { return this.cmProperties && this.cmProperties.searchPath; }, getType: function() { var v_sType = this.cmProperties && this.cmProperties.type; if (!v_sType) { //When a classic report is launched from shared URL, we will not have cmPromperties, nor the type, we need to get the type from the viewer itself. var v_oCV = this.getCognosViewer(); v_sType = v_oCV && v_oCV.envParams["ui.objectClass"]; } return v_sType; }, getTimeStamp: function() { //console.log("In cvContentView.getTimeStamp\n"); return new Date().toUTCString(); }, updateButtons: function() { // Determine if readable. Assume readable if permissions not provided. var v_bRead = true; if (this.cmProperties && this.cmProperties.permissions && this.cmProperties.permissions.indexOf("read") == -1) { v_bRead = false; } var v_bShowEdit = false; //StoreId will be null if Authoring has launched classic viewer (because we are doing a runspec) if (this.glassContext.hasCapability("canUseReportStudio") && this.getReportStoreId() && v_bRead) { v_bShowEdit = true; } if (this.cmProperties && this.cmProperties.type == 'reportView') { // Don't allow edit on report views v_bShowEdit = false; } else if (this.cmProperties && this.cmProperties.type == 'report' && this.cmProperties.metadataModelPackage && this.cmProperties.metadataModelPackage[0] && this.cmProperties.metadataModelPackage[0].effectiveUserCapabilities) { if (this.cmProperties.metadataModelPackage[0].effectiveUserCapabilities.indexOf('canUseReportStudio') === -1 ) { v_bShowEdit = false; } } if (this.type == "output" || (this.cmProperties && this.cmProperties.type == "output")) { var v_bRun = this.cmProperties.permissions.indexOf("execute") != -1; this._setDisplayForPlugins(v_bRun, ["com.ibm.bi.classicviewer.outputBtn"]); this._setDisplayForPlugins(false, ["com.ibm.bi.classicviewer.saveBtn", "com.ibm.bi.classicviewer.editBtn", "com.ibm.bi.classicviewer.runMenu", "com.ibm.bi.classicviewer.previousReportBtn"]); } else { var v_bHasStoreId = !!this.getReportStoreId(); var v_sPluginId = "com.ibm.bi.classicviewer.editBtn"; this._setDisplayForPlugins(v_bShowEdit, [v_sPluginId]); this._setDisplayForPlugins(v_bHasStoreId, ["com.ibm.bi.classicviewer.saveBtn"]); this._setDisplayForPlugins(v_bHasStoreId, ["com.ibm.bi.classicviewer.runMenu"]); this._setDisplayForPlugins(false, ["com.ibm.bi.classicviewer.previousReportBtn","com.ibm.bi.classicviewer.outputBtn"]); } }, /** * Make the viewer iframe visible and hide the 'wait' indicator. */ _showViewer: function() { this.hideWaitIndicator(); this.updateButtons(); delete window.OnErrorPage; //console.log("end: cvContentView._showViewer\n"); }, show: function() { this.m_bDeactivated = undefined; cvContentView.inherited('show', this, arguments); if (this.m_aFnCallbacks) { // show saved plugings status var fnCallback; while (this.m_aFnCallbacks.length > 0) { fnCallback = this.m_aFnCallbacks.shift(); fnCallback(); } } }, _setEnabledForPlugins: function(v_bEnabled, v_aPluginIds) { v_aPluginIds.forEach(function(v_sPluginId) { var v_oPlugin = this.findPlugin(v_sPluginId); if (v_oPlugin) { if (v_bEnabled) { // console.log('%s show', v_sPluginId); v_oPlugin.enable(); } else { // console.log('%s hide', v_sPluginId); v_oPlugin.disable(); } } else { console.log('could not find plugin: %s', v_sPluginId); } }, this.glassContext); }, _setDisplayForPlugins: function(v_bShow, v_aPluginIds) { //console.group("cvContentView._setDisplayForPlugins"); //console.log("v_bShow:%s", v_bShow); v_aPluginIds.forEach( function(v_sPluginId) { var v_oPlugin = this.findPlugin(v_sPluginId); if ( v_oPlugin ) { if (v_bShow) { // console.log('%s show', v_sPluginId); v_oPlugin.show(); } else { // console.log('%s hide', v_sPluginId); v_oPlugin.hide(); } } else { console.log('could not find plugin: %s', v_sPluginId); } }, this.glassContext ); //console.groupEnd(); }, _isInternetExplorer: function() { var v_sAgent = navigator.userAgent.toLowerCase(); var v_fIEVersion = ( v_sAgent.search(/trident\/([0-9]+\.[0-9]+)/) != -1 ) ? parseFloat( RegExp.$1 ) : 0; return (v_fIEVersion >= 7.0); }, removePdfClass: function() { if (this._isInternetExplorer()) { this.m_elDivViewerContainer.classList.remove('PdfViewer'); } }, addPdfClass: function() { if (this._isInternetExplorer()) { //console.log("Setting PdfViewer class for IE"); this.m_elDivViewerContainer.classList.add('PdfViewer'); } }, onReportStatusComplete: function() { rsPerformance.mark('cvContentView.onReportStatusComplete'); console.timeEnd('rsperf: render->reportStatusComplete'); if (!!this.getReportStoreId()) { this._setEnabledForPluginsLazily(true, ["com.ibm.bi.classicviewer.saveBtn", "com.ibm.bi.classicviewer.runMenu"]); } // did we do something that changed the title? //if (this.m_sTitle) //{ // var v_sViewerName = this._getNameFromViewer(); // if (v_sViewerName && this.m_sTitle != v_sViewerName) // { // this.m_sTitle = v_sViewerName; // this.trigger('change:title', {'value': this.m_sTitle}); // } //} var v_oCognosViewer = this.getCognosViewer(); if (v_oCognosViewer && v_oCognosViewer.outputFormat == "PDF") { this.addPdfClass(); // Get PDF iframe this.m_iFramePDF = this.m_iframeClassicViewer.contentDocument.querySelector("iframe"); } else { this.removePdfClass(); delete this.m_iFramePDF; } }, onReportStatusPrompting: function() { if (!!this.getReportStoreId()) { this._setEnabledForPluginsLazily(false, ["com.ibm.bi.classicviewer.saveBtn", "com.ibm.bi.classicviewer.runMenu"]); // NOTE : Setting focus on the window did not work, but setting focus to the control did. // Not sure why. If you can think of a better way...great. // Change at your own risk. // get a node list of all the prompting control widgets var v_sCSSSelectors = ".clsTextWidget, .clsSelectDateEditBox, .clsSelectDateYearEditBox, .clsSelectDateEditBox, .clsSelectDateYearEditBox"; var v_nlPromptingControl = this.m_iframeClassicViewer.contentDocument.querySelectorAll(v_sCSSSelectors); // classnames of all the prompting control widgets including the prompt buttons var v_sCSSAllSelectors = v_sCSSSelectors + ", .bp"; if (v_nlPromptingControl.length > 0) { var v_aSelectors = v_sCSSAllSelectors.split(", "); // Check the active element matches one of the desired classname var bFound = v_aSelectors.includes("." + this.m_iframeClassicViewer.contentDocument.activeElement.className); // if none of them has a focus, set focus to the first non-button one. if (bFound == false) { v_nlPromptingControl[0].focus(); } } } }, _setEnabledForPluginsLazily: function(v_bEnabled, v_aPluginIds) { if (this.m_bDeactivated) { /** * this is for a long run report. when the running report's appView is hided behind and the report finish running, * this.findPlugin() function could find any plugin correctly, because glass always try to find plugin from current appView * which is not the long run report belong's to. so here, keep those status and do them when user switch the long run report's appView back to active */ if (!this.m_aFnCallbacks) { this.m_aFnCallbacks = []; } this.m_aFnCallbacks.push(function() { this._setEnabledForPlugins(v_bEnabled, v_aPluginIds); }.bind(this)); } else { this._setEnabledForPlugins(v_bEnabled, v_aPluginIds); } }, getViewerConfiguration: function() { console.timeEnd('rsperf: render->getViewerConfiguration'); rsPerformance.mark('cvContentView.getViewerConfiguration'); return { httpRequestCallbacks: { reportStatus: { complete: this.onReportStatusComplete.bind(this), prompting: this.onReportStatusPrompting.bind(this) } } }; }, render: function() { if (this.rsResolved) { // urlMap already fully resolved so proceed with rendering return this._render(); } // Perspective was launched directly without going through rsOpenHelper // Complete open resolution then proceed with render. if (!this.cmProperties && this.objRef) { // Create cmProperties from available information so resolution has something to work with this.cmProperties = { id: this.objRef, type: this.type // may or not be available but that is OK }; } var v_oOpenSpec = { cmProperties: this.cmProperties, glassContext: this.glassContext, urlMap: this }; return rsOpenHelper.resolveUrlMap(v_oOpenSpec).then(function(v_oResolvedOpenSpec) { // Merge resolved urlMap back into this instance and proceed with rendering $.extend(this, v_oResolvedOpenSpec.urlMap); return this._render(); }.bind(this)); }, _cleanPromptContext: function() { delete window.OnReportOutput; delete window.OnErrorPage; delete window.FinishCollectPrompts; this.m_oPromptContext.promptOpener.close(); }, _render: function() { // Perform any final initialization now that urlMap is fully resolved this._postInit(); // Update the buttons before we display the view in order to prevent flicker (REPORT-11732) this.updateButtons(); // This method returns a promise whose resolution signals the glass that our content view is done drawing. // Our view adds an iframe to the document and we use the onload event to trigger further processing to avoid race conditions. // The problem is the onload is called when the iframe is added to the document but also when the glass processes the promise resolution. // We need to defer our onload processing to the second call because any work done on the first load will get erased by the second load // (iframe src is about:blank). // One wrinkle in this is that under Edge, the iframe is not loaded when the glass promise is resolved so it must process things slightly differently. var deferred = $.Deferred(); console.timeEnd('rsperf: onSelectItem->render'); console.time('rsperf: render->loadIframe'); rsPerformance.mark('cvContentView.render'); this.$el.empty(); // Create wait indicator var v_aWaiting = document.getElementsByClassName("loadingIndicatorContainer"); var v_oWaiting = (v_aWaiting && v_aWaiting.length > 0) ? v_aWaiting.item(0) : null; this.m_elDivStartUp = document.createElement('div'); this.m_elDivStartUp.innerHTML = v_oWaiting ? v_oWaiting.outerHTML : ""; this.$el.append(this.m_elDivStartUp); // Create viewer div this.m_elDivViewerContainer = document.createElement('div'); this.m_elDivViewerContainer.style.width = "100%"; this.m_elDivViewerContainer.style.height = "100%"; this.m_elDivViewerContainer.style.position = "absolute"; this.m_elDivViewerContainer.style.visibility = "hidden"; this.$el.append(this.m_elDivViewerContainer); // Create viewer iframe this.m_iframeClassicViewer = document.createElement('iframe'); this.m_iframeClassicViewer.name = this.m_iframeClassicViewer.title = this.id || '_classicViewer'; this.m_iframeClassicViewer.src = "about:blank"; this.m_iframeClassicViewer.style.border = "none"; this.m_iframeClassicViewer.style.width = "100%"; this.m_iframeClassicViewer.style.height = "100%"; this.m_iframeClassicViewer.style.position = "absolute"; // HACK: the Glass doesn't have an API to squish the sidebar this.m_oAppView.$('.navbar').addClass('narrow'); console.time('rsperf: render->getViewerConfiguration'); window.getViewerConfiguration = this.getViewerConfiguration.bind(this); console.time('rsperf: render->reportStatusComplete'); // prompting for collectParameterValues in classical viewer if (this.m_oPromptContext && this.m_oPromptContext.promptOpener && this.getReportStoreId()) { // The following callback is invoked from prompt pages. // If a report has no parameters then no prompt page is rendered so we never // show the window - this is what we want. If we do show the window when there a no prompt pages, then // when we close the window in FinishCollectPrompts (see above), this terminates the java script which prevents // the caller from displaying the correct toasts. window.OnReportOutput = function() { // show prompting window if we have not already done so if (!this.m_oPromptContext.promptOpenerShown) { this._showViewer(); this.m_oPromptContext.promptOpener.show(); this.m_oPromptContext.promptOpenerShown = true; } }.bind(this); // Callback from classic error page window.OnErrorPage = function( code, message, details ) { if (this.m_oPromptContext.promptFnErrorCallback) { var error = { "code": code, "message": message, "details": details }; this.m_oPromptContext.promptFnErrorCallback( error ); } else if (this.m_oPromptContext.promptFnCancelCallback) { this.m_oPromptContext.promptFnCancelCallback(); } this._cleanPromptContext(); }.bind(this); // classical API function, this is called when finishing prompting window.FinishCollectPrompts = function(success) { if (success) { if (this.m_oPromptContext.promptFnOkCallback1) { console.log("promptContext.promptFnOkCallback1"); // This version of the OK callback will invoke the prompting service to retrieve the results. // This resolves a strange behavior in IE (see APAR 14584 which applies to reports as well as QS) this.m_oPromptContext.promptFnOkCallback1(); this._cleanPromptContext(); } else { console.log("promptContext.promptFnOkCallback"); this.glassContext.getSvc('.Prompting').then(function(promptingSvc) { promptingSvc.getPromptAnswers(this.m_oPromptContext.promptRDSId).then( function(values) { this.m_oPromptContext.promptFnOkCallback(values); this._cleanPromptContext(); }.bind(this)); }.bind(this)); } } else { if (this.m_oPromptContext.promptFnCancelCallback) { this.m_oPromptContext.promptFnCancelCallback(); } this._cleanPromptContext(); } }.bind(this); // RDS request for prompt ID this.glassContext.services.ajax.ajax({ url: classicViewerGatewaySuffix + promptPageEndpoint + this.getReportStoreId(), type: 'GET', dataType: 'xml' }).done(function(xmlDoc, status, jqXHR) { this.m_oPromptContext.promptRDSId = xmlDoc.getElementsByTagNameNS('http://developer.cognos.com/schemas/rds/types/2', 'promptID').item(0).textContent; this.m_oPromptContext.promptOpener.id = this.m_oPromptContext.promptRDSId; // Store any parameter values provided by the caller in the runTimeState object which is created by the // call to the promptPageEndpoint above. // The promting XTS pages look for initial parameter values in this runTimeState object. var v_sParameterValues = rsPromptParameters.rsBuildPromptParameters( null, this.m_oPromptContext.parameters ); this.glassContext.services.ajax.ajax({ type: 'PUT', url: 'v1/objects/' + this.m_oPromptContext.promptRDSId, data: JSON.stringify( { type: 'runTimeState', state: v_sParameterValues }), headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }).done(function(){ // submit collectParameterValues request based on report id and prompt id this._createAndSubmitCollectParameterValuesForm(this.getReportStoreId(), xmlDoc.getElementsByTagNameNS('http://developer.cognos.com/schemas/rds/types/2', 'url').item(0).textContent); deferred.resolve(this.$el); }.bind(this)); }.bind(this)); } else { // onload must be specified before iframe is attached to the document because Chrome will trigger the load immediately this.m_iframeClassicViewer.onload = this._onLoad.bind(this); this.loadClassicViewer(); // This is the "early" resolve - show the StartUp div right away deferred.resolve(this.$el); } // On Chrome, adding the iframe to the document triggers the onload event immediately whereas other browsers load the iframe // when the current js call stack finishes. We must delay adding the iframe until all work is done in this method to ensure // all callbacks are properly configured before the ifrmae loads so this is the last thing we do. this.m_elDivViewerContainer.appendChild(this.m_iframeClassicViewer); return deferred.promise(); }, /** * This method is called by the classic viewer right after the classic viewer object is created but before the page finishes loading. * The timing is important because it lets us know about the classic viewer before any iframes are processed which may trigger a download. * The div containing the classic viewer is hidden until we are notified the classic viewer exists so this must happen before download is initiated. * @param v_sCV Name of the classic viewer object */ _onClassicViewerCreated: function( v_sCV ) { //console.log("CV create callback"); // Get the classic viewer object if (this.m_iframeClassicViewer && this.m_iframeClassicViewer.contentWindow) { // Ensure getClassicViewer returns the the classic viewer without having to look for it this.m_oCognosViewer = this.m_iframeClassicViewer.contentWindow[v_sCV]; } this._onClassicViewerLoaded(); }, /** * Hook up the classic viewer to the cvContentView * and display the viewer iframe */ _onClassicViewerLoaded: function() { console.timeEnd('rsperf: render->loadIframe'); console.timeEnd('rsperf: total_RunReport'); rsPerformance.mark('cvContentView._onClassicViewerLoaded'); rsPerformance.mark('authoring-selectItemAndDraw-stop'); //console.log("cvContentView._onClassicViewerLoaded(). "); if (this.isViewerLoaded()) { // Either classic viewer or RDS prompt page is loaded var v_oCognosViewer = this.getCognosViewer(); if (v_oCognosViewer) { this.m_iframeClassicViewer.contentWindow.onunload = this._release.bind(this); // get a reference to the original executeBackURL method...just in case we need to call it this.original_executeBackURL = this.m_iframeClassicViewer.contentWindow.executeBackURL; // point the existing method to our method this.m_iframeClassicViewer.contentWindow.executeBackURL = this.executeBackURL.bind(this); // get a reference to the original doSingleDrill method...we need to call it later this.original_doSingleDrill = this.m_iframeClassicViewer.contentWindow.doSingleDrill; // point the existing method to our method this.m_iframeClassicViewer.contentWindow.doSingleDrill = this.doSingleDrill.bind(this); // Define goto page handler this.m_iframeClassicViewer.contentWindow.rsGoToHandler = this.gotoHandler.bind(this); // Prevent old PDF drill logic from trying to restore PDF using browser history (see viewer drill-from-pdf.xts) this.m_iframeClassicViewer.contentWindow.f_restorePDF = this.f_restorePDF.bind(this); // get a reference to the original addDrillEnvironmentFormFields method...we need to call it later this.original_addDrillEnvironmentFormFields = this.m_iframeClassicViewer.contentWindow.addDrillEnvironmentFormFields; // point the existing method to our method this.m_iframeClassicViewer.contentWindow.addDrillEnvironmentFormFields = this.addDrillEnvironmentFormFields.bind(this); if (this.glassContext && this.glassContext.isDevInstall && this.glassContext.isDevInstall()) { rsPerformance.summarizeClassicViewerRun( this ); } if (v_oCognosViewer.updateNewBrowserWindow && this.m_iframeClassicViewer.contentWindow.getFormWarpRequest) { var form = this.m_iframeClassicViewer.contentWindow.getFormWarpRequest(); var v_sBackURL = v_oCognosViewer.m_bIgnoreCloseWindow ? "" : (form ? form["ui.backURL"].value : ""); if (v_sBackURL == "javascript:window.close();") { v_oCognosViewer.updateNewBrowserWindow = function() { this.glassContext.closeAppView("classicviewer", this.id); }.bind(this); } } /** * inject a function to classical viewer, when keyboard conbination ctrl-shift-1 is hit, * this function will be called to fucus to Appbar */ v_oCognosViewer.focusBackToContent = function(evt) { this.glassContext.accessibilityController.setFocusToAppbar(); }.bind(this); /** * inject a function to classical viewer, when keyboard conbination ctrl-shift-2 is hit, * this function will be called to fucus to MainContent */ v_oCognosViewer.focusBackToMainContent = function(evt) { this.setFocus(); }.bind(this); } this._showViewer(); } // Stop processing load event this.m_iframeClassicViewer.onload = null; }, createLaunchSpec : function(v_oCmObject, format, method, locale, sPrompt) { // Convert HTML-like formats to HTML to ensure perspective resolution works // Viewer will handle specifying the actual format that it really wants. format = format.indexOf('HTML') != -1 ? 'HTML' : format; var v_oLaunchSpec = { // string of output format // one of HTML, PDF, xlsxData, CSV, spreadsheetML, layoutDataXML, rawXML, singleXLS, HTMLFragment format: format, objRef: v_oCmObject.id, type: v_oCmObject.type, contentLocale: locale, }; switch (method) { case "execute": case "run": v_oLaunchSpec.action = "run"; break; case "view": case "viewOutput": v_oLaunchSpec.action = "viewOutput"; break; case "edit": v_oLaunchSpec.action = "edit"; break; } switch (sPrompt) { case "yes": case "true": v_oLaunchSpec.prompt = true; break; case "no": case "false": v_oLaunchSpec.prompt = false; break; } return v_oLaunchSpec; }, // we are hijacking the viewer's copy of this method so that we can // add a form field to the form before being submitted addDrillEnvironmentFormFields : function(drillForm, oCV) { // call the original viewer method this.original_addDrillEnvironmentFormFields (drillForm, oCV); // append the cv.keepWindowOpen field to the form // we probably do not need to check to see if the "createFormField" method exists, but // I would rather make sure before I called it. if (this.m_iframeClassicViewer && this.m_iframeClassicViewer.contentWindow && this.m_iframeClassicViewer.contentWindow.createFormField) { drillForm.appendChild(this.m_iframeClassicViewer.contentWindow.createFormField("cv.keepWindowOpen", "true")); } }, /** * Handler called from goto page for authored drill. * @param drillType Indicates what kind of drill is being performed * @param drill drill information specific to drill type */ gotoHandler : function(drillType, drill) { if (drillType == 'authoredDrillthru') { this._authoredDrillHandler(drill); } else { this._packageDrillHandler(drill); } }, /** * Submit form described by drill as AJAX request after adding option * to make request return results of calling drill service on package drill object. */ _packageDrillHandler : function(drillForm) { this._sendDrillThroughRequest( {packageDrill: true}, drillForm ); }, /** * Perform authored drill. Converts the drill information into the parameters expected by the doSingleDrill method * and then calls said method. As a result, authored drill from goto page behaves the same * as single authored drill. */ _authoredDrillHandler : function(drill) { var target, args, method, format, locale, bookmark, sourceContext, objectPaths, cvId, sPrompt, dynamicDrill; var v_aObj = []; var v_aParams = []; var v_oDrillDoc = this.parseXML(drill); var v_nDrillNode = v_oDrillDoc && v_oDrillDoc.documentElement.firstChild; while (v_nDrillNode) { switch (v_nDrillNode.nodeName) { case 'param': switch (v_nDrillNode.getAttribute('name')) { case 'action': method = this.getNodeText(v_nDrillNode); break; case 'format': format = this.getNodeText(v_nDrillNode); break; case 'locale': locale = this.getNodeText(v_nDrillNode); break; case 'target': var v_sTarget = this.getNodeText(v_nDrillNode); // When action on drill is view, the target search path provided from the goto page // is based on the defaultOutput( path, format, locale ) CM search path function. // Use a pattern to extract the path parameter. var v_aMatch = v_sTarget.match(g_reDefaultOutput); if (v_aMatch && v_aMatch.length > 1) { v_sTarget = v_aMatch[1]; } v_aObj.push('obj'); v_aObj.push(v_sTarget); break; case 'prompt': sPrompt = this.getNodeText(v_nDrillNode); break; case 'dynamicDrill': dynamicDrill = this.getNodeText(v_nDrillNode); break; case 'showInNewWindow': target = (this.getNodeText(v_nDrillNode) == 'false') ? '' : '_blank'; break; case 'executionParameters': break; case 'metadataModel': break; case 'sourceContext': sourceContext = this.getNodeText(v_nDrillNode); break; case 'bookmark': bookmark = this.getNodeText(v_nDrillNode); break; case 'objectPaths': objectPaths = this.getNodeText(v_nDrillNode); break; } break; case 'drillParameters': var v_nParamNode = v_nDrillNode.firstChild; while (v_nParamNode) { if (v_nParamNode.nodeName == 'param') { var v_sName = v_nParamNode.getAttribute('name'); var v_sValue = this.getNodeText(v_nParamNode); v_aParams.push([v_sName, v_sValue]); } v_nParamNode = v_nParamNode.nextSibling; } break; } v_nDrillNode = v_nDrillNode.nextSibling; } args = [v_aObj]; cvId = this.getCognosViewer().getId(); this.doSingleDrill(target, args.concat(v_aParams), method, format, locale, bookmark, sourceContext, objectPaths, cvId, sPrompt, dynamicDrill ); }, doSingleDrill : function(target,args,method,format,locale,bookmark,sourceContext,objectPaths,cvId,sPrompt,dynamicDrill) { // This method is called by the classic viewer when doing a single drill. The viewer first determines whether or // not a drill to self should be done. If not, then it calls this method. We need to take over processing // so that we can determine which perspective should be used on the target. // But first, we use the classic viewer to call the drill service. var v_oArguments = { target: target, args: args, method: method, format: format, locale: locale, bookmark: bookmark, sourceContext: sourceContext, objectPaths: objectPaths, cvId: cvId, sPrompt: sPrompt, dynamicDrill: dynamicDrill }; this.showWaitIndicator(); // Override how classic viewer issues it's drill request and call original drill method this.getCognosViewer().sendDrillThroughRequest = this._sendDrillThroughRequest.bind(this, v_oArguments); this.original_doSingleDrill(target,args,method,format,locale,bookmark,sourceContext,objectPaths,cvId,sPrompt,dynamicDrill); }, _htmlDecode: function (v_sText) { var v_oDoc = new DOMParser().parseFromString('