1/** 2 * provide XHR functionality 3 * 4 * @version 5.7.0 2017-07-04 5 * @author Gregor Kofler 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code 9*/ 10 11"use strict"; 12 13/** 14 * get host XHR object 15 */ 16vxJS.xhrObj = (function() { 17 var ok; 18 19 // any reasonable browser 20 21 try { ok = new XMLHttpRequest(); } catch (e) { } 22 if(ok) { 23 return function() { return new XMLHttpRequest(); }; 24 } 25 // IE6 26 27 try { ok = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { } 28 if(ok) { 29 return function() { return new ActiveXObject("Microsoft.XMLHTTP"); }; 30 } 31 throw Error("vxJS.xhr: Can't instantiate XMLHttpRequest!"); 32}()); 33 34/** 35 * XHR wrapper 36 * 37 * @param {Object} request, { command: {string}, uri: {String}, echo: {Boolean}, timeout: {Number}, forceXMLResponse: {Boolean} 38 * @param {Object} param, object containing all additional parameters needed by request 39 * @param {Object} animation, object containing a node reference 40 * @param {Object} container with callback functions { complete: {Function}, timeout: {Function}, fail: {Function} } 41 * 42 * served events: "timeout", "complete", "fail", "beforeSend" 43 */ 44vxJS.xhr = function(req, param, anim, cb) { 45 46 if(!req) { req = {}; } 47 if(!param) { param = {}; } 48 if(!anim) { anim = {}; } 49 50 var timeout = req.timeout || 5000, timer, active, 51 headers = {}, 52 xhrO = vxJS.xhrObj(), that = { response: {} }; 53 54 var abort = function() { 55 if(anim.node) { 56 vxJS.dom.removeClassName(anim.node, "active"); 57 } 58 if(timer) { 59 window.clearTimeout(timer); 60 } 61 if(xhrO) { 62 xhrO.onreadystatechange = function() {}; 63 if(xhrO.readyState !== 0 && xhrO.readyState !== 4) { 64 xhrO.abort(); 65 } 66 } 67 active = false; 68 }; 69 70 var startTimer = function() { 71 if(timeout > 0) { 72 timer = window.setTimeout( function() { 73 abort(); 74 75 if(cb && typeof cb.timeout === "function") { 76 cb.timeout.call(that); 77 } 78 79 vxJS.event.serve(that, "timeout"); 80 vxJS.event.serveXhr(that, "timeout"); 81 82 }, timeout); 83 } 84 }; 85 86 var stateChange = function () { 87 if(xhrO.readyState === 4) { 88 89 abort(); 90 91 if(xhrO.status >= 200 && xhrO.status < 300 || xhrO.status === 1223) { 92 93 if(req.forcePlainTextResponse) { 94 that.response = xhrO.responseText; 95 } 96 else if(req.forceXMLResponse) { 97 that.response = xhrO.responseXML || xhrO.responseText; 98 } 99 else { 100 that.response = JSON.parse(xhrO.responseText || "{}"); 101 } 102 103 if(cb && typeof cb.complete === "function") { 104 cb.complete.call(that); 105 } 106 107 vxJS.event.serve(that, "complete"); 108 vxJS.event.serveXhr(that, "complete"); 109 110 } 111 else { 112 if(cb && typeof cb.fail === "function") { 113 cb.fail.call(that); 114 } 115 116 vxJS.event.serve(that, "fail"); 117 vxJS.event.serveXhr(that, "fail"); 118 } 119 } 120 }; 121 122 var setHeader = function(field, value) { 123 headers[field] = value; 124 }; 125 126 /** 127 * try to build query string from mixed and nested data as it is done by PHP 128 */ 129 var buildQueryString = function(data) { 130 131 var parameters = [], key, ndx; 132 133 var builQueryParameter = function(key, val) { 134 135 var k, parameters = []; 136 137 if(typeof val === "function") { 138 return ""; 139 } 140 if (true === val) { 141 return encodeURIComponent(key) + "=1"; 142 } 143 if (false === val) { 144 return encodeURIComponent(key) + "=0"; 145 } 146 if (val === null) { 147 return encodeURIComponent(key) + "="; 148 } 149 if (Array.isArray(val)) { 150 ndx = 0; 151 val.forEach(function(a) { 152 parameters.push(builQueryParameter(key + "[" + ndx++ + "]", a)); 153 }); 154 return parameters.join("&"); 155 } 156 if (typeof(val) === "object") { 157 for (k in val) { 158 if(val.hasOwnProperty(k)) { 159 parameters.push(builQueryParameter(key + "[" + k + "]", val[k])); 160 } 161 } 162 return parameters.join('&'); 163 } 164 165 return encodeURIComponent(key) + "=" + encodeURIComponent(val); 166 }; 167 168 for (key in data) { 169 if(data.hasOwnProperty(key)) { 170 parameters.push(builQueryParameter(key, data[key])); 171 } 172 } 173 174 return parameters.join("&"); 175 }; 176 177 var submit = function() { 178 var l = window.location, i, f, 179 uri = encodeURI(req.uri || (l.hash ? l.href.substring(0, l.href.indexOf(l.hash)) : l.href)); 180 181 abort(); 182 183 if(req.command) { 184 param.httpRequest = req.command; 185 } 186 if(req.echo) { 187 param.echo = 1; 188 } 189 190 setHeader("X-Requested-With", "XMLHttpRequest"); 191 192 if(req.forceXMLResponse && xhrO.overrideMimeType) { 193 xhrO.overrideMimeType("text/xml"); 194 } 195 196 // do GET 197 198 if(req.method && req.method.toUpperCase() == "GET") { 199 xhrO.open( "GET", 200 uri += (uri.indexOf("?") !== -1 ? "&" : "?") + 201 (new Date()).getTime() + 202 "&" + 203 (req.useJsonSerialization ? 204 "xmlHttpRequest=" + encodeURIComponent(JSON.stringify(param)) : 205 buildQueryString(param) 206 ) 207 , true); 208 209 for(i = 0, f = Object.keys(headers); i < f.length; ++i) { 210 xhrO.setRequestHeader(f[i], headers[f[i]]); 211 } 212 213 xhrO.onreadystatechange = stateChange; 214 vxJS.event.serve(that, "beforeSend"); 215 xhrO.send(null); 216 } 217 218 // do POST 219 220 else { 221 xhrO.open("POST",uri, true); 222 223 if(!req.upload) { 224 setHeader("Content-Type", "application/x-www-form-urlencoded"); 225 for(i = 0, f = Object.keys(headers); i < f.length; ++i) { 226 xhrO.setRequestHeader(f[i], headers[f[i]]); 227 } 228 xhrO.onreadystatechange = stateChange; 229 vxJS.event.serve(that, "beforeSend"); 230 231 if(req.useJsonSerialization) { 232 xhrO.send("xmlHttpRequest="+encodeURIComponent(JSON.stringify(param))); 233 } 234 else { 235 xhrO.send(buildQueryString(param)); 236 } 237 } 238 239 // do POST with file upload 240 241 else if(param.file) { 242 setHeader("X-File-Name", (param.filename || param.file.name).replace(/[^\x00-\x7F]/g, function(c) { return encodeURIComponent(c); })); 243 setHeader("X-File-Size", param.file.size); 244 setHeader("X-File-Type", param.file.type); 245 for(i = 0, f = Object.keys(headers); i < f.length; ++i) { 246 xhrO.setRequestHeader(f[i], headers[f[i]]); 247 } 248 xhrO.onreadystatechange = stateChange; 249 vxJS.event.serve(that, "beforeSend"); 250 xhrO.send(param.file); 251 } 252 } 253 254 active = true; 255 256 startTimer(); 257 258 if(anim.node) { 259 vxJS.dom.addClassName(anim.node, "active"); 260 } 261 }; 262
263 that.setHeader = function(field, value) { 264 setHeader(field, value); 265 return this; 266 }; 267 268 that.use = function(r, p, a, c) { 269 if(r) { 270 req = vxJS.merge(req, r); 271 } 272 if(p) { 273 param = p; 274 } 275 if(a) { 276 anim = a; 277 } 278 if(c) { 279 cb = c; 280 } 281 282 return this; 283 }; 284 285 that.getRequestParameters = function() { 286 return req; 287 }; 288 289 that.getParameters = function() { 290 return param; 291 }; 292 293 that.getAnimationParameters = function() { 294 return anim; 295 }; 296 297 that.getCallbacks = function() { 298 return cb; 299 }; 300 301 that.isActive = function() { 302 return active; 303 }; 304 305 that.xhrObj = xhrO; 306 that.abort = abort; 307 that.submit = submit; 308 309 return that; 310};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.