diff --git a/www/js/app.js b/www/js/app.js index bae843510..f9fbea82d 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -1,22 +1,22 @@ /** * app.js : User Interface implementation * This file handles the interaction between the application and the user - * + * * Copyright 2013-2014 Mossroy and contributors * License GPL v3: - * + * * This file is part of Kiwix. - * + * * Kiwix is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * Kiwix is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with Kiwix (file LICENSE-GPLv3.txt). If not, see */ @@ -28,7 +28,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesystemAccess'], function($, zimArchiveLoader, uiUtil, settingsStore, abstractFilesystemAccess) { - + /** * The delay (in milliseconds) between two "keepalive" messages sent to the ServiceWorker (so that it is not stopped * by the browser, and keeps the MessageChannel to communicate with the application) @@ -39,12 +39,12 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys /** * The name of the Cache API cache to use for caching Service Worker requests and responses for certain asset types * We need access to the cache name in app.js in order to complete utility actions when Service Worker is not initialized, - * so we have to duplicate it here + * so we have to duplicate it here * @type {String} */ // DEV: Ensure this matches the name defined in service-worker.js (a check is provided in refreshCacheStatus() below) const ASSETS_CACHE = 'kiwixjs-assetsCache'; - + /** * Memory cache for CSS styles contained in ZIM: it significantly speeds up subsequent page display * This cache is used by default in jQuery mode, but can be turned off in Configuration for low-memory devices @@ -55,7 +55,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys /** * A global object for storing app state - * + * * @type Object */ var appstate = {}; @@ -64,7 +64,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys * @type ZIMArchive */ var selectedArchive = null; - + /** * Set parameters from the Settings Store, together with any defaults * Note that the params global object is declared in init.js so that it is available to modules @@ -93,7 +93,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // A parameter to access the URL of any extension that this app was launched from params['referrerExtensionURL'] = settingsStore.getItem('referrerExtensionURL'); // A parameter to set the content injection mode ('jquery' or 'serviceworker') used by this app - params['contentInjectionMode'] = settingsStore.getItem('contentInjectionMode') || + params['contentInjectionMode'] = settingsStore.getItem('contentInjectionMode') || // Defaults to jquery in extensions, and serviceworker if accessing as a PWA ((/^https?:$/i.test(window.location.protocol) && isServiceWorkerAvailable()) ? 'serviceworker' : 'jquery'); @@ -106,7 +106,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // A Boolean to store the update status of the PWA version (currently only used with Firefox Extension) appstate['pwaUpdateNeeded'] = false; // This will be set to true if the Service Worker has an update waiting - + /** * Apply any override parameters that might be in the querystring. * This is used for communication between the PWA and any local code (e.g. Firefox Extension), both ways. @@ -168,10 +168,10 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // Define globalDropZone (universal drop area) and configDropZone (highlighting area on Config page) var globalDropZone = document.getElementById('search-article'); var configDropZone = document.getElementById('configuration'); - + // Unique identifier of the article expected to be displayed var expectedArticleURLToBeDisplayed = ""; - + /** * Resize the IFrame height, so that it fills the whole available height in the window */ @@ -182,7 +182,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys if (iframe.style.display === 'none') { // We are in About or Configuration, so we only set the region height region.style.height = window.innerHeight + 'px'; - } else { + } else { // IE cannot retrieve computed headerStyles till the next paint, so we wait a few ticks setTimeout(function() { // Get header height *including* its bottom margin @@ -195,7 +195,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys } $(document).ready(resizeIFrame); $(window).resize(resizeIFrame); - + // Define behavior of HTML elements var searchArticlesFocused = false; $('#searchArticles').on('click', function() { @@ -285,7 +285,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys }); // Restore the search results if user goes back into prefix field $('#prefix').on('focus', function() { - if ($('#prefix').val() !== '') + if ($('#prefix').val() !== '') $('#articleListWithHeader').show(); }); // Hide the search results if user moves out of prefix field @@ -303,7 +303,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys $('#articleListWithHeader').hide(); $('.navbar-collapse').collapse('hide'); }); - + $('#btnRescanDeviceStorage').on("click", function() { searchForArchivesInStorage(); }); @@ -334,7 +334,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys $('.navbar-collapse').collapse('hide'); // Show the selected content in the page uiUtil.removeAnimationClasses(); - if (params.showUIAnimations) { + if (params.showUIAnimations) { uiUtil.applyAnimationToSection("home"); } else { $('#articleContent').show(); @@ -368,13 +368,13 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys $('.navbar-collapse').collapse('hide'); // Show the selected content in the page uiUtil.removeAnimationClasses(); - if (params.showUIAnimations) { + if (params.showUIAnimations) { uiUtil.applyAnimationToSection("config"); } else { $('#about').hide(); $('#configuration').show(); $('#articleContent').hide(); - } + } $('#navigationButtons').hide(); $('#formArticleSearch').hide(); $("#welcomeText").hide(); @@ -395,7 +395,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys $('.navbar-collapse').collapse('hide'); // Show the selected content in the page uiUtil.removeAnimationClasses(); - if (params.showUIAnimations) { + if (params.showUIAnimations) { uiUtil.applyAnimationToSection("about"); } else { $('#about').show(); @@ -625,7 +625,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys }); } - /** + /** * Refreshes the UI (Configuration) with the cache attributes obtained from getAssetsCacheAttributes() */ function refreshCacheStatus() { @@ -652,7 +652,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys var keepAliveServiceWorkerHandle; var serviceWorkerRegistration; - + /** * Send an 'init' message to the ServiceWorker with a new MessageChannel * to initialize it, or to keep it alive. @@ -677,7 +677,6 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // If this is the first time we are initiating the SW, allow Promises to complete by delaying potential reload till next tick delay = 0; } - messageChannel = tmpMessageChannel; // Schedule to do it again regularly to keep the 2-way communication alive. // See https://github.com/kiwix/kiwix-js/issues/145 to understand why clearTimeout(keepAliveServiceWorkerHandle); @@ -689,7 +688,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys * Sets the given injection mode. * This involves registering (or re-enabling) the Service Worker if necessary * It also refreshes the API status for the user afterwards. - * + * * @param {String} value The chosen content injection mode : 'jquery' or 'serviceworker' */ function setContentInjectionMode(value) { @@ -708,7 +707,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys settingsStore.setItem('allowInternetAccess', false, Infinity); var uriParams = '?allowInternetAccess=false&contentInjectionMode=jquery&hideActiveContentWarning=false'; uriParams += '&appTheme=' + params.appTheme; - uriParams += '&showUIAnimations=' + params.showUIAnimations; + uriParams += '&showUIAnimations=' + params.showUIAnimations; window.location.href = params.referrerExtensionURL + '/www/index.html' + uriParams; 'Beam me down, Scotty!'; }; @@ -797,7 +796,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys if (protocol === 'file:') { message += "\n\nYou seem to be opening kiwix-js with the file:// protocol. You should open it through a web server : either through a local one (http://localhost/...) or through a remote one (but you need SSL : https://webserver/...)"; } - alert(message); + alert(message); setContentInjectionMode("jquery"); } }); @@ -817,7 +816,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys refreshCacheStatus(); refreshAPIStatus(); } - + /** * Tells if the ServiceWorker API is available * https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker @@ -826,7 +825,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys function isServiceWorkerAvailable() { return ('serviceWorker' in navigator); } - + /** * Tells if the MessageChannel API is available * https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel @@ -842,7 +841,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys } return false; } - + /** * Tells if the ServiceWorker is registered, and ready to capture HTTP requests * and inject content in articles. @@ -854,12 +853,12 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys } function launchMozillaExtensionServiceWorker () { - // DEV: See explanation below for why we access localStorage directly here + // DEV: See explanation below for why we access localStorage directly here var PWASuccessfullyLaunched = localStorage.getItem(params.keyPrefix + 'PWA_launch') === 'success'; var allowInternetAccess = settingsStore.getItem('allowInternetAccess') === 'true'; - var message = 'To enable the Service Worker, we need one-time access to our secure server ' + + var message = 'To enable the Service Worker, we need one-time access to our secure server ' + 'so that the app can re-launch as a Progressive Web App (PWA).\n\n' + - 'The PWA will be able to run offline, but will auto-update periodically when online ' + + 'The PWA will be able to run offline, but will auto-update periodically when online ' + 'as per the Service Worker spec.\n\n' + 'You can switch back any time by returning to JQuery mode.\n\n' + 'WARNING: This will attempt to access the following server: \n' + params.PWAServer + '\n'; @@ -912,12 +911,12 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys else { setContentInjectionMode('jquery'); settingsStore.setItem('allowInternetAccess', false, Infinity); - } + } } } - + /** - * + * * @type Array. */ var storages = []; @@ -957,7 +956,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // If DeviceStorage is not available, we display the file select components displayFileSelect(); if (document.getElementById('archiveFiles').files && document.getElementById('archiveFiles').files.length>0) { - // Archive files are already selected, + // Archive files are already selected, setLocalArchiveFromFileSelect(); } else { @@ -971,7 +970,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys if (event.state) { var title = event.state.title; var titleSearch = event.state.titleSearch; - + $('#prefix').val(""); $("#welcomeText").hide(); $("#searchingArticles").hide(); @@ -979,7 +978,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys $('#configuration').hide(); $('#articleListWithHeader').hide(); $('#articleContent').contents().empty(); - + if (title && !(""===title)) { goToArticle(title); } @@ -993,7 +992,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys } } }; - + /** * Populate the drop-down list of archives with the given list * @param {Array.} archiveDirectories @@ -1014,7 +1013,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys } // Store the list of archives in the Settings Store, to avoid rescanning at each start settingsStore.setItem("listOfArchives", archiveDirectories.join('|'), Infinity); - + $('#archiveList').on('change', setLocalArchiveFromArchiveList); if (comboArchiveList.options.length > 0) { var lastSelectedArchive = settingsStore.getItem("lastSelectedArchive"); @@ -1080,10 +1079,10 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // The archive is set : go back to home page to start searching $("#btnHome").click(); }); - + } } - + /** * Resets the CSS Cache (used only in jQuery mode) */ @@ -1180,7 +1179,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys /** * 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 {String} url The URL of the archive to read * @returns {Promise} A promise for the requested file (blob) */ @@ -1204,10 +1203,10 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys request.send(); }); } - + /** * This is used in the testing interface to inject remote archives - * @returns {Promise} A Promise for an array of archives + * @returns {Promise} A Promise for an array of archives */ window.setRemoteArchives = function () { var readRequests = []; @@ -1298,13 +1297,13 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // NB We use encodeURIComponent rather than encodeURI here because we know that any question marks in the title are not querystrings, // and should be encoded [kiwix-js #806]. DEV: be very careful if you edit the dirEntryId attribute below, because the contents must be // inside double quotes (in the final HTML string), given that dirEntryStringId may contain bare apostrophes - // Info: encodeURIComponent encodes all characters except A-Z a-z 0-9 - _ . ! ~ * ' ( ) + // Info: encodeURIComponent encodes all characters except A-Z a-z 0-9 - _ . ! ~ * ' ( ) var dirEntryStringId = encodeURIComponent(dirEntry.toStringId()); articleListDivHtml += '' + dirEntry.getTitleOrUrl() + ''; } articleListDiv.html(articleListDivHtml); - // We have to use mousedown below instead of click as otherwise the prefix blur event fires first + // We have to use mousedown below instead of click as otherwise the prefix blur event fires first // and prevents this event from firing; note that touch also triggers mousedown $('#articleList a').on('mousedown', function (e) { // Cancel search immediately @@ -1321,7 +1320,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys * @param {Event} event The click event to handle * @returns {Boolean} Always returns false for JQuery event handling */ - function handleTitleClick(event) { + function handleTitleClick(event) { var dirEntryId = decodeURIComponent(event.target.getAttribute('dirEntryId')); findDirEntryFromDirEntryIdAndLaunchArticleRead(dirEntryId); return false; @@ -1357,7 +1356,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys var curArticleURL = dirEntry.namespace + "/" + dirEntry.url; if (expectedArticleURLToBeDisplayed !== curArticleURL) { - console.debug("url of current article :" + curArticleURL + ", does not match the expected url :" + + console.debug("url of current article :" + curArticleURL + ", does not match the expected url :" + expectedArticleURLToBeDisplayed); return false; } @@ -1425,7 +1424,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys if(! isDirEntryExpectedToBeDisplayed(dirEntry)){ return; - } + } // We put the ZIM filename as a prefix in the URL, so that browser caches are separate for each ZIM file iframeArticleContent.src = "../" + selectedArchive._file.name + "/" + dirEntry.namespace + "/" + encodedUrl; @@ -1441,13 +1440,11 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys } } } - - var messageChannel; - + /** * Function that handles a message of the messageChannel. * It tries to read the content in the backend, and sends it back to the ServiceWorker - * + * * @param {Event} event The event object of the message channel */ function handleMessageChannelMessage(event) { @@ -1467,7 +1464,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys } else if (dirEntry.isRedirect()) { selectedArchive.resolveRedirect(dirEntry, function (resolvedDirEntry) { var redirectURL = resolvedDirEntry.namespace + "/" + resolvedDirEntry.url; - // Ask the ServiceWork to send an HTTP redirect to the browser. + // Ask the ServiceWorker to send an HTTP redirect to the browser. // We could send the final content directly, but it is necessary to let the browser know in which directory it ends up. // Else, if the redirect URL is in a different directory than the original URL, // the relative links in the HTML content would fail. See #312 @@ -1491,7 +1488,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys } } } - + // Compile some regular expressions needed to modify links // Pattern to find a ZIM URL (with its namespace) - see https://wiki.openzim.org/wiki/ZIM_file_format#Namespaces var regexpZIMUrlWithNamespace = /^[./]*([-ABCIJMUVWX]\/.+)$/; @@ -1506,11 +1503,11 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys // Regex below tests the html of an article for active content [kiwix-js #466] // It inspects every