mirror of
https://github.com/kiwix/kiwix-js-pwa.git
synced 2025-09-11 13:18:21 -04:00
* Open closest section when scrolling * Ensure sections inside closed sections are opened * Remove redundant comments * Update open-close algorithm to account for details-summary tags * Remove erroneous restryling and table caption issue * Restore functionality for IE11 * Check for details support (but doesn't work in Edge) * Provide option to open all sections * Add option in config to open all sections * Better method of opening all sections * Fix for use with Edge and simplify * Move closest function to util.js Former-commit-id: 08bf54c6f195f6e1b1d6bdc79bff4e498f1ea84a [formerly fd4a6bbe6a10a55b3b7d650df55ff6143e4924ee [formerly 232f2bacaf5d754697b33175ee1f0e7fb86902be]] Former-commit-id: b8766106786d4bcbffc05a635b1d4d2bbfac3c77 Former-commit-id: b57854d302f81170b33a44aeac54e5d93be27739
This commit is contained in:
parent
159286731e
commit
1f15d52b97
@ -3262,7 +3262,7 @@ sub, sup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content table caption {
|
.content table caption {
|
||||||
display: table-caption
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content table tbody {
|
.content table tbody {
|
||||||
|
@ -669,6 +669,11 @@
|
|||||||
<span class="checkmark"></span>
|
<span class="checkmark"></span>
|
||||||
<b>Enable opening articles in a separate browser tab</b> (slightly increases app's memory usage)
|
<b>Enable opening articles in a separate browser tab</b> (slightly increases app's memory usage)
|
||||||
</label>
|
</label>
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox" name="openAllSections" id="openAllSectionsCheck">
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
<b>Open all headings</b> (<i>for WikiMedia ZIMs</i>: sets the state of collapsible headings on article load)
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
166
www/js/app.js
166
www/js/app.js
@ -83,7 +83,6 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
ToCList.style.maxHeight = ~~(window.innerHeight * 0.75) + 'px';
|
ToCList.style.maxHeight = ~~(window.innerHeight * 0.75) + 'px';
|
||||||
ToCList.style.marginLeft = ~~(window.innerWidth / 2) - ~~(window.innerWidth * 0.16) + 'px';
|
ToCList.style.marginLeft = ~~(window.innerWidth / 2) - ~~(window.innerWidth * 0.16) + 'px';
|
||||||
}
|
}
|
||||||
removePageMaxWidth();
|
|
||||||
if (window.outerWidth <= 470) {
|
if (window.outerWidth <= 470) {
|
||||||
document.getElementById('dropup').classList.remove('col-xs-4');
|
document.getElementById('dropup').classList.remove('col-xs-4');
|
||||||
document.getElementById('dropup').classList.add('col-xs-3');
|
document.getElementById('dropup').classList.add('col-xs-3');
|
||||||
@ -364,6 +363,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
btnContinue.disabled = false;
|
btnContinue.disabled = false;
|
||||||
btnContinue.innerHTML = "Continue";
|
btnContinue.innerHTML = "Continue";
|
||||||
var printModalContent = document.getElementById('print-modal-content');
|
var printModalContent = document.getElementById('print-modal-content');
|
||||||
|
openAllSections(true);
|
||||||
printModalContent.classList.remove('dark');
|
printModalContent.classList.remove('dark');
|
||||||
var determinedTheme = params.cssUITheme;
|
var determinedTheme = params.cssUITheme;
|
||||||
determinedTheme = determinedTheme == 'auto' ? cssUIThemeGetOrSet('auto', true) : determinedTheme;
|
determinedTheme = determinedTheme == 'auto' ? cssUIThemeGetOrSet('auto', true) : determinedTheme;
|
||||||
@ -1283,6 +1283,11 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
docStyle.margin = "0 auto";
|
docStyle.margin = "0 auto";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
document.getElementById('openAllSectionsCheck').addEventListener('click', function (e) {
|
||||||
|
params.openAllSections = this.checked;
|
||||||
|
cookies.setItem('openAllSections', params.openAllSections, Infinity);
|
||||||
|
openAllSections();
|
||||||
|
});
|
||||||
$('input:radio[name=useMathJax]').on('click', function (e) {
|
$('input:radio[name=useMathJax]').on('click', function (e) {
|
||||||
params.useMathJax = /true/i.test(this.value);
|
params.useMathJax = /true/i.test(this.value);
|
||||||
cookies.setItem('useMathJax', params.useMathJax, Infinity);
|
cookies.setItem('useMathJax', params.useMathJax, Infinity);
|
||||||
@ -2734,6 +2739,8 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
removePageMaxWidth();
|
removePageMaxWidth();
|
||||||
setupTableOfContents();
|
setupTableOfContents();
|
||||||
listenForSearchKeys();
|
listenForSearchKeys();
|
||||||
|
openAllSections();
|
||||||
|
setupHeadings();
|
||||||
// The content is ready : we can hide the spinner
|
// The content is ready : we can hide the spinner
|
||||||
setTab();
|
setTab();
|
||||||
checkToolbar();
|
checkToolbar();
|
||||||
@ -3026,9 +3033,12 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
htmlArticle = htmlArticle.replace(/background:url\([^)]+\)[^;}]*/ig, '');
|
htmlArticle = htmlArticle.replace(/background:url\([^)]+\)[^;}]*/ig, '');
|
||||||
|
|
||||||
//Remove the details polyfill: it's poor and doesn't recognize Edgium
|
//Remove the details polyfill: it's poor and doesn't recognize Edgium
|
||||||
htmlArticle = htmlArticle.replace(/<script\b[^<]+details_polyfill\.js[^<]+<\/script>\s*/i, '');
|
htmlArticle = htmlArticle.replace(/<script\b[^<]+details[^"']*polyfill\.js[^<]+<\/script>\s*/i, '');
|
||||||
//And make sure all sections are open
|
// And make sure all sections are open - this doesn't work, because they are all subsequently closed by JS
|
||||||
htmlArticle = htmlArticle.replace(/(<details\b(?![^>]+\sopen)[^>]+)>/ig, '$1 open>');
|
// htmlArticle = htmlArticle.replace(/(<details\b(?![^>]+\sopen)[^>]+)>/ig, '$1 open>');
|
||||||
|
// Remove the script.js that closes top-level sections if user requested this
|
||||||
|
if (params.openAllSections) htmlArticle = htmlArticle.replace(/<script\b[^>]+-\/j\/js_modules\/script\.js"[^<]*<\/script>/i, "");
|
||||||
|
|
||||||
|
|
||||||
//Remove empty div that causes layout issues in desktop style
|
//Remove empty div that causes layout issues in desktop style
|
||||||
htmlArticle = htmlArticle.replace(/<div\b[^>]*?>\s*<\/div>\s*/, '');
|
htmlArticle = htmlArticle.replace(/<div\b[^>]*?>\s*<\/div>\s*/, '');
|
||||||
@ -3315,46 +3325,8 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
|
|
||||||
setupTableOfContents();
|
setupTableOfContents();
|
||||||
|
|
||||||
// Attach listeners to headers to open-close following sections
|
setupHeadings();
|
||||||
var eles = ["H2", "H3"];
|
|
||||||
for (var i = 0; i < eles.length; i++) {
|
|
||||||
// Process headers
|
|
||||||
var collection = docBody.getElementsByTagName(eles[i]);
|
|
||||||
for (var j = 0; j < collection.length; j++) {
|
|
||||||
// Prevent heading from getting selected when clicking on it
|
|
||||||
collection[j].style.userSelect = 'none';
|
|
||||||
collection[j].style.msUserSelect = 'none';
|
|
||||||
//collection[j].classList.add("open-block");
|
|
||||||
collection[j].addEventListener("click", function (e) {
|
|
||||||
var that = e.currentTarget;
|
|
||||||
var topTag = that.tagName;
|
|
||||||
that.classList.toggle("open-block");
|
|
||||||
var nextElement = that.nextElementSibling;
|
|
||||||
that = that.parentNode;
|
|
||||||
if (!nextElement) nextElement = that.nextElementSibling;
|
|
||||||
if (!nextElement) return;
|
|
||||||
// Decide toggle direction based on first sibling element
|
|
||||||
var toggleDirection = nextElement.classList.contains("collapsible-block") && !nextElement.classList.contains("open-block") || nextElement.style.display == "none" ? "block" : "none";
|
|
||||||
//if (nextElement.style.display == "none") {
|
|
||||||
// this.innerHTML += "<br />";
|
|
||||||
//} else {
|
|
||||||
// this.innerHTML = this.innerHTML.replace(/<br\s*\/?>$/i, "");
|
|
||||||
//}
|
|
||||||
while (nextElement && !~nextElement.tagName.indexOf(topTag) && !~nextElement.tagName.indexOf("H1")) {
|
|
||||||
if (nextElement.classList.contains("collapsible-block")) {
|
|
||||||
nextElement.classList.toggle("open-block");
|
|
||||||
} else if (that.classList.contains("collapsible-block")) {
|
|
||||||
// We're in a document that has been marked up, but we've encountered one that doesn't have markup, so stop
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
nextElement.style.display = toggleDirection;
|
|
||||||
}
|
|
||||||
that = nextElement;
|
|
||||||
nextElement = that.nextElementSibling;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Process endnote references (so they open the reference block if closed)
|
// Process endnote references (so they open the reference block if closed)
|
||||||
var refs = docBody.getElementsByClassName("mw-reflink-text");
|
var refs = docBody.getElementsByClassName("mw-reflink-text");
|
||||||
if (refs) {
|
if (refs) {
|
||||||
@ -3396,10 +3368,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Hide top-level scrolling -- gets rid of interfering useless scroll bar, but re-enable for Config and About pages
|
openAllSections();
|
||||||
// document.getElementById('search-article').scrollTop = 0;
|
|
||||||
// document.getElementById('search-article').style.overflow = "hidden";
|
|
||||||
|
|
||||||
var makeLink = uiUtil.makeReturnLink(dirEntry.getTitleOrUrl());
|
var makeLink = uiUtil.makeReturnLink(dirEntry.getTitleOrUrl());
|
||||||
var linkListener = eval(makeLink);
|
var linkListener = eval(makeLink);
|
||||||
//Prevent multiple listeners being attached on each browse
|
//Prevent multiple listeners being attached on each browse
|
||||||
@ -3419,17 +3388,6 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
// Pattern to match a local anchor in an href even if prefixed by escaped url; will also match # on its own
|
// Pattern to match a local anchor in an href even if prefixed by escaped url; will also match # on its own
|
||||||
var regexpLocalAnchorHref = new RegExp('^(?:#|' + escapedUrl + '#)([^#]*$)');
|
var regexpLocalAnchorHref = new RegExp('^(?:#|' + escapedUrl + '#)([^#]*$)');
|
||||||
|
|
||||||
// Set state of collapsible sections
|
|
||||||
if (params.openAllSections === true) {
|
|
||||||
var collapsedBlocks = iframeContentDocument.querySelectorAll('details:not([open]), .collapsible-block:not(.open-block), .collapsible-heading:not(.open-block)');
|
|
||||||
for (var x = collapsedBlocks.length; x--;) {
|
|
||||||
if (/DETAILS/.test(collapsedBlocks[x].tagName)) {
|
|
||||||
collapsedBlocks[x].open = true;
|
|
||||||
} else {
|
|
||||||
collapsedBlocks[x].classList.add('open-block');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// function insertAnchorsJQuery
|
// function insertAnchorsJQuery
|
||||||
Array.prototype.slice.call(iframeContentDocument.querySelectorAll('a, area')).forEach(function (anchor) {
|
Array.prototype.slice.call(iframeContentDocument.querySelectorAll('a, area')).forEach(function (anchor) {
|
||||||
// Attempts to access any properties of 'this' with malformed URLs causes app crash in Edge/UWP [kiwix-js #430]
|
// Attempts to access any properties of 'this' with malformed URLs causes app crash in Edge/UWP [kiwix-js #430]
|
||||||
@ -3664,6 +3622,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
var innerDoc = iframe.contentDocument;
|
var innerDoc = iframe.contentDocument;
|
||||||
var tableOfContents = new uiUtil.toc(innerDoc);
|
var tableOfContents = new uiUtil.toc(innerDoc);
|
||||||
var headings = tableOfContents.getHeadingObjects();
|
var headings = tableOfContents.getHeadingObjects();
|
||||||
|
|
||||||
document.getElementById('dropup').style.fontSize = ~~(params.relativeUIFontSize * 0.14) + "px";
|
document.getElementById('dropup').style.fontSize = ~~(params.relativeUIFontSize * 0.14) + "px";
|
||||||
var dropup = "";
|
var dropup = "";
|
||||||
headings.forEach(function (heading) {
|
headings.forEach(function (heading) {
|
||||||
@ -3681,14 +3640,95 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'cook
|
|||||||
ToCList.innerHTML = dropup;
|
ToCList.innerHTML = dropup;
|
||||||
Array.prototype.slice.call(ToCList.getElementsByTagName('a')).forEach(function (listElement) {
|
Array.prototype.slice.call(ToCList.getElementsByTagName('a')).forEach(function (listElement) {
|
||||||
listElement.addEventListener('click', function () {
|
listElement.addEventListener('click', function () {
|
||||||
var iframeWin = document.getElementById('articleContent').contentWindow;
|
var sectionEle = innerDoc.getElementById(this.dataset.headingId);
|
||||||
iframeWin.location.hash = this.dataset.headingId;
|
var i;
|
||||||
iframeWin.scrollBy(0, -5);
|
var csec = util.closest(sectionEle, 'details, section');
|
||||||
|
csec = csec && /DETAILS|SECTION/.test(csec.parentElement.tagName) ? csec.parentElement : csec;
|
||||||
|
openAllSections(true, csec);
|
||||||
|
// if (csec) {
|
||||||
|
// if (/DETAILS/i.test(csec.parentElement.tagName)) csec = csec.parentElement;
|
||||||
|
// csec.open = true;
|
||||||
|
// var closedEles = csec.querySelectorAll('details:not([open])');
|
||||||
|
// for (i = closedEles.length; i--;) {
|
||||||
|
// closedEles[i].open = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// csec = closest(sectionEle, '[style*=display]');
|
||||||
|
// if (csec && csec.style.display === 'none') {
|
||||||
|
// var hiddenEles = csec.parentElement.querySelectorAll('[style*=display]');
|
||||||
|
// for (i = hiddenEles.length; i--;) {
|
||||||
|
// if (hiddenEles[i].style.display === 'none') hiddenEles[i].style.display = '';
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Scroll to element
|
||||||
|
sectionEle.scrollIntoView();
|
||||||
|
// Scrolling up then down ensures that the toolbars show according to user settings
|
||||||
|
iframe.contentWindow.scrollBy(0, -5);
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
iframeWin.scrollBy(0, 5);
|
iframe.contentWindow.scrollBy(0, 5);
|
||||||
}, 250);
|
}, 250);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the state of collapsible sections for the iframe document, or for the given node
|
||||||
|
* @param {Boolean} override An optional value that overrides params.openAllSections (true to open, false to close)
|
||||||
|
* @param {Node} node An optional node within which elements will be opened or closed (this will normally be a details element)
|
||||||
|
*/
|
||||||
|
// Sets state of collapsible sections
|
||||||
|
function openAllSections(override, node) {
|
||||||
|
var open = override === false ? false : override || params.openAllSections;
|
||||||
|
var container = node || frames[0].frameElement.contentDocument;
|
||||||
|
var blocks = container.querySelectorAll('details, section:not([data-mw-section-id="0"]), .collapsible-block, .collapsible-heading');
|
||||||
|
if (node) processSection(open, node);
|
||||||
|
for (var x = blocks.length; x--;) {
|
||||||
|
processSection(open, blocks[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processSection(open, node) {
|
||||||
|
if (/DETAILS|SECTION/.test(node.tagName)) {
|
||||||
|
if (open) node.setAttribute('open', '');
|
||||||
|
else node.removeAttribute('open');
|
||||||
|
if (typeof HTMLDetailsElement === 'undefined' || node.tagName === 'SECTION') {
|
||||||
|
var children = node.children;
|
||||||
|
for (var y = children.length; y--;) {
|
||||||
|
if (/SUMMARY|H\d/.test(children[y].tagName)) continue;
|
||||||
|
if (open) {
|
||||||
|
if (/DETAILS|SECTION/.test(children[y].tagName)) children[y].setAttribute('open', '');
|
||||||
|
children[y].style.removeProperty('display');
|
||||||
|
} else {
|
||||||
|
if (/DETAILS|SECTION/.test(children[y].tagName)) children[y].removeAttribute('open');
|
||||||
|
children[y].style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (open) node.classList.add('open-block');
|
||||||
|
else node.classList.remove('open-block');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach listeners to headers to open-close following sections
|
||||||
|
function setupHeadings() {
|
||||||
|
var headings = frames[0].frameElement.contentDocument.querySelectorAll('h2, h3, h4, h5');
|
||||||
|
for (var i = headings.length; i--;) {
|
||||||
|
// Prevent heading from being selected when user clicks on it
|
||||||
|
headings[i].style.userSelect = 'none';
|
||||||
|
headings[i].style.msUserSelect = 'none';
|
||||||
|
headings[i].addEventListener('click', function(e) {
|
||||||
|
// Override the built-in simplistic polyfill
|
||||||
|
e.preventDefault();
|
||||||
|
var that = e.currentTarget;
|
||||||
|
var detailsEl = util.closest(that, 'details, section');
|
||||||
|
if (detailsEl) {
|
||||||
|
var toggle = !detailsEl.hasAttribute('open');
|
||||||
|
openAllSections(toggle, detailsEl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
params.preloadAllImages = function () {
|
params.preloadAllImages = function () {
|
||||||
|
@ -122,6 +122,7 @@ document.getElementById('removePageMaxWidthCheck').checked = params.removePageMa
|
|||||||
document.getElementById('removePageMaxWidthCheck').indeterminate = params.removePageMaxWidth == "auto";
|
document.getElementById('removePageMaxWidthCheck').indeterminate = params.removePageMaxWidth == "auto";
|
||||||
document.getElementById('removePageMaxWidthCheck').readOnly = params.removePageMaxWidth == "auto";
|
document.getElementById('removePageMaxWidthCheck').readOnly = params.removePageMaxWidth == "auto";
|
||||||
document.getElementById('pageMaxWidthState').innerHTML = (params.removePageMaxWidth == "auto" ? "auto" : params.removePageMaxWidth ? "always" : "never");
|
document.getElementById('pageMaxWidthState').innerHTML = (params.removePageMaxWidth == "auto" ? "auto" : params.removePageMaxWidth ? "always" : "never");
|
||||||
|
document.getElementById('openAllSectionsCheck').checked = params.openAllSections;
|
||||||
document.getElementById('cssUIDarkThemeCheck').checked = params.cssUITheme == "dark"; // Will be true, or false if light or auto
|
document.getElementById('cssUIDarkThemeCheck').checked = params.cssUITheme == "dark"; // Will be true, or false if light or auto
|
||||||
document.getElementById('cssUIDarkThemeCheck').indeterminate = params.cssUITheme == "auto";
|
document.getElementById('cssUIDarkThemeCheck').indeterminate = params.cssUITheme == "auto";
|
||||||
document.getElementById('cssUIDarkThemeCheck').readOnly = params.cssUITheme == "auto";
|
document.getElementById('cssUIDarkThemeCheck').readOnly = params.cssUITheme == "auto";
|
||||||
|
@ -673,6 +673,16 @@ define(['q', 'filecache'], function(Q, FileCache) {
|
|||||||
el && (fn(el) ? el : getClosestBack(el.parentNode, fn));
|
el && (fn(el) ? el : getClosestBack(el.parentNode, fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a closest function alternative because IE11 and others do not support closest
|
||||||
|
function closest (ele, s) {
|
||||||
|
var cele = ele;
|
||||||
|
var cmatches = Element.prototype.matches || Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
|
||||||
|
do {
|
||||||
|
if (cmatches.call(cele, s)) return cele;
|
||||||
|
cele = cele.parentElement || cele.parentNode;
|
||||||
|
} while (cele !== null && cele.nodeType === 1);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functions and classes exposed by this module
|
* Functions and classes exposed by this module
|
||||||
@ -695,6 +705,7 @@ define(['q', 'filecache'], function(Q, FileCache) {
|
|||||||
matchInner: matchInner,
|
matchInner: matchInner,
|
||||||
Hilitor: Hilitor,
|
Hilitor: Hilitor,
|
||||||
getClosestForward: getClosestForward,
|
getClosestForward: getClosestForward,
|
||||||
getClosestBack: getClosestBack
|
getClosestBack: getClosestBack,
|
||||||
|
closest: closest
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user