JSL - AJAX plugin

An AJAX plugin for JSL

Questo script non dovrebbe essere installato direttamente. È una libreria per altri script da includere con la chiave // @require https://update.greatest.deepsurf.us/scripts/2817/7911/JSL%20-%20AJAX%20plugin.js

  1. // ==UserScript==
  2. // @name JSL - AJAX plugin
  3. // @namespace http://userscripts.org/users/23652
  4. // @description An AJAX plugin for JSL
  5. // @include *
  6. // @version 1.1.0
  7. // @grant GM_xmlhttpRequest
  8. // ==/UserScript==
  9.  
  10. /* CHANGELOG
  11.  
  12. 1.1.0 (3/28/2014)
  13. - added JSL.ajaxClear() to clear all current and pending requests
  14.  
  15. 1.0.21 (10/6/2013)
  16. - fixed bug with .clear()
  17.  
  18. 1.0.2 (10/6/2013)
  19. - added a new option: async
  20. false (default) ==> synchronous, but non-freezing requests (sequential)
  21. waits for previous request to finish before starting a new one
  22. true ==> sends all requests immediately when they are added to the queue
  23. - fixed delay issue.
  24. the next request would get run on the 'onprogress' & 'onreadystatechange' events
  25. instead of when they actually load fully
  26. - added a .clear() method
  27. it may be called on any ajax instance like JSL.ajax(...).clear()
  28. it can even simply be called as JSL.ajax().clear()
  29. it will clear ALL requests at the moment
  30.  
  31. 1.0.1 (10/3/2013)
  32. - fixed small bug with passing a url array
  33. - fixed bug not allowing HEAD requests to be recognized
  34.  
  35. 1.0.0 (10/1/2013)
  36. - created
  37.  
  38. */
  39.  
  40. (function (undefined) {
  41.  
  42. 'use strict'; // use strict mode in ECMAScript-5
  43.  
  44. var queue = [], // the request queue
  45. blank = function () {}, // blank function to use as default callback
  46. xhrInProgress = false, // boolean to know if we should load the next request
  47. xhrCleared = false; // boolean to know if the xhr has been cleared and if
  48. // we should execute any of the callbacks
  49.  
  50. var core = {
  51. // object
  52. 'hasOwnProperty' : Object.prototype.hasOwnProperty
  53. };
  54.  
  55. function copyObject(o) {
  56. var key, value, newO = {};
  57.  
  58. for (key in o) {
  59. value = o[key];
  60.  
  61. if (core.hasOwnProperty.call(o, key) && value != null) {
  62. newO[key] = value;
  63. }
  64. }
  65.  
  66. return newO;
  67. }
  68.  
  69. function toDataString(o) {
  70. var key, value, dataString = '';
  71.  
  72. for (key in o) {
  73. value = o[key];
  74.  
  75. if (core.hasOwnProperty.call(o, key) && value != null) {
  76. dataString += key + '=' + encodeURIComponent(value) + '&';
  77. }
  78. }
  79.  
  80. return dataString.slice(0, -1);
  81. }
  82.  
  83. function xhr() {
  84. var req = queue[0], // get the object which is first in the queue
  85. xhrObj = {}, key;
  86.  
  87. function handleEvents(type, resp, event) {
  88. var event = event || {}, newResp, context;
  89. req.delay = req.delay > 15 ? req.delay : 15; // don't want to mess up callbacks
  90.  
  91. if (xhrCleared === true) {
  92. return;
  93. }
  94.  
  95. if (req[type] !== blank) {
  96. // define a new response object to give to the user
  97. newResp = {
  98. lengthComputable : resp.lengthComputable || event.lengthComputable || null,
  99. loaded : resp.loaded || event.loaded || null,
  100. readyState : resp.readyState,
  101. responseHeaders : resp.responseHeaders ||
  102. ( typeof resp.getAllResponseHeaders === 'function' ? resp.getAllResponseHeaders() : null) || '',
  103. responseText : resp.responseText,
  104. status : resp.status,
  105. statusText : resp.statusText,
  106. total : resp.total || event.total || null,
  107. url : resp.finalUrl || req.url,
  108. };
  109.  
  110. // allow new requests to be run if our request is done
  111. if (type === 'onerror' || type === 'onload') {
  112. xhrInProgress = false;
  113.  
  114. // run the next in queue, if any
  115. window.setTimeout(xhr, req.delay);
  116. }
  117.  
  118. // run the callback
  119. context = req.context || newResp;
  120. req[type].call(context, newResp);
  121. }
  122. }
  123.  
  124. if ( req && (xhrInProgress === false || req.async === true) && queue.length > 0) {
  125. // make it so no other requests get run while we
  126. // run this one, if async isn't enabled
  127. xhrInProgress = true;
  128.  
  129. // remove the first item in the queue if it is going to be run
  130. queue.shift();
  131.  
  132. if (typeof GM_xmlhttpRequest === 'function') {
  133. if (req.method.toUpperCase() === 'GET' && req.data !== '') {
  134. req.url += '?' + req.data;
  135. req.data = '';
  136. }
  137.  
  138. GM_xmlhttpRequest({
  139. 'data' : req.data,
  140. 'headers' : req.headers,
  141. 'method' : req.method,
  142. 'onerror' : function (resp) {
  143. handleEvents('onerror', resp);
  144. },
  145. 'onload' : function (resp) {
  146. handleEvents('onload', resp);
  147. },
  148. 'onreadystatechange' : function (resp) {
  149. handleEvents('onreadystatechange', resp);
  150. },
  151. 'onprogress' : function (resp) {
  152. handleEvents('onprogress', resp);
  153. },
  154. 'url' : req.url,
  155. });
  156. } else if (typeof XMLHttpRequest === 'function' || typeof ActiveXObject === 'function') {
  157. xhrObj = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
  158.  
  159. // set events
  160. xhrObj.onload = function (resp) {
  161. handleEvents('onload', xhrObj);
  162. };
  163. xhrObj.onerror = function (resp) {
  164. handleEvents('onerror', xhrObj);
  165. };
  166. xhrObj.onprogress = function (resp) {
  167. handleEvents('onprogress', xhrObj, resp);
  168. };
  169.  
  170. if (req.mimeType !== '') {
  171. xhrObj.overrideMimeType(req.mimeType);
  172. }
  173.  
  174. // add headers
  175. for (key in req.headers) {
  176. xhrObj.setRequestHeader( key, req.headers[key] );
  177. }
  178.  
  179. xhrObj.open(req.method, req.url, true);
  180. xhrObj.send( (req.data || null) );
  181. }
  182. }
  183. }
  184.  
  185. function init(url, settings) {
  186. var urls = [],
  187. realSettings = { // defaults
  188. async : false,
  189. data : '',
  190. headers : {},
  191. method : 'GET',
  192. mimeType : '',
  193. onload : blank,
  194. onerror : blank,
  195. onprogress : blank,
  196. onreadystatechange : blank,
  197. delay : 0
  198. },
  199. key, value;
  200.  
  201. if (typeof url === 'string') {
  202. urls.push(url);
  203. } else if (JSL.typeOf(url) === 'array') {
  204. urls = urls.concat(url);
  205. }
  206.  
  207. if (JSL.typeOf(settings) === 'object') {
  208. for (key in settings) {
  209. value = settings[key];
  210.  
  211. switch (key) {
  212. case 'async': {
  213. if (typeof value === 'boolean') {
  214. realSettings[key] = value;
  215. }
  216. break;
  217. }
  218. case 'context': {
  219. if (value != null) {
  220. realSettings[key] = value;
  221. }
  222. break;
  223. }
  224. case 'data': {
  225. if (typeof value === 'string') {
  226. realSettings[key] = value;
  227. } else if (JSL.typeOf(value) === 'object') {
  228. realSettings[key] = toDataString(value);
  229. }
  230. break;
  231. }
  232. case 'delay': {
  233. if (typeof value === 'number' && value > 0) {
  234. realSettings[key] = value;
  235. }
  236. break;
  237. }
  238. case 'headers': {
  239. if (JSL.typeOf(value) === 'object') {
  240. realSettings[key] = toDataString(value);
  241. }
  242. break;
  243. }
  244. case 'method': {
  245. if ( typeof value === 'string' && /get|post|head/i.test(value) ) {
  246. realSettings[key] = value.toUpperCase();
  247. }
  248. break;
  249. }
  250. case 'mimeType': {
  251. if (typeof value === 'string') {
  252. realSettings[key] = value;
  253. }
  254. break;
  255. }
  256. case 'onload': case 'onerror': case 'onreadystatechange': case 'onprogress': {
  257. if (typeof value === 'function') {
  258. realSettings[key] = value;
  259. }
  260. break;
  261. }
  262. }
  263. }
  264. }
  265.  
  266. // add an object to the queue for each url
  267. if (urls.length > 0) {
  268. JSL.each(urls, function (url) {
  269. var newO = copyObject(realSettings);
  270. newO.url = url;
  271. queue.push(newO);
  272. });
  273.  
  274. // enable ajax if it was cleared earlier
  275. xhrCleared = false;
  276.  
  277. // run the xhr function
  278. // it will determine whether or not a request needs to be sent
  279. xhr();
  280. }
  281. }
  282.  
  283. init.prototype = {
  284. constructor: init,
  285.  
  286. clear : function() {
  287. queue.length = 0;
  288. xhrInProgress = false;
  289. xhrCleared = true;
  290. },
  291.  
  292. get length() {
  293. return queue.length;
  294. }
  295. };
  296.  
  297. JSL.extend({
  298. ajax : function (url, settings) {
  299. return new init(url, settings);
  300. },
  301. ajaxClear : init.prototype.clear
  302. });
  303.  
  304. }());