@internetarchive/bookreader 5.0.0-4 → 5.0.0-40-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 +75 -4
- package/.github/workflows/npm-publish.yml +2 -16
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +83 -323
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +24 -0
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1623 -0
- package/BookReader/{bookreader-component-bundle.js.LICENSE.txt → ia-bookreader-bundle.js.LICENSE.txt} +14 -10
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/close-circle-dark.svg +1 -0
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +1 -1
- package/BookReader/icons/voice.svg +1 -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 +1 -1
- 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.mobile_nav.js +1 -1
- package/BookReader/plugins/plugin.mobile_nav.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 +1 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +1 -1
- package/BookReader/plugins/plugin.text_selection.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 -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 +14 -1
- package/BookReaderDemo/IADemoBr.js +120 -0
- package/BookReaderDemo/demo-advanced.html +1 -1
- package/BookReaderDemo/demo-autoplay.html +1 -0
- package/BookReaderDemo/demo-embed-iframe-src.html +1 -0
- package/BookReaderDemo/demo-fullscreen-mobile.html +1 -0
- package/BookReaderDemo/demo-fullscreen.html +1 -0
- package/BookReaderDemo/demo-iiif.html +1 -0
- package/BookReaderDemo/demo-internetarchive.html +74 -17
- package/BookReaderDemo/demo-multiple.html +1 -0
- package/BookReaderDemo/demo-preview-pages.html +1 -0
- package/BookReaderDemo/demo-simple.html +1 -0
- package/BookReaderDemo/demo-vendor-fullscreen.html +1 -0
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +1 -0
- package/BookReaderDemo/immersion-mode.html +1 -0
- package/BookReaderDemo/toggle_controls.html +1 -0
- package/BookReaderDemo/view_mode.html +1 -0
- package/BookReaderDemo/viewmode-cycle.html +1 -2
- package/CHANGELOG.md +166 -0
- package/README.md +14 -1
- package/babel.config.js +18 -0
- package/codecov.yml +6 -0
- package/index.html +3 -0
- package/jsconfig.json +19 -0
- package/package.json +62 -47
- package/renovate.json +43 -0
- package/src/BookNavigator/assets/bookmark-colors.js +1 -1
- package/src/BookNavigator/assets/button-base.js +9 -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/assets/icon_sort_asc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_desc.js +5 -0
- package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
- package/src/BookNavigator/assets/icon_volumes.js +11 -0
- package/src/BookNavigator/book-navigator.js +556 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
- package/src/BookNavigator/bookmarks/bookmark-edit.js +4 -4
- package/src/BookNavigator/bookmarks/bookmarks-list.js +3 -3
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +23 -12
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +98 -62
- package/src/BookNavigator/delete-modal-actions.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +23 -17
- package/src/BookNavigator/downloads/downloads.js +17 -25
- package/src/BookNavigator/search/a-search-result.js +3 -3
- package/src/BookNavigator/search/search-provider.js +57 -24
- package/src/BookNavigator/search/search-results.js +8 -20
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -13
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +4 -3
- package/src/BookNavigator/volumes/volumes-provider.js +114 -0
- package/src/BookNavigator/volumes/volumes.js +188 -0
- package/src/BookReader/DebugConsole.js +3 -3
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +51 -351
- package/src/BookReader/Mode1UpLit.js +441 -0
- package/src/BookReader/Mode2Up.js +104 -71
- package/src/BookReader/ModeSmoothZoom.js +179 -0
- package/src/BookReader/ModeThumb.js +16 -8
- package/src/BookReader/Navbar/Navbar.js +2 -31
- package/src/BookReader/PageContainer.js +57 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +7 -7
- package/src/BookReader/options.js +10 -0
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils.js +68 -13
- package/src/BookReader.js +375 -289
- package/src/assets/icons/close-circle-dark.svg +1 -0
- 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 +0 -12
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +19 -24
- package/src/css/_BRnav.scss +4 -26
- package/src/css/_BRpages.scss +35 -0
- package/src/css/_BRsearch.scss +11 -215
- package/src/css/_TextSelection.scss +14 -17
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +16 -3
- package/src/css/_icons.scss +6 -0
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.chapters.js +26 -33
- package/src/plugins/plugin.mobile_nav.js +11 -10
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +26 -39
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +106 -107
- package/src/plugins/search/view.js +50 -163
- package/src/plugins/tts/AbstractTTSEngine.js +46 -37
- package/src/plugins/tts/FestivalTTSEngine.js +12 -13
- package/src/plugins/tts/PageChunk.js +15 -21
- package/src/plugins/tts/PageChunkIterator.js +8 -12
- package/src/plugins/tts/WebTTSEngine.js +64 -68
- package/src/plugins/tts/plugin.tts.js +79 -108
- package/src/plugins/url/UrlPlugin.js +184 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +28 -6
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +7 -7
- package/tests/e2e/helpers/base.js +8 -3
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/desktopSearch.js +14 -13
- package/tests/e2e/helpers/mobileSearch.js +3 -3
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/models/Navigation.js +12 -3
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +38 -33
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +3 -3
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +176 -0
- package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
- package/tests/jest/BookReader/Mode1UpLit.test.js +88 -0
- package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +5 -7
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +149 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +7 -7
- package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +79 -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/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
- package/tests/jest/BookReader/utils.test.js +136 -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} +20 -4
- package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +8 -8
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +5 -5
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
- package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +39 -47
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +24 -25
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +6 -6
- 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 +1 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +3 -3
- package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +33 -14
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/{util → jest/util}/docCookies.test.js +1 -1
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/tests/karma/BookNavigator/book-navigator.test.js +501 -0
- package/tests/karma/BookNavigator/bookmarks/bookmark-button.test.js +44 -0
- package/tests/karma/BookNavigator/bookmarks/bookmark-edit.test.js +1 -3
- package/tests/karma/BookNavigator/bookmarks/bookmarks-list.test.js +3 -4
- package/tests/karma/BookNavigator/bookmarks/ia-bookmarks.test.js +57 -0
- package/tests/karma/BookNavigator/downloads/downloads-provider.test.js +67 -0
- package/tests/karma/BookNavigator/downloads/downloads.test.js +54 -0
- package/tests/karma/BookNavigator/search/search-provider.test.js +123 -0
- package/tests/karma/BookNavigator/{search-results.test.js → search/search-results.test.js} +1 -4
- package/tests/karma/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -2
- package/tests/karma/BookNavigator/volumes/volumes-provider.test.js +184 -0
- package/tests/karma/BookNavigator/volumes/volumes.test.js +98 -0
- package/webpack.config.js +10 -4
- 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.map +0 -1
- package/BookReader/plugins/plugin.menu_toggle.js +0 -2
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
- package/src/BookNavigator/BookModel.js +0 -14
- package/src/BookNavigator/BookNavigator.js +0 -435
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- package/src/BookReaderComponent/BookReaderComponent.js +0 -112
- package/src/ItemNavigator/ItemNavigator.js +0 -372
- package/src/ItemNavigator/providers/sharing.js +0 -29
- package/src/dragscrollable-br.js +0 -261
- package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
- package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
- package/tests/BookReader/Mode1Up.test.js +0 -164
- package/tests/BookReader/utils.test.js +0 -109
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
@@ -1,16 +1,21 @@
|
|
1
1
|
// @ts-check
|
2
2
|
// effect.js gives acces to extra easing function (e.g. easeInSine)
|
3
3
|
import 'jquery-ui/ui/effect.js';
|
4
|
-
import '../dragscrollable-br.js';
|
5
4
|
import { clamp } from './utils.js';
|
6
5
|
import { EVENTS } from './events.js';
|
6
|
+
import { ModeSmoothZoom } from "./ModeSmoothZoom.js";
|
7
|
+
import { HTMLDimensionsCacher } from './utils/HTMLDimensionsCacher.js';
|
8
|
+
import { DragScrollable } from './DragScrollable.js';
|
9
|
+
import { ScrollClassAdder } from './utils/ScrollClassAdder.js';
|
7
10
|
|
8
11
|
/** @typedef {import('../BookReader.js').default} BookReader */
|
9
12
|
/** @typedef {import('./BookModel.js').BookModel} BookModel */
|
10
13
|
/** @typedef {import('./BookModel.js').PageIndex} PageIndex */
|
11
14
|
/** @typedef {import('./options.js').BookReaderOptions} BookReaderOptions */
|
12
15
|
/** @typedef {import('./PageContainer.js').PageContainer} PageContainer */
|
16
|
+
/** @typedef {import('./ModeSmoothZoom').SmoothZoomable} SmoothZoomable */
|
13
17
|
|
18
|
+
/** @implements {SmoothZoomable} */
|
14
19
|
export class Mode2Up {
|
15
20
|
/**
|
16
21
|
* @param {BookReader} br
|
@@ -27,6 +32,28 @@ export class Mode2Up {
|
|
27
32
|
|
28
33
|
/** @type {{ [index: number]: PageContainer }} */
|
29
34
|
this.pageContainers = {};
|
35
|
+
|
36
|
+
/** @type {ModeSmoothZoom} */
|
37
|
+
this.smoothZoomer = null;
|
38
|
+
this._scale = 1;
|
39
|
+
this.scaleCenter = { x: 0.5, y: 0.5 };
|
40
|
+
|
41
|
+
/** @type {ScrollClassAdder} */
|
42
|
+
this.scrollClassAdder = null;
|
43
|
+
}
|
44
|
+
|
45
|
+
get $container() {
|
46
|
+
return this.br.refs.$brContainer[0];
|
47
|
+
}
|
48
|
+
get $visibleWorld() {
|
49
|
+
return this.br.refs.$brTwoPageView?.[0];
|
50
|
+
}
|
51
|
+
|
52
|
+
get scale() { return this._scale; }
|
53
|
+
set scale(newVal) {
|
54
|
+
this.$visibleWorld.style.transform = `scale(${newVal})`;
|
55
|
+
this.updateViewportOnZoom(newVal, this._scale);
|
56
|
+
this._scale = newVal;
|
30
57
|
}
|
31
58
|
|
32
59
|
/**
|
@@ -42,18 +69,6 @@ export class Mode2Up {
|
|
42
69
|
}
|
43
70
|
}
|
44
71
|
|
45
|
-
/**
|
46
|
-
* @template T
|
47
|
-
* @param {HTMLElement} element
|
48
|
-
* @param {T} data
|
49
|
-
* @param {function(HTMLElement, { data: T }): void} handler
|
50
|
-
*/
|
51
|
-
setClickHandler(element, data, handler) {
|
52
|
-
$(element).unbind('mouseup').bind('mouseup', data, function(e) {
|
53
|
-
handler(this, e);
|
54
|
-
});
|
55
|
-
}
|
56
|
-
|
57
72
|
/**
|
58
73
|
* Draws book spread,
|
59
74
|
* sets event handlers,
|
@@ -74,7 +89,6 @@ export class Mode2Up {
|
|
74
89
|
.appendTo($twoPageViewEl);
|
75
90
|
|
76
91
|
this.displayedIndices = [this.br.twoPage.currentIndexL, this.br.twoPage.currentIndexR];
|
77
|
-
this.setMouseHandlers();
|
78
92
|
this.br.displayedIndices = this.displayedIndices;
|
79
93
|
this.br.updateToolbarZoom(this.br.reduce);
|
80
94
|
this.br.trigger('pageChanged');
|
@@ -176,13 +190,22 @@ export class Mode2Up {
|
|
176
190
|
|
177
191
|
// Add the two page view
|
178
192
|
// $$$ Can we get everything set up and then append?
|
179
|
-
|
180
|
-
this.br.refs.$brTwoPageView
|
193
|
+
this.br.refs.$brTwoPageView = this.br.refs.$brTwoPageView || $('<div class="BRtwopageview"></div>');
|
194
|
+
const $twoPageViewEl = this.br.refs.$brTwoPageView;
|
195
|
+
$twoPageViewEl.empty();
|
196
|
+
$twoPageViewEl[0].style.transformOrigin = '0 0';
|
181
197
|
this.br.refs.$brContainer.append($twoPageViewEl);
|
182
198
|
|
183
199
|
// Attaches to first child, so must come after we add the page view
|
184
|
-
this.br.refs.$brContainer
|
185
|
-
|
200
|
+
this.dragScrollable = this.dragScrollable || new DragScrollable(this.br.refs.$brContainer[0], {
|
201
|
+
preventDefault: true,
|
202
|
+
// Only handle mouse events; let browser/HammerJS handle touch
|
203
|
+
dragstart: 'mousedown',
|
204
|
+
dragcontinue: 'mousemove',
|
205
|
+
dragend: 'mouseup',
|
206
|
+
});
|
207
|
+
|
208
|
+
this.attachMouseHandlers();
|
186
209
|
|
187
210
|
// $$$ calculate container size first
|
188
211
|
this.br.refs?.$brTwoPageView.css(this.mainContainerCss);
|
@@ -219,13 +242,57 @@ export class Mode2Up {
|
|
219
242
|
|
220
243
|
this.drawLeafs();
|
221
244
|
this.br.updateToolbarZoom(this.br.reduce);
|
245
|
+
this.br.updateBrClasses();
|
222
246
|
|
223
|
-
|
224
|
-
|
225
|
-
|
247
|
+
this.smoothZoomer = this.smoothZoomer || new ModeSmoothZoom(this);
|
248
|
+
this.smoothZoomer.attach();
|
249
|
+
if (!this.scrollClassAdder) {
|
250
|
+
this.scrollClassAdder = new ScrollClassAdder(this.$container, 'BRscrolling-active');
|
226
251
|
}
|
252
|
+
this.scrollClassAdder.detach();
|
253
|
+
this.scrollClassAdder.element = this.$container;
|
254
|
+
this.scrollClassAdder.attach();
|
227
255
|
|
228
|
-
this.
|
256
|
+
this.htmlDimensionsCacher = this.htmlDimensionsCacher || new HTMLDimensionsCacher(this.$container);
|
257
|
+
}
|
258
|
+
|
259
|
+
unprepare() {
|
260
|
+
// Mode2Up attaches these listeners to the main BR container, so we need to
|
261
|
+
// detach these or it will cause issues for the other modes.
|
262
|
+
this.smoothZoomer.detach();
|
263
|
+
this.scrollClassAdder.detach();
|
264
|
+
}
|
265
|
+
|
266
|
+
/**
|
267
|
+
* @param {number} newScale
|
268
|
+
* @param {number} oldScale
|
269
|
+
*/
|
270
|
+
updateViewportOnZoom(newScale, oldScale) {
|
271
|
+
const container = this.br.refs.$brContainer[0];
|
272
|
+
const { scrollTop: T, scrollLeft: L } = container;
|
273
|
+
const W = this.htmlDimensionsCacher.clientWidth;
|
274
|
+
const H = this.htmlDimensionsCacher.clientHeight;
|
275
|
+
|
276
|
+
// Scale factor change
|
277
|
+
const F = newScale / oldScale;
|
278
|
+
|
279
|
+
// Where in the viewport the zoom is centered on
|
280
|
+
const XPOS = this.scaleCenter.x;
|
281
|
+
const YPOS = this.scaleCenter.y;
|
282
|
+
const oldCenter = {
|
283
|
+
x: L + XPOS * W,
|
284
|
+
y: T + YPOS * H,
|
285
|
+
};
|
286
|
+
const newCenter = {
|
287
|
+
x: F * oldCenter.x,
|
288
|
+
y: F * oldCenter.y,
|
289
|
+
};
|
290
|
+
container.scrollTop = newCenter.y - YPOS * H;
|
291
|
+
container.scrollLeft = newCenter.x - XPOS * W;
|
292
|
+
|
293
|
+
// Also update the visible page containers to load in highres if necessary
|
294
|
+
this.pageContainers[this.br.twoPage.currentIndexL]?.update({ reduce: this.br.reduce / newScale });
|
295
|
+
this.pageContainers[this.br.twoPage.currentIndexR]?.update({ reduce: this.br.reduce / newScale });
|
229
296
|
}
|
230
297
|
|
231
298
|
prunePageContainers() {
|
@@ -616,8 +683,6 @@ export class Mode2Up {
|
|
616
683
|
|
617
684
|
$(this.br.leafEdgeTmp).animate({left: gutter}, this.br.flipSpeed, 'easeInSine');
|
618
685
|
|
619
|
-
if (this.br.enableSearch) this.br.removeSearchHilites();
|
620
|
-
|
621
686
|
this.pageContainers[leftLeaf].$container.animate({width: '0px'}, this.br.flipSpeed, 'easeInSine', () => {
|
622
687
|
|
623
688
|
$(this.br.leafEdgeTmp).animate({left: `${gutter + newWidthR}px`}, this.br.flipSpeed, 'easeOutSine');
|
@@ -663,10 +728,6 @@ export class Mode2Up {
|
|
663
728
|
|
664
729
|
this.resizeSpread();
|
665
730
|
|
666
|
-
if (this.br.enableSearch) this.br.updateSearchHilites();
|
667
|
-
|
668
|
-
this.setMouseHandlers();
|
669
|
-
|
670
731
|
if (this.br.animationFinishedCallback) {
|
671
732
|
this.br.animationFinishedCallback();
|
672
733
|
this.br.animationFinishedCallback = null;
|
@@ -690,11 +751,11 @@ export class Mode2Up {
|
|
690
751
|
/**
|
691
752
|
* @param {PageIndex} index
|
692
753
|
*/
|
693
|
-
createPageContainer(index
|
754
|
+
createPageContainer(index) {
|
694
755
|
if (!this.pageContainers[index]) {
|
695
756
|
this.pageContainers[index] = this.br._createPageContainer(index);
|
696
757
|
}
|
697
|
-
this.pageContainers[index].update({ reduce: this.br.reduce });
|
758
|
+
this.pageContainers[index].update({ reduce: this.br.reduce / this.scale });
|
698
759
|
return this.pageContainers[index];
|
699
760
|
}
|
700
761
|
|
@@ -778,8 +839,6 @@ export class Mode2Up {
|
|
778
839
|
$(this.leafEdgeR).css({width: `${newLeafEdgeWidthR}px`, left: `${gutter + newWidthR}px` });
|
779
840
|
const speed = this.br.flipSpeed;
|
780
841
|
|
781
|
-
if (this.br.enableSearch) this.br.removeSearchHilites();
|
782
|
-
|
783
842
|
$(this.br.leafEdgeTmp).animate({left: gutter}, speed, 'easeInSine');
|
784
843
|
this.pageContainers[this.br.twoPage.currentIndexR].$container.animate({width: '0px'}, speed, 'easeInSine', () => {
|
785
844
|
this.br.$('BRgutter').css({left: `${gutter - this.br.twoPage.bookSpineDivWidth * 0.5}px`});
|
@@ -814,10 +873,6 @@ export class Mode2Up {
|
|
814
873
|
|
815
874
|
this.resizeSpread();
|
816
875
|
|
817
|
-
if (this.br.enableSearch) this.br.updateSearchHilites();
|
818
|
-
|
819
|
-
this.setMouseHandlers();
|
820
|
-
|
821
876
|
if (this.br.animationFinishedCallback) {
|
822
877
|
this.br.animationFinishedCallback();
|
823
878
|
this.br.animationFinishedCallback = null;
|
@@ -837,40 +892,18 @@ export class Mode2Up {
|
|
837
892
|
});
|
838
893
|
}
|
839
894
|
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
// right click
|
848
|
-
return !e.data.self.br.protected;
|
849
|
-
}
|
850
|
-
e.data.self.br.trigger(EVENTS.stop);
|
851
|
-
e.data.self.br[e.data.direction === 'L' ? 'left' : 'right']();
|
852
|
-
|
853
|
-
// Removed event handler for mouse movement, seems not to be needed
|
854
|
-
/*
|
855
|
-
// Changes per WEBDEV-2737
|
856
|
-
BookReader: zoomed-in 2 page view, clicking page should change the page
|
857
|
-
$(element)
|
858
|
-
.mousemove(function() {
|
859
|
-
e.preventDefault();
|
860
|
-
})
|
861
|
-
*/
|
862
|
-
}
|
895
|
+
attachMouseHandlers() {
|
896
|
+
this.br.refs.$brTwoPageView
|
897
|
+
.off('mouseup').on('mouseup', ev => {
|
898
|
+
if (ev.which == 3) {
|
899
|
+
// right click
|
900
|
+
return !this.br.protected;
|
901
|
+
}
|
863
902
|
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
);
|
869
|
-
this.setClickHandler(
|
870
|
-
this.pageContainers[this.br.twoPage.currentIndexL].$container[0],
|
871
|
-
{ self: this, direction: 'L' },
|
872
|
-
handler
|
873
|
-
);
|
903
|
+
const $page = $(ev.target).closest('.BRpagecontainer');
|
904
|
+
if ($page.data('side') == 'L') this.br.left();
|
905
|
+
else if ($page.data('side') == 'R') this.br.right();
|
906
|
+
});
|
874
907
|
}
|
875
908
|
|
876
909
|
/**
|
@@ -1248,7 +1281,7 @@ export class Mode2Up {
|
|
1248
1281
|
...this.heightCss,
|
1249
1282
|
left: `${this.br.twoPage.gutter - this.br.twoPage.scaledWL}px`,
|
1250
1283
|
width: `${this.br.twoPage.scaledWL}px`,
|
1251
|
-
}
|
1284
|
+
};
|
1252
1285
|
}
|
1253
1286
|
|
1254
1287
|
/** Left side book thickness */
|
@@ -1269,7 +1302,7 @@ export class Mode2Up {
|
|
1269
1302
|
...this.heightCss,
|
1270
1303
|
left: `${this.br.twoPage.gutter}px`,
|
1271
1304
|
width: `${this.br.twoPage.scaledWR}px`,
|
1272
|
-
}
|
1305
|
+
};
|
1273
1306
|
}
|
1274
1307
|
|
1275
1308
|
/** Right side book thickness */
|
@@ -0,0 +1,179 @@
|
|
1
|
+
// @ts-check
|
2
|
+
import Hammer from "hammerjs";
|
3
|
+
/** @typedef {import('./utils/HTMLDimensionsCacher.js').HTMLDimensionsCacher} HTMLDimensionsCacher */
|
4
|
+
|
5
|
+
/**
|
6
|
+
* @typedef {object} SmoothZoomable
|
7
|
+
* @property {HTMLElement} $container
|
8
|
+
* @property {HTMLElement} $visibleWorld
|
9
|
+
* @property {number} scale
|
10
|
+
* @property {{ x: number, y: number }} scaleCenter
|
11
|
+
* @property {HTMLDimensionsCacher} htmlDimensionsCacher
|
12
|
+
* @property {function(): void} [attachScrollListeners]
|
13
|
+
* @property {function(): void} [detachScrollListeners]
|
14
|
+
*/
|
15
|
+
|
16
|
+
/** Manages pinch-zoom, ctrl-wheel, and trackpad pinch smooth zooming. */
|
17
|
+
export class ModeSmoothZoom {
|
18
|
+
/** @param {SmoothZoomable} mode */
|
19
|
+
constructor(mode) {
|
20
|
+
/** @type {SmoothZoomable} */
|
21
|
+
this.mode = mode;
|
22
|
+
|
23
|
+
/** Non-null when a scale has been enqueued/is being processed by the buffer function */
|
24
|
+
this.pinchMoveFrame = null;
|
25
|
+
/** Promise for the current/enqueued pinch move frame. Resolves when it is complete. */
|
26
|
+
this.pinchMoveFramePromise = Promise.resolve();
|
27
|
+
this.oldScale = 1;
|
28
|
+
/** @type {{ scale: number, center: { x: number, y: number }}} */
|
29
|
+
this.lastEvent = null;
|
30
|
+
this.attached = false;
|
31
|
+
|
32
|
+
/** @type {function(function(): void): any} */
|
33
|
+
this.bufferFn = window.requestAnimationFrame.bind(window);
|
34
|
+
|
35
|
+
// Hammer.js by default set userSelect to None; we don't want that!
|
36
|
+
// TODO: Is there any way to do this not globally on Hammer?
|
37
|
+
delete Hammer.defaults.cssProps.userSelect;
|
38
|
+
this.hammer = new Hammer.Manager(this.mode.$container, {
|
39
|
+
touchAction: "pan-x pan-y",
|
40
|
+
});
|
41
|
+
|
42
|
+
this.hammer.add(new Hammer.Pinch());
|
43
|
+
}
|
44
|
+
|
45
|
+
attach() {
|
46
|
+
if (this.attached) return;
|
47
|
+
|
48
|
+
this.attachCtrlZoom();
|
49
|
+
|
50
|
+
// GestureEvents work only on Safari; they interfere with Hammer,
|
51
|
+
// so block them.
|
52
|
+
this.mode.$container.addEventListener('gesturestart', this._preventEvent);
|
53
|
+
this.mode.$container.addEventListener('gesturechange', this._preventEvent);
|
54
|
+
this.mode.$container.addEventListener('gestureend', this._preventEvent);
|
55
|
+
|
56
|
+
// The pinch listeners
|
57
|
+
this.hammer.on("pinchstart", this._pinchStart);
|
58
|
+
this.hammer.on("pinchmove", this._pinchMove);
|
59
|
+
this.hammer.on("pinchend", this._pinchEnd);
|
60
|
+
this.hammer.on("pinchcancel", this._pinchCancel);
|
61
|
+
|
62
|
+
this.attached = true;
|
63
|
+
}
|
64
|
+
|
65
|
+
detach() {
|
66
|
+
this.detachCtrlZoom();
|
67
|
+
|
68
|
+
// GestureEvents work only on Safari; they interfere with Hammer,
|
69
|
+
// so block them.
|
70
|
+
this.mode.$container.removeEventListener('gesturestart', this._preventEvent);
|
71
|
+
this.mode.$container.removeEventListener('gesturechange', this._preventEvent);
|
72
|
+
this.mode.$container.removeEventListener('gestureend', this._preventEvent);
|
73
|
+
|
74
|
+
// The pinch listeners
|
75
|
+
this.hammer.off("pinchstart", this._pinchStart);
|
76
|
+
this.hammer.off("pinchmove", this._pinchMove);
|
77
|
+
this.hammer.off("pinchend", this._pinchEnd);
|
78
|
+
this.hammer.off("pinchcancel", this._pinchCancel);
|
79
|
+
|
80
|
+
this.attached = false;
|
81
|
+
}
|
82
|
+
|
83
|
+
/** @param {Event} ev */
|
84
|
+
_preventEvent = (ev) => {
|
85
|
+
ev.preventDefault();
|
86
|
+
return false;
|
87
|
+
}
|
88
|
+
|
89
|
+
_pinchStart = () => {
|
90
|
+
// Do this in case the pinchend hasn't fired yet.
|
91
|
+
this.oldScale = 1;
|
92
|
+
this.mode.$visibleWorld.classList.add("BRsmooth-zooming");
|
93
|
+
this.mode.$visibleWorld.style.willChange = "transform";
|
94
|
+
this.detachCtrlZoom();
|
95
|
+
this.mode.detachScrollListeners?.();
|
96
|
+
}
|
97
|
+
|
98
|
+
/** @param {{ scale: number, center: { x: number, y: number }}} e */
|
99
|
+
_pinchMove = async (e) => {
|
100
|
+
this.lastEvent = e;
|
101
|
+
if (!this.pinchMoveFrame) {
|
102
|
+
let pinchMoveFramePromiseRes = null;
|
103
|
+
this.pinchMoveFramePromise = new Promise(
|
104
|
+
(res) => (pinchMoveFramePromiseRes = res)
|
105
|
+
);
|
106
|
+
|
107
|
+
// Buffer these events; only update the scale when request animation fires
|
108
|
+
this.pinchMoveFrame = this.bufferFn(() => {
|
109
|
+
this.updateScaleCenter({
|
110
|
+
clientX: this.lastEvent.center.x,
|
111
|
+
clientY: this.lastEvent.center.y,
|
112
|
+
});
|
113
|
+
this.mode.scale *= this.lastEvent.scale / this.oldScale;
|
114
|
+
this.oldScale = this.lastEvent.scale;
|
115
|
+
this.pinchMoveFrame = null;
|
116
|
+
pinchMoveFramePromiseRes();
|
117
|
+
});
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
_pinchEnd = async () => {
|
122
|
+
// Want this to happen after the pinchMoveFrame,
|
123
|
+
// if one is in progress; otherwise setting oldScale
|
124
|
+
// messes up the transform.
|
125
|
+
await this.pinchMoveFramePromise;
|
126
|
+
this.mode.scaleCenter = { x: 0.5, y: 0.5 };
|
127
|
+
this.oldScale = 1;
|
128
|
+
this.mode.$visibleWorld.classList.remove("BRsmooth-zooming");
|
129
|
+
this.mode.$visibleWorld.style.willChange = "auto";
|
130
|
+
this.attachCtrlZoom();
|
131
|
+
this.mode.attachScrollListeners?.();
|
132
|
+
}
|
133
|
+
|
134
|
+
_pinchCancel = async () => {
|
135
|
+
// iOS fires pinchcancel ~randomly; it looks like it sometimes
|
136
|
+
// thinks the pinch becomes a pan, at which point it cancels?
|
137
|
+
await this._pinchEnd();
|
138
|
+
}
|
139
|
+
|
140
|
+
/** @private */
|
141
|
+
attachCtrlZoom() {
|
142
|
+
window.addEventListener("wheel", this._handleCtrlWheel, { passive: false });
|
143
|
+
}
|
144
|
+
|
145
|
+
/** @private */
|
146
|
+
detachCtrlZoom() {
|
147
|
+
window.removeEventListener("wheel", this._handleCtrlWheel);
|
148
|
+
}
|
149
|
+
|
150
|
+
/** @param {WheelEvent} ev **/
|
151
|
+
_handleCtrlWheel = (ev) => {
|
152
|
+
if (!ev.ctrlKey) return;
|
153
|
+
ev.preventDefault();
|
154
|
+
const zoomMultiplier =
|
155
|
+
// Zooming on macs was painfully slow; likely due to their better
|
156
|
+
// trackpads. Give them a higher zoom rate.
|
157
|
+
/Mac/i.test(navigator.platform)
|
158
|
+
? 0.045
|
159
|
+
: // This worked well for me on Windows
|
160
|
+
0.03;
|
161
|
+
|
162
|
+
// Zoom around the cursor
|
163
|
+
this.updateScaleCenter(ev);
|
164
|
+
this.mode.scale *= 1 - Math.sign(ev.deltaY) * zoomMultiplier;
|
165
|
+
}
|
166
|
+
|
167
|
+
/**
|
168
|
+
* @param {object} param0
|
169
|
+
* @param {number} param0.clientX
|
170
|
+
* @param {number} param0.clientY
|
171
|
+
*/
|
172
|
+
updateScaleCenter({ clientX, clientY }) {
|
173
|
+
const bc = this.mode.htmlDimensionsCacher.boundingClientRect;
|
174
|
+
this.mode.scaleCenter = {
|
175
|
+
x: (clientX - bc.left) / this.mode.htmlDimensionsCacher.clientWidth,
|
176
|
+
y: (clientY - bc.top) / this.mode.htmlDimensionsCacher.clientHeight,
|
177
|
+
};
|
178
|
+
}
|
179
|
+
}
|
@@ -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 */
|
@@ -234,20 +235,27 @@ export class ModeThumb {
|
|
234
235
|
}
|
235
236
|
|
236
237
|
/**
|
237
|
-
* @param {
|
238
|
+
* @param {'in' | 'out'} direction
|
238
239
|
*/
|
239
240
|
zoom(direction) {
|
240
241
|
const oldColumns = this.br.thumbColumns;
|
241
242
|
switch (direction) {
|
242
|
-
case
|
243
|
-
this.br.thumbColumns += 1;
|
244
|
-
break;
|
245
|
-
case 1:
|
243
|
+
case 'in':
|
246
244
|
this.br.thumbColumns -= 1;
|
247
245
|
break;
|
246
|
+
case 'out':
|
247
|
+
this.br.thumbColumns += 1;
|
248
|
+
break;
|
249
|
+
default:
|
250
|
+
console.error(`Unsupported direction: ${direction}`);
|
248
251
|
}
|
249
252
|
|
250
|
-
|
253
|
+
// Limit zoom in/out columns
|
254
|
+
this.br.thumbColumns = clamp(
|
255
|
+
this.br.thumbColumns,
|
256
|
+
this.br.options.thumbMinZoomColumns,
|
257
|
+
this.br.options.thumbMaxZoomColumns
|
258
|
+
);
|
251
259
|
|
252
260
|
if (this.br.thumbColumns != oldColumns) {
|
253
261
|
this.br.displayedRows = []; /* force a gallery redraw */
|
@@ -279,7 +287,7 @@ export class ModeThumb {
|
|
279
287
|
|
280
288
|
this.br.refs.$brPageViewEl = $("<div class='BRpageview'></div>");
|
281
289
|
this.br.refs.$brContainer.append(this.br.refs.$brPageViewEl);
|
282
|
-
this.br.refs.$brContainer
|
290
|
+
this.dragScrollable = this.dragScrollable || new DragScrollable(this.br.refs.$brContainer[0], {preventDefault: true});
|
283
291
|
|
284
292
|
this.br.bindGestures(this.br.refs.$brContainer);
|
285
293
|
|
@@ -330,7 +338,7 @@ export class ModeThumb {
|
|
330
338
|
} else {
|
331
339
|
this.br.animating = true;
|
332
340
|
this.br.refs.$brContainer.stop(true)
|
333
|
-
.animate({ scrollTop: leafTop }, 'fast', () => { this.br.animating = false });
|
341
|
+
.animate({ scrollTop: leafTop }, 'fast', () => { this.br.animating = false; });
|
334
342
|
}
|
335
343
|
}
|
336
344
|
}
|
@@ -240,35 +240,6 @@ export class Navbar {
|
|
240
240
|
return this.$nav;
|
241
241
|
}
|
242
242
|
|
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
243
|
/**
|
273
244
|
* Returns the textual representation of the current page for the navbar
|
274
245
|
* @param {number} index
|
@@ -331,9 +302,9 @@ export function getNavPageNumHtml(index, numLeafs, pageNum, pageType, maxPageNum
|
|
331
302
|
|
332
303
|
if (!pageIsAsserted) {
|
333
304
|
const pageIndex = index + 1;
|
334
|
-
return `
|
305
|
+
return `(${pageIndex} of ${numLeafs})`; // Page (8 of 10)
|
335
306
|
}
|
336
307
|
|
337
308
|
const bookLengthLabel = maxPageNum ? ` of ${maxPageNum}` : '';
|
338
|
-
return
|
309
|
+
return `${pageNum}${bookLengthLabel}`;
|
339
310
|
}
|
@@ -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,48 @@ 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 {{ l: number, r: number, b: number, t: number }} box
|
99
|
+
*/
|
100
|
+
export function boxToSVGRect({ l: left, r: right, b: bottom, t: top }) {
|
101
|
+
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
102
|
+
rect.setAttribute("x", left.toString());
|
103
|
+
rect.setAttribute("y", top.toString());
|
104
|
+
rect.setAttribute("width", (right - left).toString());
|
105
|
+
rect.setAttribute("height", (bottom - top).toString());
|
106
|
+
return rect;
|
107
|
+
}
|
108
|
+
|
109
|
+
/**
|
110
|
+
* @param {string} layerClass
|
111
|
+
* @param {Array<{ l: number, r: number, b: number, t: number }>} boxes
|
112
|
+
* @param {PageModel} page
|
113
|
+
* @param {HTMLElement} containerEl
|
114
|
+
*/
|
115
|
+
export function renderBoxesInPageContainerLayer(layerClass, boxes, page, containerEl) {
|
116
|
+
const mountedSvg = containerEl.querySelector(`.${layerClass}`);
|
117
|
+
// Create the layer if it's not there
|
118
|
+
const svg = mountedSvg || createSVGPageLayer(page, layerClass);
|
119
|
+
if (!mountedSvg) {
|
120
|
+
// Insert after the image if the image is already loaded.
|
121
|
+
const imgEl = containerEl.querySelector('.BRpageimage');
|
122
|
+
if (imgEl) $(svg).insertAfter(imgEl);
|
123
|
+
else $(svg).prependTo(containerEl);
|
124
|
+
}
|
125
|
+
boxes.forEach(box => svg.appendChild(boxToSVGRect(box)));
|
126
|
+
}
|