commit a9dda10a7dbd2f8a1834d56606fed750edf2013a
parent 57626101acadbc99169ce90b968a76ca19bdd3e7
Author: Dan Stillman <dstillman@zotero.org>
Date: Fri, 24 Feb 2017 18:39:23 -0500
Add Zotero.Sync.APIClient.getPaginatedResults()
Function that automatically follows Link headers and makes additional
requests as necessary, feeding the XMLHTTPRequest object from each
request to a reducer function.
Diffstat:
1 file changed, 71 insertions(+), 0 deletions(-)
diff --git a/chrome/content/zotero/xpcom/sync/syncAPIClient.js b/chrome/content/zotero/xpcom/sync/syncAPIClient.js
@@ -661,6 +661,77 @@ Zotero.Sync.APIClient.prototype = {
}),
+ /**
+ * Retrieve paginated requests automatically based on the Link header, passing the results to a
+ * reducer
+ *
+ * @param {String} initialURL
+ * @param {Function} reducer - Reducer function taking (previousValue, xmlhttp, restart)
+ * accumulator: Return value from previous invocation, or initialValue
+ * xmlhttp: XMLHTTPRequest object from previous request
+ * restart: A function to restart from the beginning
+ * @param {mixed} initialValue
+ * @return {mixed} - The reduced value
+ */
+ getPaginatedResults: Zotero.Promise.coroutine(function* (initialURL, reducer, initialValue) {
+ let url = initialURL;
+ let accumulator;
+ let restart = false;
+ while (true) {
+ let xmlhttp = yield this.makeRequest("GET", url);
+ accumulator = reducer(
+ accumulator === undefined ? initialValue : accumulator,
+ xmlhttp,
+ function () {
+ restart = true;
+ }
+ );
+ if (restart) {
+ accumulator = undefined;
+ url = initialURL;
+ restart = false;
+ continue;
+ }
+ let link = this._parseLinkHeader(xmlhttp.getResponseHeader('Link'));
+ if (link && link.next) {
+ url = link.next;
+ }
+ else {
+ break;
+ }
+ }
+ return accumulator;
+ }),
+
+
+ /**
+ * Parse a Link header
+ *
+ * From https://gist.github.com/deiu/9335803
+ * MIT-licensed
+ */
+ _parseLinkHeader: function (link) {
+ var linkexp = /<[^>]*>\s*(\s*;\s*[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|$)/g;
+ var paramexp = /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g;
+ var matches = link.match(linkexp);
+ var rels = {};
+ for (var i = 0; i < matches.length; i++) {
+ var split = matches[i].split('>');
+ var href = split[0].substring(1);
+ var ps = split[1];
+ var s = ps.match(paramexp);
+ for (var j = 0; j < s.length; j++) {
+ var p = s[j];
+ var paramsplit = p.split('=');
+ var name = paramsplit[0];
+ var rel = paramsplit[1].replace(/["']/g, '');
+ rels[rel] = href;
+ }
+ }
+ return rels;
+ },
+
+
_parseJSON: function (json) {
try {
json = JSON.parse(json);