@internetarchive/bookreader 5.0.0-7-multiple-files → 5.0.0-70

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 (319) hide show
  1. package/.eslintrc.js +17 -15
  2. package/.github/workflows/node.js.yml +78 -6
  3. package/.github/workflows/npm-publish.yml +6 -20
  4. package/.testcaferc.js +10 -0
  5. package/BookReader/BookReader.css +416 -1365
  6. package/BookReader/BookReader.js +2 -21564
  7. package/BookReader/BookReader.js.LICENSE.txt +20 -20
  8. package/BookReader/BookReader.js.map +1 -1
  9. package/BookReader/ia-bookreader-bundle.js +1509 -0
  10. package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +19 -0
  11. package/BookReader/ia-bookreader-bundle.js.map +1 -0
  12. package/BookReader/icons/1up.svg +1 -12
  13. package/BookReader/icons/2up.svg +1 -15
  14. package/BookReader/icons/advance.svg +3 -26
  15. package/BookReader/icons/chevron-right.svg +1 -1
  16. package/BookReader/icons/close-circle-dark.svg +1 -0
  17. package/BookReader/icons/close-circle.svg +1 -1
  18. package/BookReader/icons/fullscreen.svg +1 -17
  19. package/BookReader/icons/fullscreen_exit.svg +1 -17
  20. package/BookReader/icons/hamburger.svg +1 -15
  21. package/BookReader/icons/left-arrow.svg +1 -12
  22. package/BookReader/icons/magnify-minus.svg +1 -16
  23. package/BookReader/icons/magnify-plus.svg +1 -17
  24. package/BookReader/icons/magnify.svg +1 -15
  25. package/BookReader/icons/pause.svg +1 -23
  26. package/BookReader/icons/play.svg +1 -22
  27. package/BookReader/icons/playback-speed.svg +1 -34
  28. package/BookReader/icons/read-aloud.svg +1 -22
  29. package/BookReader/icons/review.svg +3 -22
  30. package/BookReader/icons/thumbnails.svg +1 -17
  31. package/BookReader/icons/voice.svg +1 -0
  32. package/BookReader/icons/volume-full.svg +1 -22
  33. package/BookReader/images/BRicons.svg +5 -94
  34. package/BookReader/images/books_graphic.svg +1 -177
  35. package/BookReader/images/icon_book.svg +1 -12
  36. package/BookReader/images/icon_bookmark.svg +1 -12
  37. package/BookReader/images/icon_gear.svg +1 -14
  38. package/BookReader/images/icon_hamburger.svg +1 -20
  39. package/BookReader/images/icon_home.svg +1 -21
  40. package/BookReader/images/icon_info.svg +1 -11
  41. package/BookReader/images/icon_one_page.svg +1 -8
  42. package/BookReader/images/icon_pause.svg +1 -1
  43. package/BookReader/images/icon_play.svg +1 -1
  44. package/BookReader/images/icon_playback-rate.svg +1 -15
  45. package/BookReader/images/icon_search_button.svg +1 -8
  46. package/BookReader/images/icon_share.svg +1 -9
  47. package/BookReader/images/icon_skip-ahead.svg +1 -6
  48. package/BookReader/images/icon_skip-back.svg +2 -13
  49. package/BookReader/images/icon_speaker.svg +1 -18
  50. package/BookReader/images/icon_speaker_open.svg +1 -10
  51. package/BookReader/images/icon_thumbnails.svg +1 -12
  52. package/BookReader/images/icon_toc.svg +1 -5
  53. package/BookReader/images/icon_two_pages.svg +1 -9
  54. package/BookReader/images/marker_chap-off.svg +1 -11
  55. package/BookReader/images/marker_chap-on.svg +1 -11
  56. package/BookReader/images/marker_srch-on.svg +1 -11
  57. package/BookReader/jquery-3.js +2 -0
  58. package/BookReader/jquery-3.js.LICENSE.txt +24 -0
  59. package/BookReader/plugins/plugin.archive_analytics.js +1 -172
  60. package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
  61. package/BookReader/plugins/plugin.autoplay.js +1 -165
  62. package/BookReader/plugins/plugin.autoplay.js.map +1 -1
  63. package/BookReader/plugins/plugin.chapters.js +22 -301
  64. package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
  65. package/BookReader/plugins/plugin.chapters.js.map +1 -1
  66. package/BookReader/plugins/plugin.iframe.js +1 -74
  67. package/BookReader/plugins/plugin.iframe.js.map +1 -1
  68. package/BookReader/plugins/plugin.resume.js +1 -368
  69. package/BookReader/plugins/plugin.resume.js.map +1 -1
  70. package/BookReader/plugins/plugin.search.js +2 -1420
  71. package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
  72. package/BookReader/plugins/plugin.search.js.map +1 -1
  73. package/BookReader/plugins/plugin.text_selection.js +2 -1080
  74. package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
  75. package/BookReader/plugins/plugin.text_selection.js.map +1 -1
  76. package/BookReader/plugins/plugin.tts.js +2 -9193
  77. package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
  78. package/BookReader/plugins/plugin.tts.js.map +1 -1
  79. package/BookReader/plugins/plugin.url.js +1 -269
  80. package/BookReader/plugins/plugin.url.js.map +1 -1
  81. package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -379
  82. package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
  83. package/BookReader/webcomponents-bundle.js +3 -0
  84. package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
  85. package/BookReader/webcomponents-bundle.js.map +1 -0
  86. package/BookReaderDemo/BookReaderDemo.css +16 -19
  87. package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
  88. package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
  89. package/BookReaderDemo/BookReaderJSSimple.js +1 -0
  90. package/BookReaderDemo/IADemoBr.js +147 -0
  91. package/BookReaderDemo/demo-advanced.html +2 -2
  92. package/BookReaderDemo/demo-autoplay.html +2 -3
  93. package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
  94. package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
  95. package/BookReaderDemo/demo-fullscreen.html +2 -4
  96. package/BookReaderDemo/demo-iiif.html +2 -1
  97. package/BookReaderDemo/demo-iiif.js +0 -1
  98. package/BookReaderDemo/demo-internetarchive.html +213 -17
  99. package/BookReaderDemo/demo-multiple.html +2 -1
  100. package/BookReaderDemo/demo-preview-pages.html +2 -1
  101. package/BookReaderDemo/demo-simple.html +2 -1
  102. package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
  103. package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
  104. package/BookReaderDemo/immersion-1up.html +2 -2
  105. package/BookReaderDemo/immersion-mode.html +2 -4
  106. package/BookReaderDemo/toggle_controls.html +3 -2
  107. package/BookReaderDemo/view_mode.html +2 -1
  108. package/BookReaderDemo/viewmode-cycle.html +2 -3
  109. package/CHANGELOG.md +289 -0
  110. package/README.md +14 -1
  111. package/babel.config.js +20 -0
  112. package/codecov.yml +6 -0
  113. package/index.html +4 -1
  114. package/jsconfig.json +19 -0
  115. package/netlify.toml +9 -0
  116. package/package.json +71 -60
  117. package/renovate.json +52 -0
  118. package/scripts/preversion.js +4 -1
  119. package/src/BookNavigator/assets/bookmark-colors.js +1 -1
  120. package/src/BookNavigator/assets/button-base.js +9 -2
  121. package/src/BookNavigator/assets/ia-logo.js +17 -0
  122. package/src/BookNavigator/assets/icon_checkmark.js +1 -1
  123. package/src/BookNavigator/assets/icon_close.js +1 -1
  124. package/src/BookNavigator/assets/icon_sort_asc.js +5 -0
  125. package/src/BookNavigator/assets/{icon_sort_ascending.js → icon_sort_desc.js} +2 -2
  126. package/src/BookNavigator/assets/icon_sort_neutral.js +5 -0
  127. package/src/BookNavigator/assets/icon_volumes.js +11 -0
  128. package/src/BookNavigator/book-navigator.js +586 -0
  129. package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
  130. package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
  131. package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
  132. package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
  133. package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
  134. package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
  135. package/src/BookNavigator/delete-modal-actions.js +1 -1
  136. package/src/BookNavigator/downloads/downloads-provider.js +36 -21
  137. package/src/BookNavigator/downloads/downloads.js +41 -25
  138. package/src/BookNavigator/search/search-provider.js +80 -28
  139. package/src/BookNavigator/search/search-results.js +28 -25
  140. package/src/BookNavigator/sharing.js +27 -0
  141. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
  142. package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
  143. package/src/BookNavigator/volumes/volumes-provider.js +88 -53
  144. package/src/BookNavigator/volumes/volumes.js +41 -14
  145. package/src/BookReader/BookModel.js +64 -34
  146. package/src/BookReader/DragScrollable.js +233 -0
  147. package/src/BookReader/Mode1Up.js +56 -351
  148. package/src/BookReader/Mode1UpLit.js +388 -0
  149. package/src/BookReader/Mode2Up.js +73 -1318
  150. package/src/BookReader/Mode2UpLit.js +776 -0
  151. package/src/BookReader/ModeCoordinateSpace.js +29 -0
  152. package/src/BookReader/ModeSmoothZoom.js +312 -0
  153. package/src/BookReader/ModeThumb.js +18 -12
  154. package/src/BookReader/Navbar/Navbar.js +12 -38
  155. package/src/BookReader/PageContainer.js +81 -6
  156. package/src/BookReader/ReduceSet.js +1 -1
  157. package/src/BookReader/Toolbar/Toolbar.js +10 -37
  158. package/src/BookReader/events.js +2 -3
  159. package/src/BookReader/options.js +24 -2
  160. package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
  161. package/src/BookReader/utils/ScrollClassAdder.js +31 -0
  162. package/src/BookReader/utils/SelectionObserver.js +43 -0
  163. package/src/BookReader/utils.js +118 -13
  164. package/src/BookReader.js +446 -1062
  165. package/src/assets/icons/close-circle-dark.svg +1 -0
  166. package/src/assets/icons/magnify-minus.svg +3 -7
  167. package/src/assets/icons/magnify-plus.svg +3 -7
  168. package/src/assets/icons/voice.svg +1 -0
  169. package/src/css/BookReader.scss +1 -17
  170. package/src/css/_BRBookmarks.scss +1 -1
  171. package/src/css/_BRComponent.scss +1 -1
  172. package/src/css/_BRmain.scss +33 -24
  173. package/src/css/_BRnav.scss +11 -38
  174. package/src/css/_BRpages.scss +149 -40
  175. package/src/css/_BRsearch.scss +67 -226
  176. package/src/css/_TextSelection.scss +87 -27
  177. package/src/css/_colorbox.scss +2 -2
  178. package/src/css/_controls.scss +20 -7
  179. package/src/css/_icons.scss +7 -1
  180. package/src/ia-bookreader/ia-bookreader.js +224 -0
  181. package/src/plugins/plugin.archive_analytics.js +3 -3
  182. package/src/plugins/plugin.autoplay.js +5 -11
  183. package/src/plugins/plugin.chapters.js +211 -186
  184. package/src/plugins/plugin.resume.js +3 -3
  185. package/src/plugins/plugin.text_selection.js +464 -134
  186. package/src/plugins/plugin.vendor-fullscreen.js +4 -4
  187. package/src/plugins/search/plugin.search.js +175 -120
  188. package/src/plugins/search/utils.js +43 -0
  189. package/src/plugins/search/view.js +64 -202
  190. package/src/plugins/tts/AbstractTTSEngine.js +68 -40
  191. package/src/plugins/tts/FestivalTTSEngine.js +13 -14
  192. package/src/plugins/tts/PageChunk.js +15 -21
  193. package/src/plugins/tts/PageChunkIterator.js +8 -12
  194. package/src/plugins/tts/WebTTSEngine.js +87 -71
  195. package/src/plugins/tts/plugin.tts.js +95 -126
  196. package/src/plugins/tts/utils.js +0 -25
  197. package/src/plugins/url/UrlPlugin.js +191 -0
  198. package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
  199. package/src/util/browserSniffing.js +22 -0
  200. package/src/util/docCookies.js +21 -2
  201. package/tests/e2e/README.md +37 -0
  202. package/tests/e2e/autoplay.test.js +2 -2
  203. package/tests/e2e/base.test.js +8 -16
  204. package/tests/e2e/helpers/base.js +53 -48
  205. package/tests/e2e/helpers/debug.js +1 -1
  206. package/tests/e2e/helpers/params.js +17 -0
  207. package/tests/e2e/helpers/rightToLeft.js +8 -14
  208. package/tests/e2e/helpers/search.js +73 -0
  209. package/tests/e2e/models/Navigation.js +20 -37
  210. package/tests/e2e/rightToLeft.test.js +4 -5
  211. package/tests/e2e/viewmode.test.js +40 -33
  212. package/tests/jest/BookNavigator/book-navigator.test.js +658 -0
  213. package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
  214. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
  215. package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
  216. package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
  217. package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
  218. package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
  219. package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
  220. package/tests/{karma/BookNavigator → jest/BookNavigator/search}/search-results.test.js +109 -60
  221. package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
  222. package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
  223. package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +184 -0
  224. package/tests/jest/BookNavigator/volumes/volumes.test.js +97 -0
  225. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
  226. package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
  227. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
  228. package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
  229. package/tests/jest/BookReader/Mode2Up.test.js +98 -0
  230. package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
  231. package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
  232. package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
  233. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  234. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
  235. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
  236. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
  237. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
  238. package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
  239. package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
  240. package/tests/jest/BookReader/utils/SelectionObserver.test.js +43 -0
  241. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
  242. package/tests/jest/BookReader/utils.test.js +229 -0
  243. package/tests/jest/BookReader.keyboard.test.js +190 -0
  244. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
  245. package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
  246. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
  247. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
  248. package/tests/jest/plugins/plugin.chapters.test.js +145 -0
  249. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
  250. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
  251. package/tests/jest/plugins/plugin.text_selection.test.js +317 -0
  252. package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
  253. package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +26 -47
  254. package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +39 -6
  255. package/tests/jest/plugins/search/utils.js +25 -0
  256. package/tests/jest/plugins/search/utils.test.js +29 -0
  257. package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +29 -9
  258. package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
  259. package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
  260. package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
  261. package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
  262. package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
  263. package/tests/jest/plugins/url/UrlPlugin.test.js +198 -0
  264. package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
  265. package/tests/jest/setup.js +3 -0
  266. package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
  267. package/tests/jest/util/docCookies.test.js +24 -0
  268. package/tests/{util → jest/util}/strings.test.js +1 -1
  269. package/tests/{utils.js → jest/utils.js} +38 -0
  270. package/webpack.config.js +11 -6
  271. package/.babelrc +0 -12
  272. package/.dependabot/config.yml +0 -6
  273. package/.testcaferc.json +0 -5
  274. package/BookReader/bookreader-component-bundle.js +0 -14311
  275. package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
  276. package/BookReader/bookreader-component-bundle.js.map +0 -1
  277. package/BookReader/icons/sort-ascending.svg +0 -1
  278. package/BookReader/icons/sort-descending.svg +0 -1
  279. package/BookReader/jquery-1.10.1.js +0 -108
  280. package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
  281. package/BookReader/plugins/plugin.menu_toggle.js +0 -369
  282. package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
  283. package/BookReader/plugins/plugin.mobile_nav.js +0 -335
  284. package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
  285. package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
  286. package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
  287. package/karma.conf.js +0 -23
  288. package/src/BookNavigator/BookModel.js +0 -14
  289. package/src/BookNavigator/BookNavigator.js +0 -452
  290. package/src/BookNavigator/assets/book-loader.js +0 -27
  291. package/src/BookNavigator/assets/icon_sort_descending.js +0 -5
  292. package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
  293. package/src/BookNavigator/search/a-search-result.js +0 -55
  294. package/src/BookReader/DebugConsole.js +0 -54
  295. package/src/BookReaderComponent/BookReaderComponent.js +0 -112
  296. package/src/ItemNavigator/ItemNavigator.js +0 -372
  297. package/src/ItemNavigator/providers/sharing.js +0 -29
  298. package/src/assets/icons/sort-ascending.svg +0 -1
  299. package/src/assets/icons/sort-descending.svg +0 -1
  300. package/src/css/_MobileNav.scss +0 -194
  301. package/src/dragscrollable-br.js +0 -261
  302. package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
  303. package/src/plugins/plugin.mobile_nav.js +0 -287
  304. package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
  305. package/tests/BookReader/DebugConsole.test.js +0 -25
  306. package/tests/BookReader/Mode1Up.test.js +0 -164
  307. package/tests/BookReader/Mode2Up.test.js +0 -247
  308. package/tests/BookReader/utils.test.js +0 -109
  309. package/tests/e2e/helpers/desktopSearch.js +0 -72
  310. package/tests/e2e/helpers/mobileSearch.js +0 -85
  311. package/tests/e2e/ia-production/ia-prod-base.js +0 -17
  312. package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
  313. package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
  314. package/tests/karma/BookNavigator/volumes.test.js +0 -101
  315. package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
  316. package/tests/plugins/plugin.chapters.test.js +0 -130
  317. package/tests/plugins/plugin.mobile_nav.test.js +0 -66
  318. package/tests/plugins/plugin.text_selection.test.js +0 -203
  319. package/tests/util/docCookies.test.js +0 -15
@@ -0,0 +1,191 @@
1
+ export class UrlPlugin {
2
+ constructor(options = {}) {
3
+ this.bookReaderOptions = options;
4
+
5
+ // the canonical order of elements is important in the path and query string
6
+ this.urlSchema = [
7
+ { name: 'page', position: 'path', default: 'n0' },
8
+ { name: 'mode', position: 'path', default: '2up' },
9
+ { name: 'search', position: 'path', deprecated_for: 'q' },
10
+ { name: 'q', position: 'query_param' },
11
+ { name: 'sort', position: 'query_param' },
12
+ { name: 'view', position: 'query_param' },
13
+ { name: 'admin', position: 'query_param' },
14
+ ];
15
+
16
+ this.urlState = {};
17
+ this.urlMode = this.bookReaderOptions.urlMode || 'hash';
18
+ this.urlHistoryBasePath = this.bookReaderOptions.urlHistoryBasePath || '/';
19
+ this.urlLocationPollId = null;
20
+ this.oldLocationHash = null;
21
+ this.oldUserHash = null;
22
+ }
23
+
24
+ /**
25
+ * Parse JSON object URL state to string format
26
+ * Arrange path names in an order that it is positioned on the urlSchema
27
+ * @param {Object} urlState
28
+ * @returns {string}
29
+ */
30
+ urlStateToUrlString(urlState) {
31
+ const searchParams = new URLSearchParams();
32
+ const pathParams = {};
33
+
34
+ Object.keys(urlState).forEach(key => {
35
+ let schema = this.urlSchema.find(schema => schema.name === key);
36
+ if (schema?.deprecated_for) {
37
+ schema = this.urlSchema.find(schemaKey => schemaKey.name === schema.deprecated_for);
38
+ }
39
+ if (schema?.position == 'path') {
40
+ pathParams[schema?.name] = urlState[key];
41
+ } else {
42
+ searchParams.append(schema?.name || key, urlState[key]);
43
+ }
44
+ });
45
+
46
+ const strPathParams = this.urlSchema
47
+ .filter(s => s.position == 'path')
48
+ .map(schema => pathParams[schema.name] ? `${schema.name}/${encodeURIComponent(pathParams[schema.name])}` : '')
49
+ .join('/');
50
+
51
+ // replace consecutive slashes with a single slash + remove trailing slashes
52
+ const strStrippedTrailingSlash = `${strPathParams.replace(/\/+/g, '/').replace(/\/+$/, '')}`;
53
+ const concatenatedPath = `${strStrippedTrailingSlash}?${searchParams.toString()}`;
54
+ return searchParams.toString() ? concatenatedPath : `${strStrippedTrailingSlash}`;
55
+ }
56
+
57
+ /**
58
+ * Parse string URL and add it in the current urlState
59
+ * Example:
60
+ * /page/n7/mode/2up => {page: 'n7', mode: '2up'}
61
+ * /page/n7/mode/2up/search/hello => {page: 'n7', mode: '2up', q: 'hello'}
62
+ * @param {string} urlString
63
+ * @returns {object}
64
+ */
65
+ urlStringToUrlState(urlString) {
66
+ const urlState = {};
67
+
68
+ // Fetch searchParams from given {str}
69
+ // Note: whole URL path is needed for URL parsing
70
+ const urlPath = new URL(urlString, 'http://example.com');
71
+ const urlSearchParamsObj = Object.fromEntries(urlPath.searchParams.entries());
72
+ const splitUrlMatches = urlPath.pathname.match(/[^\\/]+\/[^\\/]+/g);
73
+ const urlStrSplitSlashObj = splitUrlMatches ? Object.fromEntries(splitUrlMatches.map(x => x.split('/'))) : {};
74
+
75
+ const doesKeyExists = (_object, _key) => {
76
+ return Object.keys(_object).some(value => value == _key);
77
+ };
78
+
79
+ // Add path objects to urlState
80
+ this.urlSchema
81
+ .filter(schema => schema.position == 'path')
82
+ .forEach(schema => {
83
+ const hasPropertyKey = doesKeyExists(urlStrSplitSlashObj, schema.name);
84
+ const hasDeprecatedKey = doesKeyExists(schema, 'deprecated_for') && hasPropertyKey;
85
+
86
+ // Not in the URL
87
+ if (!hasPropertyKey && !hasDeprecatedKey) {
88
+ return;
89
+ }
90
+
91
+ const urlStateParam = hasDeprecatedKey ? schema.deprecated_for : schema.name;
92
+ urlState[urlStateParam] = decodeURIComponent(urlStrSplitSlashObj[schema.name]);
93
+ });
94
+
95
+ // Add searchParams to urlState
96
+ Object.entries(urlSearchParamsObj).forEach(([key, value]) => {
97
+ urlState[key] = value;
98
+ });
99
+
100
+ return urlState;
101
+ }
102
+
103
+ /**
104
+ * Add or update key-value to the urlState
105
+ * @param {string} key
106
+ * @param {string} val
107
+ */
108
+ setUrlParam(key, value) {
109
+ this.urlState[key] = value;
110
+
111
+ this.pushToAddressBar();
112
+ }
113
+
114
+ /**
115
+ * Delete key-value to the urlState
116
+ * @param {string} key
117
+ */
118
+ removeUrlParam(key) {
119
+ delete this.urlState[key];
120
+
121
+ this.pushToAddressBar();
122
+ }
123
+
124
+ /**
125
+ * Get key-value from the urlState
126
+ * @param {string} key
127
+ * @return {string}
128
+ */
129
+ getUrlParam(key) {
130
+ return this.urlState[key];
131
+ }
132
+
133
+ /**
134
+ * Push URL params to addressbar
135
+ */
136
+ pushToAddressBar() {
137
+ const urlStrPath = this.urlStateToUrlString(this.urlState);
138
+ const concatenatedPath = urlStrPath !== '/' ? urlStrPath : '';
139
+ if (this.urlMode == 'history') {
140
+ if (!window.history || !window.history.replaceState) {
141
+ this.options.urlMode = 'hash';
142
+ } else {
143
+ const newUrlPath = `${this.urlHistoryBasePath}${concatenatedPath}`.trim().replace(/(\/+)/g, '/');
144
+ try {
145
+ window.history.replaceState({}, null, newUrlPath);
146
+ } catch (e) {
147
+ // DOMException on Chrome when in sandboxed iframe
148
+ this.urlMode = 'hash';
149
+ }
150
+ }
151
+ }
152
+
153
+ if (this.urlMode == 'hash') {
154
+ window.location.replace('#' + concatenatedPath);
155
+ }
156
+ this.oldLocationHash = urlStrPath;
157
+ }
158
+
159
+ /**
160
+ * Get the url and check if it has changed
161
+ * If it was changeed, update the urlState
162
+ */
163
+ listenForHashChanges() {
164
+ this.oldLocationHash = window.location.hash.substr(1);
165
+ if (this.urlLocationPollId) {
166
+ clearInterval(this.urlLocationPollId);
167
+ this.urlLocationPollId = null;
168
+ }
169
+
170
+ // check if the URL changes
171
+ const updateHash = () => {
172
+ const newFragment = window.location.hash.substr(1);
173
+ const hasFragmentChange = newFragment != this.oldLocationHash;
174
+
175
+ if (!hasFragmentChange) { return; }
176
+
177
+ this.urlState = this.urlStringToUrlState(newFragment);
178
+ };
179
+ this.urlLocationPollId = setInterval(updateHash, 500);
180
+ }
181
+
182
+ /**
183
+ * Will read either the hash or URL and return the bookreader fragment
184
+ */
185
+ pullFromAddressBar (location = window.location) {
186
+ const path = this.urlMode === 'history'
187
+ ? (location.pathname.substr(this.urlHistoryBasePath.length) + location.search)
188
+ : location.hash.substr(1);
189
+ this.urlState = this.urlStringToUrlState(path);
190
+ }
191
+ }
@@ -1,4 +1,7 @@
1
1
  /* global BookReader */
2
+
3
+ import { UrlPlugin } from "./UrlPlugin";
4
+
2
5
  /**
3
6
  * Plugin for URL management in BookReader
4
7
  * Note read more about the url "fragment" here:
@@ -22,7 +25,7 @@ jQuery.extend(BookReader.defaultOptions, {
22
25
  urlHistoryBasePath: '/',
23
26
 
24
27
  /** Only these params will be reflected onto the URL */
25
- urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight'],
28
+ urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight', 'view'],
26
29
 
27
30
  /** If true, don't update the URL when `page == n0 (eg "/page/n0")` */
28
31
  urlTrackIndex0: false,
@@ -50,7 +53,7 @@ BookReader.prototype.init = (function(super_) {
50
53
  this.bind(BookReader.eventNames.PostInit, () => {
51
54
  const { updateWindowTitle, urlMode } = this.options;
52
55
  if (updateWindowTitle) {
53
- document.title = this.shortTitle(50);
56
+ document.title = this.shortTitle(this.bookTitle, 50);
54
57
  }
55
58
  if (urlMode === 'hash') {
56
59
  this.urlStartLocationPolling();
@@ -86,7 +89,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
86
89
  this.oldLocationHash = this.urlReadFragment();
87
90
 
88
91
  if (this.locationPollId) {
89
- clearInterval(this.locationPollID);
92
+ clearInterval(this.locationPollId);
90
93
  this.locationPollId = null;
91
94
  }
92
95
 
@@ -110,7 +113,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
110
113
  updateParams();
111
114
  }
112
115
  this.oldUserHash = newFragment;
113
- }
116
+ };
114
117
 
115
118
  this.locationPollId = setInterval(updateHash, 500);
116
119
  };
@@ -121,7 +124,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
121
124
  */
122
125
  BookReader.prototype.urlUpdateFragment = function() {
123
126
  const allParams = this.paramsFromCurrent();
124
- const { urlMode, urlTrackIndex0, urlTrackedParams } = this.options;
127
+ const { urlTrackIndex0, urlTrackedParams } = this.options;
125
128
 
126
129
  if (!urlTrackIndex0
127
130
  && (typeof(allParams.index) !== 'undefined')
@@ -134,32 +137,39 @@ BookReader.prototype.urlUpdateFragment = function() {
134
137
  if (paramName in allParams) {
135
138
  validParams[paramName] = allParams[paramName];
136
139
  }
137
- return validParams
140
+ return validParams;
138
141
  }, {});
139
142
 
140
- const newFragment = this.fragmentFromParams(params, urlMode);
143
+ const newFragment = this.fragmentFromParams(params, this.options.urlMode);
141
144
  const currFragment = this.urlReadFragment();
142
145
  const currQueryString = this.getLocationSearch();
143
- const newQueryString = this.queryStringFromParams(params, currQueryString, urlMode);
146
+ const newQueryString = this.queryStringFromParams(params, currQueryString, this.options.urlMode);
144
147
  if (currFragment === newFragment && currQueryString === newQueryString) {
145
148
  return;
146
149
  }
147
150
 
148
- if (urlMode === 'history') {
149
- if (window.history && window.history.replaceState) {
151
+ if (this.options.urlMode === 'history') {
152
+ if (!window.history || !window.history.replaceState) {
153
+ this.options.urlMode = 'hash';
154
+ } else {
150
155
  const baseWithoutSlash = this.options.urlHistoryBasePath.replace(/\/+$/, '');
151
156
  const newFragmentWithSlash = newFragment === '' ? '' : `/${newFragment}`;
152
157
 
153
158
  const newUrlPath = `${baseWithoutSlash}${newFragmentWithSlash}${newQueryString}`;
154
- window.history.replaceState({}, null, newUrlPath);
155
- this.oldLocationHash = newFragment + newQueryString;
156
-
159
+ try {
160
+ window.history.replaceState({}, null, newUrlPath);
161
+ this.oldLocationHash = newFragment + newQueryString;
162
+ } catch (e) {
163
+ // DOMException on Chrome when in sandboxed iframe
164
+ this.options.urlMode = 'hash';
165
+ }
157
166
  }
158
- } else {
167
+ }
168
+
169
+ if (this.options.urlMode === 'hash') {
159
170
  const newQueryStringSearch = this.urlParamsFiltersOnlySearch(this.readQueryString());
160
171
  window.location.replace('#' + newFragment + newQueryStringSearch);
161
172
  this.oldLocationHash = newFragment + newQueryStringSearch;
162
-
163
173
  }
164
174
  };
165
175
 
@@ -173,7 +183,7 @@ BookReader.prototype.urlUpdateFragment = function() {
173
183
  BookReader.prototype.urlParamsFiltersOnlySearch = function(url) {
174
184
  const params = new URLSearchParams(url);
175
185
  return params.has('q') ? `?${new URLSearchParams({ q: params.get('q') })}` : '';
176
- }
186
+ };
177
187
 
178
188
 
179
189
  /**
@@ -196,3 +206,22 @@ BookReader.prototype.urlReadFragment = function() {
196
206
  BookReader.prototype.urlReadHashFragment = function() {
197
207
  return window.location.hash.substr(1);
198
208
  };
209
+ export class BookreaderUrlPlugin extends BookReader {
210
+ init() {
211
+ if (this.options.enableUrlPlugin) {
212
+ this.urlPlugin = new UrlPlugin(this.options);
213
+ this.bind(BookReader.eventNames.PostInit, () => {
214
+ const { urlMode } = this.options;
215
+
216
+ if (urlMode === 'hash') {
217
+ this.urlPlugin.listenForHashChanges();
218
+ }
219
+ });
220
+ }
221
+
222
+ super.init();
223
+ }
224
+ }
225
+
226
+ window.BookReader = BookreaderUrlPlugin;
227
+ export default BookreaderUrlPlugin;
@@ -28,3 +28,25 @@ export function isFirefox(userAgent = navigator.userAgent) {
28
28
  export function isSafari(userAgent = navigator.userAgent) {
29
29
  return /safari/i.test(userAgent) && !/chrome|chromium/i.test(userAgent);
30
30
  }
31
+
32
+ /**
33
+ * Checks whether the current browser is iOS (and hence iOS webkit)
34
+ * @return {boolean}
35
+ */
36
+ export function isIOS() {
37
+ // We can't just check the userAgent because as of iOS 13,
38
+ // the userAgent is the same as desktop Safari because
39
+ // they wanted iPad's to be served the same version of websites
40
+ // as desktops.
41
+ return 'ongesturestart' in window && navigator.maxTouchPoints > 0;
42
+ }
43
+
44
+ /**
45
+ * Checks whether the current browser is Samsung Internet
46
+ * https://stackoverflow.com/a/40684162/2317712
47
+ * @param {string} [userAgent]
48
+ * @return {boolean}
49
+ */
50
+ export function isSamsungInternet(userAgent = navigator.userAgent) {
51
+ return /SamsungBrowser/i.test(userAgent);
52
+ }
@@ -9,6 +9,22 @@
9
9
  * http://www.gnu.org/licenses/gpl-3.0-standalone.html
10
10
  */
11
11
 
12
+ /**
13
+ * Check to see if the browser has cookies enabled.
14
+ * Accessing document.cookies errors if eg iframe with sandbox enabled.
15
+ * @returns {boolean}
16
+ */
17
+ export function areCookiesBlocked(doc = document) {
18
+ try {
19
+ doc.cookie;
20
+ return false;
21
+ } catch (e) {
22
+ return true;
23
+ }
24
+ }
25
+
26
+ const COOKIES_BLOCKED = areCookiesBlocked();
27
+
12
28
  /**
13
29
  * Get specific key's value stored in cookie
14
30
  *
@@ -17,7 +33,7 @@
17
33
  * @returns {string|null}
18
34
  */
19
35
  export function getItem(sKey) {
20
- if (!sKey) return null;
36
+ if (COOKIES_BLOCKED || !sKey) return null;
21
37
 
22
38
  return decodeURIComponent(
23
39
  // eslint-disable-next-line no-useless-escape
@@ -34,9 +50,11 @@ export function getItem(sKey) {
34
50
  * @param {string} [sDomain] domain name
35
51
  * @param {boolean} [bSecure]
36
52
  *
37
- * @returns {true}
53
+ * @returns {boolean}
38
54
  */
39
55
  export function setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
56
+ if (COOKIES_BLOCKED) return false;
57
+
40
58
  document.cookie = encodeURIComponent(sKey) + '=' + encodeURIComponent(sValue)
41
59
  + (vEnd ? `; expires=${vEnd.toUTCString()}` : '')
42
60
  + (sDomain ? `; domain=${sDomain}` : '')
@@ -56,6 +74,7 @@ export function setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure) {
56
74
  * @returns {boolean}
57
75
  */
58
76
  export function removeItem(sKey, sPath, sDomain) {
77
+ if (COOKIES_BLOCKED) return false;
59
78
  // eslint-disable-next-line
60
79
  if (!hasItem(sKey)) return false;
61
80
 
@@ -48,6 +48,43 @@ To run a particular fixture, add the path to the file at the end of your argumen
48
48
 
49
49
  `npm run test:e2e chrome tests/e2e/example.test.js`
50
50
 
51
+ ### Testing netlify or archive.org
52
+
53
+ ```sh
54
+ BASE_URL='https://lucid-poitras-9a1249.netlify.app' npx testcafe
55
+ BASE_URL='https://archive.org' npx testcafe
56
+ ```
57
+
58
+ ### Testing any OCAID
59
+
60
+ For OCAIDs you should pick the specific test file to run, since things like autoplay tests won't work. The main tests are in `base.test.js`.
61
+
62
+ ```sh
63
+ OCAIDS='goody,goodytwoshoes00newyiala' npx testcafe tests/e2e/base.test.js
64
+ OCAIDS='goody,goodytwoshoes00newyiala' BASE_URL='https://archive.org' npx testcafe tests/e2e/base.test.js
65
+
66
+ # right to left book; note this also runs the base tests
67
+ OCAIDS='gendaitankashu00meijuoft' BASE_URL='https://archive.org' npx testcafe tests/e2e/rightToLeft.test.js
68
+ ```
69
+
70
+ ### Running tests with browserstack
71
+
72
+ Note these can only test a public url, so you either need to create a draft PR and use the netlify link, or use ngrok to publish your dev server's port.
73
+
74
+ Note: Windows users, there is a bug that prevents spaces in the browser field when using `npx`, so you'll need to have `testcafe` globally installed, and run it without `npx`. (See https://github.com/DevExpress/testcafe/issues/6600 ). Or, you can add browserstack browsers the `.testcaferc.js` file.
75
+
76
+ ```sh
77
+ # Set auth; find yours at https://www.browserstack.com/accounts/settings
78
+ export BROWSERSTACK_USERNAME="YOUR_USERNAME"
79
+ export BROWSERSTACK_ACCESS_KEY="YOUR_ACCESS_KEY"
80
+
81
+ BASE_URL='https://archive.org' OCAIDS='goody,goodytwoshoes00newyiala' npx testcafe 'browserstack:iPad Pro 12.9 2018@15' tests/e2e/base.test.js
82
+ ```
83
+
84
+ See a list of available browsers with `npx testcafe -b browserstack`. Note there are some browsers which appear to not work for some reason (eg `browserstack:iPad Mini 4@9.3`).
85
+
86
+ Read more about other options/etc at the browserstack docs: https://www.browserstack.com/docs/automate/selenium/getting-started/nodejs/testcafe .
87
+
51
88
  ## Pending (skip) tests
52
89
 
53
90
  You can skip any tests by calling the method `.skip` on the test object rather
@@ -1,11 +1,11 @@
1
1
  import { ClientFunction } from 'testcafe';
2
+ import params from './helpers/params';
2
3
 
3
- const { BASE_URL } = process.env;
4
4
  const getLocationHref = ClientFunction(() => window.location.href.toString());
5
5
  const FLIP_SPEED = 1000;
6
6
  const FIRST_PAGE_DELAY = 2000;
7
7
 
8
- fixture `Autoplay plugin`.page `${BASE_URL}demo-autoplay.html`;
8
+ fixture `Autoplay plugin`.page `${params.baseUrl}/BookReaderDemo/demo-autoplay.html`;
9
9
 
10
10
  test('page auto-advances after allotted flip speed and delay', async t => {
11
11
  await t.wait(2 * FLIP_SPEED + FIRST_PAGE_DELAY);
@@ -1,11 +1,9 @@
1
1
  import { runBaseTests } from './helpers/base';
2
2
  import BookReader from './models/BookReader';
3
- import { runDesktopSearchTests } from './helpers/desktopSearch';
4
- // import { runMobileSearchTests } from './helpers/mobileSearch';
3
+ import { runSearchTests } from './helpers/search';
4
+ import params from './helpers/params';
5
5
 
6
-
7
- const { BASE_URL } = process.env;
8
- const OCAIDS = [
6
+ const ocaids = params.ocaids || [
9
7
  'theworksofplato01platiala',
10
8
  // Removed because failing test 'Canonical URL with cookie shows paramters'
11
9
  // in tests/e2e/helpers/base.js
@@ -15,21 +13,15 @@ const OCAIDS = [
15
13
  // /BookReaderDemo/demo-ia-olivertwist.html/page/n13/mode/2up
16
14
  // 'demo-ia-olivertwist.html',
17
15
  ];
18
- const DEMO_PATH = 'demo-internetarchive.html?ocaid='
19
16
 
20
- OCAIDS.forEach(ocaid => {
21
- const url = `${BASE_URL}${DEMO_PATH }${ocaid}`;
17
+ ocaids.forEach(ocaid => {
18
+ const url = params.getArchiveUrl(ocaid);
22
19
 
23
20
  fixture `Base Tests for: ${ocaid}`.page `${url}`;
24
21
  runBaseTests(new BookReader());
25
22
 
26
- fixture `Desktop Search Tests for: ${ocaid}`
27
- .page `${url}`
28
- runDesktopSearchTests(new BookReader());
29
-
30
- // fixture `Mobile Search Tests for: ${ocaid}`
31
- // .page `${url}`
32
- // runMobileSearchTests(new BookReader());
33
-
34
23
 
24
+ fixture `Search Tests for: ${ocaid}`
25
+ .page `${url}`;
26
+ runSearchTests(new BookReader());
35
27
  });