@@ -239,7 +239,7 @@ function trim(str) {
239239}
240240
241241function getEventTarget ( xhr ) {
242- return xhr . watcher || ( xhr . watcher = document . createElement ( 'a' ) ) ;
242+ return xhr . watcher || ( xhr . watcher = typeof document . createDocumentFragment === 'function' ? document . createDocumentFragment ( ) : document . createElement ( 'a' ) ) ;
243243}
244244
245245function triggerListener ( xhr , name ) {
@@ -275,11 +275,21 @@ Handler[prototype] = Object.create({
275275 triggerListener ( xhr , eventReadyStateChange ) ;
276276 triggerListener ( xhr , eventLoad ) ;
277277 triggerListener ( xhr , eventLoadEnd ) ;
278+ if ( xhr . readyState === 4 ) {
279+ if ( xhr . config ) xhr . config . xhr = null ;
280+ xhr [ 'on' + eventReadyStateChange ] = null ;
281+ xhr . config = null ;
282+ }
278283 } ,
279284 reject : function reject ( error ) {
280285 this . xhrProxy . status = 0 ;
281286 triggerListener ( this . xhr , error . type ) ;
282287 triggerListener ( this . xhr , eventLoadEnd ) ;
288+ if ( xhr . readyState === 4 ) {
289+ if ( xhr . config ) xhr . config . xhr = null ;
290+ xhr [ 'on' + eventReadyStateChange ] = null ;
291+ xhr . config = null ;
292+ }
283293 }
284294} ) ;
285295
@@ -313,16 +323,33 @@ var ErrorHandler = makeHandler(function (error) {
313323} ) ;
314324
315325function proxyAjax ( proxy , win ) {
316- var onRequest = proxy . onRequest ,
317- onResponse = proxy . onResponse ,
318- onError = proxy . onError ;
326+ var onConfig = proxy . onConfig ,
327+ onRequest = null ,
328+ onRequest_ = proxy . onRequest ,
329+ onResponse = proxy . onResponse ,
330+ onError = proxy . onError ;
319331
320332 function handleResponse ( xhr , xhrProxy ) {
321333 var handler = new ResponseHandler ( xhr ) ;
322- var responseType = xhrProxy . responseType ;
323- var responseData = ! responseType || responseType === 'text' || responseType === 'json' ? xhrProxy . responseText : xhrProxy . response ;
324334 var ret = {
325- response : responseData , //ie9
335+ get response ( ) {
336+ // object getter is part of ES5
337+ // getter to avoid uncessary processing. only proceed if response.response is called.
338+ // property 'response' is enumerable such that JSON.stringify(response) contains response
339+ var responseType = xhrProxy . responseType ;
340+ if ( ! responseType || responseType === 'text' ) {
341+ return xhrProxy . responseText ;
342+ }
343+ // reference: https://shanabrian.com/web/html-css-js-technics/js-ie10-ie11-xhr-json-string.php
344+ // reference: https://github.com/axios/axios/issues/2390
345+ // json - W3C standard - xhrProxy.response = JSON object; responseText is unobtainable
346+ // For details, see https://github.com/wendux/ajax-hook/issues/117
347+ // IE 9, 10 & 11 - only responseText
348+ if ( responseType === 'json' && typeof JSON === 'object' && ( ( navigator || 0 ) . userAgent || '' ) . indexOf ( 'Trident' ) !== - 1 ) {
349+ return JSON . parse ( xhrProxy . responseText ) ;
350+ }
351+ return xhrProxy . response ;
352+ } , //ie9
326353 status : xhrProxy . status ,
327354 statusText : xhrProxy . statusText ,
328355 config : xhr . config ,
@@ -359,14 +386,21 @@ function proxyAjax(proxy, win) {
359386 }
360387
361388 function stateChangeCallback ( xhr , xhrProxy ) {
362- if ( xhr . readyState === 4 && xhr . status !== 0 ) {
363- handleResponse ( xhr , xhrProxy ) ;
364- } else if ( xhr . readyState !== 4 ) {
365- triggerListener ( xhr , eventReadyStateChange ) ;
389+ var config = xhr ? xhr . config : null ;
390+ if ( config && xhr && config . xhr === xhr ) {
391+ if ( xhr . readyState === 4 && xhr . status !== 0 ) {
392+ handleResponse ( xhr , xhrProxy ) ;
393+ } else if ( xhr . readyState !== 4 ) {
394+ triggerListener ( xhr , eventReadyStateChange ) ;
395+ }
366396 }
367397 return true ;
368398 }
369399
400+ var eventListenerFnMap = typeof WeakMap === 'function' ? function ( _this ) {
401+ return _this . eventListenerFnMap || ( _this . eventListenerFnMap = new WeakMap ( ) ) ;
402+ } : null ;
403+
370404 var _hook = ( 0 , _xhrHook . hook ) ( {
371405 onload : preventXhrProxyCallback ,
372406 onloadend : preventXhrProxyCallback ,
@@ -384,18 +418,33 @@ function proxyAjax(proxy, win) {
384418 config . async = args [ 2 ] ;
385419 config . user = args [ 3 ] ;
386420 config . password = args [ 4 ] ;
387- config . xhr = xhr ;
421+ Object . defineProperty ( config , 'xhr' , {
422+ get ( ) {
423+ return xhr ; // xhr wil be set to null after xhr.readyState === XMLHttpRequest.DONE (4)
424+ } ,
425+ set ( nv ) {
426+ if ( nv === null ) xhr = null ;
427+ return true ;
428+ } ,
429+ enumerable : false ,
430+ configurable : true
431+ } ) ;
432+ // config.xhr = xhr;
388433 var evName = 'on' + eventReadyStateChange ;
389434 if ( ! xhr [ evName ] ) {
390435 xhr [ evName ] = function ( ) {
391- return stateChangeCallback ( xhr , _this ) ;
436+ return stateChangeCallback ( this , _this ) ;
392437 } ;
393438 }
394439
395440 // 如果有请求拦截器,则在调用onRequest后再打开链接。因为onRequest最佳调用时机是在send前,
396441 // 所以我们在send拦截函数中再手动调用open,因此返回true阻止xhr.open调用。
397442 //
398443 // 如果没有请求拦截器,则不用阻断xhr.open调用
444+ onRequest = onRequest_ ;
445+ if ( onConfig ) {
446+ if ( onConfig ( config , this ) === false ) onRequest = null ;
447+ }
399448 if ( onRequest ) return true ;
400449 } ,
401450 send : function send ( args , xhr ) {
@@ -419,18 +468,37 @@ function proxyAjax(proxy, win) {
419468 if ( onRequest ) return true ;
420469 } ,
421470 addEventListener : function addEventListener ( args , xhr ) {
471+ // args = (type:string , listener: EventListener, opt: any?)
422472 var _this = this ;
423473 if ( _xhrHook . events . indexOf ( args [ 0 ] ) !== - 1 ) {
424474 var handler = args [ 1 ] ;
425- getEventTarget ( xhr ) . addEventListener ( args [ 0 ] , function ( e ) {
426- var event = ( 0 , _xhrHook . configEvent ) ( e , _this ) ;
427- event . type = args [ 0 ] ;
475+ var Gn = function ( e ) {
476+ var event = _xhrHook . configEvent ( e , _this ) ;
428477 event . isTrusted = true ;
429478 handler . call ( _this , event ) ;
430- } ) ;
479+ } ;
480+ if ( eventListenerFnMap ) {
481+ var map = eventListenerFnMap ( _this ) ;
482+ map . set ( handler , Gn ) ;
483+ }
484+ getEventTarget ( xhr ) . addEventListener ( args [ 0 ] , Gn , false ) ;
431485 return true ;
432486 }
433487 } ,
488+ removeEventListener : function removeEventListener ( args , xhr ) {
489+ // args = (type:string , listener: EventListener, opt: any?)
490+ if ( _xhrHook . events . indexOf ( args [ 0 ] ) !== - 1 ) {
491+ var handler = args [ 1 ] ;
492+ if ( eventListenerFnMap ) {
493+ var map = eventListenerFnMap ( this ) ;
494+ var Gn = map . get ( handler ) ;
495+ if ( Gn ) {
496+ getEventTarget ( xhr ) . removeEventListener ( args [ 0 ] , Gn , false ) ;
497+ return true ;
498+ }
499+ }
500+ }
501+ } ,
434502 getAllResponseHeaders : function getAllResponseHeaders ( _ , xhr ) {
435503 var headers = xhr . resHeader ;
436504 if ( headers ) {
0 commit comments