mirror of
https://github.com/kiwix/kiwix-js.git
synced 2025-09-22 12:01:15 -04:00
Merge branch 'master' into jquery-fallback
Conflicts: service-worker.js
This commit is contained in:
commit
727c11928a
@ -25,6 +25,32 @@
|
|||||||
// TODO : remove requirejs if it's really useless here
|
// TODO : remove requirejs if it's really useless here
|
||||||
importScripts('./www/js/lib/require.js');
|
importScripts('./www/js/lib/require.js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From https://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
|
||||||
|
*/
|
||||||
|
function b64toBlob(b64Data, contentType, sliceSize) {
|
||||||
|
contentType = contentType || '';
|
||||||
|
sliceSize = sliceSize || 512;
|
||||||
|
|
||||||
|
var byteCharacters = atob(b64Data);
|
||||||
|
var byteArrays = [];
|
||||||
|
|
||||||
|
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
||||||
|
var slice = byteCharacters.slice(offset, offset + sliceSize);
|
||||||
|
|
||||||
|
var byteNumbers = new Array(slice.length);
|
||||||
|
for (var i = 0; i < slice.length; i++) {
|
||||||
|
byteNumbers[i] = slice.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
var byteArray = new Uint8Array(byteNumbers);
|
||||||
|
|
||||||
|
byteArrays.push(byteArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
var blob = new Blob(byteArrays, {type: contentType});
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
self.addEventListener('install', function(event) {
|
self.addEventListener('install', function(event) {
|
||||||
event.waitUntil(self.skipWaiting());
|
event.waitUntil(self.skipWaiting());
|
||||||
@ -55,15 +81,6 @@ function(util, utf8) {
|
|||||||
console.log('Init message received', event.data);
|
console.log('Init message received', event.data);
|
||||||
outgoingMessagePort = event.ports[0];
|
outgoingMessagePort = event.ports[0];
|
||||||
console.log('outgoingMessagePort initialized', outgoingMessagePort);
|
console.log('outgoingMessagePort initialized', outgoingMessagePort);
|
||||||
self.addEventListener('fetch', fetchEventListener);
|
|
||||||
console.log('fetchEventListener enabled');
|
|
||||||
}
|
|
||||||
if (event.data.action === 'disable') {
|
|
||||||
console.log('Disable message received');
|
|
||||||
outgoingMessagePort = null;
|
|
||||||
console.log('outgoingMessagePort deleted');
|
|
||||||
self.removeEventListener('fetch', fetchEventListener);
|
|
||||||
console.log('fetchEventListener removed');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,13 +93,13 @@ function(util, utf8) {
|
|||||||
|
|
||||||
var regexpContentUrl = new RegExp(/\/(.)\/(.*[^\/]+)$/);
|
var regexpContentUrl = new RegExp(/\/(.)\/(.*[^\/]+)$/);
|
||||||
var regexpDummyArticle = new RegExp(/dummyArticle\.html$/);
|
var regexpDummyArticle = new RegExp(/dummyArticle\.html$/);
|
||||||
|
|
||||||
function fetchEventListener(event) {
|
|
||||||
console.log('ServiceWorker handling fetch event for : ' + event.request.url);
|
|
||||||
|
|
||||||
|
self.addEventListener('fetch', function(event) {
|
||||||
|
console.log('ServiceWorker handling fetch event for : ' + event.request.url);
|
||||||
|
|
||||||
// TODO handle the dummy article more properly
|
// TODO handle the dummy article more properly
|
||||||
if (regexpContentUrl.test(event.request.url) && !regexpDummyArticle.test(event.request.url)) {
|
if (regexpContentUrl.test(event.request.url) && !regexpDummyArticle.test(event.request.url)) {
|
||||||
|
|
||||||
console.log('Asking app.js for a content', event.request.url);
|
console.log('Asking app.js for a content', event.request.url);
|
||||||
event.respondWith(new Promise(function(resolve, reject) {
|
event.respondWith(new Promise(function(resolve, reject) {
|
||||||
var regexpResult = regexpContentUrl.exec(event.request.url);
|
var regexpResult = regexpContentUrl.exec(event.request.url);
|
||||||
@ -113,19 +130,6 @@ function(util, utf8) {
|
|||||||
else if (regexpCSS.test(titleName)) {
|
else if (regexpCSS.test(titleName)) {
|
||||||
contentType = 'image/css';
|
contentType = 'image/css';
|
||||||
}
|
}
|
||||||
var responseInit = {
|
|
||||||
status: 200,
|
|
||||||
statusText: 'OK',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': contentType
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var httpResponse = new Response(';', responseInit);
|
|
||||||
|
|
||||||
// TODO : temporary before the backend actually sends a proper content
|
|
||||||
resolve(httpResponse);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's instanciate a new messageChannel, to allow app.s to give us the content
|
// Let's instanciate a new messageChannel, to allow app.s to give us the content
|
||||||
@ -158,5 +162,6 @@ function(util, utf8) {
|
|||||||
}
|
}
|
||||||
// If event.respondWith() isn't called because this wasn't a request that we want to handle,
|
// If event.respondWith() isn't called because this wasn't a request that we want to handle,
|
||||||
// then the default request/response behavior will automatically be used.
|
// then the default request/response behavior will automatically be used.
|
||||||
}
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -532,5 +532,19 @@ define(['jquery', 'title', 'archive', 'zimArchive', 'zimDirEntry', 'util', 'geom
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
asyncTest("Image 's/style.css' can be loaded", function() {
|
||||||
|
expect(4);
|
||||||
|
localZimArchive.getTitleByName("-/s/style.css").then(function(title) {
|
||||||
|
ok(title !== null, "Title found");
|
||||||
|
equal(title.url, "-/s/style.css", "URL is correct.");
|
||||||
|
localZimArchive.readBinaryFile(title, function(title, data) {
|
||||||
|
equal(data.length, 104495, "Data length is correct.");
|
||||||
|
data = utf8.parse(data);
|
||||||
|
var beginning = "\n/* start http://en.wikipedia.org/w/load.php?debug=false&lang=en&modules=site&only=styles&skin=vector";
|
||||||
|
equal(data.slice(0, beginning.length), beginning, "Content starts correctly.");
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -864,11 +864,11 @@ define(['jquery', 'abstractBackend', 'util', 'cookies','geometry','osabstraction
|
|||||||
console.log("Reading binary file...");
|
console.log("Reading binary file...");
|
||||||
selectedArchive.readBinaryFile(title, function(readableTitleName, content) {
|
selectedArchive.readBinaryFile(title, function(readableTitleName, content) {
|
||||||
messagePort.postMessage({'action': 'giveContent', 'titleName' : titleName, 'content': content});
|
messagePort.postMessage({'action': 'giveContent', 'titleName' : titleName, 'content': content});
|
||||||
console.log("content sent to ServiceWorker)");
|
console.log("content sent to ServiceWorker");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("Fetching tile " + titleName);
|
console.log("Fetching title " + titleName);
|
||||||
selectedArchive.getTitleByName(titleName).then(readFile).fail(function() {
|
selectedArchive.getTitleByName(titleName).then(readFile).fail(function() {
|
||||||
console.log("could not find title:" + arguments);
|
console.log("could not find title:" + arguments);
|
||||||
messagePort.postMessage({'action': 'giveContent', 'titleName' : titleName, 'content': new UInt8Array()});
|
messagePort.postMessage({'action': 'giveContent', 'titleName' : titleName, 'content': new UInt8Array()});
|
||||||
|
@ -338,6 +338,7 @@ define(['normalize_string', 'geometry', 'title', 'util', 'titleIterators', 'q'],
|
|||||||
* Look for a title by its name, and call the callbackFunction with this Title
|
* Look for a title by its name, and call the callbackFunction with this Title
|
||||||
* If the title is not found, the callbackFunction is called with parameter null
|
* If the title is not found, the callbackFunction is called with parameter null
|
||||||
* @param {String} titleName
|
* @param {String} titleName
|
||||||
|
* @return {Promise} resolving to the title object or null if not found.
|
||||||
*/
|
*/
|
||||||
LocalArchive.prototype.getTitleByName = function(titleName) {
|
LocalArchive.prototype.getTitleByName = function(titleName) {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
@ -43,10 +43,6 @@ define(['q'], function(q) {
|
|||||||
function Decompressor(reader, chunkSize) {
|
function Decompressor(reader, chunkSize) {
|
||||||
this._chunkSize = chunkSize || 1024 * 5;
|
this._chunkSize = chunkSize || 1024 * 5;
|
||||||
this._reader = reader;
|
this._reader = reader;
|
||||||
this._decHandle = xzdec._init_decompression(this._chunkSize);
|
|
||||||
this._inStreamPos = 0;
|
|
||||||
this._outStreamPos = 0;
|
|
||||||
this._outBuffer = null;
|
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Read length bytes, offset into the decompressed stream. Consecutive calls may only
|
* Read length bytes, offset into the decompressed stream. Consecutive calls may only
|
||||||
@ -55,15 +51,16 @@ define(['q'], function(q) {
|
|||||||
* @param {Integer} length
|
* @param {Integer} length
|
||||||
*/
|
*/
|
||||||
Decompressor.prototype.readSlice = function(offset, length) {
|
Decompressor.prototype.readSlice = function(offset, length) {
|
||||||
|
var that = this;
|
||||||
|
this._inStreamPos = 0;
|
||||||
|
this._outStreamPos = 0;
|
||||||
|
this._decHandle = xzdec._init_decompression(this._chunkSize);
|
||||||
this._outBuffer = new Int8Array(new ArrayBuffer(length));
|
this._outBuffer = new Int8Array(new ArrayBuffer(length));
|
||||||
this._outBufferPos = 0;
|
this._outBufferPos = 0;
|
||||||
return this._readLoop(offset, length);
|
return this._readLoop(offset, length).then(function(data) {
|
||||||
};
|
xzdec._release(that._decHandle);
|
||||||
/**
|
return data;
|
||||||
* Finish the decompressing and release resources.
|
});
|
||||||
*/
|
|
||||||
Decompressor.prototype.end = function() {
|
|
||||||
xzdec._release(this._decHandle);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,23 +85,19 @@ define(['q'], function(q) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var outPos = xzdec._get_out_pos(that._decHandle);
|
var outPos = xzdec._get_out_pos(that._decHandle);
|
||||||
if (finished || outPos === that._chunkSize || that._outStreamPos + outPos >= offset + length) {
|
if (outPos > 0 && that._outStreamPos + outPos >= offset)
|
||||||
if (that._outStreamPos + outPos >= offset)
|
{
|
||||||
{
|
var outBuffer = xzdec._get_out_buffer(that._decHandle);
|
||||||
var outBuffer = xzdec._get_out_buffer(that._decHandle);
|
var copyStart = offset - that._outStreamPos;
|
||||||
var copyStart = offset - that._outStreamPos;
|
if (copyStart < 0)
|
||||||
if (copyStart < 0)
|
copyStart = 0;
|
||||||
copyStart = 0;
|
for (var i = copyStart; i < outPos && that._outBufferPos < that._outBuffer.length; i++)
|
||||||
for (var i = copyStart; i < outPos && that._outBufferPos < that._outBuffer.length; i++)
|
that._outBuffer[that._outBufferPos++] = xzdec.HEAP8[outBuffer + i];
|
||||||
that._outBuffer[that._outBufferPos++] = xzdec.HEAP8[outBuffer + i];
|
|
||||||
}
|
|
||||||
if (outPos === that._chunkSize)
|
|
||||||
{
|
|
||||||
that._outStreamPos += outPos;
|
|
||||||
xzdec._out_buffer_cleared(that._decHandle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (finished || that._outStreamPos + outPos >= offset + length)
|
that._outStreamPos += outPos;
|
||||||
|
if (outPos > 0)
|
||||||
|
xzdec._out_buffer_cleared(that._decHandle);
|
||||||
|
if (finished || that._outStreamPos >= offset + length)
|
||||||
return that._outBuffer;
|
return that._outBuffer;
|
||||||
else
|
else
|
||||||
return that._readLoop(offset, length);
|
return that._readLoop(offset, length);
|
||||||
|
@ -198,8 +198,9 @@ define(['zimfile', 'zimDirEntry', 'util', 'utf8'],
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Searches a title (article / page) by name.
|
||||||
* @param {String} titleName
|
* @param {String} titleName
|
||||||
|
* @return {Promise} resolving to the title object or null if not found.
|
||||||
*/
|
*/
|
||||||
ZIMArchive.prototype.getTitleByName = function(titleName) {
|
ZIMArchive.prototype.getTitleByName = function(titleName) {
|
||||||
var that = this;
|
var that = this;
|
||||||
|
@ -154,7 +154,6 @@ define(['xzdec_wrapper', 'util', 'utf8'], function(xz, util, utf8) {
|
|||||||
ZIMFile.prototype.blob = function(cluster, blob)
|
ZIMFile.prototype.blob = function(cluster, blob)
|
||||||
{
|
{
|
||||||
var that = this;
|
var that = this;
|
||||||
//@todo decompress in a streaming way, otherwise we have to "guess" the sizes
|
|
||||||
return this._readSlice(this.clusterPtrPos + cluster * 8, 16).then(function(clusterOffsets)
|
return this._readSlice(this.clusterPtrPos + cluster * 8, 16).then(function(clusterOffsets)
|
||||||
{
|
{
|
||||||
var clusterOffset = readInt(clusterOffsets, 0, 8);
|
var clusterOffset = readInt(clusterOffsets, 0, 8);
|
||||||
@ -166,7 +165,7 @@ define(['xzdec_wrapper', 'util', 'utf8'], function(xz, util, utf8) {
|
|||||||
};
|
};
|
||||||
if (compressionType[0] === 0 || compressionType[0] === 1) {
|
if (compressionType[0] === 0 || compressionType[0] === 1) {
|
||||||
// uncompressed
|
// uncompressed
|
||||||
decompressor = { readSlice: plainBlobReader, end: function() {} };
|
decompressor = { readSlice: plainBlobReader };
|
||||||
} else if (compressionType[0] === 4) {
|
} else if (compressionType[0] === 4) {
|
||||||
decompressor = new xz.Decompressor(plainBlobReader);
|
decompressor = new xz.Decompressor(plainBlobReader);
|
||||||
} else {
|
} else {
|
||||||
@ -175,10 +174,7 @@ define(['xzdec_wrapper', 'util', 'utf8'], function(xz, util, utf8) {
|
|||||||
return decompressor.readSlice(blob * 4, 8).then(function(data) {
|
return decompressor.readSlice(blob * 4, 8).then(function(data) {
|
||||||
var blobOffset = readInt(data, 0, 4);
|
var blobOffset = readInt(data, 0, 4);
|
||||||
var nextBlobOffset = readInt(data, 4, 4);
|
var nextBlobOffset = readInt(data, 4, 4);
|
||||||
return decompressor.readSlice(blobOffset, nextBlobOffset - blobOffset).then(function(data) {
|
return decompressor.readSlice(blobOffset, nextBlobOffset - blobOffset);
|
||||||
decompressor.end();
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user