mirror of
https://github.com/kiwix/kiwix-js-pwa.git
synced 2025-09-09 12:19:46 -04:00
Major improvements in stylesheet transformations
Former-commit-id: a4a9b6f44d5bf611fb51387d283351f327b3c357 [formerly dc1584995a0e6df7087b61fcb6c658949c145b0c] Former-commit-id: a0f4808622254de2c34243d393e6e93fe5cd7540
This commit is contained in:
parent
8b309d3b65
commit
8abb11d6f8
File diff suppressed because one or more lines are too long
@ -202,16 +202,34 @@
|
||||
</div>
|
||||
<br />
|
||||
<h2>Display settings</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<td style="vertical-align:top; min-width : 20em;">
|
||||
<div id="cssSettingsDiv">
|
||||
Please select the display style: <br />
|
||||
<input type="radio" name="cssInjectionMode" value="local" id="cssModeLocalRadio" checked><label for="cssModeLocalRadio"> Use locally cached display styles</label> (faster if using a Wikipedia ZIM file, falls back to the styles stored in the ZIM)
|
||||
<input type="radio" name="cssInjectionMode" value="desktop" id="cssModeDesktopRadio" checked>
|
||||
<span style="margin-left: 22px; text-indent: -22px;">
|
||||
<label for="cssModeDesktopRadio"> Use Wikipedia desktop display style</label> (for Wikipedia files)
|
||||
<br />
|
||||
<input type="radio" name="cssInjectionMode" value="mobile" id="cssModeMobileRadio"><label for="cssModeMobileRadio"> Use Wikipedia mobile display style</label> (only works with standard Wikipedia ZIM files)
|
||||
<br />
|
||||
<input type="radio" name="cssInjectionMode" value="desktop" id="cssModeMobileRadio"><label for="cssModeMobileRadio"> Use Wikipedia desktop display style</label> (strips mobile formatting if your ZIM file is pre-formatted for mobile)
|
||||
<br />
|
||||
<input type="radio" name="cssInjectionMode" value="zimfile" id="cssModeZIMfileRadio"><label for="cssModeZIMfileRadio"> Use styles embedded in the ZIM file</label> (slower retrieval, uses more memory if accessing large Wikipedia ZIMs)
|
||||
</span>
|
||||
<input type="radio" name="cssInjectionMode" value="mobile" id="cssModeMobileRadio">
|
||||
<span style="margin-left: 22px; text-indent: -22px;">
|
||||
<label for="cssModeMobileRadio"> Use Wikipedia mobile display style</label> (for Wikipedia files)
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td style="vertical-align:top; padding-left: 1em;">
|
||||
<div id="cssSettingsDiv">
|
||||
Please select the display option: <br />
|
||||
<input type="checkbox" name="cssCacheMode" value="local" id="cssCacheModeCheck">
|
||||
<span style="padding-left: 22px; text-indent: -22px;">
|
||||
<label for="cssCacheModeCheck"> Use locally cached display styles</label> (<i>recommended</i> for Wikipedia ZIM)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>Expert settings</h2>
|
||||
<div id="contentInjectionModeDiv">
|
||||
Do not touch unless you know what you're doing. <br />
|
||||
|
@ -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', 'module'],
|
||||
function($, zimArchiveLoader, util, uiUtil, cookies, abstractFilesystemAccess, module) {
|
||||
define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFilesystemAccess', 'module', 'transformStyles'],
|
||||
function($, zimArchiveLoader, util, uiUtil, cookies, abstractFilesystemAccess, module, transformStyles) {
|
||||
|
||||
/**
|
||||
* Maximum number of articles to display in a search
|
||||
@ -192,12 +192,19 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
setContentInjectionMode('jquery');
|
||||
}
|
||||
});
|
||||
$('input:checkbox[name=cssCacheMode]').on('change', function (e) {
|
||||
params['cssCache'] = this.checked ? true : false;
|
||||
});
|
||||
$('input:radio[name=cssInjectionMode]').on('change', function (e) {
|
||||
params['cssSource'] = this.value;
|
||||
});
|
||||
$(document).ready(function (e) {
|
||||
// Set checkbox for cssCache and radio for cssSource
|
||||
document.getElementById('cssCacheModeCheck').checked = params['cssCache'];
|
||||
});
|
||||
|
||||
/**
|
||||
* Displays of refreshes the API status shown to the user
|
||||
* Displays or refreshes the API status shown to the user
|
||||
*/
|
||||
function refreshAPIStatus() {
|
||||
if (isMessageChannelAvailable()) {
|
||||
@ -786,21 +793,36 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
//Set up blobArray of promises
|
||||
var cssArray = htmlArticle.match(regexpSheetHref);
|
||||
var blobArray = [];
|
||||
cssSource = params['cssSource'];
|
||||
var cssSource = params['cssSource'];
|
||||
var cssCache = params['cssCache'];
|
||||
var zimType = "";
|
||||
getBLOB(cssArray);
|
||||
|
||||
//Extract CSS URLs from given array of links
|
||||
function getBLOB(arr) {
|
||||
if (cssSource == "desktop" && (!arr.join().match(/-\/s\/style\.css/i))) {
|
||||
arr.push('<link href="../-/s/style.css" rel="stylesheet">'); //Insert the standard desktop style
|
||||
}
|
||||
zimType = arr.join().match(/-\/s\/style\.css/i) ? "desktop" : zimType;
|
||||
zimType = arr.join().match(/minerva|mobile/i) ? "mobile" : zimType;
|
||||
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
var linkArray = regexpSheetHref.exec(arr[i]);
|
||||
regexpSheetHref.lastIndex = 0; //Reset start position for next loop
|
||||
if (regexpMetadataUrl.test(linkArray[2])) { //It's a CSS file contained in ZIM
|
||||
var zimLink = decodeURIComponent(uiUtil.removeUrlParameters(linkArray[2]));
|
||||
if ((zimType != cssSource) && zimLink.match(/(-\/s\/style\.css)|minerva|mobile|parsoid/i)) { //If it's the wrong ZIM type and style matches main styles...
|
||||
if (zimLink.match(/(-\/s\/style\.css)|(minerva)/i)) { //If it matches one of the required styles...
|
||||
zimLink = (cssSource == "mobile") ? "../-/s/style-mobile.css" : "../-/s/style.css"; //Take it from cache, because not in the ZIM
|
||||
console.log("Matched #" + i + " [" + zimLink + "] from local filesystem because style is not in ZIM" +
|
||||
"\nbut your display options require a " + cssSource + " style");
|
||||
}
|
||||
if (cssSource == "desktop" && zimLink.match(/minerva|mobile|parsoid/)) { //If user selected desktop style and style is one of the mobile styles
|
||||
console.log("Voiding #" + i + " [" + zimLink + "] from document header \nbecause your display options require a desktop style");
|
||||
zimLink = "#"; //Void these mobile styles
|
||||
}
|
||||
blobArray[i] = zimLink;
|
||||
injectCSS();
|
||||
} else {
|
||||
//If this is a standard Wikipedia css use stylesheet cached in the filesystem...
|
||||
if ((cssSource != "zimfile") &&
|
||||
if ( cssCache &&
|
||||
(zimLink.match(/-\/s\/style\.css/i) ||
|
||||
zimLink.match(/-\/s\/css_modules\/mediawiki\.toc\.css/i) ||
|
||||
zimLink.match(/-\/s\/css_modules\/ext\.cite\.styles\.css/i) ||
|
||||
@ -813,21 +835,16 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
zimLink.match(/-\/s\/css_modules\/mobile\.css/i) ||
|
||||
zimLink.match(/-\/s\/css_modules\/skins\.minerva\.base\.reset\|skins\.minerva\.content\.styles\|ext\.cite\.style\|mediawiki\.page\.gallery\.styles\|mobile\.app\.pagestyles\.android\|mediawiki\.skinning\.content\.parsoid\.css/i)
|
||||
)) {
|
||||
if (cssSource == "desktop" && zimLink.match(/minerva|mobile|parsoid/)) { //If user selected desktop style and the ZIM is formatted for mobile...
|
||||
zimLink = "#"; //Void the style
|
||||
}
|
||||
if ((cssSource == "mobile") || (zimLink.match(/minerva/))) { //If user has selected mobile display mode or mobile is built into ZIM, substitute main stylesheet
|
||||
zimLink = zimLink.match(/(-\/s\/style\.css)|(minerva)/i) ? "../-/s/style-mobile.css" : zimLink;
|
||||
}
|
||||
blobArray[i] = zimLink.replace(/\|/ig, "_"); //Replace "|" with "_" (legacy for some stylesheets with pipes in filename)
|
||||
console.log("Matched #" + i + " [" + blobArray[i] + "] from local filesystem");
|
||||
injectCSS();
|
||||
} else { //Try to get the stylesheet from the ZIM file
|
||||
} else { //Try to get the stylesheet from the ZIM file unless it's the wrong ZIM type
|
||||
var linkURL = zimLink.match(regexpMetadataUrl)[1];
|
||||
console.log("Attempting to resolve CSS link #" + i + " [" + linkURL + "] from ZIM file..." +
|
||||
(cssSource != "zimfile" ? "\n(Consider adding file #" + i + " to the local filesystem)" : ""));
|
||||
(cssCache ? "\n(Consider adding file #" + i + " to the local filesystem)" : ""));
|
||||
resolveCSS(linkURL, i); //Pass link and index
|
||||
}
|
||||
}
|
||||
} else {
|
||||
blobArray[i] = linkArray[2]; //If CSS not in ZIM, store URL in blobArray
|
||||
injectCSS(); //Ensure this is called even if none of CSS links are in ZIM
|
||||
@ -856,35 +873,19 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
if (blobArray.length === cssArray.length) { //If all promised values have been obtained
|
||||
for (var i in cssArray) {
|
||||
cssArray[i] = cssArray[i].replace(/(href\s*=\s*["'])([^"']+)/i, "$1" + blobArray[i]);
|
||||
//DEV note: do not attempt to add onload="URL.revokeObjectURL...)": it fires before the
|
||||
//stylesheet changes have been painted and causes a crash...
|
||||
//Use oneTimeOnly=true when creating blob instead (implemented above)
|
||||
//DEV note: do not attempt to add onload="URL.revokeObjectURL...)": see [kiwix.js #284]
|
||||
}
|
||||
htmlArticle = htmlArticle.replace(regexpSheetHref, ""); //Void existing stylesheets
|
||||
var cssArray$ = "\r\n" + cssArray.join("\r\n") + "\r\n";
|
||||
if (cssSource == "mobile") { //If user has selected mobile display mode, insert extra stylesheets
|
||||
cssArray$ += cssArray$.match(/-\/s\/css_modules\/content\.parsoid\.css/i) ? "" : '<link href="../-/s/css_modules/content.parsoid.css" rel="stylesheet" type="text/css">\r\n';
|
||||
cssArray$ += cssArray$.match(/-\/s\/css_modules\/inserted_style_mobile\.css/i) ? "" : '<link href="../-/s/css_modules/inserted_style_mobile.css" rel="stylesheet" type="text/css">\r\n';
|
||||
cssArray$ += cssArray$.match(/-\/s\/css_modules\/mobile\.css/i) ? "" : '<link href="../-/s/css_modules/mobile.css" rel="stylesheet" type="text/css">\r\n';
|
||||
//Allow images to float right or left
|
||||
htmlArticle = htmlArticle.replace(/class\s*=\s*["']\s*thumb\s+tright\s*["']\s*/ig, 'style="float: right; clear: right; margin-left: 1.4em;"');
|
||||
htmlArticle = htmlArticle.replace(/class\s*=\s*["']\s*thumb\s+tleft\s*["']\s*/ig, 'style="float: left; clear: left; margin-right: 1.4em;"');
|
||||
//Add styling to image captions that is hard-coded in Wikipedia mobile
|
||||
htmlArticle = htmlArticle.replace(/class\s*=\s*["']\s*thumbcaption\s*["']\s*/ig, 'style="margin: 0.5em 0 0.5em; font-size: 0.8em; line-height: 1.5; padding: 0 !important; color: #54595d; width: auto !important;"');
|
||||
//Move info-box below lead paragraph like on Wikipedia mobile
|
||||
htmlArticle = htmlArticle.replace(/(<table\s+(?=[^>]*infobox)[\s\S]+?<\/table>[^<]*)(<p\b[^>]*>(?:(?=([^<]+))\3|<(?!p\b[^>]*>))*?<\/p>)/ig, "$2$1");
|
||||
//Set infobox styling hard-coded in Wikipedia mobile
|
||||
htmlArticle = htmlArticle.replace(/(table\s+(?=[^>]*class\s*=\s*["'][^"']*infobox)[^>]*style\s*=\s*["'][^"']+[^;'"]);?\s*["']/ig, '$1; position: relative; border: 1px solid #eaecf0; text-align: left; background-color: #f8f9fa;"');
|
||||
//Wrap <h2> tags in <div> to control bottom border width if there's an infobox
|
||||
htmlArticle = htmlArticle.match(/table\s+(?=[^>]*class\s*=\s*["'][^"']*infobox)/i) ? htmlArticle.replace(/(<h2\s+[^<]*<\/h2>)/ig, '<div style="width: 60%;">$1</div>') : htmlArticle;
|
||||
if (cssSource == "mobile") { //If user has selected mobile display mode...
|
||||
var mobileCSS = transformStyles.toMobileCSS(htmlArticle, zimType, cssCache, cssArray$);
|
||||
htmlArticle = mobileCSS.html;
|
||||
cssArray$ = mobileCSS.css;
|
||||
}
|
||||
if (cssSource == "desktop") { //If user has selected desktop display mode...
|
||||
//Ensure white background colour
|
||||
htmlArticle = htmlArticle.replace(/class\s*=\s*["']\s*mw-body\s*["']\s*/ig, 'style="background-color: white; padding: 1em; border-width: 0px; max-width: 55.8em; margin: 0 auto 0 auto;"');
|
||||
//Void empty header title
|
||||
htmlArticle = htmlArticle.replace(/<h1\s*[^>]+titleHeading[^>]+>\s*<\/h1>\s*/ig, "");
|
||||
htmlArticle = transformStyles.toDesktopCSS(htmlArticle,zimType,cssCache).html;
|
||||
}
|
||||
if (cssSource != "zimfile") { //For all cases except where user wants exactly what's in the zimfile...
|
||||
if (cssCache) { //For all cases except where user wants exactly what's in the zimfile...
|
||||
//Reduce the hard-coded top padding to 0
|
||||
htmlArticle = htmlArticle.replace(/(<div\s+[^>]*mw-body[^>]+style[^>]+padding\s*:\s*)1em/i, "$10 1em");
|
||||
}
|
||||
@ -1097,5 +1098,4 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies','abstractFiles
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -23,14 +23,14 @@
|
||||
'use strict';
|
||||
var params = {};
|
||||
var results = params['results'] || 10; //Number of search results to display
|
||||
var cssSource = params['cssSource'] || "local"; //One of "zimfile", "local", "desktop" or "mobile""
|
||||
params['cssSource'] = params['cssSource'] || "desktop"; //Set default to "desktop" or "mobile"
|
||||
params['cssCache'] = params['cssCache'] || true; //Set default to true to use cached CSS, false to use Zim only
|
||||
|
||||
require.config({
|
||||
baseUrl: 'js/lib',
|
||||
config: { '../app': { results: results, cssSource: cssSource } },
|
||||
config: { '../app': { results: results, params: params } },
|
||||
paths: {
|
||||
//'jquery': 'jquery-3.2.1',
|
||||
'jquery': 'jquery-3.2.1.slim', //GK testing
|
||||
'jquery': 'jquery-3.2.1.slim',
|
||||
//'bootstrap': 'bootstrap'
|
||||
'bootstrap': 'bootstrap.min' //GK testing
|
||||
},
|
||||
|
69
www/js/lib/transformStyles.js
Normal file
69
www/js/lib/transformStyles.js
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* transformCSS.js: Provides transformations in CSS of Wikipedia articles contained in the ZIM file
|
||||
* This allows the user to choose the presentation style for the page to be viewed.
|
||||
* Currently available are "mobile" and "desktop" display modes.
|
||||
*
|
||||
* Copyright 2017 Kiwix developers
|
||||
* 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 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
'use strict';
|
||||
define([], function () {
|
||||
|
||||
function toMobileCSS(html, zim, cc, css) {
|
||||
css += css.match(/-\/s\/css_modules\/content\.parsoid\.css/i) ? "" : '<link href="../-/s/css_modules/content.parsoid.css" rel="stylesheet" type="text/css">\r\n';
|
||||
css += css.match(/-\/s\/css_modules\/inserted_style_mobile\.css/i) ? "" : '<link href="../-/s/css_modules/inserted_style_mobile.css" rel="stylesheet" type="text/css">\r\n';
|
||||
css += css.match(/-\/s\/css_modules\/mobile\.css/i) ? "" : '<link href="../-/s/css_modules/mobile.css" rel="stylesheet" type="text/css">\r\n';
|
||||
if (cc || (zim == "desktop")) { //If user requested cached styles OR the ZIM does not contain mobile styles
|
||||
console.log(zim == "desktop" ? "Transforming display style to mobile..." : "Optimizing cached styhles for mobile display...");
|
||||
//Allow images to float right or left
|
||||
html = html.replace(/class\s*=\s*["']\s*thumb\s+tright\s*["']\s*/ig, 'style="float: right; clear: right; margin-left: 1.4em;"');
|
||||
html = html.replace(/class\s*=\s*["']\s*thumb\s+tleft\s*["']\s*/ig, 'style="float: left; clear: left; margin-right: 1.4em;"');
|
||||
//Add styling to image captions that is hard-coded in Wikipedia mobile
|
||||
html = html.replace(/class\s*=\s*["']\s*thumbcaption\s*["']\s*/ig, 'style="margin: 0.5em 0 0.5em; font-size: 0.8em; line-height: 1.5; padding: 0 !important; color: #54595d; width: auto !important;"');
|
||||
//If it's in desktop position, move info-box below lead paragraph like on Wikipedia mobile
|
||||
html = /<\/p>[\s\S]*?<table\s+[^>]*(?:infobox|vertical-navbox)/i.test(html) ? html : html.replace(/(<table\s+(?=[^>]*(?:infobox|vertical-navbox))[\s\S]+?<\/table>[^<]*)((?:<span\s*>\s*)?<p\b[^>]*>(?:(?=([^<]+))\3|<(?!p\b[^>]*>))*?<\/p>(?:<span\s*>)?)/i, "$2\r\n$1");
|
||||
//Set infobox styling hard-coded in Wikipedia mobile
|
||||
html = html.replace(/(table\s+(?=[^>]*class\s*=\s*["'][^"']*infobox)[^>]*style\s*=\s*["'][^"']+[^;'"]);?\s*["']/ig, '$1; position: relative; border: 1px solid #eaecf0; text-align: left; background-color: #f8f9fa;"');
|
||||
//Wrap <h2> tags in <div> to control bottom border width if there's an infobox
|
||||
html = html.match(/table\s+(?=[^>]*class\s*=\s*["'][^"']*infobox)/i) ? html.replace(/(<h2\s+[^<]*<\/h2>)/ig, '<div style="width: 60%;">$1</div>') : html;
|
||||
}
|
||||
return { html: html, css: css };
|
||||
}
|
||||
|
||||
function toDesktopCSS(html, zim, cc, css) {
|
||||
if (cc || (zim == "mobile")) { //If user requested cached styles OR the ZIM does not contain desktop styles
|
||||
console.log(zim == "mobile" ? "Transforming display style to desktop..." : "Optimizing cached styhles for desktop display...");
|
||||
//If it's in mobile position, move info-box above lead paragraph like on Wikipedia desktop
|
||||
//html = html.replace(/((?:<span\s*>\s*)?<p\b[^>]*>(?:(?=([^<]+))\2|<(?!p\b[^>]*>))*?<\/p>(?:<\/span\s*>)?[^<]*)([\s\S]*?)(<table\s*(?=[^>]*infobox)[\s\S]+?<\/table>)/i, "$4$3$1");
|
||||
html = html.replace(/((?:<span\s*>\s*)?<p\b[\s\S]+?)(<table\s*(?=[^>]*(?:infobox|vertical-navbox))[\s\S]+?<\/table>)/i, "$2\r\n$1");
|
||||
//Ensure white background colour
|
||||
html = html.replace(/class\s*=\s*["']\s*mw-body\s*["']\s*/ig, 'style="background-color: white; padding: 1em; border-width: 0px; max-width: 55.8em; margin: 0 auto 0 auto;"');
|
||||
//Void empty header title
|
||||
html = html.replace(/<h1\s*[^>]+titleHeading[^>]+>\s*<\/h1>\s*/ig, "");
|
||||
}
|
||||
return { html : html, css : css };
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions and classes exposed by this module
|
||||
*/
|
||||
return {
|
||||
toMobileCSS: toMobileCSS,
|
||||
toDesktopCSS: toDesktopCSS
|
||||
};
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user