@internetarchive/bookreader 5.0.0-88-alpha.8 → 5.0.0-88-alpha.10

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.
Files changed (182) hide show
  1. package/dist/esm/BookNavigator/assets/bookmark-colors.js +4 -0
  2. package/dist/esm/BookNavigator/assets/button-base.js +4 -0
  3. package/dist/esm/BookNavigator/assets/ia-logo.js +4 -0
  4. package/dist/esm/BookNavigator/assets/icon_checkmark.js +8 -0
  5. package/dist/esm/BookNavigator/assets/icon_close.js +4 -0
  6. package/dist/esm/BookNavigator/book-navigator.js +612 -0
  7. package/dist/esm/BookNavigator/bookmarks/bookmark-button.js +35 -0
  8. package/dist/esm/BookNavigator/bookmarks/bookmark-edit.js +78 -0
  9. package/dist/esm/BookNavigator/bookmarks/bookmarks-list.js +160 -0
  10. package/dist/esm/BookNavigator/bookmarks/bookmarks-loginCTA.js +24 -0
  11. package/dist/esm/BookNavigator/bookmarks/bookmarks-provider.js +55 -0
  12. package/dist/esm/BookNavigator/bookmarks/ia-bookmarks.js +521 -0
  13. package/dist/esm/BookNavigator/delete-modal-actions.js +29 -0
  14. package/dist/esm/BookNavigator/downloads/downloads-provider.js +84 -0
  15. package/dist/esm/BookNavigator/downloads/downloads.js +69 -0
  16. package/dist/esm/BookNavigator/search/search-provider.js +238 -0
  17. package/dist/esm/BookNavigator/search/search-results.js +161 -0
  18. package/dist/esm/BookNavigator/sharing.js +26 -0
  19. package/dist/esm/BookNavigator/viewable-files.js +94 -0
  20. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments-provider.js +83 -0
  21. package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments.js +131 -0
  22. package/dist/esm/BookReader/BookModel.js +575 -0
  23. package/dist/esm/BookReader/DragScrollable.js +224 -0
  24. package/dist/esm/BookReader/ImageCache.js +122 -0
  25. package/dist/esm/BookReader/Mode1Up.js +114 -0
  26. package/dist/esm/BookReader/Mode1UpLit.js +579 -0
  27. package/dist/esm/BookReader/Mode2Up.js +106 -0
  28. package/dist/esm/BookReader/Mode2UpLit.js +1020 -0
  29. package/dist/esm/BookReader/ModeCoordinateSpace.js +28 -0
  30. package/dist/esm/BookReader/ModeSmoothZoom.js +318 -0
  31. package/dist/esm/BookReader/ModeThumb.js +366 -0
  32. package/dist/esm/BookReader/Navbar/Navbar.js +253 -0
  33. package/dist/esm/BookReader/PageContainer.js +165 -0
  34. package/dist/esm/BookReader/ReduceSet.js +27 -0
  35. package/dist/esm/BookReader/Toolbar/Toolbar.js +242 -0
  36. package/dist/esm/BookReader/events.js +20 -0
  37. package/dist/esm/BookReader/options.js +331 -0
  38. package/dist/esm/BookReader/utils/HTMLDimensionsCacher.js +48 -0
  39. package/dist/esm/BookReader/utils/ScrollClassAdder.js +31 -0
  40. package/dist/esm/BookReader/utils/SelectionObserver.js +42 -0
  41. package/dist/esm/BookReader/utils/classes.js +37 -0
  42. package/dist/esm/BookReader/utils.js +315 -0
  43. package/dist/esm/BookReader.js +1827 -0
  44. package/dist/esm/assets/icons/1up.svg +12 -0
  45. package/dist/esm/assets/icons/2up.svg +15 -0
  46. package/dist/esm/assets/icons/advance.svg +26 -0
  47. package/dist/esm/assets/icons/chevron-right.svg +1 -0
  48. package/dist/esm/assets/icons/close-circle-dark.svg +1 -0
  49. package/dist/esm/assets/icons/close-circle.svg +1 -0
  50. package/dist/esm/assets/icons/fullscreen.svg +17 -0
  51. package/dist/esm/assets/icons/fullscreen_exit.svg +17 -0
  52. package/dist/esm/assets/icons/hamburger.svg +15 -0
  53. package/dist/esm/assets/icons/left-arrow.svg +12 -0
  54. package/dist/esm/assets/icons/magnify-minus.svg +12 -0
  55. package/dist/esm/assets/icons/magnify-plus.svg +13 -0
  56. package/dist/esm/assets/icons/magnify.svg +15 -0
  57. package/dist/esm/assets/icons/pause.svg +23 -0
  58. package/dist/esm/assets/icons/play.svg +22 -0
  59. package/dist/esm/assets/icons/playback-speed.svg +34 -0
  60. package/dist/esm/assets/icons/read-aloud.svg +22 -0
  61. package/dist/esm/assets/icons/review.svg +22 -0
  62. package/dist/esm/assets/icons/thumbnails.svg +17 -0
  63. package/dist/esm/assets/icons/voice.svg +1 -0
  64. package/dist/esm/assets/icons/volume-full.svg +22 -0
  65. package/dist/esm/assets/images/BRicons.png +0 -0
  66. package/dist/esm/assets/images/BRicons.svg +94 -0
  67. package/dist/esm/assets/images/BRicons_ia.png +0 -0
  68. package/dist/esm/assets/images/back_pages.png +0 -0
  69. package/dist/esm/assets/images/book_bottom_icon.png +0 -0
  70. package/dist/esm/assets/images/book_down_icon.png +0 -0
  71. package/dist/esm/assets/images/book_left_icon.png +0 -0
  72. package/dist/esm/assets/images/book_leftmost_icon.png +0 -0
  73. package/dist/esm/assets/images/book_right_icon.png +0 -0
  74. package/dist/esm/assets/images/book_rightmost_icon.png +0 -0
  75. package/dist/esm/assets/images/book_top_icon.png +0 -0
  76. package/dist/esm/assets/images/book_up_icon.png +0 -0
  77. package/dist/esm/assets/images/books_graphic.svg +177 -0
  78. package/dist/esm/assets/images/booksplit.png +0 -0
  79. package/dist/esm/assets/images/control_pause_icon.png +0 -0
  80. package/dist/esm/assets/images/control_play_icon.png +0 -0
  81. package/dist/esm/assets/images/embed_icon.png +0 -0
  82. package/dist/esm/assets/images/icon-home-ia.png +0 -0
  83. package/dist/esm/assets/images/icon_OL-logo-xs.png +0 -0
  84. package/dist/esm/assets/images/icon_alert-xs.png +0 -0
  85. package/dist/esm/assets/images/icon_book.svg +12 -0
  86. package/dist/esm/assets/images/icon_bookmark.svg +12 -0
  87. package/dist/esm/assets/images/icon_close-pop.png +0 -0
  88. package/dist/esm/assets/images/icon_download.png +0 -0
  89. package/dist/esm/assets/images/icon_gear.svg +14 -0
  90. package/dist/esm/assets/images/icon_hamburger.svg +20 -0
  91. package/dist/esm/assets/images/icon_home.png +0 -0
  92. package/dist/esm/assets/images/icon_home.svg +21 -0
  93. package/dist/esm/assets/images/icon_home_ia.png +0 -0
  94. package/dist/esm/assets/images/icon_indicator.png +0 -0
  95. package/dist/esm/assets/images/icon_info.svg +11 -0
  96. package/dist/esm/assets/images/icon_one_page.svg +8 -0
  97. package/dist/esm/assets/images/icon_pause.svg +1 -0
  98. package/dist/esm/assets/images/icon_play.svg +1 -0
  99. package/dist/esm/assets/images/icon_playback-rate.svg +15 -0
  100. package/dist/esm/assets/images/icon_return.png +0 -0
  101. package/dist/esm/assets/images/icon_search_button.svg +8 -0
  102. package/dist/esm/assets/images/icon_share.svg +9 -0
  103. package/dist/esm/assets/images/icon_skip-ahead.svg +6 -0
  104. package/dist/esm/assets/images/icon_skip-back.svg +13 -0
  105. package/dist/esm/assets/images/icon_speaker.svg +18 -0
  106. package/dist/esm/assets/images/icon_speaker_open.svg +10 -0
  107. package/dist/esm/assets/images/icon_thumbnails.svg +12 -0
  108. package/dist/esm/assets/images/icon_toc.svg +5 -0
  109. package/dist/esm/assets/images/icon_two_pages.svg +9 -0
  110. package/dist/esm/assets/images/icon_zoomer.png +0 -0
  111. package/dist/esm/assets/images/loading.gif +0 -0
  112. package/dist/esm/assets/images/logo_icon.png +0 -0
  113. package/dist/esm/assets/images/marker_chap-off.png +0 -0
  114. package/dist/esm/assets/images/marker_chap-off.svg +11 -0
  115. package/dist/esm/assets/images/marker_chap-off_ia.png +0 -0
  116. package/dist/esm/assets/images/marker_chap-on.png +0 -0
  117. package/dist/esm/assets/images/marker_chap-on.svg +11 -0
  118. package/dist/esm/assets/images/marker_srch-on.svg +11 -0
  119. package/dist/esm/assets/images/marker_srchchap-off.png +0 -0
  120. package/dist/esm/assets/images/marker_srchchap-on.png +0 -0
  121. package/dist/esm/assets/images/nav_control-dn.png +0 -0
  122. package/dist/esm/assets/images/nav_control-dn_ia.png +0 -0
  123. package/dist/esm/assets/images/nav_control-up.png +0 -0
  124. package/dist/esm/assets/images/nav_control-up_ia.png +0 -0
  125. package/dist/esm/assets/images/nav_control.png +0 -0
  126. package/dist/esm/assets/images/one_page_mode_icon.png +0 -0
  127. package/dist/esm/assets/images/paper-badge.png +0 -0
  128. package/dist/esm/assets/images/print_icon.png +0 -0
  129. package/dist/esm/assets/images/progressbar.gif +0 -0
  130. package/dist/esm/assets/images/right_edges.png +0 -0
  131. package/dist/esm/assets/images/slider.png +0 -0
  132. package/dist/esm/assets/images/slider_ia.png +0 -0
  133. package/dist/esm/assets/images/thumbnail_mode_icon.png +0 -0
  134. package/dist/esm/assets/images/transparent.png +0 -0
  135. package/dist/esm/assets/images/two_page_mode_icon.png +0 -0
  136. package/dist/esm/assets/images/unviewable_page.png +0 -0
  137. package/dist/esm/assets/images/zoom_in_icon.png +0 -0
  138. package/dist/esm/assets/images/zoom_out_icon.png +0 -0
  139. package/dist/esm/css/BookReader.scss +85 -0
  140. package/dist/esm/css/_BRBookmarks.scss +29 -0
  141. package/dist/esm/css/_BRComponent.scss +13 -0
  142. package/dist/esm/css/_BRfloat.scss +197 -0
  143. package/dist/esm/css/_BRicon.scss +54 -0
  144. package/dist/esm/css/_BRmain.scss +262 -0
  145. package/dist/esm/css/_BRnav.scss +354 -0
  146. package/dist/esm/css/_BRpages.scss +213 -0
  147. package/dist/esm/css/_BRsearch.scss +268 -0
  148. package/dist/esm/css/_BRtoolbar.scss +84 -0
  149. package/dist/esm/css/_BRvendor.scss +5 -0
  150. package/dist/esm/css/_TextSelection.scss +108 -0
  151. package/dist/esm/css/_colorbox.scss +52 -0
  152. package/dist/esm/css/_controls.scss +257 -0
  153. package/dist/esm/css/_icons.scss +121 -0
  154. package/dist/esm/ia-bookreader/ia-bookreader.js +141 -0
  155. package/dist/esm/jquery-wrapper.js +3 -0
  156. package/dist/esm/plugins/plugin.archive_analytics.js +72 -0
  157. package/dist/esm/plugins/plugin.autoplay.js +119 -0
  158. package/dist/esm/plugins/plugin.chapters.js +288 -0
  159. package/dist/esm/plugins/plugin.iframe.js +44 -0
  160. package/dist/esm/plugins/plugin.iiif.js +146 -0
  161. package/dist/esm/plugins/plugin.resume.js +66 -0
  162. package/dist/esm/plugins/plugin.text_selection.js +621 -0
  163. package/dist/esm/plugins/plugin.vendor-fullscreen.js +227 -0
  164. package/dist/esm/plugins/search/plugin.search.js +499 -0
  165. package/dist/esm/plugins/search/utils.js +42 -0
  166. package/dist/esm/plugins/search/view.js +360 -0
  167. package/dist/esm/plugins/tts/AbstractTTSEngine.js +282 -0
  168. package/dist/esm/plugins/tts/FestivalTTSEngine.js +192 -0
  169. package/dist/esm/plugins/tts/PageChunk.js +105 -0
  170. package/dist/esm/plugins/tts/PageChunkIterator.js +155 -0
  171. package/dist/esm/plugins/tts/WebTTSEngine.js +364 -0
  172. package/dist/esm/plugins/tts/plugin.tts.js +315 -0
  173. package/dist/esm/plugins/tts/tooltip_dict.js +14 -0
  174. package/dist/esm/plugins/tts/utils.js +79 -0
  175. package/dist/esm/plugins/url/UrlPlugin.js +197 -0
  176. package/dist/esm/plugins/url/plugin.url.js +212 -0
  177. package/dist/esm/util/browserSniffing.js +56 -0
  178. package/dist/esm/util/debouncer.js +25 -0
  179. package/dist/esm/util/docCookies.js +75 -0
  180. package/dist/esm/util/strings.js +34 -0
  181. package/jsconfig.json +1 -0
  182. package/package.json +1 -7
@@ -0,0 +1,621 @@
1
+ function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
2
+ function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ //@ts-check
7
+ import { createDIVPageLayer } from '../BookReader/PageContainer.js';
8
+ import { SelectionObserver } from '../BookReader/utils/SelectionObserver.js';
9
+ import { applyVariables } from '../util/strings.js';
10
+ /** @typedef {import('../util/strings.js').StringWithVars} StringWithVars */
11
+ /** @typedef {import('../BookReader/PageContainer.js').PageContainer} PageContainer */
12
+
13
+ var BookReader = /** @type {typeof import('../BookReader').default} */window.BookReader;
14
+ export var DEFAULT_OPTIONS = {
15
+ enabled: true,
16
+ /** @type {StringWithVars} The URL to fetch the entire DJVU xml. Supports options.vars */
17
+ fullDjvuXmlUrl: null,
18
+ /** @type {StringWithVars} The URL to fetch a single page of the DJVU xml. Supports options.vars. Also has {{pageIndex}} */
19
+ singlePageDjvuXmlUrl: null,
20
+ /** Whether to fetch the XML as a jsonp */
21
+ jsonp: false
22
+ };
23
+ /** @typedef {typeof DEFAULT_OPTIONS} TextSelectionPluginOptions */
24
+
25
+ /**
26
+ * @template T
27
+ */
28
+ export class Cache {
29
+ constructor() {
30
+ var maxSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 10;
31
+ this.maxSize = maxSize;
32
+ /** @type {T[]} */
33
+ this.entries = [];
34
+ }
35
+
36
+ /**
37
+ * @param {T} entry
38
+ */
39
+ add(entry) {
40
+ if (this.entries.length >= this.maxSize) {
41
+ this.entries.shift();
42
+ }
43
+ this.entries.push(entry);
44
+ }
45
+ }
46
+ export class TextSelectionPlugin {
47
+ /**
48
+ * @param {'lr' | 'rl'} pageProgression In the future this should be in the ocr file
49
+ * since a book being right to left doesn't mean the ocr is right to left. But for
50
+ * now we do make that assumption.
51
+ */
52
+ constructor() {
53
+ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : DEFAULT_OPTIONS;
54
+ var optionVariables = arguments.length > 1 ? arguments[1] : undefined;
55
+ var pageProgression = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'lr';
56
+ /**
57
+ * @param {'started' | 'cleared'} type
58
+ * @param {HTMLElement} target
59
+ */
60
+ _defineProperty(this, "_onSelectionChange", (type, target) => {
61
+ if (type === 'started') {
62
+ this.textSelectingMode(target);
63
+ } else if (type === 'cleared') {
64
+ this.defaultMode(target);
65
+ } else {
66
+ throw new Error("Unknown type ".concat(type));
67
+ }
68
+ });
69
+ this.options = options;
70
+ this.optionVariables = optionVariables;
71
+ /**@type {PromiseLike<JQuery<HTMLElement>|undefined>} */
72
+ this.djvuPagesPromise = null;
73
+ /** Whether the book is right-to-left */
74
+ this.rtl = pageProgression === 'rl';
75
+
76
+ /** @type {Cache<{index: number, response: any}>} */
77
+ this.pageTextCache = new Cache();
78
+
79
+ /**
80
+ * Sometimes there are too many words on a page, and the browser becomes near
81
+ * unusable. For now don't render text layer for pages with too many words.
82
+ */
83
+ this.maxWordRendered = 2500;
84
+ this.selectionObserver = new SelectionObserver('.BRtextLayer', this._onSelectionChange);
85
+ }
86
+ init() {
87
+ this.selectionObserver.attach();
88
+
89
+ // Only fetch the full djvu xml if the single page url isn't there
90
+ if (this.options.singlePageDjvuXmlUrl) return;
91
+ this.djvuPagesPromise = $.ajax({
92
+ type: "GET",
93
+ url: applyVariables(this.options.fullDjvuXmlUrl, this.optionVariables),
94
+ dataType: this.options.jsonp ? "jsonp" : "html",
95
+ cache: true,
96
+ xhrFields: {
97
+ withCredentials: window.br.protected
98
+ },
99
+ error: e => undefined
100
+ }).then(res => {
101
+ try {
102
+ var xmlMap = $.parseXML(res);
103
+ return xmlMap && $(xmlMap).find("OBJECT");
104
+ } catch (e) {
105
+ return undefined;
106
+ }
107
+ });
108
+ }
109
+
110
+ /**
111
+ * @param {number} index
112
+ * @returns {Promise<HTMLElement|undefined>}
113
+ */
114
+ getPageText(index) {
115
+ var _this = this;
116
+ return _asyncToGenerator(function* () {
117
+ if (_this.options.singlePageDjvuXmlUrl) {
118
+ var cachedEntry = _this.pageTextCache.entries.find(x => x.index == index);
119
+ if (cachedEntry) {
120
+ return cachedEntry.response;
121
+ }
122
+ var res = yield $.ajax({
123
+ type: "GET",
124
+ url: applyVariables(_this.options.singlePageDjvuXmlUrl, _this.optionVariables, {
125
+ pageIndex: index
126
+ }),
127
+ dataType: _this.options.jsonp ? "jsonp" : "html",
128
+ cache: true,
129
+ xhrFields: {
130
+ withCredentials: window.br.protected
131
+ },
132
+ error: e => undefined
133
+ });
134
+ try {
135
+ var xmlDoc = $.parseXML(res);
136
+ var result = xmlDoc && $(xmlDoc).find("OBJECT")[0];
137
+ _this.pageTextCache.add({
138
+ index,
139
+ response: result
140
+ });
141
+ return result;
142
+ } catch (e) {
143
+ return undefined;
144
+ }
145
+ } else {
146
+ var XMLpagesArr = yield _this.djvuPagesPromise;
147
+ if (XMLpagesArr) return XMLpagesArr[index];
148
+ }
149
+ })();
150
+ }
151
+
152
+ /**
153
+ * Intercept copied text to remove any styling applied to it
154
+ * @param {JQuery} $container
155
+ */
156
+ interceptCopy($container) {
157
+ $container[0].addEventListener('copy', event => {
158
+ var selection = document.getSelection();
159
+ event.clipboardData.setData('text/plain', selection.toString());
160
+ event.preventDefault();
161
+ });
162
+ }
163
+
164
+ /**
165
+ * Applies mouse events when in default mode
166
+ * @param {HTMLElement} textLayer
167
+ */
168
+ defaultMode(textLayer) {
169
+ var $pageContainer = $(textLayer).closest('.BRpagecontainer');
170
+ textLayer.style.pointerEvents = "none";
171
+ $pageContainer.find("img").css("pointer-events", "auto");
172
+ $(textLayer).off(".textSelectPluginHandler");
173
+ var startedMouseDown = this.mouseIsDown;
174
+ var skipNextMouseup = this.mouseIsDown;
175
+ if (startedMouseDown) {
176
+ textLayer.style.pointerEvents = "auto";
177
+ }
178
+
179
+ // Need to stop propagation to prevent DragScrollable from
180
+ // blocking selection
181
+ $(textLayer).on("mousedown.textSelectPluginHandler", event => {
182
+ this.mouseIsDown = true;
183
+ if ($(event.target).is(".BRwordElement, .BRspace")) {
184
+ event.stopPropagation();
185
+ }
186
+ });
187
+ $(textLayer).on("mouseup.textSelectPluginHandler", event => {
188
+ this.mouseIsDown = false;
189
+ textLayer.style.pointerEvents = "none";
190
+ if (skipNextMouseup) {
191
+ skipNextMouseup = false;
192
+ event.stopPropagation();
193
+ }
194
+ });
195
+ }
196
+
197
+ /**
198
+ * This mode is active while there is a selection on the given textLayer
199
+ * @param {HTMLElement} textLayer
200
+ */
201
+ textSelectingMode(textLayer) {
202
+ var $pageContainer = $(textLayer).closest('.BRpagecontainer');
203
+ // Make text layer consume all events
204
+ textLayer.style.pointerEvents = "all";
205
+ // Block img from getting long-press to save while selecting
206
+ $pageContainer.find("img").css("pointer-events", "none");
207
+ $(textLayer).off(".textSelectPluginHandler");
208
+ $(textLayer).on('mousedown.textSelectPluginHandler', event => {
209
+ this.mouseIsDown = true;
210
+ event.stopPropagation();
211
+ });
212
+
213
+ // Prevent page flip on click
214
+ $(textLayer).on('mouseup.textSelectPluginHandler', event => {
215
+ this.mouseIsDown = false;
216
+ event.stopPropagation();
217
+ });
218
+ }
219
+
220
+ /**
221
+ * Initializes text selection modes if there is a text layer on the page
222
+ * @param {JQuery} $container
223
+ */
224
+ stopPageFlip($container) {
225
+ /** @type {JQuery<HTMLElement>} */
226
+ var $textLayer = $container.find('.BRtextLayer');
227
+ if (!$textLayer.length) return;
228
+ $textLayer.each((i, s) => this.defaultMode(s));
229
+ this.interceptCopy($container);
230
+ }
231
+
232
+ /**
233
+ * @param {PageContainer} pageContainer
234
+ */
235
+ createTextLayer(pageContainer) {
236
+ var _this2 = this;
237
+ return _asyncToGenerator(function* () {
238
+ var pageIndex = pageContainer.page.index;
239
+ var $container = pageContainer.$container;
240
+ var $textLayers = $container.find('.BRtextLayer');
241
+ if ($textLayers.length) return;
242
+ var XMLpage = yield _this2.getPageText(pageIndex);
243
+ if (!XMLpage) return;
244
+ recursivelyAddCoords(XMLpage);
245
+ var totalWords = $(XMLpage).find("WORD").length;
246
+ if (totalWords > _this2.maxWordRendered) {
247
+ console.log("Page ".concat(pageIndex, " has too many words (").concat(totalWords, " > ").concat(_this2.maxWordRendered, "). Not rendering text layer."));
248
+ return;
249
+ }
250
+ var textLayer = createDIVPageLayer(pageContainer.page, 'BRtextLayer');
251
+ var ratioW = parseFloat(pageContainer.$container[0].style.width) / pageContainer.page.width;
252
+ var ratioH = parseFloat(pageContainer.$container[0].style.height) / pageContainer.page.height;
253
+ textLayer.style.transform = "scale(".concat(ratioW, ", ").concat(ratioH, ")");
254
+ textLayer.setAttribute("dir", _this2.rtl ? "rtl" : "ltr");
255
+ var ocrParagraphs = $(XMLpage).find("PARAGRAPH[coords]").toArray();
256
+ var paragEls = ocrParagraphs.map(p => {
257
+ var el = _this2.renderParagraph(p);
258
+ textLayer.appendChild(el);
259
+ return el;
260
+ });
261
+
262
+ // Fix up paragraph positions
263
+ var paragraphRects = determineRealRects(textLayer, '.BRparagraphElement');
264
+ var yAdded = 0;
265
+ for (var [ocrParagraph, paragEl] of zip(ocrParagraphs, paragEls)) {
266
+ var ocrParagBounds = $(ocrParagraph).attr("coords").split(",").map(parseFloat);
267
+ var realRect = paragraphRects.get(paragEl);
268
+ var [ocrLeft,, ocrRight, ocrTop] = ocrParagBounds;
269
+ var newStartMargin = _this2.rtl ? realRect.right - ocrRight : ocrLeft - realRect.left;
270
+ var newTop = ocrTop - (realRect.top + yAdded);
271
+ paragEl.style[_this2.rtl ? 'marginRight' : 'marginLeft'] = "".concat(newStartMargin, "px");
272
+ paragEl.style.marginTop = "".concat(newTop, "px");
273
+ yAdded += newTop;
274
+ textLayer.appendChild(paragEl);
275
+ }
276
+ $container.append(textLayer);
277
+ _this2.stopPageFlip($container);
278
+ })();
279
+ }
280
+
281
+ /**
282
+ * @param {HTMLElement} ocrParagraph
283
+ * @returns {HTMLParagraphElement}
284
+ */
285
+ renderParagraph(ocrParagraph) {
286
+ var paragEl = document.createElement('p');
287
+ paragEl.classList.add('BRparagraphElement');
288
+ var [paragLeft, paragBottom, paragRight, paragTop] = $(ocrParagraph).attr("coords").split(",").map(parseFloat);
289
+ var wordHeightArr = [];
290
+ var lines = $(ocrParagraph).find("LINE[coords]").toArray();
291
+ if (!lines.length) return paragEl;
292
+ for (var [prevLine, line, nextLine] of lookAroundWindow(genMap(lines, augmentLine))) {
293
+ var isLastLineOfParagraph = line.ocrElement == lines[lines.length - 1];
294
+ var lineEl = document.createElement('span');
295
+ lineEl.classList.add('BRlineElement');
296
+ for (var [wordIndex, currWord] of line.words.entries()) {
297
+ var [, bottom, right, top] = $(currWord).attr("coords").split(',').map(parseFloat);
298
+ var wordHeight = bottom - top;
299
+ wordHeightArr.push(wordHeight);
300
+ if (wordIndex == 0 && prevLine !== null && prevLine !== void 0 && prevLine.lastWord.textContent.trim().endsWith('-')) {
301
+ // ideally prefer the next line to determine the left position,
302
+ // since the previous line could be the first line of the paragraph
303
+ // and hence have an incorrectly indented first word.
304
+ // E.g. https://archive.org/details/driitaleofdaring00bachuoft/page/360/mode/2up
305
+ var [newLeft,,,] = $((nextLine || prevLine).firstWord).attr("coords").split(',').map(parseFloat);
306
+ $(currWord).attr("coords", "".concat(newLeft, ",").concat(bottom, ",").concat(right, ",").concat(top));
307
+ }
308
+ var wordEl = document.createElement('span');
309
+ wordEl.setAttribute("class", "BRwordElement");
310
+ wordEl.textContent = currWord.textContent.trim();
311
+ if (wordIndex > 0) {
312
+ var space = document.createElement('span');
313
+ space.classList.add('BRspace');
314
+ space.textContent = ' ';
315
+ lineEl.append(space);
316
+
317
+ // Edge ignores empty elements (like BRspace), so add another
318
+ // space to ensure Edge's ReadAloud works correctly.
319
+ lineEl.appendChild(document.createTextNode(' '));
320
+ }
321
+ lineEl.appendChild(wordEl);
322
+ }
323
+ var hasHyphen = line.lastWord.textContent.trim().endsWith('-');
324
+ var lastWordEl = lineEl.children[lineEl.children.length - 1];
325
+ if (hasHyphen && !isLastLineOfParagraph) {
326
+ lastWordEl.textContent = lastWordEl.textContent.trim().slice(0, -1);
327
+ lastWordEl.classList.add('BRwordElement--hyphen');
328
+ }
329
+ paragEl.appendChild(lineEl);
330
+ if (!isLastLineOfParagraph && !hasHyphen) {
331
+ // Edge does not correctly have spaces between the lines.
332
+ paragEl.appendChild(document.createTextNode(' '));
333
+ }
334
+ }
335
+ wordHeightArr.sort((a, b) => a - b);
336
+ var paragWordHeight = wordHeightArr[Math.floor(wordHeightArr.length * 0.85)] + 4;
337
+ paragEl.style.left = "".concat(paragLeft, "px");
338
+ paragEl.style.top = "".concat(paragTop, "px");
339
+ paragEl.style.width = "".concat(paragRight - paragLeft, "px");
340
+ paragEl.style.height = "".concat(paragBottom - paragTop, "px");
341
+ paragEl.style.fontSize = "".concat(paragWordHeight, "px");
342
+
343
+ // Fix up sizes - stretch/crush words as necessary using letter spacing
344
+ var wordRects = determineRealRects(paragEl, '.BRwordElement');
345
+ var ocrWords = $(ocrParagraph).find("WORD").toArray();
346
+ var wordEls = paragEl.querySelectorAll('.BRwordElement');
347
+ for (var [ocrWord, _wordEl] of zip(ocrWords, wordEls)) {
348
+ var realRect = wordRects.get(_wordEl);
349
+ var [left,, _right] = $(ocrWord).attr("coords").split(',').map(parseFloat);
350
+ var ocrWidth = _right - left;
351
+ // Some books (eg theworksofplato01platiala) have a space _inside_ the <WORD>
352
+ // element. That makes it impossible to determine the correct positining
353
+ // of everything, but to avoid the BRspace's being width 0, which makes selection
354
+ // janky on Chrome Android, assume the space is the same width as one of the
355
+ // letters.
356
+ if (ocrWord.textContent.endsWith(' ')) {
357
+ ocrWidth = ocrWidth * (ocrWord.textContent.length - 1) / ocrWord.textContent.length;
358
+ }
359
+ var diff = ocrWidth - realRect.width;
360
+ _wordEl.style.letterSpacing = "".concat(diff / (ocrWord.textContent.length - 1), "px");
361
+ }
362
+
363
+ // Stretch/crush lines as necessary using line spacing
364
+ // Recompute rects after letter spacing
365
+ wordRects = determineRealRects(paragEl, '.BRwordElement');
366
+ var spaceRects = determineRealRects(paragEl, '.BRspace');
367
+ var ocrLines = $(ocrParagraph).find("LINE[coords]").toArray();
368
+ var lineEls = Array.from(paragEl.querySelectorAll('.BRlineElement'));
369
+ var ySoFar = paragTop;
370
+ for (var [ocrLine, _lineEl] of zip(ocrLines, lineEls)) {
371
+ // shift words using marginLeft to align with the correct x position
372
+ var words = $(ocrLine).find("WORD").toArray();
373
+ // const ocrLineLeft = Math.min(...words.map(w => parseFloat($(w).attr("coords").split(',')[0])));
374
+ var xSoFar = this.rtl ? paragRight : paragLeft;
375
+ for (var [_ocrWord, _wordEl2] of zip(words, _lineEl.querySelectorAll('.BRwordElement'))) {
376
+ // start of line, need to compute the offset relative to the OCR words
377
+ var wordRect = wordRects.get(_wordEl2);
378
+ var [ocrLeft,, ocrRight] = $(_ocrWord).attr("coords").split(',').map(parseFloat);
379
+ var _diff = this.rtl ? -(ocrRight - xSoFar) : ocrLeft - xSoFar;
380
+ if (_wordEl2.previousElementSibling) {
381
+ var _space = _wordEl2.previousElementSibling;
382
+ _space.style.letterSpacing = "".concat(_diff - spaceRects.get(_space).width, "px");
383
+ } else {
384
+ _wordEl2.style[this.rtl ? 'paddingRight' : 'paddingLeft'] = "".concat(_diff, "px");
385
+ }
386
+ if (this.rtl) xSoFar -= _diff + wordRect.width;else xSoFar += _diff + wordRect.width;
387
+ }
388
+ // And also fix y position
389
+ var ocrLineTop = Math.min(...words.map(w => parseFloat($(w).attr("coords").split(',')[3])));
390
+ var _diff2 = ocrLineTop - ySoFar;
391
+ if (_lineEl.previousElementSibling) {
392
+ _lineEl.previousElementSibling.style.lineHeight = "".concat(_diff2, "px");
393
+ ySoFar += _diff2;
394
+ }
395
+ }
396
+
397
+ // The last line will have a line height subtracting from the paragraph height
398
+ lineEls[lineEls.length - 1].style.lineHeight = "".concat(paragBottom - ySoFar, "px");
399
+
400
+ // Edge does not include a newline for some reason when copying/pasting the <p> els
401
+ paragEl.appendChild(document.createElement('br'));
402
+ return paragEl;
403
+ }
404
+ }
405
+ export class BookreaderWithTextSelection extends BookReader {
406
+ init() {
407
+ var options = Object.assign({}, DEFAULT_OPTIONS, this.options.plugins.textSelection);
408
+ if (options.enabled) {
409
+ this.textSelectionPlugin = new TextSelectionPlugin(options, this.options.vars, this.pageProgression);
410
+ // Write this back; this way the plugin is the source of truth, and BR just
411
+ // contains a reference to it.
412
+ this.options.plugins.textSelection = options;
413
+ this.textSelectionPlugin.init();
414
+ new SelectionObserver('.BRtextLayer', selectEvent => {
415
+ // Track how often selection is used
416
+ if (selectEvent == 'started') {
417
+ var _this$archiveAnalytic;
418
+ (_this$archiveAnalytic = this.archiveAnalyticsSendEvent) === null || _this$archiveAnalytic === void 0 || _this$archiveAnalytic.call(this, 'BookReader', 'SelectStart');
419
+
420
+ // Set a class on the page to avoid hiding it when zooming/etc
421
+ this.refs.$br.find('.BRpagecontainer--hasSelection').removeClass('BRpagecontainer--hasSelection');
422
+ $(window.getSelection().anchorNode).closest('.BRpagecontainer').addClass('BRpagecontainer--hasSelection');
423
+ }
424
+ }).attach();
425
+ }
426
+ super.init();
427
+ }
428
+
429
+ /**
430
+ * @param {number} index
431
+ */
432
+ _createPageContainer(index) {
433
+ var pageContainer = super._createPageContainer(index);
434
+ // Disable if thumb mode; it's too janky
435
+ // .page can be null for "pre-cover" region
436
+ if (this.mode !== this.constModeThumb && pageContainer.page) {
437
+ var _this$textSelectionPl;
438
+ (_this$textSelectionPl = this.textSelectionPlugin) === null || _this$textSelectionPl === void 0 || _this$textSelectionPl.createTextLayer(pageContainer);
439
+ }
440
+ return pageContainer;
441
+ }
442
+ }
443
+ window.BookReader = BookreaderWithTextSelection;
444
+ export default BookreaderWithTextSelection;
445
+
446
+ /**
447
+ * @param {HTMLElement} parentEl
448
+ * @param {string} selector
449
+ * @returns {Map<Element, Rect>}
450
+ */
451
+ function determineRealRects(parentEl, selector) {
452
+ var initals = {
453
+ position: parentEl.style.position,
454
+ visibility: parentEl.style.visibility,
455
+ top: parentEl.style.top,
456
+ left: parentEl.style.left,
457
+ transform: parentEl.style.transform
458
+ };
459
+ parentEl.style.position = 'absolute';
460
+ parentEl.style.visibility = 'hidden';
461
+ parentEl.style.top = '0';
462
+ parentEl.style.left = '0';
463
+ parentEl.style.transform = 'none';
464
+ document.body.appendChild(parentEl);
465
+ var rects = new Map(Array.from(parentEl.querySelectorAll(selector)).map(wordEl => {
466
+ var origRect = wordEl.getBoundingClientRect();
467
+ return [wordEl, new Rect(origRect.left + window.scrollX, origRect.top + window.scrollY, origRect.width, origRect.height)];
468
+ }));
469
+ document.body.removeChild(parentEl);
470
+ Object.assign(parentEl.style, initals);
471
+ return rects;
472
+ }
473
+
474
+ /**
475
+ * @param {HTMLElement} line
476
+ */
477
+ function augmentLine(line) {
478
+ var words = $(line).find("WORD").toArray();
479
+ return {
480
+ ocrElement: line,
481
+ words,
482
+ firstWord: words[0],
483
+ lastWord: words[words.length - 1]
484
+ };
485
+ }
486
+
487
+ /**
488
+ * @template TFrom, TTo
489
+ * Generator version of map
490
+ * @param {Iterable<TFrom>} gen
491
+ * @param {function(TFrom): TTo} fn
492
+ * @returns {Iterable<TTo>}
493
+ */
494
+ export function* genMap(gen, fn) {
495
+ for (var x of gen) yield fn(x);
496
+ }
497
+
498
+ /**
499
+ * @template T
500
+ * Generator that provides a sliding window of 3 elements,
501
+ * prev, current, and next.
502
+ * @param {Iterable<T>} gen
503
+ * @returns {Iterable<[T | undefined, T, T | undefined]>}
504
+ */
505
+ export function* lookAroundWindow(gen) {
506
+ var prev = undefined;
507
+ var cur = undefined;
508
+ var next = undefined;
509
+ for (var x of gen) {
510
+ if (typeof cur !== 'undefined') {
511
+ next = x;
512
+ yield [prev, cur, next];
513
+ }
514
+ prev = cur;
515
+ cur = x;
516
+ next = undefined;
517
+ }
518
+ if (typeof cur !== 'undefined') {
519
+ yield [prev, cur, next];
520
+ }
521
+ }
522
+
523
+ /**
524
+ * @template T1, T2
525
+ * Lazy zip implementation to avoid importing lodash
526
+ * Expects iterators to be of the same length
527
+ * @param {Iterable<T1>} gen1
528
+ * @param {Iterable<T2>} gen2
529
+ * @returns {Iterable<[T1, T2]>}
530
+ */
531
+ export function* zip(gen1, gen2) {
532
+ var it1 = gen1[Symbol.iterator]();
533
+ var it2 = gen2[Symbol.iterator]();
534
+ while (true) {
535
+ var r1 = it1.next();
536
+ var r2 = it2.next();
537
+ if (r1.done && r2.done) {
538
+ return;
539
+ }
540
+ if (r1.done || r2.done) {
541
+ throw new Error('zip: one of the iterators is done');
542
+ }
543
+ yield [r1.value, r2.value];
544
+ }
545
+ }
546
+
547
+ /**
548
+ * [left, bottom, right, top]
549
+ * @param {Array<[number, number, number, number]>} bounds
550
+ * @returns {[number, number, number, number]}
551
+ */
552
+ function determineBounds(bounds) {
553
+ var leftMost = Infinity;
554
+ var bottomMost = -Infinity;
555
+ var rightMost = -Infinity;
556
+ var topMost = Infinity;
557
+ for (var [left, bottom, right, top] of bounds) {
558
+ leftMost = Math.min(leftMost, left);
559
+ bottomMost = Math.max(bottomMost, bottom);
560
+ rightMost = Math.max(rightMost, right);
561
+ topMost = Math.min(topMost, top);
562
+ }
563
+ return [leftMost, bottomMost, rightMost, topMost];
564
+ }
565
+
566
+ /**
567
+ * Recursively traverses the XML tree and adds coords
568
+ * which are the bounding box of all child coords
569
+ * @param {Element} xmlEl
570
+ */
571
+ function recursivelyAddCoords(xmlEl) {
572
+ if ($(xmlEl).attr('coords') || !xmlEl.children) {
573
+ return;
574
+ }
575
+ var children = $(xmlEl).children().toArray();
576
+ if (children.length === 0) {
577
+ return;
578
+ }
579
+ for (var child of children) {
580
+ recursivelyAddCoords(child);
581
+ }
582
+ var childCoords = [];
583
+ for (var _child of children) {
584
+ if (!$(_child).attr('coords')) continue;
585
+ childCoords.push($(_child).attr('coords').split(',').map(parseFloat));
586
+ }
587
+ var boundingCoords = determineBounds(childCoords);
588
+ if (Math.abs(boundingCoords[0]) != Infinity) {
589
+ $(xmlEl).attr('coords', boundingCoords.join(','));
590
+ }
591
+ }
592
+
593
+ /**
594
+ * Basically a polyfill for the native DOMRect class
595
+ */
596
+ class Rect {
597
+ /**
598
+ * @param {number} x
599
+ * @param {number} y
600
+ * @param {number} width
601
+ * @param {number} height
602
+ */
603
+ constructor(x, y, width, height) {
604
+ this.x = x;
605
+ this.y = y;
606
+ this.width = width;
607
+ this.height = height;
608
+ }
609
+ get right() {
610
+ return this.x + this.width;
611
+ }
612
+ get bottom() {
613
+ return this.y + this.height;
614
+ }
615
+ get top() {
616
+ return this.y;
617
+ }
618
+ get left() {
619
+ return this.x;
620
+ }
621
+ }