Fix touch zoom on the iframe

Former-commit-id: 16ff820bd12a092ec1c842c20501ea4355aebed6 [formerly 11e37f7e97fdbd9415bb4a7860614a2fcc1cd322] [formerly 099eca1be67b8a87329323cdbd6136400ee57624] [formerly 288bc52cbe60a687354b9d043ea524798ae3cd2f [formerly 8ed903b4dc0530f27f057fc275da5bf764252e28 [formerly d5bd2f6e56c53c89218b39a54543217f1ef9422d]]]
Former-commit-id: 18b7afb3356dc49f38fb013ac093046da435014a [formerly 1fca164bfde88b3e3592d629e083bbc6107f7785 [formerly 5be0911614cd22b62d7222521c606f88004aa90b]]
Former-commit-id: 4aa0d376117fe298aa35adc98d1f82dea583429e [formerly 136016ba4eb8c36f626f0214e44ca4d2dbdc6d65]
Former-commit-id: 1360ec34f6d118c0c2cb6887c5b521644e83d39f
This commit is contained in:
Jaifroid 2021-07-10 15:10:52 +01:00
parent 0252d19ff9
commit 1028962d79
4 changed files with 791 additions and 674 deletions

View File

@ -4,6 +4,8 @@
* FEATURE: (Experimental) PWA is paritcipating in File Handling API origin trial
* FIX: Bug which failed to detect images correctly in a new tab
* FIX: Touch-zoom of contents of iframe no longer blanks part of the display
* FIX: Broken zoom of contents of iframe (with UI buttons) in Internet Explorer
## Release 1.4.2

View File

@ -125,6 +125,8 @@
<li>Improve handover from local code to PWA code in UWP app to prevent rogue error message</li>
<li>Improve page composition timing for non-MS browsers</li>
<li>Fix bug which failed to detect images correctly in new tab</li>
<li>Touch-zoom of contents of iframe no longer blanks part of the display</li>
<li>Fixed broken zoom of contents of iframe (with UI buttons) in Internet Explorer</li>
</ul>
<p><a href="https://github.com/kiwix/kiwix-js-windows/blob/master/CHANGELOG.md" target="_blank">Full changelog...<img src="I/s/Icon_External_Link.png"></a></p>
</div>
@ -830,7 +832,7 @@
<!-- Bootstrap alert box -->
<div id="alertBoxHeader" style="text-align: center; position: relative; z-index: 1; display: none;"></div>
<!-- Attribute nwdisable prevents scripts in iframe accessing the nwjs node APIs -->
<iframe id="articleContent" class="articleIFrame" nwdisable></iframe>
<iframe id="articleContent" class="articleIFrame" style="touch-action:none" nwdisable></iframe>
</article>
<footer id="footer">
<!-- Bootstrap alert box -->

View File

@ -86,8 +86,9 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'sett
header.style.transform = 'translateY(0)';
document.getElementById('footer').style.transform = 'translateY(0)';
iframe.style.transform = 'translateY(-1px)';
//iframe.style.height = window.innerHeight - navbarHeight + "px";
iframe.style.height = window.innerHeight + 'px';
// iframe.style.height = window.innerHeight + 'px';
// DEV: if we set the iframe with clientHeight, then it takes into account any zoom
iframe.style.height = document.documentElement.clientHeight + 'px';
//Re-enable top-level scrolling
scrollbox.style.height = window.innerHeight - navbarHeight + 'px';
@ -127,7 +128,10 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'sett
}
checkToolbar();
}
$(document).ready(resizeIFrame);
$(document).ready(function() {
resizeIFrame();
// uiUtil.initTouchZoom();
});
$(window).resize(function () {
resizeIFrame();
// We need to load any images exposed by the resize
@ -605,14 +609,16 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'sett
params.relativeFontSize += 5;
var doc = document.getElementById('articleContent').contentDocument;
var docElStyle = doc.documentElement.style;
var zoomProp = 'zoom' in docElStyle ? 'zoom' : 'fontSize';
// IE11 and Firefox need to use fontSize on the body style
var zoomProp = '-ms-zoom' in docElStyle ? 'fontSize' : 'zoom' in docElStyle ? 'zoom' : 'fontSize';
docElStyle = zoomProp === 'fontSize' ? doc.body.style : docElStyle;
docElStyle[zoomProp] = /-\/static\/main\.css/.test(doc.head.innerHTML) && zoomProp === 'fontSize' ? params.relativeFontSize * 1.5 + "%" : params.relativeFontSize + "%";
document.getElementById('lblZoom').innerHTML = params.relativeFontSize + "%";
document.getElementById('lblZoom').style = "position:absolute;right: " + window.innerWidth / 5 + "px;bottom:50px;z-index:50;";
var lblZoom = document.getElementById('lblZoom');
lblZoom.innerHTML = params.relativeFontSize + "%";
lblZoom.style.cssText = "position:absolute;right:" + window.innerWidth / 5 + "px;bottom:50px;z-index:50;";
setTimeout(function () {
document.getElementById('lblZoom').innerHTML = "";
}, 1000);
lblZoom.innerHTML = "";
}, 2000);
settingsStore.setItem('relativeFontSize', params.relativeFontSize, Infinity);
document.getElementById('articleContent').contentWindow.focus();
});
@ -620,14 +626,15 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'sett
params.relativeFontSize -= 5;
var doc = document.getElementById('articleContent').contentDocument;
var docElStyle = doc.documentElement.style;
var zoomProp = 'zoom' in docElStyle ? 'zoom' : 'fontSize';
var zoomProp = '-ms-zoom' in docElStyle ? 'fontSize' : 'zoom' in docElStyle ? 'zoom' : 'fontSize';
docElStyle = zoomProp === 'fontSize' ? doc.body.style : docElStyle;
docElStyle[zoomProp] = /-\/static\/main\.css/.test(doc.head.innerHTML) && zoomProp === 'fontSize' ? params.relativeFontSize * 1.5 + "%" : params.relativeFontSize + "%";
document.getElementById('lblZoom').innerHTML = params.relativeFontSize + "%";
document.getElementById('lblZoom').style = "position:absolute;right: " + window.innerWidth / 4 + "px;bottom:50px;z-index:50;";
var lblZoom = document.getElementById('lblZoom');
lblZoom.innerHTML = params.relativeFontSize + "%";
lblZoom.style.cssText = "position:absolute;right:" + window.innerWidth / 4 + "px;bottom:50px;z-index:50;";
setTimeout(function () {
document.getElementById('lblZoom').innerHTML = "";
}, 1000);
lblZoom.innerHTML = "";
}, 2000);
settingsStore.setItem('relativeFontSize', params.relativeFontSize, Infinity);
document.getElementById('articleContent').contentWindow.focus();
});
@ -1260,7 +1267,7 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'sett
footerDim = footer.getBoundingClientRect();
var doc = iframe.contentDocument ? iframe.contentDocument.documentElement : null;
header.style.transition = "transform 500ms";
iframe.style.transition = "transform 500ms";
// iframe.style.transition = "transform 500ms";
if (doc) doc.style.transition = "transform 500ms";
footer.style.transition = "transform 500ms";
iframe.style.zIndex = 0;
@ -3138,9 +3145,10 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'sett
zimType = /-\/static\/main\.css/i.test(doc.head.innerHTML) ? "desktop-stx" : zimType; //Support stackexchange
zimType = /minerva|mobile[^"']*\.css/i.test(doc.head.innerHTML) ? "mobile" : zimType;
var docElStyle = articleDocument.style;
var zoomProp = 'zoom' in docElStyle ? 'zoom' : 'fontSize';
var zoomProp = '-ms-zoom' in docElStyle ? 'fontSize' : 'zoom' in docElStyle ? 'zoom' : 'fontSize';
docElStyle = zoomProp === 'fontSize' ? docBody.style : docElStyle;
docElStyle[zoomProp] = ~zimType.indexOf("stx") && zoomProp === 'fontSize' ? params.relativeFontSize * 1.5 + "%" : params.relativeFontSize + "%";
if (appstate.target === 'iframe') uiUtil.initTouchZoom(articleDocument, docBody);
checkToolbar();
//Set page width according to user preference
removePageMaxWidth();
@ -3796,13 +3804,14 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'sett
}
//Set relative font size + Stackexchange-family multiplier
var docElStyle = articleDocument.style;
var zoomProp = 'zoom' in docElStyle ? 'zoom' : 'fontSize';
var zoomProp = '-ms-zoom' in docElStyle ? 'fontSize' : 'zoom' in docElStyle ? 'zoom' : 'fontSize';
docElStyle = zoomProp === 'fontSize' ? docBody.style : docElStyle;
docElStyle[zoomProp] = ~zimType.indexOf("stx") && zoomProp === 'fontSize' ? params.relativeFontSize * 1.5 + "%" : params.relativeFontSize + "%";
//Set page width according to user preference
removePageMaxWidth();
setupHeadings();
listenForNavigationKeys();
if (appstate.target === 'iframe') uiUtil.initTouchZoom(articleDocument, docBody);
// Process endnote references (so they open the reference block if closed)
var refs = docBody.getElementsByClassName("mw-reflink-text");
if (refs) {
@ -4230,7 +4239,9 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'util', 'cache', 'images', 'sett
var event = e;
// The link will be clicked if the user long-presses for more than 800ms (if the option is enabled)
setTimeout(function () {
if (!a.touched || a.newcontainer) return;
// DEV: appstate.startVector indicates that the app is processing a touch zoom event, so we cancel any new windows
// see uiUtil.pointermove_handler
if (!a.touched || a.newcontainer || appstate.startVector) return;
e.preventDefault();
a.newcontainer = true;
onDetectedClick(event);

View File

@ -626,6 +626,107 @@ define(rqDef, function() {
return string;
}
/**
* Initiates pointer touch events on the given element in order to set the zoom level
*
* @param {Element} element The element to which the pointer events should be attached
* @param {Node} container The node to which the pointer events should be applied, if different
*/
function initTouchZoom(element, container) {
container = container || element;
// Global vars to cache event state
appstate.evCache = new Array();
appstate.prevDiff = -1;
// Set initial element transforms
var contentWin = element.ownerDocument.defaultView || element.ownerDocument.parentWindow;
container.style.transformOrigin = 'left top'; // DEV: To support RTL languages, this should be 'right top'
appstate.windowScale = 1;
appstate.sessionScale = 1;
appstate.startVector = null;
// Install event handlers for the pointer target
element.onpointerdown = pointerdown_handler;
element.onpointermove = function(event) {
pointermove_handler(event, container, contentWin);
};
// Use same handler for pointer{up,cancel,out,leave} events since
// the semantics for these events - in this app - are the same.
element.onpointerup = pointerup_handler;
element.onpointercancel = pointerup_handler;
element.onpointerout = pointerup_handler;
element.onpointerleave = pointerup_handler;
}
function pointerdown_handler(ev) {
// The pointerdown event signals the start of a touch interaction.
// This event is cached to support 2-finger gestures
appstate.evCache.push(ev);
// console.debug('pointerDown', ev);
}
function pointermove_handler(ev, cont, win) {
// This function implements a 2-pointer horizontal pinch/zoom gesture.
// console.debug('pointerMove', ev);
// Find this event in the cache and update its record with this event
for (var i = 0; i < appstate.evCache.length; i++) {
if (ev.pointerId == appstate.evCache[i].pointerId) {
appstate.evCache[i] = ev;
break;
}
}
// If two pointers are down, check for pinch gestures
if (appstate.evCache.length == 2) {
ev.preventDefault();
// Calculate the distance between the two pointers
var x0 = appstate.evCache[0].clientX;
var y0 = appstate.evCache[0].clientY;
var x1 = appstate.evCache[1].clientX;
var y1 = appstate.evCache[1].clientY;
var curDiff = Math.abs(Math.sqrt(Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)));
// console.debug('Current difference: ' + curDiff);
if (appstate.prevDiff > 0) {
if (appstate.startVector === null) {
appstate.startVector = curDiff;
appstate.scrollYStart = win.scrollY / appstate.windowScale;
// console.debug('scrollYStart: ' + appstate.scrollYStart);
}
appstate.windowScale = appstate.sessionScale * curDiff / appstate.startVector;
// console.debug('winScrollY: ' + win.scrollY);
// console.debug('winScrollX: ' + win.scrollX);
// console.debug('x0x1 mean: ' + (x0 + x1)/2);
// console.debug('y0y1 mean: ' + (y0 + y1)/2);
cont.style.transform = 'scale(' + appstate.windowScale + ')';
win.scrollTo(win.scrollX, appstate.scrollYStart * appstate.windowScale);
}
// Cache the distance for the next move event
appstate.prevDiff = curDiff;
}
}
function pointerup_handler(ev) {
// console.debug(ev.type, ev);
// Remove this pointer from the cache
remove_event(ev);
// If the number of pointers down is less than two then reset diff tracker
if (appstate.evCache.length < 2) {
appstate.prevDiff = -1;
}
}
function remove_event(ev) {
// Remove this event from the target's cache
for (var i = 0; i < appstate.evCache.length; i++) {
if (appstate.evCache[i].pointerId == ev.pointerId) {
appstate.evCache.splice(i, 1);
break;
}
}
appstate.startVector = null;
appstate.sessionScale = appstate.windowScale;
}
// If global variable webpMachine was defined, then we need to initialize the WebP Polyfill
if (webpMachine) webpMachine = new webpHero.WebpMachine();
@ -651,6 +752,7 @@ define(rqDef, function() {
extractHTML: extractHTML,
systemAlert: systemAlert,
checkServerIsAccessible: checkServerIsAccessible,
htmlEscapeChars: htmlEscapeChars
htmlEscapeChars: htmlEscapeChars,
initTouchZoom: initTouchZoom
};
});