Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding browser for zim library #1127

Merged
merged 24 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
53ccd0f
[PROTOTYPE] zim library base
Rishabhg71 Sep 20, 2023
feb0cf8
[ADD] Iframe for library
Rishabhg71 Sep 20, 2023
7dc7c88
[ADD] app theme to library iframe
Rishabhg71 Sep 21, 2023
e656f98
[FIX] alignment of buttons
Rishabhg71 Sep 21, 2023
eddd6d1
[FIX] CORS issue for download.library.com
Rishabhg71 Sep 21, 2023
29a6dcd
[FIX] downloads from all mirrors
Rishabhg71 Sep 21, 2023
b0a3620
[ADD] i18n for library button
Rishabhg71 Sep 22, 2023
c6ed333
[FIX] allow all mirrors urls `*`
Rishabhg71 Sep 23, 2023
04b441b
[ADD] proper jsdocs for params
Rishabhg71 Sep 25, 2023
2e1d097
[ADD] IE support for iframe
Rishabhg71 Sep 25, 2023
507d0d9
[ADD] Fallback url old browsers
Rishabhg71 Sep 25, 2023
d253aae
[REFACTOR] updated jsdoc for `params.decompressorAPI`
Rishabhg71 Sep 25, 2023
c515f64
[REFACTOR] changes requested by @jaifroid
Rishabhg71 Sep 26, 2023
ea12093
[FIX] Download not starting due to CSP
Rishabhg71 Sep 30, 2023
b218fda
[FIX] absolute url to relative url for iframe
Rishabhg71 Sep 30, 2023
2729c0f
[ADD] script to check for `eval` support
Rishabhg71 Oct 3, 2023
279a1c7
[PROTO] Using frame communication with parent
Rishabhg71 Oct 4, 2023
1aa0d95
support for chrome extension and IE
Rishabhg71 Oct 5, 2023
de8b510
[ADD] download.kiwix load as text content
Rishabhg71 Oct 7, 2023
758bf38
[REVERT,ADD] open urls in new tab
Rishabhg71 Oct 9, 2023
a0305f3
[ADD] popup before opening link
Rishabhg71 Oct 9, 2023
fddddd6
[CLEANUP] minor changes
Rishabhg71 Oct 9, 2023
bd1059f
Update app.js
Rishabhg71 Oct 9, 2023
08b6a26
[REFACTOR] changes requested by `@jaifroid`
Rishabhg71 Oct 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions i18n/en.jsonp.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions i18n/es.jsonp.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions i18n/fr.jsonp.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@

"content_security_policy": {
"extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';",
"sandbox": "sandbox allow-scripts allow-downloads allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"
"sandbox": "sandbox allow-scripts allow-downloads allow-forms allow-popups allow-modals; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self'; frame-src library.kiwix.org"
},

Rishabhg71 marked this conversation as resolved.
Show resolved Hide resolved
"sandbox": {
"pages": [
"www/library.html"
]
},
"web_accessible_resources": [{
"resources": ["www/index.html", "www/article.html"],
"resources": ["www/index.html", "www/article.html", "www/library.html"],
"matches": ["https://*.kiwix.org/*"]
}],

Expand Down
13 changes: 11 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,12 @@ const config = {
// Prevent a fatal error in IE11 (bug with the URL constructor polyfill)
'document.baseURI': "document.location.href.replace(/[^/]*$/, '')",
// Redirect the libzim Worker loader to the new location
'js/lib/libzim': 'js/libzim',
'js/lib/darkreader.min.js': 'js/darkreader.min.js',
preventAssignment: true
}),
copy({
targets: [{
src: ['www/js/lib/*dec-wasm.wasm', 'www/js/lib/libzim-asm.js', 'www/js/lib/libzim-wasm.*', 'www/js/lib/webpHeroBundle*',
src: ['www/js/lib/*dec-wasm.wasm', 'www/js/lib/library.js', 'www/js/lib/libzim-asm.js', 'www/js/lib/libzim-wasm.*', 'www/js/lib/webpHeroBundle*',
Rishabhg71 marked this conversation as resolved.
Show resolved Hide resolved
'node_modules/bootstrap/dist/js/bootstrap.bundle.min.*', 'node_modules/jquery/dist/jquery.slim.min.*', '!www/js/lib/libzim-wasm.dev*'],
dest: 'dist/www/js'
},
Expand Down Expand Up @@ -98,6 +97,11 @@ if (process.env.BUILD === 'production') {
.replace(/(<script\s.*src=").*jquery.slim.min.js/, '$1js/jquery.slim.min.js')
.replace(/(<script\s.*src=").*bootstrap.bundle.min.js/, '$1js/bootstrap.bundle.min.js')
.replace(/(<link\s.*href=").*bootstrap.min.css/, '$1css/bootstrap.min.css')
},
{
src: 'www/library.html',
dest: 'dist/www',
transform: (contents, filename) => contents.toString().replace('./js/lib/library.js', './js/library.js')
}
],
flatten: false
Expand Down Expand Up @@ -147,6 +151,11 @@ if (process.env.BUILD === 'production') {
.replace(/(<script\s.*src=").*jquery.slim.min.js/, '$1js/jquery.slim.min.js')
.replace(/(<script\s.*src=").*bootstrap.bundle.min.js/, '$1js/bootstrap.bundle.min.js')
.replace(/(<link\s.*href=").*bootstrap.min.css/, '$1css/bootstrap.min.css')
},
{
src: 'www/library.html',
dest: 'dist/www',
transform: (contents, filename) => contents.toString().replace('./js/lib/library.js', './js/library.js')
}
],
flatten: false
Expand Down
1 change: 1 addition & 0 deletions service-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ const precacheFiles = [
'www/img/Icon_External_Link.png',
'www/index.html',
'www/article.html',
'www/library.html',
'www/main.html',
'www/js/app.js',
'www/js/init.js',
Expand Down
4 changes: 4 additions & 0 deletions www/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ input[type="file"] {
display: none;
}

iframe {
border: 0;
}

.custom-file-upload {
border: 2px solid darkgray;
display: inline-block;
Expand Down
19 changes: 13 additions & 6 deletions www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,9 @@ <h3 id="other" data-i18n="about-other-platforms">Other platforms/versions</h3>
<br/>
<br/>
</div>

<div id='library' style="display: none; color: white;">
<iframe width="100%" id="libraryContent" src="./library.html"></iframe>
</div>
<div id="configuration" style="display: none;">
<div class="container">
<h2 data-i18n="configure-title">Configuration</h2>
Expand All @@ -467,11 +469,16 @@ <h2 data-i18n="configure-title">Configuration</h2>
<div id="openLocalFiles" style="display: none;">
<p data-i18n="configure-select-instructions">Please select or drag and drop a .zim file (or all the .zimaa, .zimab etc in
case of a split ZIM file):</p>
<label class="btn btn-light custom-file-upload">
<input type="file" id="archiveFiles" multiple class="btn"
accept="application/octet-stream,.zim,.zimaa,.zimab,.zimac,.zimad,.zimae,.zimaf,.zimag,.zimah,.zimai,.zimaj,.zimak,.zimal,.zimam,.ziman,.zimao,.zimap,.zimaq,.zimar,.zimas,.zimat,.zimau,.zimav,.zimaw,.zimax,.zimay,.zimaz,.zimba,.zimbb,.zimbc,.zimbd,.zimbe,.zimbf,.zimbg,.zimbh,.zimbi,.zimbj,.zimbk,.zimbl,.zimbm,.zimbn,.zimbo,.zimbp,.zimbq,.zimbr,.zimbs,.zimbt,.zimbu,.zimbv,.zimbw,.zimbx,.zimby,.zimbz" />
<span data-i18n="home-btn-fileselect">Select ZIM file(s)</span>
</label>
<span>
<label class="btn btn-light custom-file-upload">
<input type="file" id="archiveFiles" multiple class="btn"
accept="application/octet-stream,.zim,.zimaa,.zimab,.zimac,.zimad,.zimae,.zimaf,.zimag,.zimah,.zimai,.zimaj,.zimak,.zimal,.zimam,.ziman,.zimao,.zimap,.zimaq,.zimar,.zimas,.zimat,.zimau,.zimav,.zimaw,.zimax,.zimay,.zimaz,.zimba,.zimbb,.zimbc,.zimbd,.zimbe,.zimbf,.zimbg,.zimbh,.zimbi,.zimbj,.zimbk,.zimbl,.zimbm,.zimbn,.zimbo,.zimbp,.zimbq,.zimbr,.zimbs,.zimbt,.zimbu,.zimbv,.zimbw,.zimbx,.zimby,.zimbz" />
<span data-i18n="home-btn-fileselect">Select ZIM file(s)</span>
</label>
<label class="btn btn-light custom-file-upload" id="libraryBtn" data-i18n="configure-btn-library">
Browse ZIM Library
</label>
</span>
<br />
<strong id="jqueryCompatibility" data-i18n="configure-static-content">Only ZIMs with static content (e.g. Wiki-style) are supported in JQuery mode.<br /></strong>
<span data-i18n="configure-supportedarchives">For information on ZIM compatibility, see</span> <a href="#usage" data-i18n="configure-about-usage-link" class="aboutLinks">About (Usage)</a>.<br />
Expand Down
46 changes: 31 additions & 15 deletions www/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,34 @@ darkPreference.onchange = function () {
* Resize the IFrame height, so that it fills the whole available height in the window
*/
function resizeIFrame () {
var headerStyles = getComputedStyle(document.getElementById('top'));
var iframe = document.getElementById('articleContent');
var region = document.getElementById('search-article');
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 {
// IE cannot retrieve computed headerStyles till the next paint, so we wait a few ticks
setTimeout(function () {
// Get header height *including* its bottom margin
var headerHeight = parseFloat(headerStyles.height) + parseFloat(headerStyles.marginBottom);
iframe.style.height = window.innerHeight - headerHeight + 'px';
// We have to allow a minimum safety margin of 10px for 'iframe' and 'header' to fit within 'region'
region.style.height = window.innerHeight + 10 + 'px';
}, 100);
const headerStyles = getComputedStyle(document.getElementById('top'));
const articleContent = document.getElementById('articleContent');
const libraryContent = document.getElementById('libraryContent');
const frames = [articleContent, libraryContent]
const region = document.getElementById('search-article');
libraryContent.contentWindow.postMessage({ event: 'resize', data: window.innerHeight }, '*');
// window.postMessage(window.innerHeight, '*');

for (let i = 0; i < frames.length; i++) {
const iframe = frames[i];
if (iframe.style.display === 'none') {
// We are in About or Configuration, so we only set the region height
region.style.height = window.innerHeight + 'px';
// nestedFrame.style.height = window.innerHeight - 110 + 'px';
} 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
const headerHeight = parseFloat(headerStyles.height) + parseFloat(headerStyles.marginBottom);
iframe.style.height = window.innerHeight - headerHeight + 'px';
// We have to allow a minimum safety margin of 10px for 'iframe' and 'header' to fit within 'region'
region.style.height = window.innerHeight + 10 + 'px';
// nestedFrame.style.height = window.innerHeight - 110 + 'px';
}, 100);
}
}
}

document.addEventListener('DOMContentLoaded', function () {
getDefaultLanguageAndTranslateApp();
resizeIFrame();
Expand Down Expand Up @@ -1296,6 +1307,11 @@ function handleFileDrop (packet) {
document.getElementById('archiveFiles').value = null;
}

document.getElementById('libraryBtn').addEventListener('click', function (e) {
e.preventDefault();
uiUtil.tabTransitionToSection('library', params.showUIAnimations);
});

// Add event listener to link which allows user to show file selectors
document.getElementById('selectorsDisplayLink').addEventListener('click', function (e) {
e.preventDefault();
Expand Down
40 changes: 39 additions & 1 deletion www/js/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,40 @@
* A global parameter object for storing variables that need to be remembered between page loads,
* or across different functions and modules
*
* @type Object
* @typedef {Object} AppParams
* @property {string} appVersion - The version number of the application.
* @property {string} PWAServer - The URL of the PWA server for use with the browser extensions in ServiceWorker mode.
* @property {string} storeType - A parameter to determine the Settings Store API in use.
* @property {string} keyPrefix - The key prefix used by the settingsStore.js.
* @property {boolean} hideActiveContentWarning - A boolean indicating whether to hide the active content warning.
* @property {boolean} showUIAnimations - A boolean indicating whether to show UI animations.
* @property {number} maxSearchResultsSize - The maximum number of article titles to return.
* @property {boolean} assetsCache - A boolean indicating whether to cache assets.
* @property {boolean} appCache - A boolean indicating whether to cache the PWA's code.
* @property {string} appTheme - A parameter to set the app theme and, if necessary, the CSS theme for article content.
* @property {boolean} useHomeKeyToFocusSearchBar - A global parameter to turn on/off the use of Keyboard HOME Key to focus search bar.
* @property {boolean} openExternalLinksInNewTabs - A global parameter to turn on/off opening external links in new tab (for ServiceWorker mode).
* @property {string} overrideBrowserLanguage - A global language override.
* @property {boolean} disableDragAndDrop - A parameter to disable drag-and-drop.
* @property {string} referrerExtensionURL - A parameter to access the URL of any extension that this app was launched from.
* @property {boolean} defaultModeChangeAlertDisplayed - A parameter to keep track of the fact that the user has been informed of the switch to SW mode by default.
* @property {string} contentInjectionMode - A parameter to set the content injection mode ('jquery' or 'serviceworker') used by this app.
* @property {boolean} useCanvasElementsForWebpTranscoding - A parameter to circumvent anti-fingerprinting technology in browsers that do not support WebP natively by substituting images directly with the canvas elements produced by the WebP polyfill.
* @property {string} libraryUrl - The URL of the Kiwix library.
* @property {string} altLibraryUrl - The alternative URL of the Kiwix library in non-supported browsers.
* @property {DecompressorAPI} decompressorAPI

/**
* A property of the global params object to track the assembler machine type and the last used decompressor (for reporting to the API panel)
* This is populated in the Emscripten wrappers
* @typedef {Object} DecompressorAPI
* @property {String} assemblerMachineType The assembler machine type supported and/or loaded by this app: 'ASM' or 'WASM'
* @property {String} decompressorLastUsed The decompressor that was last used to decode a compressed cluster (currently 'XZ' or 'ZSTD')
* @property {String} errorStatus A description of any detected error in loading a decompressor
*/

/**
* @type {AppParams}
*/
var params = {};

Expand Down Expand Up @@ -77,6 +110,8 @@ params['contentInjectionMode'] = getSetting('contentInjectionMode') ||
// A parameter to circumvent anti-fingerprinting technology in browsers that do not support WebP natively by substituting images
// directly with the canvas elements produced by the WebP polyfill [kiwix-js #835]. NB This is only currently used in jQuery mode.
params['useCanvasElementsForWebpTranscoding'] = null; // Value is determined in uiUtil.determineCanvasElementsWorkaround(), called when setting the content injection mode
params['libraryUrl'] = 'https://library.kiwix.org/'; // Url for iframe that will be loaded to download new zim files
params['altLibraryUrl'] = 'https://download.kiwix.org/zim/'; // Url for iframe that will be loaded to download new zim files
Rishabhg71 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Apply any override parameters that might be in the querystring.
Expand Down Expand Up @@ -140,6 +175,9 @@ document.getElementById('languageSelector').value = params.overrideBrowserLangua
document.getElementById('bypassAppCacheCheck').checked = !params.appCache;
document.getElementById('appVersion').textContent = 'Kiwix ' + params.appVersion;

// Send the required config to the iframe
document.getElementById('libraryContent').contentWindow.postMessage({ event: 'setIframeUrl', data: { libraryUrl: params.libraryUrl, altLibraryUrl: params.altLibraryUrl } }, '*');

// This is a simplified version of code in settingsStore, because that module is not available in init.js
function getSetting (name) {
var result;
Expand Down
77 changes: 77 additions & 0 deletions www/js/lib/library.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// This page will be loaded in an iframe in library.html
// If this page is directly loaded it will just throw a lot of errors

let LIB_URL = {
libraryUrl: '',
altLibraryUrl: ''
}

function resizeFrame (height) {
const iframe = document.getElementById('libraryIframe')
iframe.style.height = height - 20 + 'px'
}

function setIframeUrl () {
// const libraryURl = urls.libraryUrl
// const fallbackLibraryURl = urls.altLibraryUrl
const libraryURl = LIB_URL.libraryUrl
const fallbackLibraryURl = LIB_URL.altLibraryUrl
const iframe = document.getElementById('libraryIframe')

if (!libraryURl && !fallbackLibraryURl && iframe.getElementsByTagName('body')[0]) return

let isOptionalChainSupported = true // if not supported, that means the browser is too old
let isParentWindowSupported = true // if not supported, that means it's chrome extension
try {
// eslint-disable-next-line no-eval
eval('try{}catch{}')
} catch (error) {
isOptionalChainSupported = false
}
try {
window.parent.params

Check notice on line 32 in www/js/lib/library.js

View check run for this annotation

codefactor.io / CodeFactor

www/js/lib/library.js#L32

Expected an assignment or function call and instead saw an expression. (no-unused-expressions)
} catch (error) {
isParentWindowSupported = false
}

console.log(iframe);
if (isOptionalChainSupported && isParentWindowSupported && false) {

Check warning on line 38 in www/js/lib/library.js

View check run for this annotation

codefactor.io / CodeFactor

www/js/lib/library.js#L38

Unexpected constant condition. (no-constant-condition)
iframe.setAttribute('src', libraryURl)
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
console.log('library loaded');
} else {
const xhr = new XMLHttpRequest();
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
console.log(xhr, fallbackLibraryURl);
xhr.open('GET', fallbackLibraryURl);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
iframe.setAttribute('srcdoc', xhr.responseText)
} else {
throw new Error('Failed to get content from');
}
}
};
console.log('download.kiwix loaded');
}
}

window.addEventListener('DOMContentLoaded', function () {
setIframeUrl()
})

window.addEventListener('message', function (e) {
console.log(e.data);
if (e.data.event === 'resize') {
const height = e.data.data
resizeFrame(height)
}
if (e.data.event === 'setIframeUrl') {
const urls = e.data.data
LIB_URL = {
libraryUrl: urls.libraryUrl,
altLibraryUrl: urls.altLibraryUrl
}
setIframeUrl()
}
})
Loading
Loading