From e2c77d6f3aa26e0f575c66f325a60b30c90de463 Mon Sep 17 00:00:00 2001 From: Ali Dubaisi Date: Sat, 13 Jul 2019 02:58:54 +0300 Subject: [PATCH] Major RTL fixes --- src/contents.js | 11 ++--- src/layout.js | 2 +- src/managers/continuous/index.js | 46 ++++++++++++++----- src/managers/default/index.js | 78 ++++++++++++++++++++++++++------ src/packaging.js | 16 ++++++- 5 files changed, 121 insertions(+), 32 deletions(-) diff --git a/src/contents.js b/src/contents.js index be6e5fc1f..98305a871 100644 --- a/src/contents.js +++ b/src/contents.js @@ -578,10 +578,10 @@ class Contents { if(range) { try { if (!range.endContainer || - (range.startContainer == range.endContainer + (range.startContainer == range.endContainer && range.startOffset == range.endOffset)) { // If the end for the range is not set, it results in collapsed becoming - // true. This in turn leads to inconsistent behaviour when calling + // true. This in turn leads to inconsistent behaviour when calling // getBoundingRect. Wrong bounds lead to the wrong page being displayed. // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/15684911/ let pos = range.startContainer.textContent.indexOf(" ", range.startOffset); @@ -995,7 +995,7 @@ class Contents { * @param {number} columnWidth * @param {number} gap */ - columns(width, height, columnWidth, gap){ + columns(width, height, columnWidth, gap, dir){ let COLUMN_AXIS = prefixed("column-axis"); let COLUMN_GAP = prefixed("column-gap"); let COLUMN_WIDTH = prefixed("column-width"); @@ -1006,9 +1006,8 @@ class Contents { this.layoutStyle("paginated"); - // Fix body width issues if rtl is only set on body element - if (this.content.dir === "rtl") { - this.direction("rtl"); + if (dir === "rtl") { + this.direction(dir); } this.width(width); diff --git a/src/layout.js b/src/layout.js index 46cbfc13f..977d48280 100644 --- a/src/layout.js +++ b/src/layout.js @@ -195,7 +195,7 @@ class Layout { if (this.name === "pre-paginated") { formating = contents.fit(this.columnWidth, this.height); } else if (this._flow === "paginated") { - formating = contents.columns(this.width, this.height, this.columnWidth, this.gap); + formating = contents.columns(this.width, this.height, this.columnWidth, this.gap, this.settings.direction); } else { // scrolled formating = contents.size(this.width, null); } diff --git a/src/managers/continuous/index.js b/src/managers/continuous/index.js index 7f6406ed0..706755864 100644 --- a/src/managers/continuous/index.js +++ b/src/managers/continuous/index.js @@ -265,20 +265,34 @@ class ContinuousViewManager extends DefaultViewManager { } }; + //Horizontal negative scrooling + if (horizontal && rtl && this.settings.rtlScrollType === "negative") { - if (offset + visibleLength + delta >= contentLength) { - if (horizontal && rtl) { - prepend(); - } else { - append(); + if (offset - delta <= (-1 * contentLength)) { + append(); + } + + if (offset + delta > 0) { + prepend(); } + } + //default scrooling + else { + if (offset + visibleLength + delta >= contentLength) { + if (horizontal && rtl) { + prepend(); + } else { + append(); + } + } - if (offset - delta < 0 ) { - if (horizontal && rtl) { - append(); - } else { - prepend(); + if (offset - delta < 0) { + if (horizontal && rtl) { + append(); + } else { + prepend(); + } } } @@ -355,7 +369,17 @@ class ContinuousViewManager extends DefaultViewManager { if(this.settings.axis === "vertical") { this.scrollTo(0, prevTop - bounds.height, true); } else { - this.scrollTo(prevLeft - Math.floor(bounds.width), 0, true); + if(this.settings.direction === 'rtl') { + if (this.settings.rtlScrollType === "default") { + this.scrollTo(prevLeft, 0, true); + } + else { + this.scrollTo(prevLeft + Math.floor(bounds.width), 0, true); + } + } + else { + this.scrollTo(prevLeft - Math.floor(bounds.width), 0, true); + } } } diff --git a/src/managers/default/index.js b/src/managers/default/index.js index f5ddf96cb..d6a84b07e 100644 --- a/src/managers/default/index.js +++ b/src/managers/default/index.js @@ -60,6 +60,29 @@ class DefaultViewManager { this.settings.size = size; + //Detect RTL scroll type + var definer = document.createElement('div'); + definer.style.position = "absolute"; + definer.style.width = "1px"; + definer.style.height = "1px"; + definer.style.overflow = "scroll"; + definer.dir="rtl"; + definer.appendChild(document.createTextNode('A')); + + document.body.appendChild(definer); + var type = 'reverse'; + + if (definer.scrollLeft > 0) { + type = 'default'; + } else { + definer.scrollLeft = 1; + if (definer.scrollLeft === 0) { + type = 'negative'; + } + } + document.body.removeChild(definer); + this.settings.rtlScrollType = type; + // Save the stage this.stage = new Stage({ width: size.width, @@ -423,13 +446,25 @@ class DefaultViewManager { this.scrollLeft = this.container.scrollLeft; - left = this.container.scrollLeft; + if (this.settings.rtlScrollType === "default"){ + left = this.container.scrollLeft; - if(left > 0) { - this.scrollBy(this.layout.delta, 0, true); - } else { - next = this.views.last().section.next(); - } + if (left > 0) { + this.scrollBy(this.layout.delta, 0, true); + } else { + next = this.views.last().section.next(); + } + } + else{ + left = this.container.scrollLeft + ( this.layout.delta * -1 ); + if (left > this.container.scrollWidth * -1){ + this.scrollBy(this.layout.delta, 0, true); + } + else{ + next = this.views.last().section.next(); + + } + } } else if (this.isPaginated && this.settings.axis === "vertical") { @@ -493,13 +528,25 @@ class DefaultViewManager { this.scrollLeft = this.container.scrollLeft; - left = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta; + if (this.settings.rtlScrollType === "default"){ + left = this.container.scrollLeft + this.container.offsetWidth + this.layout.delta; - if(left <= this.container.scrollWidth) { - this.scrollBy(-this.layout.delta, 0, true); - } else { - prev = this.views.first().section.prev(); - } + if (left <= this.container.scrollWidth) { + this.scrollBy(-this.layout.delta, 0, true); + } else { + prev = this.views.first().section.prev(); + } + } + else{ + left = this.container.scrollLeft; + + if (left < 0) { + this.scrollBy(-this.layout.delta, 0, true); + } else { + prev = this.views.first().section.prev(); + } + + } } else if (this.isPaginated && this.settings.axis === "vertical") { @@ -537,7 +584,12 @@ class DefaultViewManager { .then(function(){ if(this.isPaginated && this.settings.axis === "horizontal") { if (this.settings.direction === "rtl") { - this.scrollTo(0, 0, true); + if (this.settings.rtlScrollType === "default"){ + this.scrollTo(0, 0, true); + } + else{ + this.scrollTo((this.container.scrollWidth * -1) + this.layout.delta, 0, true); + } } else { this.scrollTo(this.container.scrollWidth - this.layout.delta, 0, true); } diff --git a/src/packaging.js b/src/packaging.js index abaa16e7d..5e2d7a649 100644 --- a/src/packaging.js +++ b/src/packaging.js @@ -59,7 +59,21 @@ class Packaging { this.uniqueIdentifier = this.findUniqueIdentifier(packageDocument); this.metadata = this.parseMetadata(metadataNode); - this.metadata.direction = spineNode.getAttribute("page-progression-direction"); + // Detect book direction - default ltr + //RTL detection + //1. spineNode attributes page-progression-direction + //2. Language metadata field check against rtl languages + this.metadata.direction = ( function() { + var defaultDirection = "ltr"; + var rtlLanguages = + ["ar", "arc", "dv", "fa", "ha", "he", "khw", "ku", "ps", "ur", "yi"]; + + var isRTLLanguage = rtlLanguages.indexOf(this.metadata.language.toLowerCase()) > -1; + + return spineNode.getAttribute("page-progression-direction") || + isRTLLanguage ? "rtl" : "" || + defaultDirection; + }.bind(this))(); return {