📄 comm.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
*/
//> @class Comm// Provide background communication with an HTTP server//<// create the Comm singleton objectisc.ClassFactory.defineClass("Comm");// add properties to the Comm objectisc.Comm.addClassProperties( { //> @classAttr isc.Comm.sendMethod (string : isc.Comm.sendMethod : I) // communication method // @group communication //< sendMethod: "POST", //> @type SendMethod // @visibility external // @group communication // @value "GET" GET method (regular URL encoding) // @value "POST" POST method (form field encoding) //< // Sequence number for forms created in IE to send data to the server. Used to give each // form a unique name. _generatedFormNumber : 0});isc.Comm.addClassMethods({// XMLHttpRequest vs IFrame Comm//// Advantages:// - doesn't add to history in older Moz// - no request for empty.html in HTTPS// - doesn't add to document.frames and potentially screw up numbering// - ability to detect load with a server-initiated callback// - synchronous option//// Disadvantages / neutral// - can't handle upload fields// - is subject to concurrent requests limit in IE (test by adding Thread.sleep(5000) to// IDACall - responses come in closely-spaced pairs)// - no persistent connections in IE (server push), see:// http://jszen.blogspot.com/2005/03/xmlhttp-and-readystate.html// - no compression in IE 5.5//// XMLHttpRequest behavior with file:// URL - works on FF, Safari, and IE but on all these// platforms the URL must be relative or it doesn't work. SO e.g. ../foo.html is ok, but// /foo.html is not. Haven't tested specifying the full path (e.g. c:\foo\bar.html). //// For XMLHttpRequest, FF uses the baseURL of the window object that started thread that// eventually calls XMLHttpRequest.send() as the baseURL for resolving the relative reference.// This means that if you send an RPC using XMLHttpRequest out of the eval area of the// Developer Console, your base URL will be /isomorphic/system/helpers - because that's where// Log.html came from. You can use a timeout to restart the thread in the appropriate context// - just be aware of this oddity._fireXMLCallback : function (request, callback) { isc.EH._setThread("XRP"); // NOTE: last param tells fireCalllback to trap errors in Moz isc.Class.fireCallback(callback, "xmlHttpRequest", [request], null, true); isc.EH._clearThread();},// ==========================================================================================// IMPORTANT: If you update the XMLHttp code here, also update FileLoader.js// ==========================================================================================_getStateChangeHandler : function () { return function () { var request = arguments.callee.request; // IE 5.5 manages to call this handler after readyState changes to 4 and we process the // request, which would cause the whole RPC reply logic to run more than once which // breaks badly. If we run more than once, the request will be null becase we null it out // below, so just trap this case and return. if (!request) return; if (request.readyState != 4) return; arguments.callee.request = null; // Bizarre IE-only bug: in the middle of a readyStateChange thread, we draw a // new widget, and on touching the newly created handle in // Canvas._browserDoneDrawing(), IE decides it's a good time to interrupt the current // thread and fire readyStateChange from another xmlHttpRequest that has arrived in the // meantime - this can actually be seen in the stack trace, which shows this handler // being called (impossibly) by _browserDoneDrawing(). // So far as we know, IE is not willing to similarly interrupt a timer thread, so we // fire the callback on a 0ms timer instead, which should be order-preserving. // NOTE: do not use a closure here or a leak will be introduced //isc.Comm._fireXMLCallback(request, arguments.callee.callback); isc.Timer.setTimeout({ target:isc.Comm, methodName:"_fireXMLCallback", args:[request, arguments.callee.callback] }, 0); }},// Upon shipping XML3.0, Microsoft started installing XML parsers in "side by side mode"// meaning the previous version is left intact and a new version is installed parallel to// the existing one. Prior to this the latest XML parser being installed by some piece of// software would overwrite the previous verison and potentially break the software that// depended on that version. The catch is that to get the later versions of the parser, you// need to specify a version-specific prefix.//// We use a version independent prefix to get the 2.0 parser in IE6.0 and IE5.5 and then// fall back on version-specific prefixes if that fails for some reason. But we expect// MSXML2.XMLHTTP or Microsoft.XMLHTTP to actually work.//// MSXML2 prefix specifies the version independent control. The "Microsoft" and "MSXML"// prefixes are old-style version independent controls. MSXML3 is version specific 3.0 parser.// IE6+ IE5.5 pre-IE5.5 style IE6+xmlHttpConstructors : ["MSXML2.XMLHTTP", "Microsoft.XMLHTTP", "MSXML.XMLHTTP", "MSXML3.XMLHTTP"],// ==========================================================================================// IMPORTANT: If you update this function, also update its copy in FileLoader.js// ==========================================================================================createXMLHttpRequest : function () { if (isc.Browser.isIE) { var xmlHttpRequest; // We prefer the ActiveX version of XMLHttpRequest if it's available because IE7's // native implementation has some quirks - for example it doesn't allow requests to // file:// URLs no matter what overrides you set in IE's options panel. Also there // are scattered reports of the native implementation being less performant. if (this.preferNativeXMLHttpRequest) { xmlHttpRequest = this.getNativeRequest(); if (!xmlHttpRequest) xmlHttpRequest = this.getActiveXRequest(); } else { xmlHttpRequest = this.getActiveXRequest(); if (!xmlHttpRequest) xmlHttpRequest = this.getNativeRequest(); } if (!xmlHttpRequest) isc.rpc.logWarn("Couldn't create XMLHttpRequest"); return xmlHttpRequest; } else { // Moz, Safari return new XMLHttpRequest(); }},getNativeRequest : function () { var xmlHttpRequest; if (isc.Browser.version >= 7) { isc.rpc.logDebug("Using native XMLHttpRequest"); xmlHttpRequest = new XMLHttpRequest(); } return xmlHttpRequest;},getActiveXRequest : function () { var xmlHttpRequest; if (!this._xmlHttpConstructor) { for (var i = 0; i < this.xmlHttpConstructors.length; i++) { try { var cons = this.xmlHttpConstructors[i]; xmlHttpRequest = new ActiveXObject(cons); // cache selected constructor if (xmlHttpRequest) { this._xmlHttpConstructor = cons; break; } } catch (e) { } } } else { xmlHttpRequest = new ActiveXObject(this._xmlHttpConstructor); } if (xmlHttpRequest) isc.rpc.logDebug("Using ActiveX XMLHttpRequest via constructor: " + this._xmlHttpConstructor); return xmlHttpRequest;},// _transactionCallbacks - array of callbacks for outstanding transactions// fired from the various 'reply' methods_transactionCallbacks:[],// scriptInclude transport// ---------------------------------------------------------------------------------------sendScriptInclude : function (request) { var URL = request.URL, fields = request.fields, data = request.data, callbackParam = request.callbackParam, transaction = request.transaction ; // create a function for server-generated code to call, and capture the // transactionNum by having the function share this scope var cbName = "_scriptIncludeReply_"+transaction.transactionNum; this[cbName] = function () { // copy arguments to a real array var values = arguments.length == 1 ? arguments[0] : []; if (arguments.length > 1) { for (var i = 0; i < arguments.length; i++) values[i] = arguments[i]; } isc.Comm.performScriptIncludeReply(transaction.transactionNum, values); } var callback = "isc.Comm."+cbName; var callbackParamObj = {}; callbackParamObj[callbackParam ? callbackParam : "callback"] = callback; URL = isc.rpc.addParamsToURL(URL, fields); URL = isc.rpc.addParamsToURL(URL, callbackParamObj); if (transaction) transaction.mergedActionURL = URL; isc.rpc.logInfo("scriptInclude call to: " + URL); // store the transactionCallback to fire when the server returns this._transactionCallbacks[transaction.transactionNum] = transaction.callback; var document = this.getDocument(), body = this.getDocumentBody(), scriptElement = document.createElement("script"); scriptElement.src = URL; body.appendChild(scriptElement);},performScriptIncludeReply : function (transactionNum, values) { // destroy auto-generated function for this transaction delete this["_scriptIncludeReply_"+transactionNum]; var callback = this._transactionCallbacks[transactionNum]; delete this._transactionCallbacks[transactionNum]; this.logDebug("scriptInclude reply for transactionNum: " + transactionNum + ", data: " + this.echoLeaf(values), "xmlBinding"); this.fireCallback(callback, "transactionNum,results,wd", [transactionNum, values]);},// send via an xmlHttpRequestsendXmlHttpRequest : function (request) { var URL = request.URL, fields = request.fields, httpMethod = request.httpMethod, contentType = request.contentType, headers = request.httpHeaders, data = request.data, transaction = request.transaction, blocking = request.blocking != null ? request.blocking : false ; if (request.useSimpleHttp) { transaction._clearOnTimeout = true; } this._transactionCallbacks[transaction.transactionNum] = transaction.callback; // set up a callback to notify us when the request completes var callback = "isc.Comm.performXmlTransactionReply(" +transaction.transactionNum+ ", xmlHttpRequest)"; if (!httpMethod) httpMethod = "POST"; var xmlHttpRequest = this.createXMLHttpRequest(); var loadFunc; if (isc.Browser.isIE) { loadFunc = this._getStateChangeHandler(); loadFunc.request = xmlHttpRequest; loadFunc.callback = callback; } else { // we'll install this function to fire onreadystatechange loadFunc = function () { if (xmlHttpRequest.readyState != 4) return; isc.Comm._fireXMLCallback(xmlHttpRequest, callback); } } xmlHttpRequest.onreadystatechange = loadFunc; if (isc.rpc.logIsDebugEnabled()) { this.lastXmlHttpRequest = xmlHttpRequest; // HACK for debugging } if (httpMethod == "POST" || httpMethod == "PUT") { // if data was passed in, use that as the body and encode any fields into the query // params if (data) { // assume the body being posted is XML if contentType is unset contentType = contentType || "text/xml"; URL = isc.rpc.addParamsToURL(URL, fields); } else { // send fields like a form post contentType = contentType || "application/x-www-form-urlencoded; charset=UTF-8"; data = isc.SB.create(); var first = true; for (var fieldName in fields) { if (!first) data.append("&"); var value = fields[fieldName]; data.append(isc.rpc.encodeParameter(fieldName, value)); first = false; } data = data.toString(); } if (isc.rpc.logIsDebugEnabled()) { isc.rpc.logDebug("XMLHttpRequest POST to " + URL + " contentType: " + contentType + " with body -->"+decodeURIComponent(data)+"<--"); } xmlHttpRequest.open(httpMethod, URL, !blocking); xmlHttpRequest.setRequestHeader("Content-Type", contentType); this._setHttpHeaders(xmlHttpRequest, headers); if (transaction) { transaction.xhrHeaders = headers; transaction.xhrData = data; } if (data != null && !isc.isA.String(data)) { this.logWarn("Non-string data object passed to sendXML as request.data:"+ this.echo(data) + " attempting to convert to a string."); data = data.toString ? data.toString() : "" + data; } xmlHttpRequest.send(data); } else { // httpMethod == GET, DELETE, HEAD var urlWithFields = isc.rpc.addParamsToURL(URL, fields); xmlHttpRequest.open(httpMethod, urlWithFields, !blocking); // by default, IE will cache XMLHttp GET responses. Setting bypassCache: true forces IE to // fetch a new copy. if (request.bypassCache) xmlHttpRequest.setRequestHeader("If-Modified-Since", new Date(0)); this._setHttpHeaders(xmlHttpRequest, headers); if (isc.rpc.logIsDebugEnabled()) { isc.rpc.logDebug("XMLHttpRequest GET from " + URL + " with fields: " + isc.Log.echoAll(fields) + " full URL string: " + urlWithFields); } xmlHttpRequest.send(null); } return xmlHttpRequest;},performXmlTransactionReply : function (transactionNum, xmlHttpRequest) { //!OBFUSCATEOK var callback = this._transactionCallbacks[transactionNum] delete this._transactionCallbacks[transactionNum]; this.fireCallback(callback, "transactionNum,results,wd", [transactionNum, xmlHttpRequest]);},_setHttpHeaders : function (request, headers) { if (headers == null) return; for (var headerName in headers) { var headerValue = headers[headerName]; if (headerValue != null) request.setRequestHeader(headerName, headerValue); }}});
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -