📄 htmlflow.js
字号:
//<httpMethod:"GET", // default would POST//> @attr htmlFlow.contentsType (String : null : IR)// The default setting of 'null' or 'fragment' indicates that HTML loaded from// +link{contentsURL} is assumed to be an HTML fragment rather than a complete page. Set to// "page" to load HTML as a standalone page, via an IFRAME. // <P>// <code>contentsType:"page"</code> should only be used for controlled HTML content, and only// when such content cannot be delivered as an HTML fragment instead (the default). To// dynamically load SmartClient components, use +link{ViewLoader}, <b>never</b> this mechanism// (click +link{group:noFrames,here} for why).// <P>// Loading HTML content as a fragment is less resource intensive and avoids visual artifacts// such as translucent media becoming opaque or disappearing when placed over an IFRAME. // <P>// Loading third-party, uncontrolled content could lead to the surrounding page disappearing if// a user clicks on an HTML link with <code>target=_top</code>.// <P>// With <code>contentsType:"page"</code>, +link{loadingMessage} is not supported, and only// "GET" is supported for +link{httpMethod,httpMethod}.//// @group contentLoading// @visibility external//<useSimpleHttp:true, // don't send stuff that RPC layer usually sends (serialized transaction, etc)// custom properties for RPC. Maybe be needed in the future for cache control, etc//contentRPCProperties: null,//> @attr htmlFlow.evalScriptBlocks (boolean : true : IR)// If <code>evalScriptBlocks</code> is true, HTMLFlow will pre-process the loaded HTML in order to// mimic how the HTML would execute if it were loaded as an independent page or loaded via an// IFRAME. // <P>// This feature is intended to assist with migrating existing applications to SmartClient.// <P>// Note that, if evalScriptBlocks is false, <SCRIPT> blocks will still be detected and disabled// to avoid the inconsistent results across different browsers.//// @group contentLoading// @visibility external//<evalScriptBlocks: true,//> @attr htmlFlow.captureSCComponents (boolean : true : IR)// If true, SmartClient components created while executing the loaded HTML are captured// for rendering inside the HTMLFlow.//// @group contentLoading// @visibility external//<captureSCComponents: true});isc.HTMLFlow.addMethods({initWidget : function () { // We can't auto-size to the contents of the IFRAME at present. When we contain an // IFRAME, the only meaningful overflows are "auto" or "hidden" because "visible" produces // inconsistent results that you would never want (never overflows in FF, oveflows to 200px // in IE). // // overflow: "auto" correctly introduces a native scrollbar on the IFRAME when its content // exceeds the space allocated to this component, but this component overflows to the max // space allowed by its container - which is generally what the user wants. // // ovefflow: "hidden" works like "auto", but native IFRAME scrollbars are suppressed. This // is controlled in Canvas.getIFrameHTML by setting the "scrolling" property of the IFRAME. if (this.contentsType == "page" && this.overflow == "visible") this.setOverflow("auto");},// Don't load content until draw to allow declarative delayed loadingdraw : function () { if (!this.readyToDraw()) return this; this.Super("draw", arguments); // in this case content isn't loaded until draw, when the IFRAME is created. // NOTE: actual code for this resides in Canvas var undef; if (this.containsIFrame()) return this; else if (this.canSelectText === undef) this.canSelectText = true; // this will cause contents to be loaded if they are not already loading if (this.contentsURL && !(this._loadedContentsURL == this.contentsURL || this.loadingContent())) { this.setContentsURL(); } return this;}, //> @method htmlFlow.setContentsURL()// Change the URL this component loads content from. Triggers a fetch for content from the new// URL.// <p>// Can also be called with no arguments to reload content from the existing +link{contentsURL}.// <P>// This feature relies on the XMLHttpRequest object which can be disabled by end-users in some// supported browsers. See +link{group:platformDependencies} for more information.//// @param [url] (URL) URL to retrieve contents from// @param [params] (Object) Parameters to send to the contentsURL. Merged with// <code>component.contentsURLParams</code> if both are set.// @group contentLoading// @visibility external// @example loadHtmlPages//<setContentsURL : function (url, params, rpcProperties) { // for IFRAME-based loading, leave it up to Canvas code if (this.contentsType == "page") { return this.invokeSuper(isc.HTMLFlow, "setContentsURL", url); } // store new URL if (url != null) this.contentsURL = url; // during the reload, re-show the loading message if (this.loadingMessage) this.setContents(this.loadingMessage); var allParams = isc.addProperties({}, this.contentsURLParams, params), useSimpleHttp = this.useSimpleHttp, httpMethod = this.httpMethod, serverOutputAsString = true; var reloadRequest = isc.addProperties({ showPrompt:false, actionURL: this.contentsURL, httpMethod: httpMethod, useSimpleHttp: useSimpleHttp, // IE caches very aggressively by default, which can be confusing, so disable caching // unless this (currently undocumented) flag is set bypassCache: !this.allowCaching, params: allParams }, this.contentRPCProperties, // widget rpc properties rpcProperties, // method rpc properties // non-overrideable { willHandleError: true, serverOutputAsString: serverOutputAsString, callback: this.getID()+"._loadContentReply(rpcRequest, rpcResponse)" }); // remember the transactionNum so we load the last request only this._loadNumber = isc.rpc.sendProxied(reloadRequest, true).transactionNum; },//> @method htmlFlow.loadingContent() (A)// Returns true if this htmlFlow is currently loading content from the server.<br>// Note: Does not apply to htmlFlows with +link{htmlFlow.contentsType, contentsType} set to // <code>"page"</code>//// @group contentLoading// @see htmlFlow.contentLoaded()// @visibility external//<loadingContent : function () { return this._loadNumber != null; }, _loadContentReply : function (rpcRequest, rpcResponse) { //!OBFUSCATEOK var html = rpcResponse.data; if (rpcResponse.status != isc.RPCResponse.STATUS_SUCCESS) { if (this.handleError(rpcRequest, rpcResponse) === false) return; } // handles case of setContentsURL() being called while we're fetching from some other URL if (rpcRequest.transactionNum != this._loadNumber) { return; } // We need to execute Script embedded in the HTML [which we may have to load asynchronously from // script src=... tags]. // Steps: // 1: Extract any script tags from the HTML and store them // 2: Set our contents to match the sanitized HTML // 3: Execute scripts isc.HTMLFlow.getScript(html, {target:this, methodName:"_setContentsAndExecute"}, true, !this.evalScriptBlocks);},_relPosID: 0,_captureSCComponentsRelPos : function (component) { if (!component.parentElement) this.addChild(component); var componentID = "HTMLFlow" + this._relPosID++; component.htmlElement = componentID; var returnHtml = '<DIV id="' + componentID + '"></DIV>'; return returnHtml;},_captureSCComponentsAbsPos : function (component) { if (!component.parentElement) this.addChild(component); return null;},// setContentsAndExecute - helper method for 'loadContentReply()' when we have// separated any JS from the HTML_setContentsAndExecute : function (htmlFragments, scripts) { // render the html this.setContents(this.transformHTML(htmlFragments.join(""))); // Any split of htmlFragments into multiple entries must imply that a script was // found that must be executed. if (htmlFragments.length > 1) { if (this.evalScriptBlocks) { // At this point we know we don't have any script src=... blocks // If we have any inline script, eval it now. if (this.isDirty()) this.redraw(); if (this.captureSCComponents) { this._oldAutoDraw = isc.Canvas.autoDraw; isc.setAutoDraw(false); } for (var i=0; i<htmlFragments.length; i++) { // put together a callback that writes directly into htmlFragments. // (but if !captureSCComponents, don't.) var callback = null; var mythis = this; if (this.captureSCComponents) callback = function (globals, error) { if (!globals.length) return; htmlFragments[i] = globals.map(function (newGlobalID) { var newGlobal = window[newGlobalID]; if (!newGlobal || !isc.isA.Canvas(newGlobal)) return null; if (newGlobal.position == isc.Canvas.RELATIVE) return mythis._captureSCComponentsRelPos(newGlobal); else return mythis._captureSCComponentsAbsPos(newGlobal); }).join(""); }; // note that this relies on the callback being executed // synchronously if (scripts[i]) isc.Class.globalEvalWithCapture(scripts[i], callback); } if (this.captureSCComponents) { this.setContents(this.transformHTML(htmlFragments.join(""))); if (this._oldAutoDraw) { // Reenable autodraw and redraw everything that originally // had autodraw enabled isc.setAutoDraw(true); for (var global in window) if (isc.isA.Canvas(global) && global.autoDraw) global.markForRedraw(); } } } //>DEBUG else { this.logWarn("html returned by server appears to contain <script> blocks. " + "If you want these to be evaluated, you must set evalScriptBlocks:true."); } //<DEBUG } this._loadContentsReplyComplete(); },//> @method htmlFlow.handleError()//// This method is called when a transport error occurs. Typically, this is the result of the// server returning an HTTP error code such as 404 - document not found. You can inspect the// RPCResponse object for the reasons for the error and take appropriate action. Typical// properties to look at are rpcResponse.status, and rpcResponse.httpResponseCode.// <p>// This method is called from the response processing pipeline. If you want to provide your// own HTML response that should be rendered into this component as the result of the error,// you can do so by setting rpcResponse.data to your HTML string. Returning false from this// method suppresses any further response handling. The default implementation of this method// causes an error message to be logged to the Developer Console and sets the HTML to the error// string.//// @param rpcRequest (RPCRequest) The RPCRequest that was made to the server// @param rpcResponse (RPCResponse) The RPCResponse that was received//// @return (boolean) false to suppress further response processing// // @group contentLoading// @visibility external//<handleError : function (rpcRequest, rpcResponse) { this.logWarn(rpcResponse.data);},_loadContentsReplyComplete : function () { this._loadedContentsURL = this.contentsURL; this._loadNumber = null; this.contentLoaded();},//> @method htmlFlow.transformHTML// Translates html content into a form most suitable for rendering inside this component.// @group contentLoading// @visibility external//<transformHTML : function (html) { return html;},//> @method htmlFlow.contentLoaded()// StringMethod fired when content is completely loaded in this htmlFlow. Has no default // implementation. May be observed or overridden as a notification type method to fire custom// logic when loading completes.<br>// Note: Does not apply to htmlFlows with +link{htmlFlow.contentsType, contentsType} set // to <code>"page"</code>// @group contentLoading// @visibility external//<contentLoaded : function () { }});isc.HTMLFlow.registerStringMethods({ // contentLoaded takes no arguments contentLoaded:""})//> @class HTMLPane// Use the HTMLPane component to display HTML content in a pane of specified size. If the HTML// content is larger than the size of the pane, the pane will provide scrollbars for viewing// clipped content.// <P>// You can set the size of an HTMLPane directly via the width and height properties, or// indirectly by placing the HTMLPane in a container component (+link{Layout}, +link{Window}, // +link{SectionStack}, etc) that manages the sizes of its members.//// @treeLocation Client Reference/Foundation// @visibility external// @example htmlPane//<isc.defineClass("HTMLPane", isc.HTMLFlow).addProperties({ overflow:isc.Canvas.AUTO,defaultHeight:200 });
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -