📄 htmlflow.js
字号:
/*
* Isomorphic SmartClient
* Version 6.5 (2008-04-30)
* Copyright(c) 1998-2007 Isomorphic Software, Inc. All rights reserved.
* "SmartClient" is a trademark of Isomorphic Software, Inc.
*
* licensing@smartclient.com
*
* http://smartclient.com/license
*/
// HTMLFlow / HTMLPane// ---------------------------------------------------------------------------------------// Behaviors in these classes are slated to be moved down to Canvas. Theses class principally// exist as a way of organizing functionality for more useful defaults, documentation, tool and// skinning purposes.//> @class HTMLFlow//// Use the HTMLFlow component to display HTML content that should expand to its natural size// without scrolling. // <p>// HTML content can be loaded and reloaded from a URL via the property// <code>contentsURL</code>. This method of loading is for simple HTML content// only; SmartClient components should be loaded via the +link{class:ViewLoader} class.// <P>// NOTE: Since the size of an HTMLFlow component is determined by its HTML contents, this// component will draw at varying sizes if given content of varying size. When using HTMLFlow// components within a Layout, consider what will happen if the HTMLFlow renders at various// sizes. An HTMLFlow which can expand should be placed in a container where other components// can render smaller, where the container is allowed to scroll, or where there is padding to// expand into.// // @group contentLoading// @treeLocation Client Reference/Foundation// @visibility external// @example htmlFlow//<isc.ClassFactory.defineClass("HTMLFlow", "Canvas");isc.HTMLFlow.addClassMethods({ //> @classMethod htmlFlow.executeScript() (A)// Given a block of HTML extract any JavaScript from it (including script loaded from external // files via <code>script src=...</code> tags), and execute it.<br>// Note: This method will be asynchronous if script blocks needs to be loaded from the server.// @param html (HTML) Block of HTML from which script tags will be extracted and executed// @param callback (callback) Callback to fire when the script has been executed. If a// script error occured during execution, it will be passed to this parameter as the// first parameter <code>error</code>// @param [displayErrors] (boolean) By default script errors encountered executing the// extracted script will be logged to the developer console. Pass in a false value for this// parameter to suppress this behavior// @visibility internal//<// Not currently used anywhere_scriptID:0,_executeContext:[],executeScript : function (html, callback, displayErrors) { this._executeContext[this._scriptID] = {callback:callback, displayErrors:displayErrors}; this._scriptID++; this.getScript( html, "isc.HTMLFlow._completeExecuteScript(" + this._scriptID + ",htmlFragments, scripts);" );},// helper for asynchronous executeScript() method_completeExecuteScript : function (scriptID, htmlFragments, scripts) { var context = this._executeContext[scriptID]; delete this._executeContext[scriptID]; // reset scriptID to 0 if we've got no other outstanding executions so we dont let // the array get large var empty=true; for (var i = 0; i < this._executeContext.length; i++) { if (this._executeContext[i] != null) { empty = false; break; } } if (empty) this._scriptID = 0; isc.Class.globalEvalWithCapture(scripts, context.callback, null, context.displayErrors);}, //> @classMethod htmlFlow.getScript() (A)// Retrieves any JavaScript embedded in a snippet of HTML as a string of script that// can be executed.<br>// If the HTML contains a <code><script src=...</code> tag, this method will load that external// script file, extract its contents and included it in the returned block of script.<br>// Note that since the script may have to be loaded from the server, this method may be asynchronous.// @param html (HTML) Snippet of HTML to retrieve the script from// @param callback (callback) callback fired when the script has been retrieved. Parameters passed to this callback// are <code>html</code> [the block of html] and <code>script</code> [the script].// @param [extractScriptFromHTML] (boolean) Should the <code>html</code> parameter passed to the callback// include the extracted script blocks, or have them removed.// @visibility internal//<// Used by _loadContentReplygetScript : function (html, callback, extractScriptFromHTML, dontFetchScripts) { // Make a copy of the HTML for us to return if extractScriptFromHTML if false var originalHTML = html; // Strip all <!-- --> comment blocks from the html before extracting script tags so we // only get script that would natively execute var commentStart, commentEnd, commentStartIndex, commentEndIndex; while ((commentStart = html.match(/<!--/i)) != null) { commentEnd = html.match(/-->/i); if (commentEnd == null || (commentEnd.index < commentStart.index)) { this.logWarn('HTMLFlow content contains an opening comment tag "<!--"' + ' with no closing tag "-->", or vice versa. We recommend you review this ' + 'HTML (original HTML follows):\n' + originalHTML); // strip the mismatched comment tag from the working html as if it were a // full comment block if (commentEnd) { commentStartIndex = commentEnd.index; commentEndIndex = commentStartIndex + 3; } else { commentStartIndex = commentStart.index; commentEndIndex = commentStartIndex + 4; } } else { commentStartIndex = commentStart.index; commentEndIndex = commentEnd.index + 3; } html = html.slice(0, commentStartIndex) + html.slice(commentEndIndex, html.length); } // parse out <SCRIPT> blocks to eval later. var scripts = []; // script accumulator var scriptIncludes = []; // src= values var htmlFragments = []; var htmlRemaining = html; html = null; var scriptStart; // match the start of a <script> block: note that the script block can contain a type or // language or type specifier or a src= while ((scriptStart = htmlRemaining.match(/(<script([^>]*)?>)/i)) != null) { var scriptStartTag = scriptStart[1]; // chop out the opening script tag, then pick up the closing script tag. // If we hit another opening script tag before the closing tag, or can't find a // closing tag, log a warning and continue. htmlFragments.add(htmlRemaining.slice(0, scriptStart.index)); scripts.add(null); scriptIncludes.add(null); htmlRemaining = htmlRemaining.slice( scriptStart.index+ scriptStartTag.length, htmlRemaining.length) // match the end of the script block var scriptEnd = htmlRemaining.match(/<\/script>/i), nextScriptStart = htmlRemaining.match(/(<script([^>]*)?>)/i); if (scriptEnd == null || (nextScriptStart && (scriptEnd.index > nextScriptStart.index))) { this.logWarn("HTMLFlow content contains an opening <script ...> tag " + "with no closing tag, or vice versa. Stripping out this tag:" + scriptStartTag); continue; } // the script block is the stuff inside the <script></script> brackets var scriptBlock = htmlRemaining.slice(0, scriptEnd.index); // pull the script block we just matched out of the html stream so we can match // additional script blocks and because it's possible that rendering the script blocks // will get the executed - which we don't want because we'll be evaling them ourselves. htmlRemaining = htmlRemaining.slice(scriptEnd.index+9, htmlRemaining.length); // only append script blocks containing JS code. A js script block either does not // specify type/language, or has a type=/language= that // contains javascript,jscript, or ecmascript var isJS = (scriptStartTag.match(/<script\s*(language|type)/i) == null) || (scriptStartTag.match(/<script\s*(language|type)\s*=["']?(javascript|ecmascript|jscript)["']?/i) != null); // skip loading SmartClient modules that are already loaded var iscMatch = scriptStartTag.match(/ISC_([^.]*)\.js/i); if (iscMatch && isc["module_" + iscMatch[1]]) continue; if (isJS) { var srcMatch; if (srcMatch = scriptStartTag.match(/src=('|")?([^'"> ]*)/i)) { scriptIncludes.add(srcMatch[2]); scripts.add(null); } else { // avoid empty script blocks which can lead to hangs if (!isc.isA.String(scriptBlock) || isc.isAn.emptyString(scriptBlock)) continue; // slot this script into our script accumulator scripts.add(scriptBlock); } htmlFragments.add(null); } else { // Warn (rather than just logInfo) if we hit non JS script tags since functionality // could actually be lost from the HTML in some cases this.logWarn("html to be evaluated contains non-JS script tags - these will be" + " ignored. Tag: " + scriptStartTag); } } // if scriptStart never matched, set htmlFragments to the entire html text if (htmlFragments.length == 0) htmlFragments = [ htmlRemaining ]; // If we had any 'script src=...' tags, we need to load their contents and fold it into // the script to evaluate if (scriptIncludes.length > 0 && !dontFetchScripts) { if (isc.RPCManager) { var loadingScripts = false; for (var i = 0; i < scriptIncludes.length; i++) { // it's a sparse array if (scriptIncludes[i] == null) { continue; } isc.RPCManager.sendRequest( {actionURL: scriptIncludes[i], serverOutputAsString:true, httpMethod:"GET", clientContext:{ scriptIndex:i, scripts:scripts, scriptIncludes:scriptIncludes, callback:callback, htmlFragments:(extractScriptFromHTML ? htmlFragments : [originalHTML]) }, callback:"isc.HTMLFlow.loadedRemoteScriptBlock(data, rpcResponse.clientContext)" } ); loadingScripts = true; } // wait for the script files to be loaded (asynchronous) before firing the // 'completion' method if (loadingScripts) return; } else { // Warn the user that their non-JS code and JS code loaded via SCRIPT SRC= will not execute. this.logWarn("html contains <script src=> blocks with the " +"following target URLs: " + scriptIncludes + " If you want " +"these to be dynamically loaded, please include the " +"DataBinding module or include the contents of " +"these files in inline <script> blocks."); } } // In this case we have no script src =, so we can synchronously fire the callback var script = scripts.join("\n"); this.fireCallback(callback, "htmlFragments,scripts", [extractScriptFromHTML ? htmlFragments : [originalHTML], scripts]);},// Helper for 'getScript()' to fold the contents of (asynchronously loaded) javascript files// into any inline script blocks encountered in html passed to that method.loadedRemoteScriptBlock : function (script, context) { var scriptIndex = context.scriptIndex, scripts = context.scripts, scriptIncludes = context.scriptIncludes; scripts[scriptIndex] = script; delete scriptIncludes[scriptIndex]; // Check whether we've loaded all outstanding scripts from the original request for (var i = 0; i < scriptIncludes.length; i++) { if (scriptIncludes[i] != null) return; } this.fireCallback(context.callback, "htmlFragments,scripts", [context.htmlFragments, scripts]);}});isc.HTMLFlow.addProperties({defaultWidth:200,defaultHeight:1,// both children and content will exist when both HTML code and SmartClient script blocks// exist in the contentsallowContentAndChildren : true,// enable text selection and i-beam cursor for HTMLFlow and HTMLPane contentscursor:"auto",//> @attr htmlFlow.contents (string : " " : [IRW])// @include canvas.contents//<//> @attr htmlFlow.dynamicContents (boolean : false : IRWA)// @include canvas.dynamicContents//<//> @attr htmlFlow.contentsURL (URL : null : IRW)// URL to load content from.// <P>// If specified, this component will load HTML content from the specified URL when it is// first drawn.// <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.//// @group contentLoading// @visibility external//<// NOTE: to load content before draw, or refresh contents from the server after draw// setContentsURL() can be called manually.//> @attr htmlFlow.loadingMessage (HTML : null : IRW)// HTML to show while content is being fetched, active only if the <code>contentsURL</code>// property has been set.// <P>// The loading message will show both during the initial load of content, and during reload if// the contents are reloaded or the contentsURL changed. For a first-time only loading// message, initialize the <code>contents</code> property instead.<br>// Note: the <code>loadingMessage</code> is never displayed when loading complete web pages // rather than HTML fragments (see +link{HTMLFlow.contentsType}).//// @group contentLoading// @visibility external//<// NOTE: no setter, intended usage is to setLoadingMessage then call setContentsURL()//loadingMessage: null,//> @attr htmlFlow.contentsURLParams (Object : null : IRW)// Parameters to be sent to the contentsURL when fetching content.// @group contentLoading// @visibility external//<// Intended usage: specifying something like a chartId for a dynamically loaded and reloaded// server-generated chart.//contentsURLParams: null,//> @attr htmlFlow.httpMethod (SendMethod : "GET" : IRW)// Selects the HTTP method that will be used when fetching content. Valid values are "POST"// and "GET".// @group contentLoading// @visibility external
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -