@internetarchive/bookreader 5.0.0-112 → 5.0.0-113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BookReader/BookReader.css +13 -7
- package/BookReader/BookReader.js +43 -1
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +3 -45
- package/BookReader/ia-bookreader-bundle.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +2 -2
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.experiments.js +1 -1
- package/BookReader/plugins/plugin.experiments.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +1 -23
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.translate.js +3 -25
- package/BookReader/plugins/plugin.translate.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -2
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/package.json +1 -1
- package/src/BookReader/utils/SelectionObserver.js +2 -2
- package/src/BookReader.js +5 -4
- package/src/css/_BRpages.scss +5 -2
- package/src/css/_TextSelection.scss +15 -9
- package/src/plugins/plugin.experiments.js +31 -5
- package/src/plugins/plugin.text_selection.js +19 -56
- package/src/plugins/url/UrlPlugin.js +2 -15
- package/src/plugins/url/plugin.url.js +7 -59
- package/src/util/TextSelectionManager.js +834 -137
- package/BookReader/plugins/plugin.url.js.LICENSE.txt +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins/plugin.vendor-fullscreen.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./node_modules/core-js/internals/string-trim-forced.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.string.trim.js","webpack://@internetarchive/bookreader/./src/plugins/plugin.vendor-fullscreen.js"],"sourcesContent":["'use strict';\nvar PROPER_FUNCTION_NAME = require('../internals/function-name').PROPER;\nvar fails = require('../internals/fails');\nvar whitespaces = require('../internals/whitespaces');\n\nvar non = '\\u200B\\u0085\\u180E';\n\n// check that a method works with the correct list\n// of whitespaces and has a correct name\nmodule.exports = function (METHOD_NAME) {\n return fails(function () {\n return !!whitespaces[METHOD_NAME]()\n || non[METHOD_NAME]() !== non\n || (PROPER_FUNCTION_NAME && whitespaces[METHOD_NAME].name !== METHOD_NAME);\n });\n};\n","'use strict';\nvar $ = require('../internals/export');\nvar $trim = require('../internals/string-trim').trim;\nvar forcedStringTrimMethod = require('../internals/string-trim-forced');\n\n// `String.prototype.trim` method\n// https://tc39.es/ecma262/#sec-string.prototype.trim\n$({ target: 'String', proto: true, forced: forcedStringTrimMethod('trim') }, {\n trim: function trim() {\n return $trim(this);\n }\n});\n","/* global BookReader */\n\n/**\n * Toggles browser's native fullscreen mode if available device is not mobile\n */\nif (!isMobile()) {\n const EVENT_NAMESPACE = '.bookreader_vendor-fullscreen';\n\n jQuery.extend(BookReader.defaultOptions, {\n /** @type {boolean} */\n enableVendorFullscreenPlugin: true,\n });\n\n /** @override */\n BookReader.prototype.setup = (function(super_) {\n return function(options) {\n super_.call(this, options);\n\n this.isVendorFullscreenActive = false;\n };\n })(BookReader.prototype.setup);\n\n /** @override */\n BookReader.prototype.getInitialMode = (function(super_) {\n return function(params) {\n let nextMode = super_.call(this, params);\n if (this.isVendorFullscreenActive) {\n nextMode = this.constMode1up;\n }\n return nextMode;\n };\n })(BookReader.prototype.getInitialMode);\n\n /** @override */\n BookReader.prototype.init = (function(super_) {\n return function() {\n super_.call(this);\n\n if (!fullscreenAllowed()) {\n return;\n }\n // In fullscreen mode the colorbox and overlay need to be inside the fullscreen element to display properly.\n bindFullscreenChangeListener(this, (e) => {\n e.data.resize();\n e.data.updateBrClasses();\n const cboxOverlay = $('#cboxOverlay');\n const cbox = $('#colorbox');\n if (isFullscreenActive()) {\n // In full screen mode, the colorbox and overlay need\n // to be children of the fullscreen element to display properly.\n const $fullscreen = $(getFullscreenElement());\n $fullscreen.append(cboxOverlay).append(cbox);\n } else {\n // In non-fullscreen mode, the colorbox and overlay need\n // to be children of the main document body.\n $(document.body).append(cboxOverlay).append(cbox);\n }\n });\n };\n })(BookReader.prototype.init);\n\n /**\n * Start fullscreen mode\n */\n BookReader.prototype.enterFullWindow = function() {\n this.refs.$brContainer.css('opacity', 0);\n\n const windowWidth = $(window).width();\n if (windowWidth <= this.onePageMinBreakpoint) {\n this.switchMode(this.constMode1up);\n }\n\n this.isVendorFullscreenActive = true;\n this.updateBrClasses();\n\n this.resize();\n this.jumpToIndex(this.currentIndex());\n\n this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');\n\n $(document).on(`keyup.${EVENT_NAMESPACE}`, e => {\n if (e.keyCode === 27) this.exitFullScreen();\n });\n };\n\n /**\n * Exit from fullscreen mode\n */\n BookReader.prototype.exitFullWindow = function() {\n this.refs.$brContainer.css('opacity', 0);\n\n $(document).off('keyup' + EVENT_NAMESPACE);\n\n this.isFullscreenActive = false;\n this.updateBrClasses();\n\n this.resize();\n this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');\n };\n\n /**\n * Returns true if fullscreen mode is enabled\n *\n * @returns {boolean}\n */\n BookReader.prototype.isFullscreen = function() {\n return isFullscreenActive() || this.isVendorFullscreenActive;\n };\n\n /**\n * Toggle screen\n */\n BookReader.prototype.toggleFullscreen = function() {\n if (this.isFullscreen()) {\n if (fullscreenAllowed()) {\n exitFullscreen();\n } else {\n this.exitFullWindow();\n }\n } else {\n if (fullscreenAllowed()) {\n requestFullscreen(this.refs.$br[0]);\n } else {\n this.enterFullWindow();\n }\n }\n };\n\n /** @deprecated */\n BookReader.util.isMobile = isMobile;\n\n /** @deprecated */\n BookReader.util.getFullscreenElement = getFullscreenElement;\n\n /** @deprecated */\n BookReader.util.bindFullscreenChangeListener = bindFullscreenChangeListener;\n\n /** @deprecated */\n BookReader.util.fullscreenAllowed = fullscreenAllowed;\n\n /** @deprecated */\n BookReader.util.requestFullscreen = requestFullscreen;\n\n /** @deprecated */\n BookReader.util.exitFullscreen = exitFullscreen;\n\n /** @deprecated */\n BookReader.util.isFullscreenActive = isFullscreenActive;\n}\n\n\n/**\n * Returns the DOM element being used for fullscreen.\n *\n * @returns {HTMLElement}\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/fullscreenElement\n */\nexport function getFullscreenElement() {\n return document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement;\n}\n\n/**\n * Returns true if the document is in fullscreen mode.\n *\n * @returns {boolean}\n */\nexport function isFullscreenActive() {\n const fullscreenElement = getFullscreenElement();\n return fullscreenElement !== null && fullscreenElement !== undefined;\n}\n\n/**\n * Exits fullscreen mode.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/exitFullscreen\n */\nexport function exitFullscreen() {\n if (document.exitFullscreen) {\n document.exitFullscreen();\n } else if (document.webkitExitFullscreen) {\n document.webkitExitFullscreen();\n } else if (document.mozCancelFullScreen) {\n document.mozCancelFullScreen();\n } else if (document.msExitFullscreen) {\n document.msExitFullscreen();\n }\n}\n\n/**\n * Requests fullscreen mode for the given element\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen\n */\nexport function requestFullscreen(element) {\n if (element.requestFullscreen) {\n element.requestFullscreen();\n } else if (element.webkitRequestFullscreen) {\n element.webkitRequestFullscreen();\n } else if (element.mozRequestFullScreen) {\n element.mozRequestFullScreen();\n } else if (element.msRequestFullscreen) {\n element.msRequestFullscreen();\n }\n}\n\n/**\n * Returns true if fullscreen mode is allowed on this device and document.\n *\n * @returns {boolean}\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenEnabled\n */\nexport function fullscreenAllowed() {\n return (document.fullscreenEnabled ||\n document.webkitFullscreenEnabled ||\n document.mozFullScreenEnabled ||\n document.msFullScreenEnabled);\n}\n\n/**\n * jQuery-style binding to a fullscreenchange event.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenchange_event\n */\nexport function bindFullscreenChangeListener(\n data, fullscreenchangeListener,\n) {\n const event = 'fullscreenchange ';\n const vendor_prefixes = [\n 'webkit',\n 'moz',\n 'ms',\n ];\n const all_events = (event + vendor_prefixes.join(event) + event).trim();\n $(document).on(all_events, data, fullscreenchangeListener);\n}\n\n/**\n * Returns true if current device is mobile\n *\n * @returns {boolean}\n */\nexport function isMobile() {\n return (typeof window.orientation !== 'undefined') || (navigator.userAgent.indexOf('IEMobile') !== -1);\n}\n"],"names":["PROPER_FUNCTION_NAME","fails","whitespaces","module","exports","METHOD_NAME","name","$","$trim","target","proto","forced","forcedStringTrimMethod","trim","this","super_","isMobile","EVENT_NAMESPACE","jQuery","extend","BookReader","defaultOptions","enableVendorFullscreenPlugin","prototype","setup","options","call","isVendorFullscreenActive","getInitialMode","params","nextMode","constMode1up","init","fullscreenAllowed","bindFullscreenChangeListener","e","data","resize","updateBrClasses","cboxOverlay","cbox","isFullscreenActive","getFullscreenElement","append","document","body","enterFullWindow","_this","refs","$brContainer","css","window","width","onePageMinBreakpoint","switchMode","jumpToIndex","currentIndex","animate","opacity","on","concat","keyCode","exitFullScreen","exitFullWindow","off","isFullscreen","toggleFullscreen","exitFullscreen","requestFullscreen","$br","util","fullscreenElement","webkitFullscreenElement","mozFullScreenElement","msFullscreenElement","webkitExitFullscreen","mozCancelFullScreen","msExitFullscreen","element","webkitRequestFullscreen","mozRequestFullScreen","msRequestFullscreen","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","msFullScreenEnabled","fullscreenchangeListener","event","all_events","join","orientation","navigator","userAgent","indexOf"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"plugins/plugin.vendor-fullscreen.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/plugins/plugin.vendor-fullscreen.js"],"sourcesContent":["/* global BookReader */\n\n/**\n * Toggles browser's native fullscreen mode if available device is not mobile\n */\nif (!isMobile()) {\n const EVENT_NAMESPACE = '.bookreader_vendor-fullscreen';\n\n jQuery.extend(BookReader.defaultOptions, {\n /** @type {boolean} */\n enableVendorFullscreenPlugin: true,\n });\n\n /** @override */\n BookReader.prototype.setup = (function(super_) {\n return function(options) {\n super_.call(this, options);\n\n this.isVendorFullscreenActive = false;\n };\n })(BookReader.prototype.setup);\n\n /** @override */\n BookReader.prototype.getInitialMode = (function(super_) {\n return function(params) {\n let nextMode = super_.call(this, params);\n if (this.isVendorFullscreenActive) {\n nextMode = this.constMode1up;\n }\n return nextMode;\n };\n })(BookReader.prototype.getInitialMode);\n\n /** @override */\n BookReader.prototype.init = (function(super_) {\n return function() {\n super_.call(this);\n\n if (!fullscreenAllowed()) {\n return;\n }\n // In fullscreen mode the colorbox and overlay need to be inside the fullscreen element to display properly.\n bindFullscreenChangeListener(this, (e) => {\n e.data.resize();\n e.data.updateBrClasses();\n const cboxOverlay = $('#cboxOverlay');\n const cbox = $('#colorbox');\n if (isFullscreenActive()) {\n // In full screen mode, the colorbox and overlay need\n // to be children of the fullscreen element to display properly.\n const $fullscreen = $(getFullscreenElement());\n $fullscreen.append(cboxOverlay).append(cbox);\n } else {\n // In non-fullscreen mode, the colorbox and overlay need\n // to be children of the main document body.\n $(document.body).append(cboxOverlay).append(cbox);\n }\n });\n };\n })(BookReader.prototype.init);\n\n /**\n * Start fullscreen mode\n */\n BookReader.prototype.enterFullWindow = function() {\n this.refs.$brContainer.css('opacity', 0);\n\n const windowWidth = $(window).width();\n if (windowWidth <= this.onePageMinBreakpoint) {\n this.switchMode(this.constMode1up);\n }\n\n this.isVendorFullscreenActive = true;\n this.updateBrClasses();\n\n this.resize();\n this.jumpToIndex(this.currentIndex());\n\n this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');\n\n $(document).on(`keyup.${EVENT_NAMESPACE}`, e => {\n if (e.keyCode === 27) this.exitFullScreen();\n });\n };\n\n /**\n * Exit from fullscreen mode\n */\n BookReader.prototype.exitFullWindow = function() {\n this.refs.$brContainer.css('opacity', 0);\n\n $(document).off('keyup' + EVENT_NAMESPACE);\n\n this.isFullscreenActive = false;\n this.updateBrClasses();\n\n this.resize();\n this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');\n };\n\n /**\n * Returns true if fullscreen mode is enabled\n *\n * @returns {boolean}\n */\n BookReader.prototype.isFullscreen = function() {\n return isFullscreenActive() || this.isVendorFullscreenActive;\n };\n\n /**\n * Toggle screen\n */\n BookReader.prototype.toggleFullscreen = function() {\n if (this.isFullscreen()) {\n if (fullscreenAllowed()) {\n exitFullscreen();\n } else {\n this.exitFullWindow();\n }\n } else {\n if (fullscreenAllowed()) {\n requestFullscreen(this.refs.$br[0]);\n } else {\n this.enterFullWindow();\n }\n }\n };\n\n /** @deprecated */\n BookReader.util.isMobile = isMobile;\n\n /** @deprecated */\n BookReader.util.getFullscreenElement = getFullscreenElement;\n\n /** @deprecated */\n BookReader.util.bindFullscreenChangeListener = bindFullscreenChangeListener;\n\n /** @deprecated */\n BookReader.util.fullscreenAllowed = fullscreenAllowed;\n\n /** @deprecated */\n BookReader.util.requestFullscreen = requestFullscreen;\n\n /** @deprecated */\n BookReader.util.exitFullscreen = exitFullscreen;\n\n /** @deprecated */\n BookReader.util.isFullscreenActive = isFullscreenActive;\n}\n\n\n/**\n * Returns the DOM element being used for fullscreen.\n *\n * @returns {HTMLElement}\n * @see https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/fullscreenElement\n */\nexport function getFullscreenElement() {\n return document.fullscreenElement ||\n document.webkitFullscreenElement ||\n document.mozFullScreenElement ||\n document.msFullscreenElement;\n}\n\n/**\n * Returns true if the document is in fullscreen mode.\n *\n * @returns {boolean}\n */\nexport function isFullscreenActive() {\n const fullscreenElement = getFullscreenElement();\n return fullscreenElement !== null && fullscreenElement !== undefined;\n}\n\n/**\n * Exits fullscreen mode.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/exitFullscreen\n */\nexport function exitFullscreen() {\n if (document.exitFullscreen) {\n document.exitFullscreen();\n } else if (document.webkitExitFullscreen) {\n document.webkitExitFullscreen();\n } else if (document.mozCancelFullScreen) {\n document.mozCancelFullScreen();\n } else if (document.msExitFullscreen) {\n document.msExitFullscreen();\n }\n}\n\n/**\n * Requests fullscreen mode for the given element\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullscreen\n */\nexport function requestFullscreen(element) {\n if (element.requestFullscreen) {\n element.requestFullscreen();\n } else if (element.webkitRequestFullscreen) {\n element.webkitRequestFullscreen();\n } else if (element.mozRequestFullScreen) {\n element.mozRequestFullScreen();\n } else if (element.msRequestFullscreen) {\n element.msRequestFullscreen();\n }\n}\n\n/**\n * Returns true if fullscreen mode is allowed on this device and document.\n *\n * @returns {boolean}\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenEnabled\n */\nexport function fullscreenAllowed() {\n return (document.fullscreenEnabled ||\n document.webkitFullscreenEnabled ||\n document.mozFullScreenEnabled ||\n document.msFullScreenEnabled);\n}\n\n/**\n * jQuery-style binding to a fullscreenchange event.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenchange_event\n */\nexport function bindFullscreenChangeListener(\n data, fullscreenchangeListener,\n) {\n const event = 'fullscreenchange ';\n const vendor_prefixes = [\n 'webkit',\n 'moz',\n 'ms',\n ];\n const all_events = (event + vendor_prefixes.join(event) + event).trim();\n $(document).on(all_events, data, fullscreenchangeListener);\n}\n\n/**\n * Returns true if current device is mobile\n *\n * @returns {boolean}\n */\nexport function isMobile() {\n return (typeof window.orientation !== 'undefined') || (navigator.userAgent.indexOf('IEMobile') !== -1);\n}\n"],"names":["super_","isMobile","EVENT_NAMESPACE","jQuery","extend","BookReader","defaultOptions","enableVendorFullscreenPlugin","prototype","setup","options","call","this","isVendorFullscreenActive","getInitialMode","params","nextMode","constMode1up","init","fullscreenAllowed","bindFullscreenChangeListener","e","data","resize","updateBrClasses","cboxOverlay","$","cbox","isFullscreenActive","getFullscreenElement","append","document","body","enterFullWindow","_this","refs","$brContainer","css","window","width","onePageMinBreakpoint","switchMode","jumpToIndex","currentIndex","animate","opacity","on","concat","keyCode","exitFullScreen","exitFullWindow","off","isFullscreen","toggleFullscreen","exitFullscreen","requestFullscreen","$br","util","fullscreenElement","webkitFullscreenElement","mozFullScreenElement","msFullscreenElement","webkitExitFullscreen","mozCancelFullScreen","msExitFullscreen","element","webkitRequestFullscreen","mozRequestFullScreen","msRequestFullscreen","fullscreenEnabled","webkitFullscreenEnabled","mozFullScreenEnabled","msFullScreenEnabled","fullscreenchangeListener","event","all_events","join","trim","orientation","navigator","userAgent","indexOf"],"sourceRoot":""}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ export class SelectionObserver {
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @param {string} selector
|
|
12
|
-
* @param {function('started' | 'cleared' | '
|
|
12
|
+
* @param {function('started' | 'cleared' | 'changed', HTMLElement): any} handler
|
|
13
13
|
*/
|
|
14
14
|
constructor(selector, handler) {
|
|
15
15
|
this.selector = selector;
|
|
@@ -42,7 +42,7 @@ export class SelectionObserver {
|
|
|
42
42
|
|
|
43
43
|
if (this.selecting && (this.lastKnownFocusNode != sel.focusNode || sel.toString() && !sel.isCollapsed)) {
|
|
44
44
|
this.lastKnownFocusNode = sel.focusNode;
|
|
45
|
-
this.handler('
|
|
45
|
+
this.handler('changed', this.target);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
if (this.selecting && (sel.isCollapsed || !sel.toString() || !$(sel.anchorNode).closest(this.selector)[0])) {
|
package/src/BookReader.js
CHANGED
|
@@ -41,6 +41,7 @@ import { ModeThumb } from './BookReader/ModeThumb.js';
|
|
|
41
41
|
import { ImageCache } from './BookReader/ImageCache.js';
|
|
42
42
|
import { PageContainer } from './BookReader/PageContainer.js';
|
|
43
43
|
import { NAMED_REDUCE_SETS } from './BookReader/ReduceSet.js';
|
|
44
|
+
import {BookReaderTextFragment} from './util/TextSelectionManager.js';
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* BookReader
|
|
@@ -644,7 +645,6 @@ BookReader.prototype.init = function() {
|
|
|
644
645
|
this.pageScale = this.reduce; // preserve current reduce
|
|
645
646
|
|
|
646
647
|
const params = this.initParams();
|
|
647
|
-
|
|
648
648
|
this.firstIndex = params.index ? params.index : 0;
|
|
649
649
|
|
|
650
650
|
// Setup Navbars and other UI
|
|
@@ -1971,12 +1971,13 @@ BookReader.prototype.queryStringFromParams = function(
|
|
|
1971
1971
|
newParams.set('q', params.search);
|
|
1972
1972
|
}
|
|
1973
1973
|
|
|
1974
|
-
|
|
1974
|
+
/** @type {BookReaderTextFragment | null} */
|
|
1975
|
+
let textFragmentParam = null;
|
|
1975
1976
|
// Need to pull out text separately to avoid the spaces becoming encoded as +, which
|
|
1976
1977
|
// the browser seems not to handle with the text fragment
|
|
1977
1978
|
if (newParams.get('text')) {
|
|
1978
1979
|
newParams.delete('text');
|
|
1979
|
-
textFragmentParam =
|
|
1980
|
+
textFragmentParam = BookReaderTextFragment.fromUrl(currQueryString, this.book, this.firstIndex);
|
|
1980
1981
|
}
|
|
1981
1982
|
|
|
1982
1983
|
// https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
|
|
@@ -1984,7 +1985,7 @@ BookReader.prototype.queryStringFromParams = function(
|
|
|
1984
1985
|
let result = newParams.toString();
|
|
1985
1986
|
if (textFragmentParam) {
|
|
1986
1987
|
if (result) result += '&';
|
|
1987
|
-
result += textFragmentParam
|
|
1988
|
+
result += `text=${textFragmentParam.toUrlString()}`;
|
|
1988
1989
|
}
|
|
1989
1990
|
if (result) result = '?' + result;
|
|
1990
1991
|
|
package/src/css/_BRpages.scss
CHANGED
|
@@ -101,8 +101,11 @@ svg.BRPageLayer {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// Hides page layers during page flip animation
|
|
104
|
-
.BRpageFlipping
|
|
105
|
-
|
|
104
|
+
.BRpageFlipping {
|
|
105
|
+
// If the text layer has an annotation, don't hide it
|
|
106
|
+
.BRpagecontainer:not(:has(hypothesis-highlight)):not(:has(.BRhighlight)) .BRtextLayer {
|
|
107
|
+
display: none;
|
|
108
|
+
}
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
.br-mode-2up__root {
|
|
@@ -54,13 +54,6 @@
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
// Style URI TextFragments, eg #:~:text=example
|
|
58
|
-
.BRtextLayer ::target-text {
|
|
59
|
-
// Similar colour to the default one used in Safari, Firefox. Note Chrome uses a purple colour
|
|
60
|
-
background-color: hsla(45, 80%, 66%, 0.6);
|
|
61
|
-
color: transparent;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
57
|
.BRtranslateLayer ::selection {
|
|
65
58
|
background: hsla(210, 74%, 62%, 0.4);
|
|
66
59
|
}
|
|
@@ -82,7 +75,7 @@
|
|
|
82
75
|
// Hide text layer for performance during zooming & scrolling
|
|
83
76
|
.BRsmooth-zooming, .BRscrolling-active {
|
|
84
77
|
// If the text layer has an annotation, don't hide it
|
|
85
|
-
.BRpagecontainer:not(.BRpagecontainer--hasSelection):not(:has(hypothesis-highlight)) .BRtextLayer {
|
|
78
|
+
.BRpagecontainer:not(.BRpagecontainer--hasSelection):not(:has(hypothesis-highlight)):not(:has(.BRhighlight)) .BRtextLayer {
|
|
86
79
|
display: none;
|
|
87
80
|
}
|
|
88
81
|
}
|
|
@@ -209,4 +202,17 @@
|
|
|
209
202
|
width: auto;
|
|
210
203
|
margin-left: 4px;
|
|
211
204
|
opacity: 1;
|
|
212
|
-
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.BRtextLayer .BRhighlight {
|
|
208
|
+
background-color: yellow;
|
|
209
|
+
pointer-events: all;
|
|
210
|
+
color: transparent;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Style URI TextFragments, eg #:~:text=example
|
|
214
|
+
.BRtextLayer .BRhighlight--target-text, .BRtextLayer ::target-text {
|
|
215
|
+
// Similar colour to the default one used in Safari, Firefox. Note Chrome uses a purple colour
|
|
216
|
+
background-color: hsla(45, 80%, 66%, 0.6);
|
|
217
|
+
color: transparent;
|
|
218
|
+
}
|
|
@@ -7,8 +7,10 @@ import { sleep } from '../BookReader/utils.js';
|
|
|
7
7
|
// @ts-ignore
|
|
8
8
|
const BookReader = /** @type {typeof import('@/src/BookReader.js').default} */(window.BookReader);
|
|
9
9
|
|
|
10
|
+
/** @typedef {'copyLinkToHighlight' | 'annotateHighlight' | 'translate' | 'hypothesis'} ExperimentName */
|
|
11
|
+
|
|
10
12
|
class ExperimentModel {
|
|
11
|
-
/** @type {
|
|
13
|
+
/** @type {ExperimentName} */
|
|
12
14
|
name;
|
|
13
15
|
/** @type {string} */
|
|
14
16
|
title;
|
|
@@ -58,13 +60,29 @@ export class ExperimentsPlugin extends BookReaderPlugin {
|
|
|
58
60
|
allExperiments = [
|
|
59
61
|
new class extends ExperimentModel {
|
|
60
62
|
name = 'copyLinkToHighlight';
|
|
61
|
-
title = 'Copy to
|
|
62
|
-
description = '
|
|
63
|
-
learnMore = 'none';
|
|
63
|
+
title = 'Copy Link to Highlight';
|
|
64
|
+
description = 'Shareable link to a text selection';
|
|
64
65
|
icon = null;
|
|
65
66
|
enabled = false;
|
|
66
67
|
async enable ({ manual = false }) {
|
|
67
|
-
|
|
68
|
+
if (manual) {
|
|
69
|
+
this.br.plugins.textSelection.textSelectionManager.selectMenu.copyLinkToHighlightEnabled = true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async disable() {
|
|
73
|
+
this.br.plugins.textSelection.textSelectionManager.selectMenu.copyLinkToHighlightEnabled = false;
|
|
74
|
+
}
|
|
75
|
+
}(),
|
|
76
|
+
new class extends ExperimentModel {
|
|
77
|
+
name = 'annotateHighlight';
|
|
78
|
+
title = 'Highlight and annotate';
|
|
79
|
+
description = 'Create private highlights and annotations for this book';
|
|
80
|
+
icon = null;
|
|
81
|
+
enabled = false;
|
|
82
|
+
async enable ({ manual = false }) {
|
|
83
|
+
if (manual) {
|
|
84
|
+
this.br.plugins.textSelection.textSelectionManager.selectMenu.highlightAnnotationEnabled = true;
|
|
85
|
+
}
|
|
68
86
|
}
|
|
69
87
|
async disable() {
|
|
70
88
|
sleep(0).then(() => {
|
|
@@ -150,6 +168,14 @@ export class ExperimentsPlugin extends BookReaderPlugin {
|
|
|
150
168
|
this._render();
|
|
151
169
|
}
|
|
152
170
|
|
|
171
|
+
/**
|
|
172
|
+
* @param {ExperimentName} experimentName
|
|
173
|
+
*/
|
|
174
|
+
isEnabled(experimentName) {
|
|
175
|
+
const experiment = this.allExperiments.find(exp => exp.name === experimentName);
|
|
176
|
+
return experiment?.enabled;
|
|
177
|
+
}
|
|
178
|
+
|
|
153
179
|
_loadExperimentStates() {
|
|
154
180
|
const savedStates = JSON.parse(localStorage.getItem(this.options.localStorageKey) || '{}');
|
|
155
181
|
this.allExperiments.forEach(experiment => {
|
|
@@ -4,7 +4,7 @@ import { BookReaderPlugin } from '../BookReaderPlugin.js';
|
|
|
4
4
|
import { applyVariables } from '../util/strings.js';
|
|
5
5
|
import { Cache } from '../util/cache.js';
|
|
6
6
|
import { toISO6391 } from './tts/utils.js';
|
|
7
|
-
import { TextSelectionManager } from '../util/TextSelectionManager.js';
|
|
7
|
+
import { BookReaderTextFragment, renderHighlight, TextSelectionManager } from '../util/TextSelectionManager.js';
|
|
8
8
|
/** @typedef {import('../util/strings.js').StringWithVars} StringWithVars */
|
|
9
9
|
/** @typedef {import('../BookReader/PageContainer.js').PageContainer} PageContainer */
|
|
10
10
|
|
|
@@ -46,7 +46,7 @@ export class TextSelectionPlugin extends BookReaderPlugin {
|
|
|
46
46
|
// now we do make that assumption.
|
|
47
47
|
/** Whether the book is right-to-left */
|
|
48
48
|
this.rtl = this.br.pageProgression === 'rl';
|
|
49
|
-
this.textSelectionManager = new TextSelectionManager('.BRtextLayer', this.br, {selectionElement: ['.BRwordElement', '.BRspace']}, this.options.maxProtectedWords);
|
|
49
|
+
this.textSelectionManager = new TextSelectionManager('.BRtextLayer', this.br, {selectionElement: ['.BRwordElement', '.BRspace', 'mark']}, this.options.maxProtectedWords);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/** @override */
|
|
@@ -54,18 +54,27 @@ export class TextSelectionPlugin extends BookReaderPlugin {
|
|
|
54
54
|
if (!this.options.enabled) return;
|
|
55
55
|
|
|
56
56
|
this.br.on('pageVisible', (_, {pageContainerEl}) => {
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const textLayer = pageContainerEl.querySelector('.BRtextLayer');
|
|
58
|
+
if (textLayer) {
|
|
59
|
+
this.br.trigger('textLayerVisible', {pageContainerEl, textLayer});
|
|
59
60
|
}
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
this.loadData();
|
|
63
64
|
this.textSelectionManager.init();
|
|
64
|
-
}
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
this.
|
|
68
|
-
this.
|
|
66
|
+
// Init text fragment
|
|
67
|
+
this.targetTextFragment = BookReaderTextFragment.fromUrl(location.search, this.br.book, this.br.firstIndex);
|
|
68
|
+
if (this.targetTextFragment) {
|
|
69
|
+
const targetTextFragment = this.targetTextFragment;
|
|
70
|
+
this.br.on('textLayerVisible', async (_, {pageContainerEl, textLayer}) => {
|
|
71
|
+
const pageIndex = targetTextFragment.pageIndex;
|
|
72
|
+
const hasTargetText = pageIndex === parseFloat(pageContainerEl.getAttribute('data-index'));
|
|
73
|
+
if (hasTargetText) {
|
|
74
|
+
renderHighlight(textLayer, targetTextFragment, 'BRhighlight--target-text');
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
/**
|
|
@@ -76,7 +85,7 @@ export class TextSelectionPlugin extends BookReaderPlugin {
|
|
|
76
85
|
_configurePageContainer(pageContainer) {
|
|
77
86
|
// Disable if thumb mode; it's too janky
|
|
78
87
|
// .page can be null for "pre-cover" region
|
|
79
|
-
if (this.br.mode !== this.br.constModeThumb && pageContainer.page) {
|
|
88
|
+
if (this.br.mode !== this.br.constModeThumb && pageContainer.page?.isViewable) {
|
|
80
89
|
this.createTextLayer(pageContainer);
|
|
81
90
|
}
|
|
82
91
|
return pageContainer;
|
|
@@ -210,7 +219,7 @@ export class TextSelectionPlugin extends BookReaderPlugin {
|
|
|
210
219
|
|
|
211
220
|
// Check if page is visible
|
|
212
221
|
if ($container.hasClass('BRpage-visible')) {
|
|
213
|
-
this.br.trigger('textLayerVisible', {pageContainerEl: $container[0]});
|
|
222
|
+
this.br.trigger('textLayerVisible', {pageContainerEl: $container[0], textLayer});
|
|
214
223
|
}
|
|
215
224
|
}
|
|
216
225
|
|
|
@@ -575,49 +584,3 @@ class Rect {
|
|
|
575
584
|
get top() { return this.y; }
|
|
576
585
|
get left() { return this.x; }
|
|
577
586
|
}
|
|
578
|
-
|
|
579
|
-
/**
|
|
580
|
-
* Depth traverse the DOM tree starting at `start`, and ending at `end`.
|
|
581
|
-
* @param {Node} start
|
|
582
|
-
* @param {Node} end
|
|
583
|
-
* @returns {Generator<Node>}
|
|
584
|
-
*/
|
|
585
|
-
export function* walkBetweenNodes(start, end) {
|
|
586
|
-
let done = false;
|
|
587
|
-
|
|
588
|
-
/**
|
|
589
|
-
* @param {Node} node
|
|
590
|
-
*/
|
|
591
|
-
function* walk(node, {children = true, parents = true, siblings = true} = {}) {
|
|
592
|
-
if (node === end) {
|
|
593
|
-
done = true;
|
|
594
|
-
yield node;
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
// yield self
|
|
599
|
-
yield node;
|
|
600
|
-
|
|
601
|
-
// First iterate children (depth-first traversal)
|
|
602
|
-
if (children && node.firstChild) {
|
|
603
|
-
yield* walk(node.firstChild, {children: true, parents: false, siblings: true});
|
|
604
|
-
if (done) return;
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
// Then iterate siblings
|
|
608
|
-
if (siblings) {
|
|
609
|
-
for (let sib = node.nextSibling; sib; sib = sib.nextSibling) {
|
|
610
|
-
yield* walk(sib, {children: true, parents: false, siblings: false});
|
|
611
|
-
if (done) return;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
// Finally, move up the tree
|
|
616
|
-
if (parents && node.parentNode) {
|
|
617
|
-
yield* walk(node.parentNode, {children: false, parents: true, siblings: true});
|
|
618
|
-
if (done) return;
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
yield* walk(start);
|
|
623
|
-
}
|
|
@@ -190,22 +190,9 @@ export class UrlPlugin {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
/**
|
|
193
|
-
* Get the hash out of the current URL
|
|
194
|
-
* from the main part of the URL, since that is not readable by JS
|
|
195
|
-
* from the actual hash
|
|
196
|
-
* @returns
|
|
193
|
+
* Get the hash out of the current URL
|
|
197
194
|
*/
|
|
198
195
|
getHash() {
|
|
199
|
-
|
|
200
|
-
const textFragment = text ? `:~:text=${text[0]}` : '';
|
|
201
|
-
return `${window.location.hash.slice(1)}${textFragment}`;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* @param {string} urlString
|
|
206
|
-
* @returns {string}
|
|
207
|
-
*/
|
|
208
|
-
retrieveTextFragment(urlString) {
|
|
209
|
-
return urlString.match(/(?<=[&?]?text=)[^&]*/);
|
|
196
|
+
return window.location.hash.slice(1);
|
|
210
197
|
}
|
|
211
198
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* global BookReader */
|
|
2
2
|
|
|
3
3
|
import { UrlPlugin } from "./UrlPlugin.js";
|
|
4
|
-
import { sleep } from "../../BookReader/utils.js";
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Plugin for URL management in BookReader
|
|
@@ -43,10 +42,6 @@ BookReader.prototype.setup = (function(super_) {
|
|
|
43
42
|
this.locationPollId = null;
|
|
44
43
|
this.oldLocationHash = null;
|
|
45
44
|
this.oldUserHash = null;
|
|
46
|
-
// Should include the :~:text= prefix
|
|
47
|
-
this.textFragment = null;
|
|
48
|
-
// Tracks the original textFragment page num when first loaded
|
|
49
|
-
this.textFragmentPage = null;
|
|
50
45
|
};
|
|
51
46
|
})(BookReader.prototype.setup);
|
|
52
47
|
|
|
@@ -146,22 +141,16 @@ BookReader.prototype.urlUpdateFragment = function() {
|
|
|
146
141
|
}, {});
|
|
147
142
|
|
|
148
143
|
// eg 'page/3/mode/2up'; no query params (in hash mode, it might have /search/term)
|
|
149
|
-
// Does NOT have the :~:text fragment
|
|
150
144
|
const newFragment = this.fragmentFromParams(params, this.options.urlMode);
|
|
151
145
|
const newFragmentWithSlash = newFragment === '' ? '' : `/${newFragment}`;
|
|
152
146
|
// eg 'page/3/mode/2up'; no query params
|
|
153
|
-
// WILL CONTAIN the :~:text fragment in hash mode (!)
|
|
154
147
|
const currFragment = this.urlReadFragment();
|
|
155
148
|
// This should have both ?q=foo&text=bar (and any other params) as an encoded string
|
|
156
149
|
const currQueryString = this.getLocationSearch();
|
|
157
150
|
// Eg ?q=foo&text=bar; only query params, no fragment
|
|
158
151
|
const newQueryString = this.queryStringFromParams(params, currQueryString, this.options.urlMode);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
// not desireable, but currently don't have a way to handle re-writing ?text to the hash text
|
|
162
|
-
// fragment form, :~:text=foo.
|
|
163
|
-
const hasTextParam = this.urlPlugin.retrieveTextFragment(currQueryString);
|
|
164
|
-
if (currFragment === newFragment && currQueryString === newQueryString && !hasTextParam) {
|
|
152
|
+
// Avoid infinite loop if there are no changes
|
|
153
|
+
if (currFragment === newFragment && currQueryString === newQueryString) {
|
|
165
154
|
return;
|
|
166
155
|
}
|
|
167
156
|
|
|
@@ -170,19 +159,11 @@ BookReader.prototype.urlUpdateFragment = function() {
|
|
|
170
159
|
this.options.urlMode = 'hash';
|
|
171
160
|
} else {
|
|
172
161
|
const baseWithoutSlash = this.options.urlHistoryBasePath.replace(/\/+$/, '');
|
|
173
|
-
const textFragment = this.urlPlugin.retrieveTextFragment(newQueryString);
|
|
174
162
|
const newUrlPath = `${baseWithoutSlash}${newFragmentWithSlash}${newQueryString}`;
|
|
175
|
-
|
|
176
|
-
if (!this.textFragmentPage && textFragment) {
|
|
177
|
-
this.textFragmentPage = extractedPage ? extractedPage : null;
|
|
178
|
-
this.textFragment = `:~:text=${textFragment}`;
|
|
179
|
-
}
|
|
163
|
+
|
|
180
164
|
try {
|
|
181
165
|
window.history.replaceState({}, null, newUrlPath);
|
|
182
166
|
this.oldLocationHash = newFragment + newQueryString;
|
|
183
|
-
if (textFragment) {
|
|
184
|
-
this.oldLocationHash += `:~:text=${textFragment[0]}`;
|
|
185
|
-
}
|
|
186
167
|
} catch (e) {
|
|
187
168
|
// DOMException on Chrome when in sandboxed iframe
|
|
188
169
|
this.options.urlMode = 'hash';
|
|
@@ -192,22 +173,8 @@ BookReader.prototype.urlUpdateFragment = function() {
|
|
|
192
173
|
|
|
193
174
|
if (this.options.urlMode === 'hash') {
|
|
194
175
|
const newQueryStringSearch = this.urlParamsFiltersOnlySearch(this.readQueryString());
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (textFragment) {
|
|
199
|
-
textFragment = `:~:text=${textFragment[0]}`;
|
|
200
|
-
} else {
|
|
201
|
-
textFragment = '';
|
|
202
|
-
}
|
|
203
|
-
if (!this.textFragmentPage && textFragment) {
|
|
204
|
-
this.textFragmentPage = extractedPage ? extractedPage : null;
|
|
205
|
-
this.textFragment = textFragment;
|
|
206
|
-
} else if (this.textFragmentPage && extractedPage != this.textFragmentPage) {
|
|
207
|
-
textFragment = '';
|
|
208
|
-
}
|
|
209
|
-
window.location.replace('#' + newFragment + newQueryStringSearch + textFragment);
|
|
210
|
-
this.oldLocationHash = newFragment + newQueryStringSearch + textFragment;
|
|
176
|
+
window.location.replace('#' + newFragment + newQueryStringSearch);
|
|
177
|
+
this.oldLocationHash = newFragment + newQueryStringSearch;
|
|
211
178
|
}
|
|
212
179
|
};
|
|
213
180
|
|
|
@@ -248,28 +215,9 @@ export class BookreaderUrlPlugin extends BookReader {
|
|
|
248
215
|
init() {
|
|
249
216
|
if (this.options.enableUrlPlugin) {
|
|
250
217
|
this.urlPlugin = new UrlPlugin(this.options);
|
|
251
|
-
const location = this.getLocationSearch();
|
|
252
|
-
if (location.includes("text=")) {
|
|
253
|
-
this.on('textLayerVisible', async (_, {pageContainerEl}) => {
|
|
254
|
-
const visiblePageNum = pageContainerEl.getAttribute('data-page-num');
|
|
255
|
-
|
|
256
|
-
// Hack: More time mode 1up page "settle down" from user scrolling
|
|
257
|
-
await sleep(this.mode === 1 ? 900 : 100);
|
|
258
|
-
|
|
259
|
-
// No textFragment found or the textFragment stored doesn't match current visible page loaded
|
|
260
|
-
if (!this.textFragment || this.textFragmentPage !== visiblePageNum) return;
|
|
261
|
-
if (this.options.urlMode === 'history') {
|
|
262
|
-
window.location.replace(`#${this.textFragment}`);
|
|
263
|
-
} else {
|
|
264
|
-
// for urlMode hash, textFragment is stored in oldLocationHash already
|
|
265
|
-
window.location.replace(`#${this.oldLocationHash}`);
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
this.bind(BookReader.eventNames.PostInit, () => {
|
|
270
|
-
const { urlMode } = this.options;
|
|
271
218
|
|
|
272
|
-
|
|
219
|
+
this.on(BookReader.eventNames.PostInit, () => {
|
|
220
|
+
if (this.options.urlMode === 'hash') {
|
|
273
221
|
this.urlPlugin.listenForHashChanges();
|
|
274
222
|
}
|
|
275
223
|
});
|