@internetarchive/bookreader 5.0.0-7 → 5.0.0-70-a1
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/.eslintrc.js +17 -15
- package/.github/workflows/node.js.yml +73 -10
- package/.github/workflows/npm-publish.yml +6 -20
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +396 -1129
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +20 -20
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1788 -0
- package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +19 -0
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/1up.svg +1 -1
- package/BookReader/icons/2up.svg +1 -1
- package/BookReader/icons/advance.svg +1 -1
- package/BookReader/icons/chevron-right.svg +1 -1
- package/BookReader/icons/close-circle-dark.svg +1 -1
- package/BookReader/icons/close-circle.svg +1 -1
- package/BookReader/icons/fullscreen.svg +1 -1
- package/BookReader/icons/fullscreen_exit.svg +1 -1
- package/BookReader/icons/hamburger.svg +1 -1
- package/BookReader/icons/left-arrow.svg +1 -1
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +1 -1
- package/BookReader/icons/magnify.svg +1 -1
- package/BookReader/icons/pause.svg +1 -1
- package/BookReader/icons/play.svg +1 -1
- package/BookReader/icons/playback-speed.svg +1 -1
- package/BookReader/icons/read-aloud.svg +1 -1
- package/BookReader/icons/review.svg +1 -1
- package/BookReader/icons/thumbnails.svg +1 -1
- package/BookReader/icons/voice.svg +1 -0
- package/BookReader/icons/volume-full.svg +1 -1
- package/BookReader/images/BRicons.svg +3 -3
- package/BookReader/images/books_graphic.svg +1 -1
- package/BookReader/images/icon_book.svg +1 -1
- package/BookReader/images/icon_bookmark.svg +1 -1
- package/BookReader/images/icon_gear.svg +1 -1
- package/BookReader/images/icon_hamburger.svg +1 -1
- package/BookReader/images/icon_home.svg +1 -1
- package/BookReader/images/icon_info.svg +1 -1
- package/BookReader/images/icon_one_page.svg +1 -1
- package/BookReader/images/icon_pause.svg +1 -1
- package/BookReader/images/icon_play.svg +1 -1
- package/BookReader/images/icon_playback-rate.svg +1 -1
- package/BookReader/images/icon_search_button.svg +1 -1
- package/BookReader/images/icon_share.svg +1 -1
- package/BookReader/images/icon_skip-ahead.svg +1 -1
- package/BookReader/images/icon_skip-back.svg +1 -1
- package/BookReader/images/icon_speaker.svg +1 -1
- package/BookReader/images/icon_speaker_open.svg +1 -1
- package/BookReader/images/icon_thumbnails.svg +1 -1
- package/BookReader/images/icon_toc.svg +1 -1
- package/BookReader/images/icon_two_pages.svg +1 -1
- package/BookReader/images/marker_chap-off.svg +1 -1
- package/BookReader/images/marker_chap-on.svg +1 -1
- package/BookReader/images/marker_srch-on.svg +1 -1
- package/BookReader/jquery-3.js +2 -0
- package/BookReader/jquery-3.js.LICENSE.txt +24 -0
- package/BookReader/plugins/plugin.archive_analytics.js +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +25 -1
- package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +1 -1
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +2 -1
- package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +2 -1
- package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -1
- 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/BookReader/webcomponents-bundle.js +3 -0
- package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
- package/BookReader/webcomponents-bundle.js.map +1 -0
- package/BookReaderDemo/BookReaderDemo.css +16 -19
- package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
- package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
- package/BookReaderDemo/BookReaderJSSimple.js +1 -0
- package/BookReaderDemo/IADemoBr.js +147 -0
- package/BookReaderDemo/demo-advanced.html +2 -2
- package/BookReaderDemo/demo-autoplay.html +2 -3
- package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
- package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
- package/BookReaderDemo/demo-fullscreen.html +2 -4
- package/BookReaderDemo/demo-iiif.html +2 -1
- package/BookReaderDemo/demo-iiif.js +0 -1
- package/BookReaderDemo/demo-internetarchive.html +213 -17
- package/BookReaderDemo/demo-multiple.html +2 -1
- package/BookReaderDemo/demo-preview-pages.html +2 -1
- package/BookReaderDemo/demo-simple.html +2 -1
- package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +2 -2
- package/BookReaderDemo/immersion-mode.html +2 -4
- package/BookReaderDemo/toggle_controls.html +3 -2
- package/BookReaderDemo/view_mode.html +2 -1
- package/BookReaderDemo/viewmode-cycle.html +2 -3
- package/CHANGELOG.md +279 -0
- package/README.md +14 -1
- package/babel.config.js +20 -0
- package/codecov.yml +6 -0
- package/index.html +4 -1
- package/jsconfig.json +19 -0
- package/netlify.toml +9 -0
- package/package.json +69 -60
- package/renovate.json +52 -0
- package/scripts/preversion.js +4 -1
- package/src/BookNavigator/assets/bookmark-colors.js +1 -1
- package/src/BookNavigator/assets/button-base.js +4 -2
- package/src/BookNavigator/assets/ia-logo.js +17 -0
- package/src/BookNavigator/assets/icon_checkmark.js +1 -1
- package/src/BookNavigator/assets/icon_close.js +1 -1
- package/src/BookNavigator/book-navigator.js +586 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
- package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
- package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
- package/src/BookNavigator/delete-modal-actions.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +36 -21
- package/src/BookNavigator/downloads/downloads.js +41 -25
- package/src/BookNavigator/search/search-provider.js +49 -27
- package/src/BookNavigator/search/search-results.js +23 -9
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
- package/src/BookNavigator/volumes/volumes-provider.js +95 -0
- package/src/BookReader/BookModel.js +64 -34
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +56 -351
- package/src/BookReader/Mode1UpLit.js +388 -0
- package/src/BookReader/Mode2Up.js +73 -1318
- package/src/BookReader/Mode2UpLit.js +776 -0
- package/src/BookReader/ModeCoordinateSpace.js +29 -0
- package/src/BookReader/ModeSmoothZoom.js +312 -0
- package/src/BookReader/ModeThumb.js +18 -12
- package/src/BookReader/Navbar/Navbar.js +12 -38
- package/src/BookReader/PageContainer.js +81 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +10 -37
- package/src/BookReader/events.js +2 -3
- package/src/BookReader/options.js +24 -2
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils/SelectionObserver.js +43 -0
- package/src/BookReader/utils.js +118 -13
- package/src/BookReader.js +423 -1056
- package/src/assets/icons/magnify-minus.svg +3 -7
- package/src/assets/icons/magnify-plus.svg +3 -7
- package/src/assets/icons/voice.svg +1 -0
- package/src/css/BookReader.scss +1 -5
- package/src/css/_BRBookmarks.scss +1 -1
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +16 -0
- package/src/css/_BRnav.scss +11 -38
- package/src/css/_BRpages.scss +149 -40
- package/src/css/_BRsearch.scss +67 -21
- package/src/css/_TextSelection.scss +87 -27
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +20 -7
- package/src/css/_icons.scss +1 -1
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.archive_analytics.js +3 -3
- package/src/plugins/plugin.autoplay.js +5 -11
- package/src/plugins/plugin.chapters.js +211 -186
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +464 -134
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +142 -125
- package/src/plugins/search/utils.js +43 -0
- package/src/plugins/search/view.js +33 -58
- package/src/plugins/tts/AbstractTTSEngine.js +46 -37
- package/src/plugins/tts/FestivalTTSEngine.js +13 -14
- package/src/plugins/tts/PageChunk.js +15 -21
- package/src/plugins/tts/PageChunkIterator.js +8 -12
- package/src/plugins/tts/WebTTSEngine.js +87 -71
- package/src/plugins/tts/plugin.tts.js +95 -126
- package/src/plugins/tts/utils.js +0 -25
- package/src/plugins/url/UrlPlugin.js +193 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
- package/src/util/browserSniffing.js +22 -0
- package/src/util/docCookies.js +21 -2
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +8 -16
- package/tests/e2e/helpers/base.js +53 -48
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/helpers/rightToLeft.js +8 -14
- package/tests/e2e/helpers/search.js +73 -0
- package/tests/e2e/models/Navigation.js +20 -37
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +40 -33
- package/tests/jest/BookNavigator/book-navigator.test.js +658 -0
- package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
- package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
- package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
- package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
- package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
- package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
- package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
- package/tests/{karma → jest}/BookNavigator/search/search-results.test.js +109 -60
- package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
- package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +80 -0
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
- package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
- package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
- package/tests/jest/BookReader/Mode2Up.test.js +98 -0
- package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
- package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
- package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
- package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
- package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
- package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
- package/tests/jest/BookReader/utils/SelectionObserver.test.js +43 -0
- package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
- package/tests/jest/BookReader/utils.test.js +229 -0
- package/tests/jest/BookReader.keyboard.test.js +190 -0
- package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
- package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
- package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
- package/tests/jest/plugins/plugin.chapters.test.js +145 -0
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
- package/tests/jest/plugins/plugin.text_selection.test.js +317 -0
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +25 -47
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +39 -6
- package/tests/jest/plugins/search/utils.js +25 -0
- package/tests/jest/plugins/search/utils.test.js +29 -0
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
- package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
- package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
- package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
- package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
- package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
- package/tests/jest/setup.js +3 -0
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/jest/util/docCookies.test.js +24 -0
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/webpack.config.js +11 -6
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/bookreader-component-bundle.js +0 -1450
- package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
- package/BookReader/bookreader-component-bundle.js.map +0 -1
- package/BookReader/jquery-1.10.1.js +0 -2
- package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
- package/BookReader/plugins/plugin.menu_toggle.js +0 -2
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReader/plugins/plugin.mobile_nav.js +0 -2
- package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
- package/karma.conf.js +0 -23
- package/src/BookNavigator/BookModel.js +0 -14
- package/src/BookNavigator/BookNavigator.js +0 -446
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- package/src/BookNavigator/search/a-search-result.js +0 -55
- package/src/BookReader/DebugConsole.js +0 -54
- package/src/BookReaderComponent/BookReaderComponent.js +0 -112
- package/src/ItemNavigator/ItemNavigator.js +0 -376
- package/src/ItemNavigator/providers/sharing.js +0 -29
- package/src/css/_MobileNav.scss +0 -194
- package/src/dragscrollable-br.js +0 -261
- package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
- package/src/plugins/plugin.mobile_nav.js +0 -287
- package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
- package/tests/BookReader/DebugConsole.test.js +0 -25
- package/tests/BookReader/Mode1Up.test.js +0 -164
- package/tests/BookReader/Mode2Up.test.js +0 -247
- package/tests/BookReader/utils.test.js +0 -109
- package/tests/e2e/helpers/desktopSearch.js +0 -72
- package/tests/e2e/helpers/mobileSearch.js +0 -85
- package/tests/e2e/ia-production/ia-prod-base.js +0 -17
- package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
- package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
- package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
- package/tests/plugins/plugin.chapters.test.js +0 -130
- package/tests/plugins/plugin.mobile_nav.test.js +0 -66
- package/tests/plugins/plugin.text_selection.test.js +0 -203
- package/tests/util/docCookies.test.js +0 -15
@@ -0,0 +1,29 @@
|
|
1
|
+
import { calcScreenDPI } from './utils';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* There are a few different "coordinate spaces" at play in BR:
|
5
|
+
* (1) World units: i.e. inches. Unless otherwise stated, all computations
|
6
|
+
* are done in world units.
|
7
|
+
* (2) Rendered Pixels: i.e. img.width = '300'. Note this does _not_ take
|
8
|
+
* into account zoom scaling.
|
9
|
+
* (3) Visible Pixels: Just rendered pixels, but taking into account scaling.
|
10
|
+
*/
|
11
|
+
export class ModeCoordinateSpace {
|
12
|
+
screenDPI = calcScreenDPI();
|
13
|
+
|
14
|
+
/**
|
15
|
+
* @param {{ scale: number }} mode
|
16
|
+
*/
|
17
|
+
constructor(mode) {
|
18
|
+
this.mode = mode;
|
19
|
+
}
|
20
|
+
|
21
|
+
worldUnitsToRenderedPixels = (/** @type {number} */inches) => inches * this.screenDPI;
|
22
|
+
renderedPixelsToWorldUnits = (/** @type {number} */px) => px / this.screenDPI;
|
23
|
+
|
24
|
+
renderedPixelsToVisiblePixels = (/** @type {number} */px) => px * this.mode.scale;
|
25
|
+
visiblePixelsToRenderedPixels = (/** @type {number} */px) => px / this.mode.scale;
|
26
|
+
|
27
|
+
worldUnitsToVisiblePixels = (/** @type {number} */px) => this.renderedPixelsToVisiblePixels(this.worldUnitsToRenderedPixels(px));
|
28
|
+
visiblePixelsToWorldUnits = (/** @type {number} */px) => this.renderedPixelsToWorldUnits(this.visiblePixelsToRenderedPixels(px));
|
29
|
+
}
|
@@ -0,0 +1,312 @@
|
|
1
|
+
// @ts-check
|
2
|
+
import interact from 'interactjs';
|
3
|
+
import { isIOS, isSamsungInternet } from '../util/browserSniffing.js';
|
4
|
+
import { sleep } from './utils.js';
|
5
|
+
/** @typedef {import('./utils/HTMLDimensionsCacher.js').HTMLDimensionsCacher} HTMLDimensionsCacher */
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @typedef {object} SmoothZoomable
|
9
|
+
* @property {HTMLElement} $container
|
10
|
+
* @property {HTMLElement} $visibleWorld
|
11
|
+
* @property {import("./options.js").AutoFitValues} autoFit
|
12
|
+
* @property {number} scale
|
13
|
+
* @property {HTMLDimensionsCacher} htmlDimensionsCacher
|
14
|
+
* @property {function(): void} [attachScrollListeners]
|
15
|
+
* @property {function(): void} [detachScrollListeners]
|
16
|
+
*/
|
17
|
+
|
18
|
+
/** Manages pinch-zoom, ctrl-wheel, and trackpad pinch smooth zooming. */
|
19
|
+
export class ModeSmoothZoom {
|
20
|
+
/** Position (in unit-less, [0, 1] coordinates) in client to scale around */
|
21
|
+
scaleCenter = { x: 0.5, y: 0.5 };
|
22
|
+
|
23
|
+
/** @param {SmoothZoomable} mode */
|
24
|
+
constructor(mode) {
|
25
|
+
/** @type {SmoothZoomable} */
|
26
|
+
this.mode = mode;
|
27
|
+
|
28
|
+
/** Whether a pinch is currently happening */
|
29
|
+
this.pinching = false;
|
30
|
+
/** Non-null when a scale has been enqueued/is being processed by the buffer function */
|
31
|
+
this.pinchMoveFrame = null;
|
32
|
+
/** Promise for the current/enqueued pinch move frame. Resolves when it is complete. */
|
33
|
+
this.pinchMoveFramePromise = Promise.resolve();
|
34
|
+
this.oldScale = 1;
|
35
|
+
/** @type {{ scale: number, clientX: number, clientY: number }}} */
|
36
|
+
this.lastEvent = null;
|
37
|
+
this.attached = false;
|
38
|
+
|
39
|
+
/** @type {function(function(): void): any} */
|
40
|
+
this.bufferFn = window.requestAnimationFrame.bind(window);
|
41
|
+
}
|
42
|
+
|
43
|
+
attach() {
|
44
|
+
if (this.attached) return;
|
45
|
+
|
46
|
+
this.attachCtrlZoom();
|
47
|
+
|
48
|
+
// GestureEvents work only on Safari; they're too glitchy to use
|
49
|
+
// fully, but they can sometimes help error correct when interact
|
50
|
+
// misses an end/start event on Safari due to Safari bugs.
|
51
|
+
this.mode.$container.addEventListener('gesturestart', this._pinchStart);
|
52
|
+
this.mode.$container.addEventListener('gesturechange', this._preventEvent);
|
53
|
+
this.mode.$container.addEventListener('gestureend', this._pinchEnd);
|
54
|
+
|
55
|
+
if (isIOS()) {
|
56
|
+
this.touchesMonitor = new TouchesMonitor(this.mode.$container);
|
57
|
+
this.touchesMonitor.attach();
|
58
|
+
}
|
59
|
+
|
60
|
+
this.mode.$container.style.touchAction = "pan-x pan-y";
|
61
|
+
|
62
|
+
// The pinch listeners
|
63
|
+
this.interact = interact(this.mode.$container);
|
64
|
+
this.interact.gesturable({
|
65
|
+
listeners: {
|
66
|
+
start: this._pinchStart,
|
67
|
+
end: this._pinchEnd,
|
68
|
+
}
|
69
|
+
});
|
70
|
+
if (isSamsungInternet()) {
|
71
|
+
// Samsung internet pinch-zoom will not work unless we disable
|
72
|
+
// all touch actions. So use interact.js' built-in drag support
|
73
|
+
// to handle moving on that browser.
|
74
|
+
this.mode.$container.style.touchAction = "none";
|
75
|
+
this.interact
|
76
|
+
.draggable({
|
77
|
+
inertia: {
|
78
|
+
resistance: 2,
|
79
|
+
minSpeed: 100,
|
80
|
+
allowResume: true,
|
81
|
+
},
|
82
|
+
listeners: { move: this._dragMove }
|
83
|
+
});
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
this.attached = true;
|
88
|
+
}
|
89
|
+
|
90
|
+
detach() {
|
91
|
+
this.detachCtrlZoom();
|
92
|
+
|
93
|
+
// GestureEvents work only on Safari; they interfere with Hammer,
|
94
|
+
// so block them.
|
95
|
+
this.mode.$container.removeEventListener('gesturestart', this._pinchStart);
|
96
|
+
this.mode.$container.removeEventListener('gesturechange', this._preventEvent);
|
97
|
+
this.mode.$container.removeEventListener('gestureend', this._pinchEnd);
|
98
|
+
|
99
|
+
this.touchesMonitor?.detach?.();
|
100
|
+
|
101
|
+
// The pinch listeners
|
102
|
+
this.interact.unset();
|
103
|
+
interact.removeDocument(document);
|
104
|
+
|
105
|
+
this.attached = false;
|
106
|
+
}
|
107
|
+
|
108
|
+
/** @param {Event} ev */
|
109
|
+
_preventEvent = (ev) => {
|
110
|
+
ev.preventDefault();
|
111
|
+
return false;
|
112
|
+
}
|
113
|
+
|
114
|
+
_pinchStart = async () => {
|
115
|
+
// Safari calls gesturestart twice!
|
116
|
+
if (this.pinching) return;
|
117
|
+
if (isIOS()) {
|
118
|
+
// Safari sometimes causes a pinch to trigger when there's only one touch!
|
119
|
+
await sleep(0); // touches monitor can receive the touch event late
|
120
|
+
if (this.touchesMonitor.touches < 2) return;
|
121
|
+
}
|
122
|
+
this.pinching = true;
|
123
|
+
|
124
|
+
// Do this in case the pinchend hasn't fired yet.
|
125
|
+
this.oldScale = 1;
|
126
|
+
this.mode.$visibleWorld.classList.add("BRsmooth-zooming");
|
127
|
+
this.mode.$visibleWorld.style.willChange = "transform";
|
128
|
+
this.mode.autoFit = "none";
|
129
|
+
this.detachCtrlZoom();
|
130
|
+
this.mode.detachScrollListeners?.();
|
131
|
+
|
132
|
+
this.interact.gesturable({
|
133
|
+
listeners: {
|
134
|
+
start: this._pinchStart,
|
135
|
+
move: this._pinchMove,
|
136
|
+
end: this._pinchEnd,
|
137
|
+
}
|
138
|
+
});
|
139
|
+
}
|
140
|
+
|
141
|
+
/** @param {{ scale: number, clientX: number, clientY: number }}} e */
|
142
|
+
_pinchMove = async (e) => {
|
143
|
+
if (!this.pinching) return;
|
144
|
+
this.lastEvent = {
|
145
|
+
scale: e.scale,
|
146
|
+
clientX: e.clientX,
|
147
|
+
clientY: e.clientY,
|
148
|
+
};
|
149
|
+
if (!this.pinchMoveFrame) {
|
150
|
+
// Buffer these events; only update the scale when request animation fires
|
151
|
+
this.pinchMoveFrame = this.bufferFn(this._drawPinchZoomFrame);
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
_pinchEnd = async () => {
|
156
|
+
if (!this.pinching) return;
|
157
|
+
this.pinching = false;
|
158
|
+
this.interact.gesturable({
|
159
|
+
listeners: {
|
160
|
+
start: this._pinchStart,
|
161
|
+
end: this._pinchEnd,
|
162
|
+
}
|
163
|
+
});
|
164
|
+
// Want this to happen after the pinchMoveFrame,
|
165
|
+
// if one is in progress; otherwise setting oldScale
|
166
|
+
// messes up the transform.
|
167
|
+
await this.pinchMoveFramePromise;
|
168
|
+
this.scaleCenter = { x: 0.5, y: 0.5 };
|
169
|
+
this.oldScale = 1;
|
170
|
+
this.mode.$visibleWorld.classList.remove("BRsmooth-zooming");
|
171
|
+
this.mode.$visibleWorld.style.willChange = "auto";
|
172
|
+
this.attachCtrlZoom();
|
173
|
+
this.mode.attachScrollListeners?.();
|
174
|
+
}
|
175
|
+
|
176
|
+
_drawPinchZoomFrame = async () => {
|
177
|
+
// Because of the buffering/various timing locks,
|
178
|
+
// this can be called after the pinch has ended, which
|
179
|
+
// results in a janky zoom after the pinch.
|
180
|
+
if (!this.pinching) {
|
181
|
+
this.pinchMoveFrame = null;
|
182
|
+
return;
|
183
|
+
}
|
184
|
+
|
185
|
+
this.mode.$container.style.overflow = "hidden";
|
186
|
+
this.pinchMoveFramePromiseRes = null;
|
187
|
+
this.pinchMoveFramePromise = new Promise(
|
188
|
+
(res) => (this.pinchMoveFramePromiseRes = res)
|
189
|
+
);
|
190
|
+
this.updateScaleCenter({
|
191
|
+
clientX: this.lastEvent.clientX,
|
192
|
+
clientY: this.lastEvent.clientY,
|
193
|
+
});
|
194
|
+
const curScale = this.mode.scale;
|
195
|
+
const newScale = curScale * this.lastEvent.scale / this.oldScale;
|
196
|
+
|
197
|
+
if (curScale != newScale) {
|
198
|
+
this.mode.scale = newScale;
|
199
|
+
await this.pinchMoveFramePromise;
|
200
|
+
}
|
201
|
+
this.mode.$container.style.overflow = "auto";
|
202
|
+
this.oldScale = this.lastEvent.scale;
|
203
|
+
this.pinchMoveFrame = null;
|
204
|
+
}
|
205
|
+
|
206
|
+
_dragMove = async (e) => {
|
207
|
+
if (this.pinching) {
|
208
|
+
await this._pinchEnd();
|
209
|
+
}
|
210
|
+
this.mode.$container.scrollTop -= e.dy;
|
211
|
+
this.mode.$container.scrollLeft -= e.dx;
|
212
|
+
}
|
213
|
+
|
214
|
+
/** @private */
|
215
|
+
attachCtrlZoom() {
|
216
|
+
window.addEventListener("wheel", this._handleCtrlWheel, { passive: false });
|
217
|
+
}
|
218
|
+
|
219
|
+
/** @private */
|
220
|
+
detachCtrlZoom() {
|
221
|
+
window.removeEventListener("wheel", this._handleCtrlWheel);
|
222
|
+
}
|
223
|
+
|
224
|
+
/** @param {WheelEvent} ev **/
|
225
|
+
_handleCtrlWheel = (ev) => {
|
226
|
+
if (!ev.ctrlKey) return;
|
227
|
+
ev.preventDefault();
|
228
|
+
const zoomMultiplier =
|
229
|
+
// Zooming on macs was painfully slow; likely due to their better
|
230
|
+
// trackpads. Give them a higher zoom rate.
|
231
|
+
/Mac/i.test(navigator.platform)
|
232
|
+
? 0.045
|
233
|
+
: // This worked well for me on Windows
|
234
|
+
0.03;
|
235
|
+
|
236
|
+
// Zoom around the cursor
|
237
|
+
this.updateScaleCenter(ev);
|
238
|
+
this.mode.autoFit = "none";
|
239
|
+
this.mode.scale *= 1 - Math.sign(ev.deltaY) * zoomMultiplier;
|
240
|
+
}
|
241
|
+
|
242
|
+
/**
|
243
|
+
* @param {object} param0
|
244
|
+
* @param {number} param0.clientX
|
245
|
+
* @param {number} param0.clientY
|
246
|
+
*/
|
247
|
+
updateScaleCenter({ clientX, clientY }) {
|
248
|
+
const bc = this.mode.htmlDimensionsCacher.boundingClientRect;
|
249
|
+
this.scaleCenter = {
|
250
|
+
x: (clientX - bc.left) / this.mode.htmlDimensionsCacher.clientWidth,
|
251
|
+
y: (clientY - bc.top) / this.mode.htmlDimensionsCacher.clientHeight,
|
252
|
+
};
|
253
|
+
}
|
254
|
+
|
255
|
+
/**
|
256
|
+
* @param {number} newScale
|
257
|
+
* @param {number} oldScale
|
258
|
+
*/
|
259
|
+
updateViewportOnZoom(newScale, oldScale) {
|
260
|
+
const container = this.mode.$container;
|
261
|
+
const { scrollTop: T, scrollLeft: L } = container;
|
262
|
+
const W = this.mode.htmlDimensionsCacher.clientWidth;
|
263
|
+
const H = this.mode.htmlDimensionsCacher.clientHeight;
|
264
|
+
|
265
|
+
// Scale factor change
|
266
|
+
const F = newScale / oldScale;
|
267
|
+
|
268
|
+
// Where in the viewport the zoom is centered on
|
269
|
+
const XPOS = this.scaleCenter.x;
|
270
|
+
const YPOS = this.scaleCenter.y;
|
271
|
+
const oldCenter = {
|
272
|
+
x: L + XPOS * W,
|
273
|
+
y: T + YPOS * H,
|
274
|
+
};
|
275
|
+
const newCenter = {
|
276
|
+
x: F * oldCenter.x,
|
277
|
+
y: F * oldCenter.y,
|
278
|
+
};
|
279
|
+
|
280
|
+
container.scrollTop = newCenter.y - YPOS * H;
|
281
|
+
container.scrollLeft = newCenter.x - XPOS * W;
|
282
|
+
this.pinchMoveFramePromiseRes?.();
|
283
|
+
}
|
284
|
+
}
|
285
|
+
|
286
|
+
export class TouchesMonitor {
|
287
|
+
/**
|
288
|
+
* @param {HTMLElement} container
|
289
|
+
*/
|
290
|
+
constructor(container) {
|
291
|
+
/** @type {HTMLElement} */
|
292
|
+
this.container = container;
|
293
|
+
this.touches = 0;
|
294
|
+
}
|
295
|
+
|
296
|
+
attach() {
|
297
|
+
this.container.addEventListener("touchstart", this._updateTouchCount);
|
298
|
+
this.container.addEventListener("touchend", this._updateTouchCount);
|
299
|
+
}
|
300
|
+
|
301
|
+
detach() {
|
302
|
+
this.container.removeEventListener("touchstart", this._updateTouchCount);
|
303
|
+
this.container.removeEventListener("touchend", this._updateTouchCount);
|
304
|
+
}
|
305
|
+
|
306
|
+
/**
|
307
|
+
* @param {TouchEvent} ev
|
308
|
+
*/
|
309
|
+
_updateTouchCount = (ev) => {
|
310
|
+
this.touches = ev.touches.length;
|
311
|
+
}
|
312
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
// @ts-check
|
2
2
|
import { notInArray, clamp } from './utils.js';
|
3
3
|
import { EVENTS } from './events.js';
|
4
|
+
import { DragScrollable } from './DragScrollable.js';
|
4
5
|
/** @typedef {import('../BookREader.js').default} BookReader */
|
5
6
|
/** @typedef {import('./BookModel.js').PageIndex} PageIndex */
|
6
7
|
/** @typedef {import('./BookModel.js').BookModel} BookModel */
|
@@ -131,7 +132,7 @@ export class ModeThumb {
|
|
131
132
|
for (let i = 1; i < this.br.thumbRowBuffer; i++) {
|
132
133
|
if (firstRow - i >= 0) { rowsToDisplay.push(firstRow - i); }
|
133
134
|
}
|
134
|
-
rowsToDisplay.sort();
|
135
|
+
rowsToDisplay.sort((a, b) => a - b);
|
135
136
|
|
136
137
|
// Create the thumbnail divs and images (lazy loaded)
|
137
138
|
for (const row of rowsToDisplay) {
|
@@ -176,7 +177,7 @@ export class ModeThumb {
|
|
176
177
|
// shift viewModeOrder after clicking on thumbsnail leaf
|
177
178
|
const nextModeID = this.br.viewModeOrder.shift();
|
178
179
|
this.br.viewModeOrder.push(nextModeID);
|
179
|
-
this.br.updateViewModeButton($('.viewmode'), 'twopg', 'Two-page view');
|
180
|
+
this.br._components.navbar.updateViewModeButton($('.viewmode'), 'twopg', 'Two-page view');
|
180
181
|
|
181
182
|
this.br.trigger(EVENTS.fragmentChange);
|
182
183
|
event.stopPropagation();
|
@@ -214,8 +215,6 @@ export class ModeThumb {
|
|
214
215
|
|
215
216
|
// highlight current page
|
216
217
|
this.br.$('.pagediv' + this.br.currentIndex()).addClass('BRpagedivthumb_highlight');
|
217
|
-
|
218
|
-
this.br.updateToolbarZoom(this.br.reduce);
|
219
218
|
}
|
220
219
|
|
221
220
|
/**
|
@@ -234,20 +233,27 @@ export class ModeThumb {
|
|
234
233
|
}
|
235
234
|
|
236
235
|
/**
|
237
|
-
* @param {
|
236
|
+
* @param {'in' | 'out'} direction
|
238
237
|
*/
|
239
238
|
zoom(direction) {
|
240
239
|
const oldColumns = this.br.thumbColumns;
|
241
240
|
switch (direction) {
|
242
|
-
case
|
243
|
-
this.br.thumbColumns += 1;
|
244
|
-
break;
|
245
|
-
case 1:
|
241
|
+
case 'in':
|
246
242
|
this.br.thumbColumns -= 1;
|
247
243
|
break;
|
244
|
+
case 'out':
|
245
|
+
this.br.thumbColumns += 1;
|
246
|
+
break;
|
247
|
+
default:
|
248
|
+
console.error(`Unsupported direction: ${direction}`);
|
248
249
|
}
|
249
250
|
|
250
|
-
|
251
|
+
// Limit zoom in/out columns
|
252
|
+
this.br.thumbColumns = clamp(
|
253
|
+
this.br.thumbColumns,
|
254
|
+
this.br.options.thumbMinZoomColumns,
|
255
|
+
this.br.options.thumbMaxZoomColumns
|
256
|
+
);
|
251
257
|
|
252
258
|
if (this.br.thumbColumns != oldColumns) {
|
253
259
|
this.br.displayedRows = []; /* force a gallery redraw */
|
@@ -279,7 +285,7 @@ export class ModeThumb {
|
|
279
285
|
|
280
286
|
this.br.refs.$brPageViewEl = $("<div class='BRpageview'></div>");
|
281
287
|
this.br.refs.$brContainer.append(this.br.refs.$brPageViewEl);
|
282
|
-
this.br.refs.$brContainer
|
288
|
+
this.dragScrollable = this.dragScrollable || new DragScrollable(this.br.refs.$brContainer[0], {preventDefault: true});
|
283
289
|
|
284
290
|
this.br.bindGestures(this.br.refs.$brContainer);
|
285
291
|
|
@@ -330,7 +336,7 @@ export class ModeThumb {
|
|
330
336
|
} else {
|
331
337
|
this.br.animating = true;
|
332
338
|
this.br.refs.$brContainer.stop(true)
|
333
|
-
.animate({ scrollTop: leafTop }, 'fast', () => { this.br.animating = false });
|
339
|
+
.animate({ scrollTop: leafTop }, 'fast', () => { this.br.animating = false; });
|
334
340
|
}
|
335
341
|
}
|
336
342
|
}
|
@@ -4,6 +4,7 @@ import 'jquery-ui/ui/widget.js';
|
|
4
4
|
import 'jquery-ui/ui/widgets/mouse.js';
|
5
5
|
import 'jquery-ui/ui/widgets/slider.js';
|
6
6
|
import { EVENTS } from '../events.js';
|
7
|
+
import { throttle } from '../utils.js';
|
7
8
|
|
8
9
|
export class Navbar {
|
9
10
|
/**
|
@@ -27,6 +28,8 @@ export class Navbar {
|
|
27
28
|
this.maximumControls = [
|
28
29
|
'book_left', 'book_right', 'zoom_in', 'zoom_out', 'onepg', 'twopg', 'thumb'
|
29
30
|
];
|
31
|
+
|
32
|
+
this.updateNavIndexThrottled = throttle(this.updateNavIndex.bind(this), 250, false);
|
30
33
|
}
|
31
34
|
|
32
35
|
controlFor(controlName) {
|
@@ -38,7 +41,7 @@ export class Navbar {
|
|
38
41
|
return `<li>
|
39
42
|
<button class="BRicon ${option.className}" title="${option.label}">
|
40
43
|
<div class="icon icon-${option.iconClassName}"></div>
|
41
|
-
<span class="
|
44
|
+
<span class="BRtooltip">${option.label}</span>
|
42
45
|
</button>
|
43
46
|
</li>`;
|
44
47
|
}
|
@@ -127,7 +130,7 @@ export class Navbar {
|
|
127
130
|
.removeClass()
|
128
131
|
.addClass(`icon icon-${iconClass}`)
|
129
132
|
.end()
|
130
|
-
.find('.
|
133
|
+
.find('.BRtooltip')
|
131
134
|
.text(tooltipText);
|
132
135
|
}
|
133
136
|
|
@@ -213,7 +216,7 @@ export class Navbar {
|
|
213
216
|
const $slider = this.$root.find('.BRpager').slider({
|
214
217
|
animate: true,
|
215
218
|
min: 0,
|
216
|
-
max: br.getNumLeafs() - 1,
|
219
|
+
max: br.book.getNumLeafs() - 1,
|
217
220
|
value: br.currentIndex(),
|
218
221
|
range: "min"
|
219
222
|
});
|
@@ -240,35 +243,6 @@ export class Navbar {
|
|
240
243
|
return this.$nav;
|
241
244
|
}
|
242
245
|
|
243
|
-
/**
|
244
|
-
* Initialize the navigation bar when embedded
|
245
|
-
*/
|
246
|
-
initEmbed() {
|
247
|
-
const { br } = this;
|
248
|
-
// IA-specific
|
249
|
-
const thisLink = (window.location + '')
|
250
|
-
.replace('?ui=embed','')
|
251
|
-
.replace('/stream/', '/details/')
|
252
|
-
.replace('#', '/');
|
253
|
-
const logoHtml = br.showLogo ? `<a class="logo" href="${br.logoURL}" target="_blank"></a>` : '';
|
254
|
-
|
255
|
-
br.refs.$BRfooter = this.$root = $('<div class="BRfooter"></div>');
|
256
|
-
br.refs.$BRnav = this.$nav = $(
|
257
|
-
`<div class="BRnav BRnavEmbed">
|
258
|
-
${logoHtml}
|
259
|
-
<span class="BRembedreturn">
|
260
|
-
<a href="${thisLink}" target="_blank">${br.bookTitle}</a>
|
261
|
-
</span>
|
262
|
-
<span class="BRtoolbarbuttons">
|
263
|
-
<button class="BRicon book_left"></button>
|
264
|
-
<button class="BRicon book_right"></button>
|
265
|
-
<button class="BRicon full"></button>
|
266
|
-
</span>
|
267
|
-
</div>`);
|
268
|
-
this.$root.append(this.$nav);
|
269
|
-
br.refs.$br.append(this.$root);
|
270
|
-
}
|
271
|
-
|
272
246
|
/**
|
273
247
|
* Returns the textual representation of the current page for the navbar
|
274
248
|
* @param {number} index
|
@@ -277,16 +251,16 @@ export class Navbar {
|
|
277
251
|
getNavPageNumString(index) {
|
278
252
|
const { br } = this;
|
279
253
|
// Accessible index starts at 0 (alas) so we add 1 to make human
|
280
|
-
const pageNum = br.getPageNum(index);
|
281
|
-
const pageType = br.getPageProp(index, 'pageType');
|
282
|
-
const numLeafs = br.getNumLeafs();
|
254
|
+
const pageNum = br.book.getPageNum(index);
|
255
|
+
const pageType = br.book.getPageProp(index, 'pageType');
|
256
|
+
const numLeafs = br.book.getNumLeafs();
|
283
257
|
|
284
258
|
if (!this.maxPageNum) {
|
285
259
|
// Calculate Max page num (used for pagination display)
|
286
260
|
let maxPageNum = 0;
|
287
261
|
let pageNumVal;
|
288
262
|
for (let i = 0; i < numLeafs; i++) {
|
289
|
-
pageNumVal = br.getPageNum(i);
|
263
|
+
pageNumVal = br.book.getPageNum(i);
|
290
264
|
if (!isNaN(pageNumVal) && pageNumVal > maxPageNum) {
|
291
265
|
maxPageNum = pageNumVal;
|
292
266
|
}
|
@@ -331,9 +305,9 @@ export function getNavPageNumHtml(index, numLeafs, pageNum, pageType, maxPageNum
|
|
331
305
|
|
332
306
|
if (!pageIsAsserted) {
|
333
307
|
const pageIndex = index + 1;
|
334
|
-
return `
|
308
|
+
return `(${pageIndex} of ${numLeafs})`; // Page (8 of 10)
|
335
309
|
}
|
336
310
|
|
337
311
|
const bookLengthLabel = maxPageNum ? ` of ${maxPageNum}` : '';
|
338
|
-
return
|
312
|
+
return `${pageNum}${bookLengthLabel}`;
|
339
313
|
}
|
@@ -46,11 +46,17 @@ export class PageContainer {
|
|
46
46
|
const alreadyLoaded = this.imageCache.imageLoaded(this.page.index, reduce);
|
47
47
|
const nextBestLoadedReduce = !alreadyLoaded && this.imageCache.getBestLoadedReduce(this.page.index, reduce);
|
48
48
|
|
49
|
-
//
|
49
|
+
// Create high res image
|
50
|
+
const $newImg = this.imageCache.image(this.page.index, reduce);
|
51
|
+
|
52
|
+
// Avoid removing/re-adding the image if it's already there
|
53
|
+
// This can be called quite a bit, so we need to be fast
|
54
|
+
if (this.$img?.[0].src == $newImg[0].src) {
|
55
|
+
return this;
|
56
|
+
}
|
57
|
+
|
50
58
|
this.$img?.remove();
|
51
|
-
this.$img = this
|
52
|
-
.image(this.page.index, reduce)
|
53
|
-
.prependTo(this.$container);
|
59
|
+
this.$img = $newImg.prependTo(this.$container);
|
54
60
|
|
55
61
|
const backgroundLayers = [];
|
56
62
|
if (!alreadyLoaded) {
|
@@ -58,14 +64,14 @@ export class PageContainer {
|
|
58
64
|
backgroundLayers.push(`url("${this.loadingImage}") center/20px no-repeat`);
|
59
65
|
}
|
60
66
|
if (nextBestLoadedReduce) {
|
61
|
-
backgroundLayers.push(`url("${this.page.getURI(nextBestLoadedReduce, 0)}") center/100% no-repeat`);
|
67
|
+
backgroundLayers.push(`url("${this.page.getURI(nextBestLoadedReduce, 0)}") center/100% 100% no-repeat`);
|
62
68
|
}
|
63
69
|
|
64
70
|
if (!alreadyLoaded) {
|
65
71
|
this.$img
|
66
72
|
.css('background', backgroundLayers.join(','))
|
67
73
|
.one('loadend', async (ev) => {
|
68
|
-
$(ev.target).css({ 'background': '' })
|
74
|
+
$(ev.target).css({ 'background': '' });
|
69
75
|
$(ev.target).parent().removeClass('BRpageloading');
|
70
76
|
});
|
71
77
|
}
|
@@ -73,3 +79,72 @@ export class PageContainer {
|
|
73
79
|
return this;
|
74
80
|
}
|
75
81
|
}
|
82
|
+
|
83
|
+
|
84
|
+
/**
|
85
|
+
* @param {PageModel} page
|
86
|
+
* @param {string} className
|
87
|
+
*/
|
88
|
+
export function createSVGPageLayer(page, className) {
|
89
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
90
|
+
svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
91
|
+
svg.setAttribute("viewBox", `0 0 ${page.width} ${page.height}`);
|
92
|
+
svg.setAttribute('class', `BRPageLayer ${className}`);
|
93
|
+
svg.setAttribute('preserveAspectRatio', 'none');
|
94
|
+
return svg;
|
95
|
+
}
|
96
|
+
|
97
|
+
/**
|
98
|
+
* @param {PageModel} page
|
99
|
+
* @param {string} className
|
100
|
+
*/
|
101
|
+
export function createDIVPageLayer(page, className) {
|
102
|
+
const div = document.createElement("div");
|
103
|
+
div.style.width = `${page.width}px`;
|
104
|
+
div.style.height = `${page.height}px`;
|
105
|
+
div.setAttribute('class', `BRPageLayer ${className}`);
|
106
|
+
return div;
|
107
|
+
}
|
108
|
+
|
109
|
+
/**
|
110
|
+
* @param {{ l: number, r: number, b: number, t: number }} box
|
111
|
+
*/
|
112
|
+
export function boxToSVGRect({ l: left, r: right, b: bottom, t: top }) {
|
113
|
+
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
114
|
+
rect.setAttribute("x", left.toString());
|
115
|
+
rect.setAttribute("y", top.toString());
|
116
|
+
rect.setAttribute("width", (right - left).toString());
|
117
|
+
rect.setAttribute("height", (bottom - top).toString());
|
118
|
+
|
119
|
+
// Some style; corner radius 4px. Can't set this in CSS yet
|
120
|
+
rect.setAttribute("rx", "4");
|
121
|
+
rect.setAttribute("ry", "4");
|
122
|
+
return rect;
|
123
|
+
}
|
124
|
+
|
125
|
+
/**
|
126
|
+
* @param {string} layerClass
|
127
|
+
* @param {Array<{ l: number, r: number, b: number, t: number }>} boxes
|
128
|
+
* @param {PageModel} page
|
129
|
+
* @param {HTMLElement} containerEl
|
130
|
+
* @param {string[]} [rectClasses] CSS classes to add to the rects
|
131
|
+
*/
|
132
|
+
export function renderBoxesInPageContainerLayer(layerClass, boxes, page, containerEl, rectClasses = null) {
|
133
|
+
const mountedSvg = containerEl.querySelector(`.${layerClass}`);
|
134
|
+
// Create the layer if it's not there
|
135
|
+
const svg = mountedSvg || createSVGPageLayer(page, layerClass);
|
136
|
+
if (!mountedSvg) {
|
137
|
+
// Insert after the image if the image is already loaded.
|
138
|
+
const imgEl = containerEl.querySelector('.BRpageimage');
|
139
|
+
if (imgEl) $(svg).insertAfter(imgEl);
|
140
|
+
else $(svg).prependTo(containerEl);
|
141
|
+
}
|
142
|
+
|
143
|
+
for (const [i, box] of boxes.entries()) {
|
144
|
+
const rect = boxToSVGRect(box);
|
145
|
+
if (rectClasses) {
|
146
|
+
rect.setAttribute('class', rectClasses[i]);
|
147
|
+
}
|
148
|
+
svg.appendChild(rect);
|
149
|
+
}
|
150
|
+
}
|