-
Notifications
You must be signed in to change notification settings - Fork 11
/
index-debug.js
432 lines (370 loc) · 13.3 KB
/
index-debug.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
/*!
* JRaiser 2 Javascript Library
* ajax - v1.1.2 (2015-04-23T17:00:22+0800)
* http://jraiser.org/ | Released under MIT license
*/
define(function(require, exports, module) { 'use strict';
/**
* 本模块提供异步请求接口
* @module ajax/1.1.x/
* @category Utility
*/
var base = require('base/1.0.x/'), qs = require('querystring/1.0.x/');
// IE10同时支持两种事件,但是当JS有缓存的时候,会先触发onreadystatechange再执行JS程序
var scriptOnloadEvent = 'onload' in document.createElement('script') ?
'onload' : 'onreadystatechange';
// 加载js或css文件统一接口
function loadFile(url, opts) {
var head = document.getElementsByTagName('head')[0] || document.documentElement, node;
function onload() {
var readyState = this.readyState;
if (!readyState || readyState === 'loaded' || readyState === 'complete') {
this[scriptOnloadEvent] = null;
// 执行回调
opts.onload && opts.onload.call(this);
// 加载js后可以移除节点,但加载css后不可以
if (this.nodeName === 'SCRIPT') { this.parentNode.removeChild(this); }
}
node = null;
}
// 添加get参数
if (opts.data) { url = qs.append(url, opts.data); }
// 添加timestamp防止缓存
if (opts.nocache) { url = qs.append(url, { _: +new Date }); }
// 设置节点属性
node = base.mix(document.createElement(opts.nodeName), opts.nodeAttrs, {
ignoreNull: true
});
node[opts.urlAttrName] = url;
node[scriptOnloadEvent] = onload;
// 插入到页面中使其生效
if (document.body) {
head.appendChild(node);
} else {
head.insertBefore(node, head.firstChild);
}
}
// JSONP回调函数计数器
var jsonpCallbackCounter = 0, randomNum = parseInt(Math.random() * 100000);
// 生成JSONP回调函数名
function generateCallbackName() {
var callbackName;
do {
callbackName = 'jsonp_callback' + randomNum + '_' + (++jsonpCallbackCounter);
} while(window[callbackName]);
return callbackName;
}
/**
* 创建XMLHttpRequest对象
* @method createXHR
* @return {XMLHttpRequest} XMLHttpRequest对象
*/
var createXHR = window.ActiveXObject ? function() {
try {
return new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) { }
} : function() {
try {
return new XMLHttpRequest();
} catch (e) { }
};
return {
/**
* 获取表单数据
* @method serializeForm
* @param {NodeList|Element} form 表单
* @param {String} [dataType] 返回数据类型,默认为数组,参数值为'string'时返回序列化后的字符串
* @return {Array<Object<name,value>>|String} 表单数据
*/
serializeForm: function(form, dataType) {
if (!('nodeType' in form) && typeof form.get === 'function') { form = form.get(0); }
if (form.tagName !== 'FORM') { throw new Error('invalid form element'); }
var data = [ ], elements = form.elements;
for (var i = 0, elt; elt = elements[i]; i++) {
if (elt.disabled || !elt.name) { continue; }
if (elt.tagName === 'INPUT' &&
(elt.type === 'radio' || elt.type === 'checkbox') && !elt.checked) {
continue;
}
data.push({
name: elt.name,
value: elt.value.trim()
});
}
if (dataType === 'string') { data = qs.stringify(data); }
return data;
},
// See line 75
createXHR: createXHR,
/**
* 加载样式表文件
* @method getCSS
* @param {String} href 文件URL
* @param {Function} [onload] 加载完成后的回调函数(某些浏览器下无效)
*/
/**
* 加载样式表文件
* @method getCSS
* @param {String} href 文件URL
* @param {Object} [opts] 加载设置
* @param {String} [opts.media] 样式对何种设备有效(link标签的media属性)
* @param {Object} [opts.data] 发送的数据
* @param {Function} [opts.onload] 加载完成后的回调函数(某些浏览器下无效)
* @param {String} [opts.charset] 文件编码,当页面编码与样式表编码不同时指定
* @param {Boolean} [opts.nocache=false] 是否在URL中添加时间戳(参数名为“_”)防止缓存
*/
getCSS: function(href, opts) {
if (typeof opts === 'function') {
opts = { onload: opts };
} else if (!opts) {
opts = { };
}
opts = base.extend({
nodeName: 'link',
urlAttrName: 'href',
nodeAttrs: {
rel: 'stylesheet',
type: 'text/css',
media: opts.media,
charset: opts.charset
}
}, opts);
loadFile(href, opts);
},
/**
* 加载脚本文件
* @method getScript
* @param {String} src 文件URL
* @param {Function} [onload] 加载完成后的回调函数
*/
/**
* 加载脚本文件
* @method getScript
* @param {String} src 文件URL
* @param {Object} [opts] 加载设置
* @param {Object} [opts.data] 发送的数据
* @param {Function} [opts.onload] 加载完成后的回调函数
* @param {String} [opts.charset] 文件编码,当页面编码与样式表编码不同时指定
* @param {Boolean} [opts.nocache=true] 是否在URL中添加时间戳(参数名为“_”)防止缓存
*/
getScript: function(src, opts) {
if (typeof opts === 'function') {
opts = { onload: opts };
} else if (!opts) {
opts = { };
}
opts = base.extend({
nodeName: 'script',
urlAttrName: 'src',
nodeAttrs: {
type: 'text/javascript',
charset: opts.charset,
async: true
},
nocache: true
}, opts);
loadFile(src, opts);
},
/**
* 发送JSONP请求
* @method jsonp
* @param {String} url URL
* @param {Object} [opts] 其他参数
* @param {String} [opts.callbackName] 回调函数名,如不指定则随机生成
* @param {Function} [opts.onsuccess] 回调函数
* @param {Function} [opts.oncomplete] 请求完成后的执行的函数
* @param {Object} [opts.data] 发送的数据
* @param {String} [opts.charset] 文件编码,当页面编码与样式表编码不同时指定
* @param {Boolean} [opts.nocache=true] 是否在URL中添加时间戳(参数名为“_”)防止缓存
*/
jsonp: function(url, opts) {
opts = opts || { };
opts.data = opts.data || { };
var callback = opts.callbackName || generateCallbackName(),
oncomplete = opts.oncomplete;
if ( base.isArray(opts.data) ) {
opts.data.push({
name: 'callback',
value: callback
});
} else {
opts.data.callback = callback;
}
// 创建全局回调函数
window[callback] = opts.onsuccess;
opts.onload = function() {
// 执行callback后将其清除
if (window[callback]) {
try {
delete window[callback];
} catch(e) {
window[callback] = null;
}
}
if (oncomplete) { oncomplete.apply(this, arguments); }
};
this.getScript(url, opts);
},
/**
* 发送AJAX请求
* @method send
* @param {String} url URL
* @param {Object} [opts] 其他参数
* @param {Object} [opts.data] 发送的数据
* @param {String} [opts.dataType='text'] 返回的数据格式,json、jsonp、xml或text
* @param {String} [opts.method='GET'] 请求方式,GET、POST或HEAD,dataType为jsonp时只能为GET
* @param {Boolean} [opts.nocache=true] 是否在URL中添加时间戳(参数名为“_”)防止缓存
* @param {Object} [opts.headers] 要设置的HTTP头,dataType为jsonp时无效
* @param {Boolean} [opts.async=true] 是否使用异步方式请求,dataType为jsonp时只能为true
* @param {Number} [opts.timeout] 超时时间,仅在异步方式且dataType不是jsonp时有效
* @param {XMLHttpRequest} [opts.xhr] 进行请求的XMLHttpRequest对象,如不指定则自动创建,dataType为jsonp时无效
* @param {String} [opts.callbackName] jsonp回调函数名,如不指定则随机生成,仅当dataType为jsonp时有效
* @param {Function(xhr)} [opts.onbeforesend] 发送请求前执行的操作,dataType为jsonp时无效
* @param {Function(xhr,statusText)} [opts.onload] 请求回应(无论HTTP状态值是什么)后执行的操作,dataType为jsonp时无效
* @param {Function(result,xhr,statusText)} [opts.onsuccess] 请求成功后执行的操作
* @param {Function(xhr,statusText)} [opts.onerror] 请求失败后执行的操作,dataType为jsonp时无效
* @param {Function(xhr,statusText)} [opts.oncomplete] 请求完成且回调结束后执行的操作
* @return {XMLHttpRequest} 进行请求的XMLHttpRequest对象,dataType为jsonp时无返回值
*/
/**
* 发送AJAX请求
* @method send
* @param {Object} [opts] 参数
* @param {String} [opts.url] URL
* @param {Object} [opts.data] 发送的数据
* @param {String} [opts.dataType='text'] 返回的数据格式,json、jsonp、xml或text
* @param {String} [opts.method='GET'] 请求方式,GET、POST或HEAD,dataType为jsonp时只能为GET
* @param {Boolean} [opts.nocache=true] 是否在URL中添加时间戳(参数名为“_”)防止缓存
* @param {Object} [opts.headers] 要设置的HTTP头,dataType为jsonp时无效
* @param {Boolean} [opts.async=true] 是否使用异步方式请求,dataType为jsonp时只能为true
* @param {Number} [opts.timeout] 超时时间,仅在异步方式且dataType不是jsonp时有效
* @param {XMLHttpRequest} [opts.xhr] 进行请求的XMLHttpRequest对象,如不指定则自动创建,dataType为jsonp时无效
* @param {String} [opts.callbackName] jsonp回调函数名,如不指定则随机生成,仅当dataType为jsonp时有效
* @param {Function(xhr)} [opts.onbeforesend] 发送请求前执行的操作,dataType为jsonp时无效
* @param {Function(xhr,statusText)} [opts.onload] 请求回应(无论HTTP状态值是什么)后执行的操作,dataType为jsonp时无效
* @param {Function(result,xhr,statusText)} [opts.onsuccess] 请求成功后执行的操作
* @param {Function(xhr,statusText)} [opts.onerror] 请求失败后执行的操作,dataType为jsonp时无效
* @param {Function(xhr,statusText)} [opts.oncomplete] 请求完成且回调结束后执行的操作
* @return {XMLHttpRequest} 进行请求的XMLHttpRequest对象,dataType为jsonp时无返回值
*/
send: function(url, opts) {
// 重载,允许把url写到opts中
if (typeof url !== 'string') {
opts = url;
url = opts.url;
}
if (opts.dataType) { opts.dataType = opts.dataType.toLowerCase(); }
if (opts.dataType === 'jsonp') {
return this.jsonp( url, base.mix({ }, opts, {
whiteList: ['callbackName', 'onsuccess', 'oncomplete', 'data', 'charset', 'nocache'],
ignoreNull: true
}) );
}
// readystatechange回调函数
var onreadystatechange = function(e, statusText) {
var readyState = xhr.readyState;
if (readyState !== 4 && !statusText) { return; }
var status = readyState === 4 ? xhr.status : 0, evtType;
if ( (status >= 200 && status < 300) || status === 1223 || status === 304 ) {
evtType = 'onsuccess';
statusText = 'success';
} else if (status || statusText) { // 忽略status为0的情况
evtType = 'onerror';
if (!statusText) { statusText = 'error'; }
}
// 触发onload事件
if (opts.onload) { opts.onload.call(window, xhr, statusText); }
if (evtType) {
var result;
if (evtType === 'onsuccess') {
switch (opts.dataType) {
case 'json':
var responseText = (xhr.responseText || '').trim();
if (responseText) {
try {
result = JSON.parse(responseText);
} catch (e) {
evtType = 'onerror';
statusText = 'parsererror';
}
}
break;
case 'xml':
result = xhr.responseXML;
if (result && !result.documentElement) { result = null; }
if (!result) {
evtType = 'onerror';
statusText = 'parsererror';
}
break;
default:
result = xhr.responseText;
}
}
// 触发回调
var callback = opts[evtType], args = [xhr, statusText];
if (evtType === 'onsuccess') { args.unshift(result); }
if (callback) { callback.apply(window, args); }
}
// 触发oncomplete事件
if (opts.oncomplete) { opts.oncomplete.call(window, xhr, statusText); }
};
// 修正设置值
var method = (opts.method || 'GET').toUpperCase(),
async = typeof opts.async === 'boolean' ? async : true,
data = opts.data,
headers = opts.headers || { },
xhr = opts.xhr || createXHR();
if (data) {
data = qs.stringify(data);
switch (method) {
case 'GET':
url = qs.append(url, data);
data = null;
break;
case 'POST':
base.mix(headers, {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}, {
overwrite: false
});
break;
}
}
if (opts.nocache !== false) {
// 添加timestamp防止缓存
url = qs.append(url, { _: +new Date });
}
if (async) {
// 超时设置仅在异步情况下有效
if (opts.timeout > 0) {
setTimeout(function() {
if (xhr.readyState !== 4) {
xhr.abort();
onreadystatechange.call(xhr, null, 'timeout');
}
}, opts.timeout);
}
xhr.onreadystatechange = onreadystatechange;
}
if (opts.username) {
xhr.open(method, url, async, opts.username, opts.password);
} else {
xhr.open(method, url, async);
}
if (!headers['X-Requested-With']) {
headers['X-Requested-With'] = 'XMLHttpRequest';
}
for (var i in headers) {
if ( headers.hasOwnProperty(i) ) {
xhr.setRequestHeader(i, headers[i]);
}
}
// 触发beforesend事件,可以在此事件中再次修改opts
opts.onbeforesend && opts.onbeforesend.call(window, xhr);
xhr.send(data || '');
if (!async) { onreadystatechange.call(xhr); }
return xhr;
}
};
});