This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
bytedo
/
wcui
Archived
1
0
Fork 0
wcui/js/lib/request/ajax.js

1052 lines
40 KiB
JavaScript
Raw Normal View History

2017-03-30 01:40:59 +08:00
//=========================================
// 数据交互模块 by 司徒正美
// 版本: 1.0.0
// 最近更新: 2015/4/30
//==========================================
avalon.Promise = Promise;
define(["avalon"], function(avalon) {
var global = window
var DOC = global.document
var encode = encodeURIComponent
var decode = decodeURIComponent
var rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/
var rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg
var rnoContent = /^(?:GET|HEAD)$/
var rprotocol = /^\/\//
var rhash = /#.*$/
var rquery = /\?/
var rjsonp = /(=)\?(?=&|$)|\?\?/
var r20 = /%20/g
var radd = /\+/g
var r5b5d = /%5B(.*?)%5D$/;
var originAnchor = document.createElement("a")
originAnchor.href = location.href
//告诉WEB服务器自己接受什么介质类型*/* 表示任何类型type/* 表示该类型下的所有子类型type/sub-type。
var accepts = {
xml: "application/xml, text/xml",
html: "text/html",
text: "text/plain",
json: "application/json, text/javascript",
script: "text/javascript, application/javascript",
"*": ["*/"] + ["*"] //避免被压缩掉
}
function IE() {
if (window.VBArray) {
var mode = document.documentMode
return mode ? mode : window.XMLHttpRequest ? 7 : 6
} else {
return 0
}
}
var useOnload = IE() === 0 || IE() > 8
function parseJS(code) {
var indirect = eval
code = code.trim()
if (code) {
if (code.indexOf("use strict") === 1) {
var script = document.createElement("script")
script.text = code;
head.appendChild(script).parentNode.removeChild(script)
} else {
indirect(code)
}
}
}
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(searchString, position) {
position = position || 0;
return this.lastIndexOf(searchString, position) === position;
}
}
var head = DOC.getElementsByTagName("head")[0] //HEAD元素
var isLocal = false
try {
//在IE下如果重置了document.domain直接访问window.location会抛错但用document.URL就ok了
//http://www.cnblogs.com/WuQiang/archive/2012/09/21/2697474.html
isLocal = rlocalProtocol.test(location.protocol)
} catch (e) {
}
new function() {
//http://www.cnblogs.com/rubylouvre/archive/2010/04/20/1716486.html
var s = ["XMLHttpRequest",
"ActiveXObject('MSXML2.XMLHTTP.6.0')",
"ActiveXObject('MSXML2.XMLHTTP.3.0')",
"ActiveXObject('MSXML2.XMLHTTP')",
"ActiveXObject('Microsoft.XMLHTTP')"
]
s[0] = IE() < 8 && IE() !== 0 && isLocal ? "!" : s[0] //IE下只能使用ActiveXObject
for (var i = 0, axo; axo = s[i++];) {
try {
if (eval("new " + axo)) {
avalon.xhr = new Function("return new " + axo)
break;
}
} catch (e) {
}
}}
var supportCors = "withCredentials" in avalon.xhr()
function parseXML(data, xml, tmp) {
try {
var mode = document.documentMode
if (window.DOMParser && (!mode || mode > 8)) { // Standard
tmp = new DOMParser()
xml = tmp.parseFromString(data, "text/xml")
} else { // IE
xml = new ActiveXObject("Microsoft.XMLDOM") //"Microsoft.XMLDOM"
xml.async = "false";
xml.loadXML(data)
}
} catch (e) {
xml = void 0
}
if (!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) {
avalon.error("Invalid XML: " + data)
}
return xml
}
//ajaxExtend是一个非常重要的内部方法负责将用法参数进行规整化
//1. data转换为字符串
//2. type转换为大写
//3. url正常化加querystring, 加时间戮
//4. 判定有没有跨域
//5. 添加hasContent参数
var defaults = {
type: "GET",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
async: true,
jsonp: "callback"
}
function ajaxExtend(opts) {
opts = avalon.mix({}, defaults, opts)
opts.type = opts.type.toUpperCase()
var querystring = typeof opts.data === "string" ? opts.data : avalon.param(opts.data)
opts.querystring = querystring || ""
opts.url = opts.url.replace(rhash, "").replace(rprotocol, location.protocol + "//")
if (typeof opts.crossDomain !== "boolean") { //判定是否跨域
var urlAnchor = document.createElement("a");
// Support: IE6-11+
// IE throws exception if url is malformed, e.g. http://example.com:80x/
try {
urlAnchor.href = opts.url;
// in IE7-, get the absolute path
var absUrl = !"1"[0] ? urlAnchor.getAttribute("href", 4) : urlAnchor.href;
urlAnchor.href = absUrl
opts.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== urlAnchor.protocol + "//" + urlAnchor.host;
} catch (e) {
opts.crossDomain = true;
}
}
opts.hasContent = !rnoContent.test(opts.type) //是否为post请求
if (!opts.hasContent) {
if (querystring) { //如果为GET请求,则参数依附于url上
opts.url += (rquery.test(opts.url) ? "&" : "?") + querystring;
}
if (opts.cache === false) { //添加时间截
opts.url += (rquery.test(opts.url) ? "&" : "?") + "_time=" + (new Date() - 0)
}
}
return opts;
}
/**
* 伪XMLHttpRequest类,用于屏蔽浏览器差异性
* var ajax = new(self.XMLHttpRequest||ActiveXObject)("Microsoft.XMLHTTP")
* ajax.onreadystatechange = function(){
* if (ajax.readyState==4 && ajax.status==200){
* alert(ajax.responseText)
* }
* }
* ajax.open("POST", url, true)
* ajax.send("key=val&key1=val2")
*/
var XHRMethods = {
setRequestHeader: function(name, value) {
this.requestHeaders[name] = value;
return this;
},
getAllResponseHeaders: function() {
return this.readyState === 4 ? this.responseHeadersString : null;
},
getResponseHeader: function(name, match) {
if (this.readyState === 4) {
while ((match = rheaders.exec(this.responseHeadersString))) {
this.responseHeaders[match[1]] = match[2];
}
match = this.responseHeaders[name];
}
return match === undefined ? null : match;
},
overrideMimeType: function(type) {
this.mimeType = type;
return this;
},
// 中止请求
abort: function(statusText) {
statusText = statusText || "abort";
if (this.transport) {
this.respond(0, statusText)
}
return this;
},
/**
* 用于派发success,error,complete等回调
* http://www.cnblogs.com/rubylouvre/archive/2011/05/18/2049989.html
* @param {Number} status 状态码
* @param {String} statusText 对应的扼要描述
*/
dispatch: function(status, nativeStatusText) {
var statusText = nativeStatusText
// 只能执行一次,防止重复执行
if (!this.transport) { //2:已执行回调
return
}
this.readyState = 4
var isSuccess = status >= 200 && status < 300 || status === 304
if (isSuccess) {
if (status === 204) {
statusText = "nocontent"
} else if (status === 304) {
statusText = "notmodified"
} else {
//如果浏览器能直接返回转换好的数据就最好不过,否则需要手动转换
if (typeof this.response === "undefined") {
var dataType = this.options.dataType || this.options.mimeType
if (!dataType && this.responseText || this.responseXML) { //如果没有指定dataType则根据mimeType或Content-Type进行揣测
dataType = this.getResponseHeader("Content-Type") || ""
dataType = dataType.match(/json|xml|script|html/i) || ["text"]
dataType = dataType[0].toLowerCase()
}
var responseText = this.responseText || '',
responseXML = this.responseXML || ''
try {
this.response = avalon.ajaxConverters[dataType].call(this, responseText, responseXML)
} catch (e) {
isSuccess = false
this.error = e
statusText = "parsererror"
}
}
}
}
this.status = status;
this.statusText = statusText + ""
if (this.timeoutID) {
clearTimeout(this.timeoutID)
delete this.timeoutID
}
this._transport = this.transport
/**
* global event handler
*/
var that = this
// 到这要么成功调用success, 要么失败,调用 error, 最终都会调用 complete
if (isSuccess) {
this._resolve([this.response, statusText, this])
/**
* global event handler
*/
window.setTimeout(function() {
avalon.ajaxGlobalEvents.success(that, that.options, that.response)
}, 0)
} else {
this._reject([this, statusText, this.error])
/**
* global event handler
*/
window.setTimeout(function() {
avalon.ajaxGlobalEvents.error(that, that.options, statusText)
}, 0)
}
delete this.transport
/**
* global event handler
*/
ajaxActive--
window.setTimeout(function() {
avalon.ajaxGlobalEvents.complete(that, that.options)
}, 0)
if (ajaxActive === 0) {
// 最后一个
window.setTimeout(function() {
avalon.ajaxGlobalEvents.stop()
}, 0)
}
}
}
/**
* global event handler
*/
// 记录当前活跃的 ajax 数
var ajaxActive = 0
//ajax主函数
avalon.ajax = function(opts, promise) {
if (!opts || !opts.url) {
avalon.error("参数必须为Object并且拥有url属性")
}
opts = ajaxExtend(opts) //处理用户参数比如生成querystring, type大写化
//创建一个伪XMLHttpRequest,能处理complete,success,error等多投事件
var XHRProperties = {
responseHeadersString: "",
responseHeaders: {},
requestHeaders: {},
querystring: opts.querystring,
readyState: 0,
uniqueID: ("" + Math.random()).replace(/0\./, ""),
status: 0
}
var _reject, _resolve
var promise = new avalon.Promise(function(resolve, reject) {
_resolve = resolve
_reject = reject
})
promise.options = opts
promise._reject = _reject
promise._resolve = _resolve
var doneList = [],
failList = []
Array("done", "fail", "always").forEach(function(method) {
promise[method] = function(fn) {
if (typeof fn === "function") {
if (method !== "fail")
doneList.push(fn)
if (method !== "done")
failList.push(fn)
}
return this
}
})
var isSync = opts.async === false
if (isSync) {
avalon.log("warnning:与jquery1.8一样,async:false这配置已经被废弃")
promise.async = false
}
avalon.mix(promise, XHRProperties, XHRMethods)
promise.then(function(value) {
value = Array.isArray(value) ? value : value === void 0 ? [] : [value]
for (var i = 0, fn; fn = doneList[i++];) {
fn.apply(promise, value)
}
return value
}, function(value) {
value = Array.isArray(value) ? value : value === void 0 ? [] : [value]
for (var i = 0, fn; fn = failList[i++];) {
fn.apply(promise, value)
}
return value
})
promise.done(opts.success).fail(opts.error).always(opts.complete)
var dataType = opts.dataType //目标返回数据类型
var transports = avalon.ajaxTransports
if ((opts.crossDomain && !supportCors || rjsonp.test(opts.url)) && dataType === "json" && opts.type === "GET") {
dataType = opts.dataType = "jsonp"
}
var name = opts.form ? "upload" : dataType
var transport = transports[name] || transports.xhr
avalon.mix(promise, transport) //取得传送器的request, respond, preproccess
if (promise.preproccess) { //这用于jsonp upload传送器
dataType = promise.preproccess() || dataType
}
//设置首部 1、Content-Type首部
if (opts.contentType) {
promise.setRequestHeader("Content-Type", opts.contentType)
}
//2.处理Accept首部
promise.setRequestHeader("Accept", accepts[dataType] ? accepts[dataType] + ", */*; q=0.01" : accepts["*"])
for (var i in opts.headers) { //3. 处理headers里面的首部
promise.setRequestHeader(i, opts.headers[i])
}
// 4.处理超时
if (opts.async && opts.timeout > 0) {
promise.timeoutID = setTimeout(function() {
promise.abort("timeout")
promise.dispatch(0, "timeout")
}, opts.timeout)
}
/**
* global event handler
*/
if (ajaxActive === 0) {
// 第一个
avalon.ajaxGlobalEvents.start()
}
avalon.ajaxGlobalEvents.send(promise, opts)
ajaxActive++
promise.request()
return promise
};
"get,post".replace(avalon.rword, function(method) {
avalon[method] = function(url, data, callback, type) {
if (typeof data === "function") {
type = type || callback
callback = data
data = void 0
}
return avalon.ajax({
type: method,
url: url,
data: data,
success: callback,
dataType: type
})
};
})
function ok(val) {
return val
}
function ng(e) {
throw e
}
avalon.getScript = function(url, callback) {
return avalon.get(url, null, callback, "script")
}
avalon.getJSON = function(url, data, callback) {
return avalon.get(url, data, callback, "json")
}
avalon.upload = function(url, form, data, callback, dataType) {
if (typeof data === "function") {
dataType = callback;
callback = data;
data = void 0;
}
return avalon.ajax({
url: url,
type: "post",
dataType: dataType,
form: form,
data: data,
success: callback
});
}
/**
* global event handler
*/
avalon.ajaxGlobalEvents = {};
["start", "stop", "complete", "error", "success", "send"].forEach(function(method) {
avalon.ajaxGlobalEvents[method] = avalon.noop
})
avalon.ajaxConverters = { //转换器,返回用户想要做的数据
text: function(text) {
// return text || "";
return text;
},
xml: function(text, xml) {
return xml !== void 0 ? xml : parseXML(text)
},
html: function(text) {
return avalon.parseHTML(text) //一个文档碎片,方便直接插入DOM树
},
json: function(text) {
if (!avalon.parseJSON) {
avalon.log("avalon.parseJSON不存在,请升级到最新版")
}
return avalon.parseJSON(text)
},
script: function(text) {
parseJS(text)
return text;
},
jsonp: function() {
var json, callbackName;
if (this.jsonpCallback.startsWith('avalon.')) {
callbackName = this.jsonpCallback.replace(/avalon\./, '')
json = avalon[callbackName]
delete avalon[callbackName]
} else {
json = window[this.jsonpCallback]
}
return json;
}
}
var rbracket = /\[\]$/
avalon.param = function(obj) {
var prefix,
s = [],
add = function(key, value) {
// If value is a function, invoke it and return its value
value = typeof value === "function" ? value() : (value == null ? "" : value);
s[s.length] = encodeURIComponent(key) + "=" + encodeURIComponent(value);
}
// 处理数组与类数组的jquery对象
if (Array.isArray(obj)) {
// Serialize the form elements
avalon.each(obj, add)
} else {
for (prefix in obj) {
paramInner(prefix, obj[prefix], add);
}
}
// Return the resulting serialization
return s.join("&").replace(r20, "+");
}
function paramInner(prefix, obj, add) {
var name;
if (Array.isArray(obj)) {
// Serialize array item.
avalon.each(obj, function(i, v) {
if (rbracket.test(prefix)) {
// Treat each array item as a scalar.
add(prefix, v);
} else {
// Item is non-scalar (array or object), encode its numeric index.
paramInner(
prefix + "[" + (typeof v === "object" ? i : "") + "]",
v,
add);
}
});
} else if (avalon.isPlainObject(obj)) {
// Serialize object item.
for (name in obj) {
paramInner(prefix + "[" + name + "]", obj[name], add);
}
} else {
// Serialize scalar item.
add(prefix, obj);
}
}
//将一个字符串转换为对象
function tryDecodeURIComponent(value) {
try {
return decodeURIComponent(value);
} catch (e) {
return value
}
}
//a%5B0%5D%5Bvalue%5D a%5B1%5D%5B%5D
function addSubObject(host, text, value) {
var match = text.match(r5b5d)
if (!match) {
return true
}
var steps = []
var first = true
var step, index, key
while (index = text.lastIndexOf("%5B")) {
if (index === -1) {
break
}
key = text.slice(index).slice(3, -3)
text = text.slice(0, index)
if (key === "") {
steps.unshift({
action: "pushArrayElement"
})
} else if ((key >>> 0) + "" === key) {
steps.unshift({
action: "setSubArray",
value: key
})
} else {
if (first) {
steps.unshift({
action: "setObjectProperty",
value: tryDecodeURIComponent(key)
})
} else {
steps.unshift({
action: "setSubObjet",
value: tryDecodeURIComponent(key)
})
}
}
first = false
}
first = true
while (step = steps.shift()) {
var isObject = /Object/.test(step.action)
if (first) {
if (!(text in host)) {
host[text] = isObject ? {} : []
}
first = false
host = host[text]
}
switch (step.action) {
case "pushArrayElement":
host.push(value)
break
case "setObjectProperty":
host[step.value] = value
break
case "setSubObjet":
if (!(step.value in host)) {
host[step.value] = {}
}
host = host[step.value]
break
case "setSubArray":
if (!(step.value in host)) {
host[step.value] = []
}
host = host[step.value]
break
}
}
}
// function add
avalon.unparam = function(qs, sep, eq) {
sep = sep || '&';
eq = eq || '=';
var obj = {};
if ((typeof qs !== "string") || qs.length === 0) {
return obj;
}
if (qs.indexOf("?") !== -1) {
qs = qs.split("?").pop()
}
var array = qs.split(sep);
for (var i = 0, el; el = array[i++];) {
var arr = el.split("=")
if (arr.length === 1) { //处理只有键名没键值的情况
obj[arr[0]] = ""
} else {
var key = arr[0].replace(radd, '%20')
var v = tryDecodeURIComponent(arr.slice(1).join("=").replace(radd, ' '));
if (addSubObject(obj, key, v)) { //处理存在中括号的情况
var k = tryDecodeURIComponent(key) //处理不存在中括号的简单的情况
if (!Object.prototype.hasOwnProperty.call(obj, k)) {
obj[k] = v;
} else if (Array.isArray(obj[k])) {
obj[k].push(v);
} else {
obj[k] = [obj[k], v];
}
}
}
}
return obj
}
var rinput = /select|input|button|textarea/i
var rcheckbox = /radio|checkbox/
var rline = /\r?\n/g
function trimLine(val) {
return val.replace(rline, "\r\n")
}
//表单元素变字符串, form为一个元素节点
avalon.serialize = function(form) {
var json = {};
// 不直接转换form.elements防止以下情况 <form > <input name="elements"/><input name="test"/></form>
Array.prototype.filter.call(form.getElementsByTagName("*"), function(el) {
if (rinput.test(el.nodeName) && el.name && !el.disabled) {
return rcheckbox.test(el.type) ? el.checked : true //只处理拥有name并且没有disabled的表单元素
}
}).forEach(function(el) {
var val = avalon(el).val()
val = Array.isArray(val) ? val.map(trimLine) : trimLine(val)
var name = el.name
if (name in json) {
if (Array.isArray(val)) {
json[name].push(val)
} else {
json[name] = [json[name], val]
}
} else {
json[name] = val
}
})
return avalon.param(json, false) // 名值键值对序列化,数组元素名字前不加 []
}
var transports = avalon.ajaxTransports = {
xhr: {
//发送请求
request: function() {
var self = this;
var opts = this.options;
var transport = this.transport = new avalon.xhr;
transport.open(opts.type, opts.url, opts.async, opts.username, opts.password)
if (this.mimeType && transport.overrideMimeType) {
transport.overrideMimeType(this.mimeType)
}
//IE6下如果transport中没有withCredentials直接设置会报错
if (opts.crossDomain && "withCredentials" in transport) {
transport.withCredentials = true
}
/*
* header 中设置 X-Requested-With 用来给后端做标示
* 这是一个 ajax 请求
*
* ChromeFirefox 3.5+ Safari 4+
* 在进行跨域请求时设置自定义 header会触发 preflighted requests
* 会预先发送 method OPTIONS 的请求
*
* 于是如果跨域禁用此功能
*/
if (!opts.crossDomain) {
this.requestHeaders["X-Requested-With"] = "XMLHttpRequest"
}
for (var i in this.requestHeaders) {
transport.setRequestHeader(i, this.requestHeaders[i] + "")
}
/*
* progress
*/
if (opts.progressCallback) {
// 判断是否 ie6-9
var isOldIE = document.all && !window.atob;
if (!isOldIE) {
transport.upload.onprogress = opts.progressCallback
}
}
var dataType = opts.dataType
if ("responseType" in transport && /^(blob|arraybuffer|text)$/.test(dataType)) {
transport.responseType = dataType
this.useResponseType = true
}
//必须要支持 FormData 和 file.fileList 的浏览器 才能用 xhr 发送
//标准规定的 multipart/form-data 发送必须用 utf-8 格式, 记得 ie 会受到 document.charset 的影响
transport.send(opts.hasContent && (this.formdata || this.querystring) || null)
//在同步模式中,IE6,7可能会直接从缓存中读取数据而不会发出请求,因此我们需要手动发出请求
if (!opts.async || transport.readyState === 4) {
this.respond()
} else {
if (useOnload) { //如果支持onerror, onload新API
transport.onload = transport.onerror = function(e) {
this.readyState = 4 //IE9+
this.status = e.type === "load" ? 200 : 500
self.respond()
}
} else {
transport.onreadystatechange = function() {
self.respond()
}
}
}
},
//用于获取原始的responseXMLresponseText 修正status statusText
//第二个参数为1时中止清求
respond: function(event, forceAbort) {
var transport = this.transport
if (!transport) {
return
}
// by zilong避免abort后还继续派发onerror等事件
if (forceAbort && this.timeoutID) {
clearTimeout(this.timeoutID);
delete this.timeoutID
}
try {
var completed = transport.readyState === 4
if (forceAbort || completed) {
transport.onreadystatechange = avalon.noop
if (useOnload) { //IE6下对XHR对象设置onerror属性可能报错
transport.onerror = transport.onload = null
}
if (forceAbort) {
if (!completed && typeof transport.abort === "function") { // 完成以后 abort 不要调用
transport.abort()
}
} else {
var status = transport.status
//设置responseText
var text = transport.responseText
this.responseText = typeof text === "string" ? text : void 0
//设置responseXML
try {
//当responseXML为[Exception: DOMException]时,
//访问它会抛“An attempt was made to use an object that is not, or is no longer, usable”异常
var xml = transport.responseXML
this.responseXML = xml.documentElement
} catch (e) {
}
//设置response
if (this.useResponseType) {
this.response = transport.response
}
//设置responseHeadersString
this.responseHeadersString = transport.getAllResponseHeaders()
try { //火狐在跨城请求时访问statusText值会抛出异常
var statusText = transport.statusText
} catch (e) {
this.error = e
statusText = "firefoxAccessError"
}
//用于处理特殊情况,如果是一个本地请求,只要我们能获取数据就假当它是成功的
if (!status && isLocal && !this.options.crossDomain) {
status = this.responseText ? 200 : 404
//IE有时会把204当作为1223
} else if (status === 1223) {
status = 204
}
this.dispatch(status, statusText)
}
}
} catch (err) {
// 如果网络问题时访问XHR的属性在FF会抛异常
// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
if (!forceAbort) {
this.dispatch(500, err)
}
}
}
},
jsonp: {
preproccess: function() {
var opts = this.options;
var name = this.jsonpCallback = opts.jsonpCallback || "avalon.jsonp" + setTimeout("1")
if (rjsonp.test(opts.url)) {
opts.url = opts.url.replace(rjsonp, "$1" + name)
} else {
opts.url = opts.url + (rquery.test(opts.url) ? "&" : "?") + opts.jsonp + "=" + name
}
//将后台返回的json保存在惰性函数中
if (name.startsWith('avalon.')) {
name = name.replace(/avalon\./, '')
avalon[name] = function(json) {
avalon[name] = json
}
} else {
window[name] = function(json) {
window[name] = json
}
}
return "script"
}
},
script: {
request: function() {
var opts = this.options;
var node = this.transport = DOC.createElement("script")
if (opts.charset) {
node.charset = opts.charset
}
var self = this;
node.onerror = node[useOnload ? "onload" : "onreadystatechange"] = function() {
self.respond()
};
node.src = opts.url
head.insertBefore(node, head.firstChild)
},
respond: function(event, forceAbort) {
var node = this.transport
if (!node) {
return
}
// by zilong避免abort后还继续派发onerror等事件
if (forceAbort && this.timeoutID) {
clearTimeout(this.timeoutID);
delete this.timeoutID
}
var execute = /loaded|complete|undefined/i.test(node.readyState)
if (forceAbort || execute) {
node.onerror = node.onload = node.onreadystatechange = null
var parent = node.parentNode;
if (parent) {
parent.removeChild(node)
}
if (!forceAbort) {
var args;
if (this.jsonpCallback) {
var jsonpCallback = this.jsonpCallback.startsWith('avalon.') ? avalon[this.jsonpCallback.replace(/avalon\./, '')] : window[this.jsonpCallback]
args = typeof jsonpCallback === "function" ? [500, "error"] : [200, "success"]
} else {
args = [200, "success"]
}
this.dispatch.apply(this, args)
}
}
}
},
upload: {
preproccess: function() {
var opts = this.options, formdata
if (typeof opts.form.append === "function") { //简单判断opts.form是否为FormData
formdata = opts.form;
opts.contentType = '';
} else {
formdata = new FormData(opts.form) //将二进制什么一下子打包到formdata
}
avalon.each(opts.data, function(key, val) {
formdata.append(key, val) //添加客外数据
})
this.formdata = formdata
}
}
}
avalon.mix(transports.jsonp, transports.script)
avalon.mix(transports.upload, transports.xhr)
if (!window.FormData) {
var str = 'Function BinaryToArray(binary)\r\n\
Dim oDic\r\n\
Set oDic = CreateObject("scripting.dictionary")\r\n\
length = LenB(binary) - 1\r\n\
For i = 1 To length\r\n\
oDic.add i, AscB(MidB(binary, i, 1))\r\n\
Next\r\n\
BinaryToArray = oDic.Items\r\n\
End Function'
execScript(str, "VBScript");
avalon.fixAjax = function() {
avalon.ajaxConverters.arraybuffer = function() {
var body = this.tranport && this.tranport.responseBody
if (body) {
return new VBArray(BinaryToArray(body)).toArray();
}
};
function createIframe(ID) {
var iframe = avalon.parseHTML("<iframe " + " id='" + ID + "'" +
" name='" + ID + "'" + " style='position:absolute;left:-9999px;top:-9999px;'/>").firstChild;
return (DOC.body || DOC.documentElement).insertBefore(iframe, null);
}
function addDataToForm(form, data) {
var ret = [],
d, isArray, vs, i, e;
for (d in data) {
isArray = Array.isArray(data[d]);
vs = isArray ? data[d] : [data[d]];
// 数组和原生一样对待,创建多个同名输入域
for (i = 0; i < vs.length; i++) {
e = DOC.createElement("input");
e.type = 'hidden';
e.name = d;
e.value = vs[i];
form.appendChild(e);
ret.push(e);
}
}
return ret;
}
//https://github.com/codenothing/Pure-Javascript-Upload/blob/master/src/upload.js
avalon.ajaxTransports.upload = {
request: function() {
var self = this;
var opts = this.options;
var ID = "iframe-upload-" + this.uniqueID;
var form = opts.form;
var iframe = this.transport = createIframe(ID);
//form.enctype的值
//1:application/x-www-form-urlencoded 在发送前编码所有字符(默认)
//2:multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
//3:text/plain 空格转换为 "+" 加号,但不对特殊字符编码。
var backups = {
target: form.target || "",
action: form.action || "",
enctype: form.enctype,
method: form.method
};
var fields = opts.data ? addDataToForm(form, opts.data) : [];
//必须指定method与enctype要不在FF报错
//表单包含文件域时,如果缺少 method=POST 以及 enctype=multipart/form-data
// 设置target到隐藏iframe避免整页刷新
form.target = ID;
form.action = opts.url;
form.method = "POST";
form.enctype = "multipart/form-data";
this.uploadcallback = avalon.bind(iframe, "load", function(event) {
self.respond(event);
});
form.submit();
//还原form的属性
for (var i in backups) {
form[i] = backups[i];
}
//移除之前动态添加的节点
fields.forEach(function(input) {
form.removeChild(input);
});
},
respond: function(event) {
var node = this.transport, child
// 防止重复调用,成功后 abort
if (!node) {
return;
}
if (event && event.type === "load") {
var doc = node.contentWindow.document;
this.responseXML = doc;
if (doc.body) { //如果存在body属性,说明不是返回XML
this.responseText = doc.body.innerHTML;
//当MIME为'application/javascript' 'text/javascript",浏览器会把内容放到一个PRE标签中
if ((child = doc.body.firstChild) && child.nodeName.toUpperCase() === 'PRE' && child.firstChild) {
this.responseText = child.firstChild.nodeValue;
}
}
this.dispatch(200, "success");
}
this.uploadcallback = avalon.unbind(node, "load", this.uploadcallback);
delete this.uploadcallback;
setTimeout(function() { // Fix busy state in FF3
node.parentNode.removeChild(node);
});
}
};
delete avalon.fixAjax;
};
avalon.fixAjax()
}
return avalon
})
/**
*
2011.8.31
将会传送器的abort方法上传到avalon.XHR.abort去处理
修复serializeArray的bug
对XMLHttpRequest.abort进行try...catch
2012.3.31 v2 大重构,支持XMLHttpRequest Level2
2013.4.8 v3 大重构 支持二进制上传与下载
http://www.cnblogs.com/heyuquan/archive/2013/05/13/3076465.html
2014.12.25 v4 大重构
2015.3.2 去掉mmPromise
2015.3.13 使用加强版mmPromise
2015.3.17 增加 xhr onprogress 回调
2015.12.10 处理全局对象BUG
*/