UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

476 lines (389 loc) 12.4 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2004-2008 1&1 Internet AG, Germany, http://www.1und1.de 2006 Derrell Lipman 2006 STZ-IDA, Germany, http://www.stz-ida.de License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Sebastian Werner (wpbasti) * Andreas Ecker (ecker) * Derrell Lipman (derrell) * Andreas Junghans (lucidcake) ************************************************************************ */ /** * Transports requests to a server using dynamic script tags. * * This class should not be used directly by client programmers. * * NOTE: Instances of this class must be disposed of after use * */ qx.Class.define("qx.io.remote.transport.Script", { extend : qx.io.remote.transport.Abstract, implement: [ qx.core.IDisposable ], /* ***************************************************************************** CONSTRUCTOR ***************************************************************************** */ construct : function() { this.base(arguments); var vUniqueId = ++qx.io.remote.transport.Script.__uniqueId; if (vUniqueId >= 2000000000) { qx.io.remote.transport.Script.__uniqueId = vUniqueId = 1; } this.__element = null; this.__uniqueId = vUniqueId; }, /* ***************************************************************************** STATICS ***************************************************************************** */ statics : { /** * Unique identifier for each instance. * * @internal */ __uniqueId : 0, /** * Registry for all script transport instances. * * @internal */ _instanceRegistry : {}, /** * Internal URL parameter prefix. * * @internal */ ScriptTransport_PREFIX : "_ScriptTransport_", /** * Internal URL parameter ID. * * @internal */ ScriptTransport_ID_PARAM : "_ScriptTransport_id", /** * Internal URL parameter data prefix. * * @internal */ ScriptTransport_DATA_PARAM : "_ScriptTransport_data", /** * Capabilities of this transport type. * * @internal */ handles : { synchronous : false, asynchronous : true, crossDomain : true, fileUpload : false, programmaticFormFields : false, responseTypes : [ "text/plain", "text/javascript", "application/json" ] }, /** * Returns always true, because script transport is supported by all browsers. * @return {Boolean} <code>true</code> */ isSupported : function() { return true; }, /* --------------------------------------------------------------------------- EVENT LISTENER --------------------------------------------------------------------------- */ /** * For reference: * http://msdn.microsoft.com/en-us/library/ie/ms534359%28v=vs.85%29.aspx * * @internal */ _numericMap : { "uninitialized" : 1, "loading" : 2, "loaded" : 2, "interactive" : 3, "complete" : 4 }, /** * This method can be called by the script loaded by the ScriptTransport * class. * * @signature function(id, content) * @param id {String} Id of the corresponding transport object, * which is passed as an URL parameter to the server an * @param content {String} This string is passed to the content property * of the {@link qx.io.remote.Response} object. */ _requestFinished : qx.event.GlobalError.observeMethod(function(id, content) { var vInstance = qx.io.remote.transport.Script._instanceRegistry[id]; if (vInstance == null) { if (qx.core.Environment.get("qx.debug")) { if (qx.core.Environment.get("qx.debug.io.remote")) { this.warn("Request finished for an unknown instance (probably aborted or timed out before)"); } } } else { vInstance._responseContent = content; vInstance._switchReadyState(qx.io.remote.transport.Script._numericMap.complete); } }) }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { __lastReadyState : 0, __element : null, __uniqueId : null, /* --------------------------------------------------------------------------- USER METHODS --------------------------------------------------------------------------- */ /** * Sends the request using "script" elements * */ send : function() { var vUrl = this.getUrl(); // -------------------------------------- // Adding parameters // -------------------------------------- vUrl += (vUrl.indexOf("?") >= 0 ? "&" : "?") + qx.io.remote.transport.Script.ScriptTransport_ID_PARAM + "=" + this.__uniqueId; var vParameters = this.getParameters(); var vParametersList = []; for (var vId in vParameters) { if (vId.indexOf(qx.io.remote.transport.Script.ScriptTransport_PREFIX) == 0) { this.error("Illegal parameter name. The following prefix is used internally by qooxdoo): " + qx.io.remote.transport.Script.ScriptTransport_PREFIX); } var value = vParameters[vId]; if (value instanceof Array) { for (var i=0; i<value.length; i++) { vParametersList.push(encodeURIComponent(vId) + "=" + encodeURIComponent(value[i])); } } else { vParametersList.push(encodeURIComponent(vId) + "=" + encodeURIComponent(value)); } } if (vParametersList.length > 0) { vUrl += "&" + vParametersList.join("&"); } // -------------------------------------- // Sending data // -------------------------------------- var vData = this.getData(); if (vData != null) { vUrl += "&" + qx.io.remote.transport.Script.ScriptTransport_DATA_PARAM + "=" + encodeURIComponent(vData); } qx.io.remote.transport.Script._instanceRegistry[this.__uniqueId] = this; this.__element = document.createElement("script"); // IE needs this (it ignores the // encoding from the header sent by the // server for dynamic script tags) this.__element.charset = "utf-8"; this.__element.src = vUrl; if (qx.core.Environment.get("qx.debug")) { if (qx.core.Environment.get("qx.debug.io.remote.data")) { this.debug("Request: " + vUrl); } } document.body.appendChild(this.__element); }, /** * Switches the readystate by setting the internal state. * * @param vReadyState {String} readystate value */ _switchReadyState : function(vReadyState) { // Ignoring already stopped requests switch(this.getState()) { case "completed": case "aborted": case "failed": case "timeout": this.warn("Ignore Ready State Change"); return; } // Updating internal state while (this.__lastReadyState < vReadyState) { this.setState(qx.io.remote.Exchange._nativeMap[++this.__lastReadyState]); } }, /* --------------------------------------------------------------------------- REQUEST HEADER SUPPORT --------------------------------------------------------------------------- */ /** * Sets a request header with the given value. * * This method is not implemented at the moment. * * @param vLabel {String} Request header name * @param vValue {var} Request header value */ setRequestHeader : function(vLabel, vValue) {}, /* --------------------------------------------------------------------------- RESPONSE HEADER SUPPORT --------------------------------------------------------------------------- */ /** * Returns the value of the given response header. * * This method is not implemented at the moment and returns always "null". * * @param vLabel {String} Response header name * @return {null} Returns null */ getResponseHeader : function(vLabel) { return null; }, /** * Provides an hash of all response headers. * * This method is not implemented at the moment and returns an empty map. * * @return {Map} empty map */ getResponseHeaders : function() { return {}; }, /* --------------------------------------------------------------------------- STATUS SUPPORT --------------------------------------------------------------------------- */ /** * Returns the current status code of the request if available or -1 if not. * This method needs implementation (returns always 200). * * @return {Integer} status code */ getStatusCode : function() { return 200; }, /** * Provides the status text for the current request if available and null otherwise. * This method needs implementation (returns always an empty string) * * @return {String} always an empty string. */ getStatusText : function() { return ""; }, /* --------------------------------------------------------------------------- RESPONSE DATA SUPPORT --------------------------------------------------------------------------- */ /** * Returns the length of the content as fetched thus far. * This method needs implementation (returns always 0). * * @return {Integer} Returns 0 */ getFetchedLength : function() { return 0; }, /** * Returns the content of the response. * * @return {null | String} If successful content of response as string. */ getResponseContent : function() { if (this.getState() !== "completed") { if (qx.core.Environment.get("qx.debug")) { if (qx.core.Environment.get("qx.debug.io.remote")) { this.warn("Transfer not complete, ignoring content!"); } } return null; } if (qx.core.Environment.get("qx.debug")) { if (qx.core.Environment.get("qx.debug.io.remote")) { this.debug("Returning content for responseType: " + this.getResponseType()); } } switch(this.getResponseType()) { case "text/plain": // server is responsible for using a string as the response case "application/json": case "text/javascript": if (qx.core.Environment.get("qx.debug")) { if (qx.core.Environment.get("qx.debug.io.remote.data")) { this.debug("Response: " + this._responseContent); } } var ret = this._responseContent; return (ret === 0 ? 0 : (ret || null)); default: this.warn("No valid responseType specified (" + this.getResponseType() + ")!"); return null; } } }, /* ***************************************************************************** DEFER ***************************************************************************** */ defer : function() { // basic registration to qx.io.remote.Exchange // the real availability check (activeX stuff and so on) follows at the first real request qx.io.remote.Exchange.registerType(qx.io.remote.transport.Script, "qx.io.remote.transport.Script"); }, /* ***************************************************************************** DESTRUCTOR ***************************************************************************** */ destruct : function() { if (this.__element) { delete qx.io.remote.transport.Script._instanceRegistry[this.__uniqueId]; document.body.removeChild(this.__element); } this.__element = this._responseContent = null; } });