mirror of
https://github.com/kiwix/kiwix-js.git
synced 2025-09-24 04:54:51 -04:00
parent
cd7b4bcbbc
commit
c2e6b5e275
@ -26,8 +26,8 @@
|
||||
// This uses require.js to structure javascript:
|
||||
// http://requirejs.org/docs/api.html#define
|
||||
|
||||
define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFilesystemAccess','q'],
|
||||
function($, zimArchiveLoader, util, uiUtil, cookies, abstractFilesystemAccess, q) {
|
||||
define(['jquery', 'zimArchiveLoader', 'uiUtil', 'cookies','abstractFilesystemAccess','q'],
|
||||
function($, zimArchiveLoader, uiUtil, cookies, abstractFilesystemAccess, Q) {
|
||||
|
||||
/**
|
||||
* Maximum number of articles to display in a search
|
||||
@ -378,7 +378,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
* @returns {Promise<Object>} A Promise for an object with cache attributes 'type', 'description', and 'count'
|
||||
*/
|
||||
function getCacheAttributes() {
|
||||
return q.Promise(function (resolve, reject) {
|
||||
return Q.Promise(function (resolve, reject) {
|
||||
if (contentInjectionMode === 'serviceworker') {
|
||||
// Create a Message Channel
|
||||
var channel = new MessageChannel();
|
||||
@ -858,44 +858,45 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
* Reads a remote archive with given URL, and returns the response in a Promise.
|
||||
* This function is used by setRemoteArchives below, for UI tests
|
||||
*
|
||||
* @param url The URL of the archive to read
|
||||
* @returns {Promise}
|
||||
* @param {String} url The URL of the archive to read
|
||||
* @returns {Promise<Blob>} A promise for the requested file (blob)
|
||||
*/
|
||||
function readRemoteArchive(url) {
|
||||
var deferred = q.defer();
|
||||
// DEV: This deferred can't be standardized to a Promise/A+ pattern (using Q) because
|
||||
// IE11 is unable to scope the callbacks inside the Promise correctly. See [kiwix.js #589]
|
||||
var deferred = Q.defer();
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", url, true);
|
||||
request.open("GET", url);
|
||||
request.responseType = "blob";
|
||||
request.onreadystatechange = function () {
|
||||
if (request.readyState === XMLHttpRequest.DONE) {
|
||||
if ((request.status >= 200 && request.status < 300) || request.status === 0) {
|
||||
if (request.status >= 200 && request.status < 300 || request.status === 0) {
|
||||
// Hack to make this look similar to a file
|
||||
request.response.name = url;
|
||||
deferred.resolve(request.response);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
deferred.reject("HTTP status " + request.status + " when reading " + url);
|
||||
}
|
||||
}
|
||||
};
|
||||
request.onabort = function (e) {
|
||||
deferred.reject(e);
|
||||
};
|
||||
request.send(null);
|
||||
request.onabort = request.onerror = deferred.reject;
|
||||
request.send();
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is used in the testing interface to inject remote archives
|
||||
* @returns {Promise<Array>} A Promise for an array of archives
|
||||
*/
|
||||
window.setRemoteArchives = function() {
|
||||
window.setRemoteArchives = function () {
|
||||
var readRequests = [];
|
||||
var i;
|
||||
for (i = 0; i < arguments.length; i++) {
|
||||
readRequests[i] = readRemoteArchive(arguments[i]);
|
||||
}
|
||||
return q.all(readRequests).then(function(arrayOfArchives) {
|
||||
Array.prototype.slice.call(arguments).forEach(function (arg) {
|
||||
readRequests.push(readRemoteArchive(arg));
|
||||
});
|
||||
return Q.all(readRequests).then(function (arrayOfArchives) {
|
||||
setLocalArchiveFromFileList(arrayOfArchives);
|
||||
}).catch(function (e) {
|
||||
console.error('Unable to load remote archive(s)', e);
|
||||
});
|
||||
};
|
||||
|
||||
@ -1136,7 +1137,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
});
|
||||
}
|
||||
};
|
||||
selectedArchive.getDirEntryByTitle(title).then(readFile).fail(function () {
|
||||
selectedArchive.getDirEntryByTitle(title).then(readFile).catch(function () {
|
||||
messagePort.postMessage({ 'action': 'giveContent', 'title': title, 'content': new UInt8Array() });
|
||||
});
|
||||
} else {
|
||||
@ -1317,7 +1318,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
var mimetype = dirEntry.getMimetype();
|
||||
uiUtil.feedNodeWithBlob(image, 'src', content, mimetype);
|
||||
});
|
||||
}).fail(function (e) {
|
||||
}).catch(function (e) {
|
||||
console.error("could not find DirEntry for image:" + title, e);
|
||||
});
|
||||
});
|
||||
@ -1370,7 +1371,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
renderIfCSSFulfilled(fileDirEntry.url);
|
||||
}
|
||||
);
|
||||
}).fail(function (e) {
|
||||
}).catch(function (e) {
|
||||
console.error("could not find DirEntry for CSS : " + title, e);
|
||||
cssCount--;
|
||||
renderIfCSSFulfilled();
|
||||
@ -1410,7 +1411,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
uiUtil.feedNodeWithBlob(script, 'src', content, 'text/javascript');
|
||||
});
|
||||
}
|
||||
}).fail(function (e) {
|
||||
}).catch(function (e) {
|
||||
console.error("could not find DirEntry for javascript : " + title, e);
|
||||
});
|
||||
});
|
||||
@ -1510,7 +1511,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
$('#activeContent').hide();
|
||||
readArticle(dirEntry);
|
||||
}
|
||||
}).fail(function(e) { alert("Error reading article with title " + title + " : " + e); });
|
||||
}).catch(function(e) { alert("Error reading article with title " + title + " : " + e); });
|
||||
}
|
||||
|
||||
function goToRandomArticle() {
|
||||
|
198
www/js/lib/q.js
198
www/js/lib/q.js
@ -1,8 +1,8 @@
|
||||
// vim:ts=4:sts=4:sw=4:
|
||||
/*!
|
||||
*
|
||||
* Copyright 2009-2012 Kris Kowal under the terms of the MIT
|
||||
* license found at http://github.com/kriskowal/q/raw/master/LICENSE
|
||||
* Copyright 2009-2017 Kris Kowal under the terms of the MIT
|
||||
* license found at https://github.com/kriskowal/q/blob/v1/LICENSE
|
||||
*
|
||||
* With parts by Tyler Close
|
||||
* Copyright 2007-2009 Tyler Close under the terms of the MIT X license found
|
||||
@ -55,8 +55,22 @@
|
||||
}
|
||||
|
||||
// <script>
|
||||
} else if (typeof self !== "undefined") {
|
||||
self.Q = definition();
|
||||
} else if (typeof window !== "undefined" || typeof self !== "undefined") {
|
||||
// Prefer window over self for add-on scripts. Use self for
|
||||
// non-windowed contexts.
|
||||
var global = typeof window !== "undefined" ? window : self;
|
||||
|
||||
// Get the `window` object, save the previous Q global
|
||||
// and initialize Q as a global.
|
||||
var previousQ = global.Q;
|
||||
global.Q = definition();
|
||||
|
||||
// Add a noConflict function so Q can be removed from the
|
||||
// global namespace.
|
||||
global.Q.noConflict = function () {
|
||||
global.Q = previousQ;
|
||||
return this;
|
||||
};
|
||||
|
||||
} else {
|
||||
throw new Error("This environment was not anticipated by Q. Please file a bug.");
|
||||
@ -91,57 +105,67 @@ var nextTick =(function () {
|
||||
var flushing = false;
|
||||
var requestTick = void 0;
|
||||
var isNodeJS = false;
|
||||
// queue for late tasks, used by unhandled rejection tracking
|
||||
var laterQueue = [];
|
||||
|
||||
function flush() {
|
||||
/* jshint loopfunc: true */
|
||||
var task, domain;
|
||||
|
||||
while (head.next) {
|
||||
head = head.next;
|
||||
var task = head.task;
|
||||
task = head.task;
|
||||
head.task = void 0;
|
||||
var domain = head.domain;
|
||||
domain = head.domain;
|
||||
|
||||
if (domain) {
|
||||
head.domain = void 0;
|
||||
domain.enter();
|
||||
}
|
||||
runSingle(task, domain);
|
||||
|
||||
try {
|
||||
task();
|
||||
}
|
||||
while (laterQueue.length) {
|
||||
task = laterQueue.pop();
|
||||
runSingle(task);
|
||||
}
|
||||
flushing = false;
|
||||
}
|
||||
// runs a single function in the async queue
|
||||
function runSingle(task, domain) {
|
||||
try {
|
||||
task();
|
||||
|
||||
} catch (e) {
|
||||
if (isNodeJS) {
|
||||
// In node, uncaught exceptions are considered fatal errors.
|
||||
// Re-throw them synchronously to interrupt flushing!
|
||||
} catch (e) {
|
||||
if (isNodeJS) {
|
||||
// In node, uncaught exceptions are considered fatal errors.
|
||||
// Re-throw them synchronously to interrupt flushing!
|
||||
|
||||
// Ensure continuation if the uncaught exception is suppressed
|
||||
// listening "uncaughtException" events (as domains does).
|
||||
// Continue in next event to avoid tick recursion.
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
}
|
||||
setTimeout(flush, 0);
|
||||
if (domain) {
|
||||
domain.enter();
|
||||
}
|
||||
|
||||
throw e;
|
||||
|
||||
} else {
|
||||
// In browsers, uncaught exceptions are not fatal.
|
||||
// Re-throw them asynchronously to avoid slow-downs.
|
||||
setTimeout(function() {
|
||||
throw e;
|
||||
}, 0);
|
||||
// Ensure continuation if the uncaught exception is suppressed
|
||||
// listening "uncaughtException" events (as domains does).
|
||||
// Continue in next event to avoid tick recursion.
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
}
|
||||
setTimeout(flush, 0);
|
||||
if (domain) {
|
||||
domain.enter();
|
||||
}
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
throw e;
|
||||
|
||||
} else {
|
||||
// In browsers, uncaught exceptions are not fatal.
|
||||
// Re-throw them asynchronously to avoid slow-downs.
|
||||
setTimeout(function () {
|
||||
throw e;
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
flushing = false;
|
||||
if (domain) {
|
||||
domain.exit();
|
||||
}
|
||||
}
|
||||
|
||||
nextTick = function (task) {
|
||||
@ -157,9 +181,16 @@ var nextTick =(function () {
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof process !== "undefined" && process.nextTick) {
|
||||
// Node.js before 0.9. Note that some fake-Node environments, like the
|
||||
// Mocha test runner, introduce a `process` global without a `nextTick`.
|
||||
if (typeof process === "object" &&
|
||||
process.toString() === "[object process]" && process.nextTick) {
|
||||
// Ensure Q is in a real Node environment, with a `process.nextTick`.
|
||||
// To see through fake Node environments:
|
||||
// * Mocha test runner - exposes a `process` global without a `nextTick`
|
||||
// * Browserify - exposes a `process.nexTick` function that uses
|
||||
// `setTimeout`. In this case `setImmediate` is preferred because
|
||||
// it is faster. Browserify's `process.toString()` yields
|
||||
// "[object Object]", while in a real Node environment
|
||||
// `process.toString()` yields "[object process]".
|
||||
isNodeJS = true;
|
||||
|
||||
requestTick = function () {
|
||||
@ -203,7 +234,16 @@ var nextTick =(function () {
|
||||
setTimeout(flush, 0);
|
||||
};
|
||||
}
|
||||
|
||||
// runs a task after all other tasks have been run
|
||||
// this is useful for unhandled rejection tracking that needs to happen
|
||||
// after all `then`d tasks have been run.
|
||||
nextTick.runAfter = function (task) {
|
||||
laterQueue.push(task);
|
||||
if (!flushing) {
|
||||
flushing = true;
|
||||
requestTick();
|
||||
}
|
||||
};
|
||||
return nextTick;
|
||||
})();
|
||||
|
||||
@ -287,6 +327,11 @@ var object_create = Object.create || function (prototype) {
|
||||
return new Type();
|
||||
};
|
||||
|
||||
var object_defineProperty = Object.defineProperty || function (obj, prop, descriptor) {
|
||||
obj[prop] = descriptor.value;
|
||||
return obj;
|
||||
};
|
||||
|
||||
var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
|
||||
|
||||
var object_keys = Object.keys || function (object) {
|
||||
@ -337,19 +382,20 @@ function makeStackTraceLong(error, promise) {
|
||||
promise.stack &&
|
||||
typeof error === "object" &&
|
||||
error !== null &&
|
||||
error.stack &&
|
||||
error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
|
||||
error.stack
|
||||
) {
|
||||
var stacks = [];
|
||||
for (var p = promise; !!p; p = p.source) {
|
||||
if (p.stack) {
|
||||
if (p.stack && (!error.__minimumStackCounter__ || error.__minimumStackCounter__ > p.stackCounter)) {
|
||||
object_defineProperty(error, "__minimumStackCounter__", {value: p.stackCounter, configurable: true});
|
||||
stacks.unshift(p.stack);
|
||||
}
|
||||
}
|
||||
stacks.unshift(error.stack);
|
||||
|
||||
var concatedStacks = stacks.join("\n" + STACK_JUMP_SEPARATOR + "\n");
|
||||
error.stack = filterStackString(concatedStacks);
|
||||
var stack = filterStackString(concatedStacks);
|
||||
object_defineProperty(error, "stack", {value: stack, configurable: true});
|
||||
}
|
||||
}
|
||||
|
||||
@ -476,6 +522,14 @@ Q.nextTick = nextTick;
|
||||
*/
|
||||
Q.longStackSupport = false;
|
||||
|
||||
/**
|
||||
* The counter is used to determine the stopping point for building
|
||||
* long stack traces. In makeStackTraceLong we walk backwards through
|
||||
* the linked list of promises, only stacks which were created before
|
||||
* the rejection are concatenated.
|
||||
*/
|
||||
var longStackCounter = 1;
|
||||
|
||||
// enable long stacks if Q_DEBUG is set
|
||||
if (typeof process === "object" && process && process.env && process.env.Q_DEBUG) {
|
||||
Q.longStackSupport = true;
|
||||
@ -548,6 +602,7 @@ function defer() {
|
||||
// At the same time, cut off the first line; it's always just
|
||||
// "[object Promise]\n", as per the `toString`.
|
||||
promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1);
|
||||
promise.stackCounter = longStackCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -557,7 +612,12 @@ function defer() {
|
||||
|
||||
function become(newPromise) {
|
||||
resolvedPromise = newPromise;
|
||||
promise.source = newPromise;
|
||||
|
||||
if (Q.longStackSupport && hasStacks) {
|
||||
// Only hold a reference to the new promise if long stacks
|
||||
// are enabled to reduce memory usage
|
||||
promise.source = newPromise;
|
||||
}
|
||||
|
||||
array_reduce(messages, function (undefined, message) {
|
||||
Q.nextTick(function () {
|
||||
@ -685,7 +745,7 @@ Promise.prototype.join = function (that) {
|
||||
// TODO: "===" should be Object.is or equiv
|
||||
return x;
|
||||
} else {
|
||||
throw new Error("Can't join: not the same: " + x + " " + y);
|
||||
throw new Error("Q can't join: not the same: " + x + " " + y);
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -697,9 +757,9 @@ Promise.prototype.join = function (that) {
|
||||
*/
|
||||
Q.race = race;
|
||||
function race(answerPs) {
|
||||
return promise(function(resolve, reject) {
|
||||
return promise(function (resolve, reject) {
|
||||
// Switch to this once we can assume at least ES5
|
||||
// answerPs.forEach(function(answerP) {
|
||||
// answerPs.forEach(function (answerP) {
|
||||
// Q(answerP).then(resolve, reject);
|
||||
// });
|
||||
// Use this in the meantime
|
||||
@ -997,6 +1057,7 @@ Promise.prototype.isRejected = function () {
|
||||
// shimmed environments, this would naturally be a `Set`.
|
||||
var unhandledReasons = [];
|
||||
var unhandledRejections = [];
|
||||
var reportedUnhandledRejections = [];
|
||||
var trackUnhandledRejections = true;
|
||||
|
||||
function resetUnhandledRejections() {
|
||||
@ -1012,6 +1073,14 @@ function trackRejection(promise, reason) {
|
||||
if (!trackUnhandledRejections) {
|
||||
return;
|
||||
}
|
||||
if (typeof process === "object" && typeof process.emit === "function") {
|
||||
Q.nextTick.runAfter(function () {
|
||||
if (array_indexOf(unhandledRejections, promise) !== -1) {
|
||||
process.emit("unhandledRejection", reason, promise);
|
||||
reportedUnhandledRejections.push(promise);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unhandledRejections.push(promise);
|
||||
if (reason && typeof reason.stack !== "undefined") {
|
||||
@ -1028,6 +1097,15 @@ function untrackRejection(promise) {
|
||||
|
||||
var at = array_indexOf(unhandledRejections, promise);
|
||||
if (at !== -1) {
|
||||
if (typeof process === "object" && typeof process.emit === "function") {
|
||||
Q.nextTick.runAfter(function () {
|
||||
var atReport = array_indexOf(reportedUnhandledRejections, promise);
|
||||
if (atReport !== -1) {
|
||||
process.emit("rejectionHandled", unhandledReasons[at], promise);
|
||||
reportedUnhandledRejections.splice(atReport, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
unhandledRejections.splice(at, 1);
|
||||
unhandledReasons.splice(at, 1);
|
||||
}
|
||||
@ -1555,7 +1633,7 @@ function any(promises) {
|
||||
|
||||
var deferred = Q.defer();
|
||||
var pendingCount = 0;
|
||||
array_reduce(promises, function(prev, current, index) {
|
||||
array_reduce(promises, function (prev, current, index) {
|
||||
var promise = promises[index];
|
||||
|
||||
pendingCount++;
|
||||
@ -1564,13 +1642,15 @@ function any(promises) {
|
||||
function onFulfilled(result) {
|
||||
deferred.resolve(result);
|
||||
}
|
||||
function onRejected() {
|
||||
function onRejected(err) {
|
||||
pendingCount--;
|
||||
if (pendingCount === 0) {
|
||||
deferred.reject(new Error(
|
||||
"Can't get fulfillment value from any promise, all " +
|
||||
"promises were rejected."
|
||||
));
|
||||
var rejection = err || new Error("" + err);
|
||||
|
||||
rejection.message = ("Q can't get fulfillment value from any promise, all " +
|
||||
"promises were rejected. Last error message: " + rejection.message);
|
||||
|
||||
deferred.reject(rejection);
|
||||
}
|
||||
}
|
||||
function onProgress(progress) {
|
||||
@ -1584,7 +1664,7 @@ function any(promises) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
Promise.prototype.any = function() {
|
||||
Promise.prototype.any = function () {
|
||||
return any(this);
|
||||
};
|
||||
|
||||
@ -1694,6 +1774,9 @@ Q["finally"] = function (object, callback) {
|
||||
|
||||
Promise.prototype.fin = // XXX legacy
|
||||
Promise.prototype["finally"] = function (callback) {
|
||||
if (!callback || typeof callback.apply !== "function") {
|
||||
throw new Error("Q can't apply finally callback");
|
||||
}
|
||||
callback = Q(callback);
|
||||
return this.then(function (value) {
|
||||
return callback.fcall().then(function () {
|
||||
@ -1857,6 +1940,9 @@ Promise.prototype.nfcall = function (/*...args*/) {
|
||||
*/
|
||||
Q.nfbind =
|
||||
Q.denodeify = function (callback /*...args*/) {
|
||||
if (callback === undefined) {
|
||||
throw new Error("Q can't wrap an undefined function");
|
||||
}
|
||||
var baseArgs = array_slice(arguments, 1);
|
||||
return function () {
|
||||
var nodeArgs = baseArgs.concat(array_slice(arguments));
|
||||
@ -1978,6 +2064,10 @@ Promise.prototype.nodeify = function (nodeback) {
|
||||
}
|
||||
};
|
||||
|
||||
Q.noConflict = function() {
|
||||
throw new Error("Q.noConflict only works when Q is used as a global");
|
||||
};
|
||||
|
||||
// All code before this point will be filtered from stack traces.
|
||||
var qEndingLine = captureLine();
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
* along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
'use strict';
|
||||
define(['q'], function(q) {
|
||||
define(['q'], function(Q) {
|
||||
|
||||
/**
|
||||
* Utility function : return true if the given string ends with the suffix
|
||||
@ -180,23 +180,21 @@ define(['q'], function(q) {
|
||||
|
||||
/**
|
||||
* Reads a Uint8Array from the given file starting at byte offset begin and
|
||||
* for given size.
|
||||
* @param {File} file
|
||||
* @param {Integer} begin
|
||||
* @param {Integer} size
|
||||
* @returns {Promise} Promise
|
||||
* for given size
|
||||
* @param {File} file The file object to be read
|
||||
* @param {Integer} begin The offset in <File> at which to begin reading
|
||||
* @param {Integer} size The number of bytes to read
|
||||
* @returns {Promise<Uint8Array>} A Promise for an array buffer with the read data
|
||||
*/
|
||||
function readFileSlice(file, begin, size) {
|
||||
var deferred = q.defer();
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
deferred.resolve(new Uint8Array(e.target.result));
|
||||
};
|
||||
reader.onerror = reader.onabort = function(e) {
|
||||
deferred.reject(e);
|
||||
};
|
||||
reader.readAsArrayBuffer(file.slice(begin, begin + size));
|
||||
return deferred.promise;
|
||||
return Q.Promise(function (resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
resolve(new Uint8Array(e.target.result));
|
||||
};
|
||||
reader.onerror = reader.onabort = reject;
|
||||
reader.readAsArrayBuffer(file.slice(begin, begin + size));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,7 @@
|
||||
* along with Kiwix (file LICENSE-GPLv3.txt). If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
'use strict';
|
||||
define(['q'], function(q) {
|
||||
define(['q'], function(Q) {
|
||||
var xzdec = Module; //@todo including via requirejs seems to not work
|
||||
xzdec._init();
|
||||
|
||||
@ -78,29 +78,25 @@ define(['q'], function(q) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Read length bytes, offset into the decompressed stream.
|
||||
* This function ensures that only one decompression runs at a time.
|
||||
*
|
||||
* @param {Integer} offset
|
||||
* @param {Integer} length
|
||||
* Reads stream of data from file offset for length of bytes to send to the decompresor
|
||||
* This function ensures that only one decompression runs at a time
|
||||
* @param {Integer} offset The file offset at which to begin reading compressed data
|
||||
* @param {Integer} length The amount of data to read
|
||||
* @returns {Promise} A Promise for the read data
|
||||
*/
|
||||
Decompressor.prototype.readSliceSingleThread = function(offset, length) {
|
||||
Decompressor.prototype.readSliceSingleThread = function (offset, length) {
|
||||
if (!busy) {
|
||||
return this.readSlice(offset, length);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// The decompressor is already in progress.
|
||||
// To avoid using too much memory, we wait until it has finished
|
||||
// before using it for another decompression.
|
||||
// Inspired by https://codereview.stackexchange.com/questions/145563/angularjs-recursive-function-call-with-timeout
|
||||
// before using it for another decompression
|
||||
var that = this;
|
||||
var deferred = q.defer();
|
||||
|
||||
setTimeout(function(){
|
||||
that.readSliceSingleThread(offset, length).then(deferred.resolve, deferred.reject);
|
||||
}, DELAY_WAITING_IDLE_DECOMPRESSOR);
|
||||
|
||||
return deferred.promise;
|
||||
return Q.Promise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
that.readSliceSingleThread(offset, length).then(resolve, reject);
|
||||
}, DELAY_WAITING_IDLE_DECOMPRESSOR);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -150,8 +146,10 @@ define(['q'], function(q) {
|
||||
* @returns {Promise}
|
||||
*/
|
||||
Decompressor.prototype._fillInBufferIfNeeded = function() {
|
||||
if (!xzdec._input_empty(this._decHandle))
|
||||
return q.when(0);
|
||||
if (!xzdec._input_empty(this._decHandle)) {
|
||||
// DEV: When converting to Promise/A+, use Promise.resolve(0) here
|
||||
return Q.when(0);
|
||||
}
|
||||
var that = this;
|
||||
return this._reader(this._inStreamPos, this._chunkSize).then(function(data) {
|
||||
if (data.length > that._chunkSize)
|
||||
|
@ -299,7 +299,7 @@ define(['zimfile', 'zimDirEntry', 'util', 'utf8'],
|
||||
callback(data);
|
||||
});
|
||||
}
|
||||
}).fail(function (e) {
|
||||
}).catch(function (e) {
|
||||
console.warn("Metadata with key " + key + " not found in the archive", e);
|
||||
callback();
|
||||
});
|
||||
|
@ -214,7 +214,7 @@ define(['xzdec_wrapper', 'util', 'utf8', 'q', 'zimDirEntry'], function(xz, util,
|
||||
* and is stored as ZIMFile.mimeTypes
|
||||
*
|
||||
* @param {File} file The ZIM file (or first file in array of files) from which the MIME type list
|
||||
* is to be extracted
|
||||
* is to be extracted
|
||||
* @param {Integer} mimeListPos The offset in <file> at which the MIME type list is found
|
||||
* @param {Integer} urlPtrPos The offset of the byte after the end of the MIME type list in <file>
|
||||
* @returns {Promise} A promise for the MIME Type list as a Map
|
||||
@ -222,13 +222,13 @@ define(['xzdec_wrapper', 'util', 'utf8', 'q', 'zimDirEntry'], function(xz, util,
|
||||
function readMimetypeMap(file, mimeListPos, urlPtrPos) {
|
||||
var typeMap = new Map;
|
||||
var size = urlPtrPos - mimeListPos;
|
||||
return util.readFileSlice(file, mimeListPos, size).then(function(data) {
|
||||
return util.readFileSlice(file, mimeListPos, size).then(function (data) {
|
||||
if (data.subarray) {
|
||||
var i = 0;
|
||||
var pos = -1;
|
||||
var mimeString;
|
||||
while (pos < size) {
|
||||
pos++;
|
||||
pos++;
|
||||
mimeString = utf8.parse(data.subarray(pos), true);
|
||||
// If the parsed data is an empty string, we have reached the end of the MIME type list, so break
|
||||
if (!mimeString) break;
|
||||
@ -241,35 +241,30 @@ define(['xzdec_wrapper', 'util', 'utf8', 'q', 'zimDirEntry'], function(xz, util,
|
||||
}
|
||||
}
|
||||
return typeMap;
|
||||
}).fail(function(err) {
|
||||
}).catch(function (err) {
|
||||
console.error('Unable to read MIME type list', err);
|
||||
return new Map;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
/**
|
||||
*
|
||||
* @param {Array.<File>} fileArray
|
||||
* @returns {Promise}
|
||||
* @param {Array.<File>} fileArray An array of picked archive files
|
||||
* @returns {Promise<Object>} A Promise for the ZimFile Object
|
||||
*/
|
||||
fromFileArray: function(fileArray) {
|
||||
fromFileArray: function (fileArray) {
|
||||
// Array of blob objects should be sorted by their name property
|
||||
fileArray.sort(function(a, b) {
|
||||
var nameA = a.name.toUpperCase();
|
||||
var nameB = b.name.toUpperCase();
|
||||
if (nameA < nameB) {
|
||||
return -1;
|
||||
}
|
||||
if (nameA > nameB) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
fileArray.sort(function (a, b) {
|
||||
var nameA = a.name.toUpperCase();
|
||||
var nameB = b.name.toUpperCase();
|
||||
if (nameA < nameB) return -1;
|
||||
if (nameA > nameB) return 1;
|
||||
return 0;
|
||||
});
|
||||
return util.readFileSlice(fileArray[0], 0, 80).then(function(header) {
|
||||
return util.readFileSlice(fileArray[0], 0, 80).then(function (header) {
|
||||
var mimeListPos = readInt(header, 56, 8);
|
||||
var urlPtrPos = readInt(header, 32, 8);
|
||||
return readMimetypeMap(fileArray[0], mimeListPos, urlPtrPos).then(function(data) {
|
||||
return readMimetypeMap(fileArray[0], mimeListPos, urlPtrPos).then(function (data) {
|
||||
var zf = new ZIMFile(fileArray);
|
||||
zf.articleCount = readInt(header, 24, 4);
|
||||
zf.clusterCount = readInt(header, 28, 4);
|
||||
|
Loading…
x
Reference in New Issue
Block a user