jquery.jsonp.js 7.5 KB

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