00001 /* 00002 Copyright (c) 2004-2006, The Dojo Foundation 00003 All Rights Reserved. 00004 00005 Licensed under the Academic Free License version 2.1 or above OR the 00006 modified BSD license. For more information on Dojo licensing, see: 00007 00008 http://dojotoolkit.org/community/licensing.shtml 00009 */ 00010 00011 00012 00013 dojo.provide("dojo.io.ScriptSrcIO"); 00014 dojo.require("dojo.io.BrowserIO"); 00015 dojo.require("dojo.undo.browser"); 00016 dojo.io.ScriptSrcTransport = new function () { 00017 this.preventCache = false; 00018 this.maxUrlLength = 1000; 00019 this.inFlightTimer = null; 00020 this.DsrStatusCodes = {Continue:100, Ok:200, Error:500}; 00021 this.startWatchingInFlight = function () { 00022 if (!this.inFlightTimer) { 00023 this.inFlightTimer = setInterval("dojo.io.ScriptSrcTransport.watchInFlight();", 100); 00024 } 00025 }; 00026 this.watchInFlight = function () { 00027 var totalCount = 0; 00028 var doneCount = 0; 00029 for (var param in this._state) { 00030 totalCount++; 00031 var currentState = this._state[param]; 00032 if (currentState.isDone) { 00033 doneCount++; 00034 delete this._state[param]; 00035 } else { 00036 if (!currentState.isFinishing) { 00037 var listener = currentState.kwArgs; 00038 try { 00039 if (currentState.checkString && eval("typeof(" + currentState.checkString + ") != 'undefined'")) { 00040 currentState.isFinishing = true; 00041 this._finish(currentState, "load"); 00042 doneCount++; 00043 delete this._state[param]; 00044 } else { 00045 if (listener.timeoutSeconds && listener.timeout) { 00046 if (currentState.startTime + (listener.timeoutSeconds * 1000) < (new Date()).getTime()) { 00047 currentState.isFinishing = true; 00048 this._finish(currentState, "timeout"); 00049 doneCount++; 00050 delete this._state[param]; 00051 } 00052 } else { 00053 if (!listener.timeoutSeconds) { 00054 doneCount++; 00055 } 00056 } 00057 } 00058 } 00059 catch (e) { 00060 currentState.isFinishing = true; 00061 this._finish(currentState, "error", {status:this.DsrStatusCodes.Error, response:e}); 00062 } 00063 } 00064 } 00065 } 00066 if (doneCount >= totalCount) { 00067 clearInterval(this.inFlightTimer); 00068 this.inFlightTimer = null; 00069 } 00070 }; 00071 this.canHandle = function (kwArgs) { 00072 return dojo.lang.inArray(["text/javascript", "text/json", "application/json"], (kwArgs["mimetype"].toLowerCase())) && (kwArgs["method"].toLowerCase() == "get") && !(kwArgs["formNode"] && dojo.io.formHasFile(kwArgs["formNode"])) && (!kwArgs["sync"] || kwArgs["sync"] == false) && !kwArgs["file"] && !kwArgs["multipart"]; 00073 }; 00074 this.removeScripts = function () { 00075 var scripts = document.getElementsByTagName("script"); 00076 for (var i = 0; scripts && i < scripts.length; i++) { 00077 var scriptTag = scripts[i]; 00078 if (scriptTag.className == "ScriptSrcTransport") { 00079 var parent = scriptTag.parentNode; 00080 parent.removeChild(scriptTag); 00081 i--; 00082 } 00083 } 00084 }; 00085 this.bind = function (kwArgs) { 00086 var url = kwArgs.url; 00087 var query = ""; 00088 if (kwArgs["formNode"]) { 00089 var ta = kwArgs.formNode.getAttribute("action"); 00090 if ((ta) && (!kwArgs["url"])) { 00091 url = ta; 00092 } 00093 var tp = kwArgs.formNode.getAttribute("method"); 00094 if ((tp) && (!kwArgs["method"])) { 00095 kwArgs.method = tp; 00096 } 00097 query += dojo.io.encodeForm(kwArgs.formNode, kwArgs.encoding, kwArgs["formFilter"]); 00098 } 00099 if (url.indexOf("#") > -1) { 00100 dojo.debug("Warning: dojo.io.bind: stripping hash values from url:", url); 00101 url = url.split("#")[0]; 00102 } 00103 var urlParts = url.split("?"); 00104 if (urlParts && urlParts.length == 2) { 00105 url = urlParts[0]; 00106 query += (query ? "&" : "") + urlParts[1]; 00107 } 00108 if (kwArgs["backButton"] || kwArgs["back"] || kwArgs["changeUrl"]) { 00109 dojo.undo.browser.addToHistory(kwArgs); 00110 } 00111 var id = kwArgs["apiId"] ? kwArgs["apiId"] : "id" + this._counter++; 00112 var content = kwArgs["content"]; 00113 var jsonpName = kwArgs.jsonParamName; 00114 if (kwArgs.sendTransport || jsonpName) { 00115 if (!content) { 00116 content = {}; 00117 } 00118 if (kwArgs.sendTransport) { 00119 content["dojo.transport"] = "scriptsrc"; 00120 } 00121 if (jsonpName) { 00122 content[jsonpName] = "dojo.io.ScriptSrcTransport._state." + id + ".jsonpCall"; 00123 } 00124 } 00125 if (kwArgs.postContent) { 00126 query = kwArgs.postContent; 00127 } else { 00128 if (content) { 00129 query += ((query) ? "&" : "") + dojo.io.argsFromMap(content, kwArgs.encoding, jsonpName); 00130 } 00131 } 00132 if (kwArgs["apiId"]) { 00133 kwArgs["useRequestId"] = true; 00134 } 00135 var state = {"id":id, "idParam":"_dsrid=" + id, "url":url, "query":query, "kwArgs":kwArgs, "startTime":(new Date()).getTime(), "isFinishing":false}; 00136 if (!url) { 00137 this._finish(state, "error", {status:this.DsrStatusCodes.Error, statusText:"url.none"}); 00138 return; 00139 } 00140 if (content && content[jsonpName]) { 00141 state.jsonp = content[jsonpName]; 00142 state.jsonpCall = function (data) { 00143 if (data["Error"] || data["error"]) { 00144 if (dojo["json"] && dojo["json"]["serialize"]) { 00145 dojo.debug(dojo.json.serialize(data)); 00146 } 00147 dojo.io.ScriptSrcTransport._finish(this, "error", data); 00148 } else { 00149 dojo.io.ScriptSrcTransport._finish(this, "load", data); 00150 } 00151 }; 00152 } 00153 if (kwArgs["useRequestId"] || kwArgs["checkString"] || state["jsonp"]) { 00154 this._state[id] = state; 00155 } 00156 if (kwArgs["checkString"]) { 00157 state.checkString = kwArgs["checkString"]; 00158 } 00159 state.constantParams = (kwArgs["constantParams"] == null ? "" : kwArgs["constantParams"]); 00160 if (kwArgs["preventCache"] || (this.preventCache == true && kwArgs["preventCache"] != false)) { 00161 state.nocacheParam = "dojo.preventCache=" + new Date().valueOf(); 00162 } else { 00163 state.nocacheParam = ""; 00164 } 00165 var urlLength = state.url.length + state.query.length + state.constantParams.length + state.nocacheParam.length + this._extraPaddingLength; 00166 if (kwArgs["useRequestId"]) { 00167 urlLength += state.idParam.length; 00168 } 00169 if (!kwArgs["checkString"] && kwArgs["useRequestId"] && !state["jsonp"] && !kwArgs["forceSingleRequest"] && urlLength > this.maxUrlLength) { 00170 if (url > this.maxUrlLength) { 00171 this._finish(state, "error", {status:this.DsrStatusCodes.Error, statusText:"url.tooBig"}); 00172 return; 00173 } else { 00174 this._multiAttach(state, 1); 00175 } 00176 } else { 00177 var queryParams = [state.constantParams, state.nocacheParam, state.query]; 00178 if (kwArgs["useRequestId"] && !state["jsonp"]) { 00179 queryParams.unshift(state.idParam); 00180 } 00181 var finalUrl = this._buildUrl(state.url, queryParams); 00182 state.finalUrl = finalUrl; 00183 this._attach(state.id, finalUrl); 00184 } 00185 this.startWatchingInFlight(); 00186 }; 00187 this._counter = 1; 00188 this._state = {}; 00189 this._extraPaddingLength = 16; 00190 this._buildUrl = function (url, nameValueArray) { 00191 var finalUrl = url; 00192 var joiner = "?"; 00193 for (var i = 0; i < nameValueArray.length; i++) { 00194 if (nameValueArray[i]) { 00195 finalUrl += joiner + nameValueArray[i]; 00196 joiner = "&"; 00197 } 00198 } 00199 return finalUrl; 00200 }; 00201 this._attach = function (id, url) { 00202 var element = document.createElement("script"); 00203 element.type = "text/javascript"; 00204 element.src = url; 00205 element.id = id; 00206 element.className = "ScriptSrcTransport"; 00207 document.getElementsByTagName("head")[0].appendChild(element); 00208 }; 00209 this._multiAttach = function (state, part) { 00210 if (state.query == null) { 00211 this._finish(state, "error", {status:this.DsrStatusCodes.Error, statusText:"query.null"}); 00212 return; 00213 } 00214 if (!state.constantParams) { 00215 state.constantParams = ""; 00216 } 00217 var queryMax = this.maxUrlLength - state.idParam.length - state.constantParams.length - state.url.length - state.nocacheParam.length - this._extraPaddingLength; 00218 var isDone = state.query.length < queryMax; 00219 var currentQuery; 00220 if (isDone) { 00221 currentQuery = state.query; 00222 state.query = null; 00223 } else { 00224 var ampEnd = state.query.lastIndexOf("&", queryMax - 1); 00225 var eqEnd = state.query.lastIndexOf("=", queryMax - 1); 00226 if (ampEnd > eqEnd || eqEnd == queryMax - 1) { 00227 currentQuery = state.query.substring(0, ampEnd); 00228 state.query = state.query.substring(ampEnd + 1, state.query.length); 00229 } else { 00230 currentQuery = state.query.substring(0, queryMax); 00231 var queryName = currentQuery.substring((ampEnd == -1 ? 0 : ampEnd + 1), eqEnd); 00232 state.query = queryName + "=" + state.query.substring(queryMax, state.query.length); 00233 } 00234 } 00235 var queryParams = [currentQuery, state.idParam, state.constantParams, state.nocacheParam]; 00236 if (!isDone) { 00237 queryParams.push("_part=" + part); 00238 } 00239 var url = this._buildUrl(state.url, queryParams); 00240 this._attach(state.id + "_" + part, url); 00241 }; 00242 this._finish = function (state, callback, event) { 00243 if (callback != "partOk" && !state.kwArgs[callback] && !state.kwArgs["handle"]) { 00244 if (callback == "error") { 00245 state.isDone = true; 00246 throw event; 00247 } 00248 } else { 00249 switch (callback) { 00250 case "load": 00251 var response = event ? event.response : null; 00252 if (!response) { 00253 response = event; 00254 } 00255 state.kwArgs[(typeof state.kwArgs.load == "function") ? "load" : "handle"]("load", response, event, state.kwArgs); 00256 state.isDone = true; 00257 break; 00258 case "partOk": 00259 var part = parseInt(event.response.part, 10) + 1; 00260 if (event.response.constantParams) { 00261 state.constantParams = event.response.constantParams; 00262 } 00263 this._multiAttach(state, part); 00264 state.isDone = false; 00265 break; 00266 case "error": 00267 state.kwArgs[(typeof state.kwArgs.error == "function") ? "error" : "handle"]("error", event.response, event, state.kwArgs); 00268 state.isDone = true; 00269 break; 00270 default: 00271 state.kwArgs[(typeof state.kwArgs[callback] == "function") ? callback : "handle"](callback, event, event, state.kwArgs); 00272 state.isDone = true; 00273 } 00274 } 00275 }; 00276 dojo.io.transports.addTransport("ScriptSrcTransport"); 00277 }; 00278 window.onscriptload = function (event) { 00279 var state = null; 00280 var transport = dojo.io.ScriptSrcTransport; 00281 if (transport._state[event.id]) { 00282 state = transport._state[event.id]; 00283 } else { 00284 var tempState; 00285 for (var param in transport._state) { 00286 tempState = transport._state[param]; 00287 if (tempState.finalUrl && tempState.finalUrl == event.id) { 00288 state = tempState; 00289 break; 00290 } 00291 } 00292 if (state == null) { 00293 var scripts = document.getElementsByTagName("script"); 00294 for (var i = 0; scripts && i < scripts.length; i++) { 00295 var scriptTag = scripts[i]; 00296 if (scriptTag.getAttribute("class") == "ScriptSrcTransport" && scriptTag.src == event.id) { 00297 state = transport._state[scriptTag.id]; 00298 break; 00299 } 00300 } 00301 } 00302 if (state == null) { 00303 throw "No matching state for onscriptload event.id: " + event.id; 00304 } 00305 } 00306 var callbackName = "error"; 00307 switch (event.status) { 00308 case dojo.io.ScriptSrcTransport.DsrStatusCodes.Continue: 00309 callbackName = "partOk"; 00310 break; 00311 case dojo.io.ScriptSrcTransport.DsrStatusCodes.Ok: 00312 callbackName = "load"; 00313 break; 00314 } 00315 transport._finish(state, callbackName, event); 00316 }; 00317
For more help developing with SiT! see http://sitracker.org/wiki/DevelopmentHowTo