jquery.jsonp.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * jQuery JSONP Core Plugin 2.4.0 (2012-08-21)
  3. *
  4. * https://github.com/jaubourg/jquery-jsonp
  5. *
  6. * Copyright (c) 2012 Julian Aubourg
  7. *
  8. * This document is licensed as free software under the terms of the
  9. * MIT License: http://www.opensource.org/licenses/mit-license.php
  10. */
  11. ( function( $ ) {
  12. // ###################### UTILITIES ##
  13. // Noop
  14. function noop() {
  15. }
  16. // Generic callback
  17. function genericCallback( data ) {
  18. lastValue = [ data ];
  19. }
  20. // Call if defined
  21. function callIfDefined( method , object , parameters ) {
  22. return method && method.apply( object.context || object , parameters );
  23. }
  24. // Give joining character given url
  25. function qMarkOrAmp( url ) {
  26. return /\?/ .test( url ) ? "&" : "?";
  27. }
  28. var // String constants (for better minification)
  29. STR_ASYNC = "async",
  30. STR_CHARSET = "charset",
  31. STR_EMPTY = "",
  32. STR_ERROR = "error",
  33. STR_INSERT_BEFORE = "insertBefore",
  34. STR_JQUERY_JSONP = "_jqjsp",
  35. STR_ON = "on",
  36. STR_ON_CLICK = STR_ON + "click",
  37. STR_ON_ERROR = STR_ON + STR_ERROR,
  38. STR_ON_LOAD = STR_ON + "load",
  39. STR_ON_READY_STATE_CHANGE = STR_ON + "readystatechange",
  40. STR_READY_STATE = "readyState",
  41. STR_REMOVE_CHILD = "removeChild",
  42. STR_SCRIPT_TAG = "<script>",
  43. STR_SUCCESS = "success",
  44. STR_TIMEOUT = "timeout",
  45. // Window
  46. win = window,
  47. // Deferred
  48. Deferred = $.Deferred,
  49. // Head element
  50. head = $( "head" )[ 0 ] || document.documentElement,
  51. // Page cache
  52. pageCache = {},
  53. // Counter
  54. count = 0,
  55. // Last returned value
  56. lastValue,
  57. // ###################### DEFAULT OPTIONS ##
  58. xOptionsDefaults = {
  59. //beforeSend: undefined,
  60. //cache: false,
  61. callback: STR_JQUERY_JSONP,
  62. //callbackParameter: undefined,
  63. //charset: undefined,
  64. //complete: undefined,
  65. //context: undefined,
  66. //data: "",
  67. //dataFilter: undefined,
  68. //error: undefined,
  69. //pageCache: false,
  70. //success: undefined,
  71. //timeout: 0,
  72. //traditional: false,
  73. url: location.href
  74. },
  75. // opera demands sniffing :/
  76. opera = win.opera,
  77. // IE < 10
  78. oldIE = !!$( "<div>" ).html( "<!--[if IE]><i><![endif]-->" ).find("i").length;
  79. // ###################### MAIN FUNCTION ##
  80. function jsonp( xOptions ) {
  81. // Build data with default
  82. xOptions = $.extend( {} , xOptionsDefaults , xOptions );
  83. // References to xOptions members (for better minification)
  84. var successCallback = xOptions.success,
  85. errorCallback = xOptions.error,
  86. completeCallback = xOptions.complete,
  87. dataFilter = xOptions.dataFilter,
  88. callbackParameter = xOptions.callbackParameter,
  89. successCallbackName = xOptions.callback,
  90. cacheFlag = xOptions.cache,
  91. pageCacheFlag = xOptions.pageCache,
  92. charset = xOptions.charset,
  93. url = xOptions.url,
  94. data = xOptions.data,
  95. timeout = xOptions.timeout,
  96. pageCached,
  97. // Abort/done flag
  98. done = 0,
  99. // Life-cycle functions
  100. cleanUp = noop,
  101. // Support vars
  102. supportOnload,
  103. supportOnreadystatechange,
  104. // Request execution vars
  105. firstChild,
  106. script,
  107. scriptAfter,
  108. timeoutTimer;
  109. // If we have Deferreds:
  110. // - substitute callbacks
  111. // - promote xOptions to a promise
  112. Deferred && Deferred(function( defer ) {
  113. defer.done( successCallback ).fail( errorCallback );
  114. successCallback = defer.resolve;
  115. errorCallback = defer.reject;
  116. }).promise( xOptions );
  117. // Create the abort method
  118. xOptions.abort = function() {
  119. !( done++ ) && cleanUp();
  120. };
  121. // Call beforeSend if provided (early abort if false returned)
  122. if ( callIfDefined( xOptions.beforeSend , xOptions , [ xOptions ] ) === !1 || done ) {
  123. return xOptions;
  124. }
  125. // Control entries
  126. url = url || STR_EMPTY;
  127. data = data ? ( (typeof data) == "string" ? data : $.param( data , xOptions.traditional ) ) : STR_EMPTY;
  128. // Build final url
  129. url += data ? ( qMarkOrAmp( url ) + data ) : STR_EMPTY;
  130. // Add callback parameter if provided as option
  131. callbackParameter && ( url += qMarkOrAmp( url ) + encodeURIComponent( callbackParameter ) + "=?" );
  132. // Add anticache parameter if needed
  133. !cacheFlag && !pageCacheFlag && ( url += qMarkOrAmp( url ) + "_" + ( new Date() ).getTime() + "=" );
  134. // Replace last ? by callback parameter
  135. url = url.replace( /=\?(&|$)/ , "=" + successCallbackName + "$1" );
  136. // Success notifier
  137. function notifySuccess( json ) {
  138. if ( !( done++ ) ) {
  139. cleanUp();
  140. // Pagecache if needed
  141. pageCacheFlag && ( pageCache [ url ] = { s: [ json ] } );
  142. // Apply the data filter if provided
  143. dataFilter && ( json = dataFilter.apply( xOptions , [ json ] ) );
  144. // Call success then complete
  145. callIfDefined( successCallback , xOptions , [ json , STR_SUCCESS, xOptions ] );
  146. callIfDefined( completeCallback , xOptions , [ xOptions , STR_SUCCESS ] );
  147. }
  148. }
  149. // Error notifier
  150. function notifyError( type ) {
  151. if ( !( done++ ) ) {
  152. // Clean up
  153. cleanUp();
  154. // If pure error (not timeout), cache if needed
  155. pageCacheFlag && type != STR_TIMEOUT && ( pageCache[ url ] = type );
  156. // Call error then complete
  157. callIfDefined( errorCallback , xOptions , [ xOptions , type ] );
  158. callIfDefined( completeCallback , xOptions , [ xOptions , type ] );
  159. }
  160. }
  161. // Check page cache
  162. if ( pageCacheFlag && ( pageCached = pageCache[ url ] ) ) {
  163. pageCached.s ? notifySuccess( pageCached.s[ 0 ] ) : notifyError( pageCached );
  164. } else {
  165. // Install the generic callback
  166. // (BEWARE: global namespace pollution ahoy)
  167. win[ successCallbackName ] = genericCallback;
  168. // Create the script tag
  169. script = $( STR_SCRIPT_TAG )[ 0 ];
  170. script.id = STR_JQUERY_JSONP + count++;
  171. // Set charset if provided
  172. if ( charset ) {
  173. script[ STR_CHARSET ] = charset;
  174. }
  175. opera && opera.version() < 11.60 ?
  176. // onerror is not supported: do not set as async and assume in-order execution.
  177. // Add a trailing script to emulate the event
  178. ( ( scriptAfter = $( STR_SCRIPT_TAG )[ 0 ] ).text = "document.getElementById('" + script.id + "')." + STR_ON_ERROR + "()" )
  179. :
  180. // onerror is supported: set the script as async to avoid requests blocking each others
  181. ( script[ STR_ASYNC ] = STR_ASYNC )
  182. ;
  183. // Internet Explorer: event/htmlFor trick
  184. if ( oldIE ) {
  185. script.htmlFor = script.id;
  186. script.event = STR_ON_CLICK;
  187. }
  188. // Attached event handlers
  189. script[ STR_ON_LOAD ] = script[ STR_ON_ERROR ] = script[ STR_ON_READY_STATE_CHANGE ] = function ( result ) {
  190. // Test readyState if it exists
  191. if ( !script[ STR_READY_STATE ] || !/i/.test( script[ STR_READY_STATE ] ) ) {
  192. try {
  193. script[ STR_ON_CLICK ] && script[ STR_ON_CLICK ]();
  194. } catch( _ ) {}
  195. result = lastValue;
  196. lastValue = 0;
  197. result ? notifySuccess( result[ 0 ] ) : notifyError( STR_ERROR );
  198. }
  199. };
  200. // Set source
  201. script.src = url;
  202. // Re-declare cleanUp function
  203. cleanUp = function( i ) {
  204. timeoutTimer && clearTimeout( timeoutTimer );
  205. script[ STR_ON_READY_STATE_CHANGE ] = script[ STR_ON_LOAD ] = script[ STR_ON_ERROR ] = null;
  206. head[ STR_REMOVE_CHILD ]( script );
  207. scriptAfter && head[ STR_REMOVE_CHILD ]( scriptAfter );
  208. };
  209. // Append main script
  210. head[ STR_INSERT_BEFORE ]( script , ( firstChild = head.firstChild ) );
  211. // Append trailing script if needed
  212. scriptAfter && head[ STR_INSERT_BEFORE ]( scriptAfter , firstChild );
  213. // If a timeout is needed, install it
  214. timeoutTimer = timeout > 0 && setTimeout( function() {
  215. notifyError( STR_TIMEOUT );
  216. } , timeout );
  217. }
  218. return xOptions;
  219. }
  220. // ###################### SETUP FUNCTION ##
  221. jsonp.setup = function( xOptions ) {
  222. $.extend( xOptionsDefaults , xOptions );
  223. };
  224. // ###################### INSTALL in jQuery ##
  225. $.jsonp = jsonp;
  226. } )( jQuery );