diff --git a/www/js/app.js b/www/js/app.js
index bcbdf7de..84d6174c 100644
--- a/www/js/app.js
+++ b/www/js/app.js
@@ -529,6 +529,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
+ " storages found with getDeviceStorages instead of 1");
}
}
+ resetCssCache();
selectedArchive = zimArchiveLoader.loadArchiveFromDeviceStorage(selectedStorage, archiveDirectory, function (archive) {
cookies.setItem("lastSelectedArchive", archiveDirectory, Infinity);
// The archive is set : go back to home page to start searching
@@ -537,6 +538,16 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
}
}
+
+ /**
+ * Resets the CSS Cache (used only in jQuery mode)
+ */
+ function resetCssCache() {
+ // Reset the cssCache. Must be done when archive changes.
+ if (cssCache) {
+ cssCache = new Map();
+ }
+ }
/**
* Displays the zone to select files from the archive
@@ -547,6 +558,7 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
}
function setLocalArchiveFromFileList(files) {
+ resetCssCache();
selectedArchive = zimArchiveLoader.loadArchiveFromFiles(files, function (archive) {
// The archive is set : go back to home page to start searching
$("#btnHome").click();
@@ -792,6 +804,10 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
// Since late 2014, all ZIM files should use relative URLs
var regexpImageUrl = /^(?:\.\.\/|\/)+(I\/.*)$/;
var regexpMetadataUrl = /^(?:\.\.\/|\/)+(-\/.*)$/;
+
+ // Cache for CSS styles contained in ZIM.
+ // It significantly speeds up subsequent page display. See kiwix-js issue #335
+ var cssCache = new Map();
/**
* Display the the given HTML article in the web page,
@@ -895,34 +911,23 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
if (hrefMatch) {
// It's a CSS file contained in the ZIM file
var title = uiUtil.removeUrlParameters(decodeURIComponent(hrefMatch[1]));
- selectedArchive.getDirEntryByTitle(title).then(function(dirEntry) {
- selectedArchive.readBinaryFile(dirEntry, function (fileDirEntry, content) {
- var cssContent = util.uintToString(content);
- // For some reason, Firefox OS does not accept the syntax
- // So we replace the tag with a
- // while copying some attributes of the original tag
- // Cf http://jonraasch.com/blog/javascript-style-node
- var cssElement = document.createElement('style');
- cssElement.type = 'text/css';
-
- if (cssElement.styleSheet) {
- cssElement.styleSheet.cssText = cssContent;
- } else {
- cssElement.appendChild(document.createTextNode(cssContent));
- }
- var mediaAttributeValue = link.attr('media');
- if (mediaAttributeValue) {
- cssElement.media = mediaAttributeValue;
- }
- var disabledAttributeValue = link.attr('media');
- if (disabledAttributeValue) {
- cssElement.disabled = disabledAttributeValue;
- }
- link.replaceWith(cssElement);
+ if (cssCache && cssCache.has(title)) {
+ var cssContent = cssCache.get(title);
+ uiUtil.replaceCSSLinkWithInlineCSS(link, cssContent);
+ } else {
+ selectedArchive.getDirEntryByTitle(title)
+ .then(function (dirEntry) {
+ return selectedArchive.readBinaryFile(dirEntry,
+ function (fileDirEntry, content) {
+ var fullUrl = fileDirEntry.namespace + "/" + fileDirEntry.url;
+ var contentString = util.uintToString(content);
+ if (cssCache) cssCache.set(fullUrl, contentString);
+ uiUtil.replaceCSSLinkWithInlineCSS(link, contentString);
+ });
+ }).fail(function (e) {
+ console.error("could not find DirEntry for CSS : " + title, e);
});
- }).fail(function (e) {
- console.error("could not find DirEntry for CSS : " + title, e);
- });
+ }
}
});
diff --git a/www/js/lib/uiUtil.js b/www/js/lib/uiUtil.js
index 6a3e48a4..fc9a3593 100644
--- a/www/js/lib/uiUtil.js
+++ b/www/js/lib/uiUtil.js
@@ -42,6 +42,36 @@ define([], function() {
});
jQueryNode.attr(nodeAttribute, url);
}
+
+ /**
+ * Replace the given CSS link (from the DOM) with an inline CSS of the given content
+ *
+ * Due to CSP, Firefox OS does not accept syntax with href="data:text/css..." or href="blob:..."
+ * So we replace the tag with a
+ * while copying some attributes of the original tag
+ * Cf http://jonraasch.com/blog/javascript-style-node
+ *
+ * @param {Element} link from the DOM
+ * @param {String} cssContent
+ */
+ function replaceCSSLinkWithInlineCSS (link, cssContent) {
+ var cssElement = document.createElement('style');
+ cssElement.type = 'text/css';
+ if (cssElement.styleSheet) {
+ cssElement.styleSheet.cssText = cssContent;
+ } else {
+ cssElement.appendChild(document.createTextNode(cssContent));
+ }
+ var mediaAttributeValue = link.attr('media');
+ if (mediaAttributeValue) {
+ cssElement.media = mediaAttributeValue;
+ }
+ var disabledAttributeValue = link.attr('disabled');
+ if (disabledAttributeValue) {
+ cssElement.disabled = disabledAttributeValue;
+ }
+ link.replaceWith(cssElement);
+ }
var regexpRemoveUrlParameters = new RegExp(/([^\?]+)\?.*$/);
@@ -58,6 +88,7 @@ define([], function() {
*/
return {
feedNodeWithBlob: feedNodeWithBlob,
+ replaceCSSLinkWithInlineCSS: replaceCSSLinkWithInlineCSS,
removeUrlParameters: removeUrlParameters
};
});