@internetarchive/bookreader 5.0.0-3 → 5.0.0-30-d
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 -5
- package/.github/dependabot.yml +8 -0
- package/.github/workflows/node.js.yml +10 -1
- package/.husky/_/husky.sh +30 -0
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +75 -323
- package/BookReader/BookReader.js +32261 -2
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +15235 -0
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/close-circle-dark.svg +1 -0
- package/BookReader/icons/voice.svg +1 -0
- package/BookReader/jquery-1.10.1.js +108 -2
- package/BookReader/plugins/plugin.archive_analytics.js +170 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +163 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +333 -1
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +72 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.mobile_nav.js +332 -1
- package/BookReader/plugins/plugin.mobile_nav.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +241 -1
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +1261 -1
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +839 -1
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +9115 -2
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +811 -1
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js +326 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +412 -0
- package/BookReader/webcomponents-bundle.js.map +1 -0
- package/BookReaderDemo/BookReaderDemo.css +14 -1
- package/BookReaderDemo/IADemoBr.js +107 -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 +66 -18
- 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/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 +114 -0
- package/babel.config.js +18 -0
- package/index.html +3 -0
- package/jsconfig.json +19 -0
- package/package.json +45 -27
- package/src/BookNavigator/assets/button-base.js +8 -1
- package/src/BookNavigator/assets/ia-logo.js +17 -0
- 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 +528 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +2 -1
- package/src/BookNavigator/bookmarks/bookmark-edit.js +2 -1
- package/src/BookNavigator/bookmarks/bookmarks-list.js +1 -0
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +4 -9
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +32 -11
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +88 -43
- package/src/BookNavigator/downloads/downloads-provider.js +22 -16
- package/src/BookNavigator/downloads/downloads.js +16 -23
- package/src/BookNavigator/search/a-search-result.js +1 -0
- package/src/BookNavigator/search/search-provider.js +54 -20
- package/src/BookNavigator/search/search-results.js +7 -18
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +10 -12
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +1 -0
- package/src/BookNavigator/volumes/volumes-provider.js +114 -0
- package/src/BookNavigator/volumes/volumes.js +189 -0
- package/src/BookReader/DebugConsole.js +3 -3
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +50 -351
- package/src/BookReader/Mode1UpLit.js +434 -0
- package/src/BookReader/Mode2Up.js +94 -72
- package/src/BookReader/ModeSmoothZoom.js +177 -0
- package/src/BookReader/ModeThumb.js +16 -8
- package/src/BookReader/Navbar/Navbar.js +2 -31
- package/src/BookReader/PageContainer.js +47 -2
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +5 -5
- package/src/BookReader/options.js +10 -0
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils.js +68 -13
- package/src/BookReader.js +316 -232
- package/src/assets/icons/close-circle-dark.svg +1 -0
- 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 +1 -17
- package/src/css/_controls.scss +16 -3
- package/src/css/_icons.scss +6 -0
- package/src/ia-bookreader/ia-bookreader.js +206 -0
- package/src/plugins/plugin.chapters.js +15 -18
- package/src/plugins/plugin.mobile_nav.js +11 -10
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +17 -29
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +113 -104
- package/src/plugins/search/view.js +48 -163
- package/src/plugins/tts/AbstractTTSEngine.js +7 -0
- package/src/plugins/tts/FestivalTTSEngine.js +2 -2
- package/src/plugins/tts/WebTTSEngine.js +5 -0
- package/src/plugins/tts/plugin.tts.js +67 -102
- package/src/plugins/url/UrlPlugin.js +184 -0
- package/src/plugins/url/plugin.url.js +220 -0
- package/{src → stat}/BookNavigator/BookModel.js +0 -0
- package/{src → stat}/BookNavigator/BookNavigator.js +151 -104
- package/stat/BookNavigator/assets/bookmark-colors.js +15 -0
- package/stat/BookNavigator/assets/button-base.js +61 -0
- package/stat/BookNavigator/assets/ia-logo.js +17 -0
- package/stat/BookNavigator/assets/icon_checkmark.js +6 -0
- package/stat/BookNavigator/assets/icon_close.js +3 -0
- package/stat/BookNavigator/assets/icon_sort_asc.js +5 -0
- package/stat/BookNavigator/assets/icon_sort_desc.js +5 -0
- package/stat/BookNavigator/assets/icon_sort_neutral.js +5 -0
- package/stat/BookNavigator/assets/icon_volumes.js +11 -0
- package/stat/BookNavigator/bookmarks/bookmark-button.js +64 -0
- package/stat/BookNavigator/bookmarks/bookmark-edit.js +215 -0
- package/stat/BookNavigator/bookmarks/bookmarks-list.js +285 -0
- package/stat/BookNavigator/bookmarks/bookmarks-loginCTA.js +28 -0
- package/stat/BookNavigator/bookmarks/bookmarks-provider.js +56 -0
- package/stat/BookNavigator/bookmarks/ia-bookmarks.js +523 -0
- package/{src → stat}/BookNavigator/br-fullscreen-mgr.js +1 -2
- package/stat/BookNavigator/delete-modal-actions.js +49 -0
- package/stat/BookNavigator/downloads/downloads-provider.js +72 -0
- package/stat/BookNavigator/downloads/downloads.js +139 -0
- package/stat/BookNavigator/provider-config.js +0 -0
- package/stat/BookNavigator/search/a-search-result.js +55 -0
- package/stat/BookNavigator/search/search-provider.js +180 -0
- package/stat/BookNavigator/search/search-results.js +360 -0
- package/stat/BookNavigator/sharing.js +31 -0
- package/stat/BookNavigator/visual-adjustments/visual-adjustments-provider.js +94 -0
- package/stat/BookNavigator/visual-adjustments/visual-adjustments.js +280 -0
- package/stat/BookNavigator/volumes/volumes-provider.js +83 -0
- package/stat/BookNavigator/volumes/volumes.js +178 -0
- package/stat/BookReader/BookModel.js +518 -0
- package/stat/BookReader/DebugConsole.js +54 -0
- package/stat/BookReader/DragScrollable.js +233 -0
- package/stat/BookReader/ImageCache.js +116 -0
- package/stat/BookReader/Mode1Up.js +102 -0
- package/stat/BookReader/Mode1UpLit.js +434 -0
- package/stat/BookReader/Mode2Up.js +1372 -0
- package/stat/BookReader/ModeSmoothZoom.js +177 -0
- package/stat/BookReader/ModeThumb.js +344 -0
- package/stat/BookReader/Navbar/Navbar.js +310 -0
- package/stat/BookReader/PageContainer.js +120 -0
- package/stat/BookReader/ReduceSet.js +26 -0
- package/stat/BookReader/Toolbar/Toolbar.js +384 -0
- package/stat/BookReader/events.js +20 -0
- package/stat/BookReader/options.js +324 -0
- package/stat/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/stat/BookReader/utils/classes.js +36 -0
- package/stat/BookReader/utils.js +240 -0
- package/stat/BookReader.js +2550 -0
- package/{src → stat}/BookReaderComponent/BookReaderComponent.js +16 -11
- package/stat/assets/icons/1up.svg +12 -0
- package/stat/assets/icons/2up.svg +15 -0
- package/stat/assets/icons/advance.svg +26 -0
- package/stat/assets/icons/chevron-right.svg +1 -0
- package/stat/assets/icons/close-circle-dark.svg +1 -0
- package/stat/assets/icons/close-circle.svg +1 -0
- package/stat/assets/icons/fullscreen.svg +17 -0
- package/stat/assets/icons/fullscreen_exit.svg +17 -0
- package/stat/assets/icons/hamburger.svg +15 -0
- package/stat/assets/icons/left-arrow.svg +12 -0
- package/stat/assets/icons/magnify-minus.svg +16 -0
- package/stat/assets/icons/magnify-plus.svg +17 -0
- package/stat/assets/icons/magnify.svg +15 -0
- package/stat/assets/icons/pause.svg +23 -0
- package/stat/assets/icons/play.svg +22 -0
- package/stat/assets/icons/playback-speed.svg +34 -0
- package/stat/assets/icons/read-aloud.svg +22 -0
- package/stat/assets/icons/review.svg +22 -0
- package/stat/assets/icons/thumbnails.svg +17 -0
- package/stat/assets/icons/voice.svg +1 -0
- package/stat/assets/icons/volume-full.svg +22 -0
- package/stat/assets/images/BRicons.png +0 -0
- package/stat/assets/images/BRicons.svg +94 -0
- package/stat/assets/images/BRicons_ia.png +0 -0
- package/stat/assets/images/back_pages.png +0 -0
- package/stat/assets/images/book_bottom_icon.png +0 -0
- package/stat/assets/images/book_down_icon.png +0 -0
- package/stat/assets/images/book_left_icon.png +0 -0
- package/stat/assets/images/book_leftmost_icon.png +0 -0
- package/stat/assets/images/book_right_icon.png +0 -0
- package/stat/assets/images/book_rightmost_icon.png +0 -0
- package/stat/assets/images/book_top_icon.png +0 -0
- package/stat/assets/images/book_up_icon.png +0 -0
- package/stat/assets/images/books_graphic.svg +177 -0
- package/stat/assets/images/booksplit.png +0 -0
- package/stat/assets/images/control_pause_icon.png +0 -0
- package/stat/assets/images/control_play_icon.png +0 -0
- package/stat/assets/images/embed_icon.png +0 -0
- package/stat/assets/images/icon-home-ia.png +0 -0
- package/stat/assets/images/icon_OL-logo-xs.png +0 -0
- package/stat/assets/images/icon_alert-xs.png +0 -0
- package/stat/assets/images/icon_book.svg +12 -0
- package/stat/assets/images/icon_bookmark.svg +12 -0
- package/stat/assets/images/icon_close-pop.png +0 -0
- package/stat/assets/images/icon_download.png +0 -0
- package/stat/assets/images/icon_gear.svg +14 -0
- package/stat/assets/images/icon_hamburger.svg +20 -0
- package/stat/assets/images/icon_home.png +0 -0
- package/stat/assets/images/icon_home.svg +21 -0
- package/stat/assets/images/icon_home_ia.png +0 -0
- package/stat/assets/images/icon_indicator.png +0 -0
- package/stat/assets/images/icon_info.svg +11 -0
- package/stat/assets/images/icon_one_page.svg +8 -0
- package/stat/assets/images/icon_pause.svg +1 -0
- package/stat/assets/images/icon_play.svg +1 -0
- package/stat/assets/images/icon_playback-rate.svg +15 -0
- package/stat/assets/images/icon_return.png +0 -0
- package/stat/assets/images/icon_search_button.svg +8 -0
- package/stat/assets/images/icon_share.svg +9 -0
- package/stat/assets/images/icon_skip-ahead.svg +6 -0
- package/stat/assets/images/icon_skip-back.svg +13 -0
- package/stat/assets/images/icon_speaker.svg +18 -0
- package/stat/assets/images/icon_speaker_open.svg +10 -0
- package/stat/assets/images/icon_thumbnails.svg +12 -0
- package/stat/assets/images/icon_toc.svg +5 -0
- package/stat/assets/images/icon_two_pages.svg +9 -0
- package/stat/assets/images/icon_zoomer.png +0 -0
- package/stat/assets/images/loading.gif +0 -0
- package/stat/assets/images/logo_icon.png +0 -0
- package/stat/assets/images/marker_chap-off.png +0 -0
- package/stat/assets/images/marker_chap-off.svg +11 -0
- package/stat/assets/images/marker_chap-off_ia.png +0 -0
- package/stat/assets/images/marker_chap-on.png +0 -0
- package/stat/assets/images/marker_chap-on.svg +11 -0
- package/stat/assets/images/marker_srch-on.svg +11 -0
- package/stat/assets/images/marker_srchchap-off.png +0 -0
- package/stat/assets/images/marker_srchchap-on.png +0 -0
- package/stat/assets/images/nav_control-dn.png +0 -0
- package/stat/assets/images/nav_control-dn_ia.png +0 -0
- package/stat/assets/images/nav_control-up.png +0 -0
- package/stat/assets/images/nav_control-up_ia.png +0 -0
- package/stat/assets/images/nav_control.png +0 -0
- package/stat/assets/images/one_page_mode_icon.png +0 -0
- package/stat/assets/images/paper-badge.png +0 -0
- package/stat/assets/images/print_icon.png +0 -0
- package/stat/assets/images/progressbar.gif +0 -0
- package/stat/assets/images/right_edges.png +0 -0
- package/stat/assets/images/slider.png +0 -0
- package/stat/assets/images/slider_ia.png +0 -0
- package/stat/assets/images/thumbnail_mode_icon.png +0 -0
- package/stat/assets/images/transparent.png +0 -0
- package/stat/assets/images/two_page_mode_icon.png +0 -0
- package/stat/assets/images/zoom_in_icon.png +0 -0
- package/stat/assets/images/zoom_out_icon.png +0 -0
- package/stat/css/BookReader.scss +89 -0
- package/stat/css/_BRBookmarks.scss +29 -0
- package/stat/css/_BRComponent.scss +13 -0
- package/stat/css/_BRfloat.scss +197 -0
- package/stat/css/_BRicon.scss +48 -0
- package/stat/css/_BRmain.scss +251 -0
- package/stat/css/_BRnav.scss +359 -0
- package/stat/css/_BRpages.scss +139 -0
- package/stat/css/_BRsearch.scss +226 -0
- package/stat/css/_BRtoolbar.scss +84 -0
- package/stat/css/_BRvendor.scss +5 -0
- package/stat/css/_MobileNav.scss +194 -0
- package/stat/css/_TextSelection.scss +32 -0
- package/stat/css/_colorbox.scss +52 -0
- package/stat/css/_controls.scss +253 -0
- package/stat/css/_icons.scss +121 -0
- package/stat/jquery-wrapper.js +4 -0
- package/stat/plugins/plugin.archive_analytics.js +86 -0
- package/stat/plugins/plugin.autoplay.js +129 -0
- package/stat/plugins/plugin.chapters.js +248 -0
- package/stat/plugins/plugin.iframe.js +48 -0
- package/stat/plugins/plugin.mobile_nav.js +288 -0
- package/stat/plugins/plugin.resume.js +68 -0
- package/stat/plugins/plugin.text_selection.js +291 -0
- package/{src → stat}/plugins/plugin.url.js +4 -4
- package/stat/plugins/plugin.vendor-fullscreen.js +247 -0
- package/stat/plugins/search/plugin.search.js +439 -0
- package/stat/plugins/search/view.js +439 -0
- package/stat/plugins/tts/AbstractTTSEngine.js +249 -0
- package/stat/plugins/tts/FestivalTTSEngine.js +169 -0
- package/stat/plugins/tts/PageChunk.js +107 -0
- package/stat/plugins/tts/PageChunkIterator.js +163 -0
- package/stat/plugins/tts/WebTTSEngine.js +357 -0
- package/stat/plugins/tts/plugin.tts.js +357 -0
- package/stat/plugins/tts/tooltip_dict.js +15 -0
- package/stat/plugins/tts/utils.js +91 -0
- package/stat/util/browserSniffing.js +30 -0
- package/stat/util/debouncer.js +26 -0
- package/stat/util/docCookies.js +67 -0
- package/stat/util/strings.js +34 -0
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +5 -7
- package/tests/e2e/helpers/base.js +8 -3
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/desktopSearch.js +1 -1
- package/tests/e2e/helpers/mobileSearch.js +3 -3
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +30 -31
- 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 +87 -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 +74 -2
- 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/{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 +14 -24
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +12 -5
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +6 -6
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +3 -3
- 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 +175 -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 +485 -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 +1 -2
- 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 +11 -5
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/BookReader.js.LICENSE.txt +0 -72
- package/BookReader/bookreader-component-bundle.js +0 -1450
- package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
- package/BookReader/bookreader-component-bundle.js.map +0 -1
- package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
- package/BookReader/plugins/plugin.menu_toggle.js +0 -2
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReader/plugins/plugin.tts.js.LICENSE.txt +0 -27
- package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
- package/src/BookNavigator/assets/book-loader.js +0 -27
- 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
|
@@ -23,7 +23,7 @@ export default class FestivalTTSEngine extends AbstractTTSEngine {
|
|
|
23
23
|
// $.browsers is sometimes undefined on some Android browsers :/
|
|
24
24
|
// Likely related to when $.browser was moved to npm
|
|
25
25
|
/** @type {'mp3' | 'ogg'} format of audio to get */
|
|
26
|
-
this.audioFormat = $.browser?.mozilla ? 'ogg' : 'mp3';
|
|
26
|
+
this.audioFormat = $.browser?.mozilla ? 'ogg' : 'mp3'; //eslint-disable-line no-jquery/no-browser
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/** @override */
|
|
@@ -107,7 +107,7 @@ class FestivalTTSSound {
|
|
|
107
107
|
this.sound = null;
|
|
108
108
|
this.rate = 1;
|
|
109
109
|
/** @type {function} calling this resolves the "play" promise */
|
|
110
|
-
this._finishResolver = null
|
|
110
|
+
this._finishResolver = null;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
get loaded() {
|
|
@@ -296,6 +296,11 @@ export class WebTTSSound {
|
|
|
296
296
|
this.reload();
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
+
/** @param {SpeechSynthesisVoice} voice */
|
|
300
|
+
setVoice(voice) {
|
|
301
|
+
this.voice = voice;
|
|
302
|
+
this.reload();
|
|
303
|
+
}
|
|
299
304
|
/**
|
|
300
305
|
* @private
|
|
301
306
|
* Chrome has a bug where it only plays 15 seconds of TTS and then
|
|
@@ -6,8 +6,9 @@ import FestivalTTSEngine from './FestivalTTSEngine.js';
|
|
|
6
6
|
import WebTTSEngine from './WebTTSEngine.js';
|
|
7
7
|
import { toISO6391, approximateWordCount } from './utils.js';
|
|
8
8
|
import { en as tooltips } from './tooltip_dict.js';
|
|
9
|
-
|
|
10
|
-
/** @typedef {import(
|
|
9
|
+
import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
|
|
10
|
+
/** @typedef {import('./PageChunk.js').default} PageChunk */
|
|
11
|
+
/** @typedef {import("./AbstractTTSEngine.js").default} AbstractTTSEngine */
|
|
11
12
|
|
|
12
13
|
// Default options for TTS
|
|
13
14
|
jQuery.extend(BookReader.defaultOptions, {
|
|
@@ -22,7 +23,9 @@ BookReader.prototype.setup = (function (super_) {
|
|
|
22
23
|
super_.call(this, options);
|
|
23
24
|
|
|
24
25
|
if (this.options.enableTtsPlugin) {
|
|
25
|
-
|
|
26
|
+
/** @type { {[pageIndex: number]: Array<{ l: number, r: number, t: number, b: number }>} } */
|
|
27
|
+
this._ttsBoxesByIndex = {};
|
|
28
|
+
|
|
26
29
|
let TTSEngine = WebTTSEngine.isSupported() ? WebTTSEngine :
|
|
27
30
|
FestivalTTSEngine.isSupported() ? FestivalTTSEngine :
|
|
28
31
|
null;
|
|
@@ -54,17 +57,6 @@ BookReader.prototype.init = (function(super_) {
|
|
|
54
57
|
if (this.options.enableTtsPlugin) {
|
|
55
58
|
// Bind to events
|
|
56
59
|
|
|
57
|
-
// TODO move this to BookReader.js or something
|
|
58
|
-
this.bind(BookReader.eventNames.fragmentChange, () => {
|
|
59
|
-
if (this.mode == this.constMode2up) {
|
|
60
|
-
// clear highlights if they're no longer valid for this page
|
|
61
|
-
const visibleIndices = [this.twoPage.currentIndexL, this.twoPage.currentIndexR];
|
|
62
|
-
const visibleSelector = visibleIndices.map(i => `.BRReadAloudHilite.Leaf-${i}`).join(', ');
|
|
63
|
-
$(this.ttsHilites).filter(visibleSelector).show();
|
|
64
|
-
$(this.ttsHilites).not(visibleSelector).hide();
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
60
|
this.bind(BookReader.eventNames.PostInit, () => {
|
|
69
61
|
this.$('.BRicon.read').click(() => {
|
|
70
62
|
this.ttsToggle();
|
|
@@ -88,6 +80,17 @@ BookReader.prototype.init = (function(super_) {
|
|
|
88
80
|
};
|
|
89
81
|
})(BookReader.prototype.init);
|
|
90
82
|
|
|
83
|
+
/** @override */
|
|
84
|
+
BookReader.prototype._createPageContainer = (function (super_) {
|
|
85
|
+
return function (index) {
|
|
86
|
+
const pageContainer = super_.call(this, index);
|
|
87
|
+
if (this.options.enableTtsPlugin && pageContainer.page && index in this._ttsBoxesByIndex) {
|
|
88
|
+
const pageIndex = pageContainer.page.index;
|
|
89
|
+
renderBoxesInPageContainerLayer('ttsHiliteLayer', this._ttsBoxesByIndex[pageIndex], pageContainer.page, pageContainer.$container[0]);
|
|
90
|
+
}
|
|
91
|
+
return pageContainer;
|
|
92
|
+
};
|
|
93
|
+
})(BookReader.prototype._createPageContainer);
|
|
91
94
|
|
|
92
95
|
// Extend buildMobileDrawerElement
|
|
93
96
|
BookReader.prototype.buildMobileDrawerElement = (function (super_) {
|
|
@@ -146,15 +149,37 @@ BookReader.prototype.initNavbar = (function (super_) {
|
|
|
146
149
|
<div class="icon icon-advance"></div>
|
|
147
150
|
</button>
|
|
148
151
|
</li>
|
|
152
|
+
<li>
|
|
153
|
+
<select class="playback-voices" name="playback-voice" style="display: none" title="Change read aloud voices">
|
|
154
|
+
</select>
|
|
155
|
+
</li>
|
|
149
156
|
</ul>
|
|
150
157
|
`);
|
|
158
|
+
|
|
151
159
|
$el.find('.BRcontrols').prepend(this.refs.$BRReadAloudToolbar);
|
|
160
|
+
|
|
161
|
+
const renderVoicesMenu = (voicesMenu) => {
|
|
162
|
+
voicesMenu.empty();
|
|
163
|
+
if (this.ttsEngine.getVoices().length > 1) {
|
|
164
|
+
voicesMenu.append(this.ttsEngine.getVoices().map(
|
|
165
|
+
voice =>
|
|
166
|
+
$(`<option value="${voice.voiceURI}">${voice.lang} - ${voice.name}</option>`)));
|
|
167
|
+
voicesMenu.val(this.ttsEngine.voice.voiceURI);
|
|
168
|
+
voicesMenu.show();
|
|
169
|
+
} else {
|
|
170
|
+
voicesMenu.hide();
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
const voicesMenu = this.refs.$BRReadAloudToolbar.find('[name=playback-voice]');
|
|
174
|
+
renderVoicesMenu(voicesMenu);
|
|
175
|
+
voicesMenu.on("change", ev => this.ttsEngine.setVoice(voicesMenu.val()));
|
|
152
176
|
this.ttsEngine.events.on('pause resume start', () => this.ttsUpdateState());
|
|
153
|
-
this.
|
|
154
|
-
this.refs.$BRReadAloudToolbar.find('[name=
|
|
155
|
-
this.refs.$BRReadAloudToolbar.find('[name=
|
|
177
|
+
this.ttsEngine.events.on('voiceschanged', () => renderVoicesMenu(voicesMenu));
|
|
178
|
+
this.refs.$BRReadAloudToolbar.find('[name=play]').on("click", this.ttsPlayPause.bind(this));
|
|
179
|
+
this.refs.$BRReadAloudToolbar.find('[name=advance]').on("click", this.ttsJumpForward.bind(this));
|
|
180
|
+
this.refs.$BRReadAloudToolbar.find('[name=review]').on("click", this.ttsJumpBackward.bind(this));
|
|
156
181
|
const $rateSelector = this.refs.$BRReadAloudToolbar.find('select[name="playback-speed"]');
|
|
157
|
-
$rateSelector.change
|
|
182
|
+
$rateSelector.on("change", ev => this.ttsEngine.setPlaybackRate(parseFloat($rateSelector.val())));
|
|
158
183
|
$(`<li>
|
|
159
184
|
<button class="BRicon read js-tooltip" title="${tooltips.readAloud}">
|
|
160
185
|
<div class="icon icon-read-aloud"></div>
|
|
@@ -233,12 +258,12 @@ BookReader.prototype.ttsStop = function () {
|
|
|
233
258
|
* @param {PageChunk} chunk
|
|
234
259
|
* @return {PromiseLike<void>} returns once the flip is done
|
|
235
260
|
*/
|
|
236
|
-
BookReader.prototype.ttsBeforeChunkPlay = function(chunk) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
261
|
+
BookReader.prototype.ttsBeforeChunkPlay = async function(chunk) {
|
|
262
|
+
await this.ttsMaybeFlipToIndex(chunk.leafIndex);
|
|
263
|
+
this.ttsHighlightChunk(chunk);
|
|
264
|
+
// This appears not to work; ttsMaybeFlipToIndex causes a scroll to the top of
|
|
265
|
+
// the active page :/ Disabling cause the extra scroll just adds an odd jitter.
|
|
266
|
+
// this.ttsScrollToChunk(chunk);
|
|
242
267
|
};
|
|
243
268
|
|
|
244
269
|
/**
|
|
@@ -275,18 +300,28 @@ BookReader.prototype.ttsMaybeFlipToIndex = function (leafIndex) {
|
|
|
275
300
|
}
|
|
276
301
|
|
|
277
302
|
return promise;
|
|
278
|
-
}
|
|
303
|
+
};
|
|
279
304
|
|
|
280
305
|
/**
|
|
281
306
|
* @param {PageChunk} chunk
|
|
282
307
|
*/
|
|
283
308
|
BookReader.prototype.ttsHighlightChunk = function(chunk) {
|
|
309
|
+
// The poorly-named variable leafIndex
|
|
310
|
+
const pageIndex = chunk.leafIndex;
|
|
311
|
+
|
|
284
312
|
this.ttsRemoveHilites();
|
|
285
313
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
314
|
+
// group by index; currently only possible to have chunks on one page :/
|
|
315
|
+
this._ttsBoxesByIndex = {
|
|
316
|
+
[pageIndex]: chunk.lineRects.map(([l, b, r, t]) => ({l, r, b, t}))
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// update any already created pages
|
|
320
|
+
for (const [pageIndexString, boxes] of Object.entries(this._ttsBoxesByIndex)) {
|
|
321
|
+
const pageIndex = parseFloat(pageIndexString);
|
|
322
|
+
const page = this._models.book.getPage(pageIndex);
|
|
323
|
+
const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);
|
|
324
|
+
pageContainers.forEach(container => renderBoxesInPageContainerLayer('ttsHiliteLayer', boxes, page, container));
|
|
290
325
|
}
|
|
291
326
|
};
|
|
292
327
|
|
|
@@ -296,84 +331,14 @@ BookReader.prototype.ttsHighlightChunk = function(chunk) {
|
|
|
296
331
|
BookReader.prototype.ttsScrollToChunk = function(chunk) {
|
|
297
332
|
if (this.constMode1up != this.mode) return;
|
|
298
333
|
|
|
299
|
-
|
|
300
|
-
let h;
|
|
301
|
-
let i;
|
|
302
|
-
for (i = 0; i < chunk.leafIndex; i++) {
|
|
303
|
-
h = parseInt(this._getPageHeight(i) / this.reduce);
|
|
304
|
-
leafTop += h + this.padding;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
const chunkTop = chunk.lineRects[0][3]; //coords are in l,b,r,t order
|
|
308
|
-
const chunkBot = chunk.lineRects[chunk.lineRects.length - 1][1];
|
|
309
|
-
|
|
310
|
-
const topOfFirstChunk = leafTop + chunkTop / this.reduce;
|
|
311
|
-
const botOfLastChunk = leafTop + chunkBot / this.reduce;
|
|
312
|
-
|
|
313
|
-
if (window?.soundManager?.debugMode) console.log('leafTop = ' + leafTop + ' topOfFirstChunk = ' + topOfFirstChunk + ' botOfLastChunk = ' + botOfLastChunk);
|
|
314
|
-
|
|
315
|
-
const containerTop = this.refs.$brContainer.prop('scrollTop');
|
|
316
|
-
const containerBot = containerTop + this.refs.$brContainer.height();
|
|
317
|
-
if (window?.soundManager?.debugMode) console.log('containerTop = ' + containerTop + ' containerBot = ' + containerBot);
|
|
318
|
-
|
|
319
|
-
if ((topOfFirstChunk < containerTop) || (botOfLastChunk > containerBot)) {
|
|
320
|
-
this.refs.$brContainer.stop(true).animate({scrollTop: topOfFirstChunk},'fast');
|
|
321
|
-
}
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* @param {PageChunk} chunk
|
|
326
|
-
*/
|
|
327
|
-
BookReader.prototype.ttsHilite1UP = function(chunk) {
|
|
328
|
-
for (let i = 0; i < chunk.lineRects.length; i++) {
|
|
329
|
-
//each rect is an array of l,b,r,t coords (djvu.xml ordering...)
|
|
330
|
-
const l = chunk.lineRects[i][0];
|
|
331
|
-
const b = chunk.lineRects[i][1];
|
|
332
|
-
const r = chunk.lineRects[i][2];
|
|
333
|
-
const t = chunk.lineRects[i][3];
|
|
334
|
-
|
|
335
|
-
const div = document.createElement('div');
|
|
336
|
-
this.ttsHilites.push(div);
|
|
337
|
-
$(div).prop('className', 'BookReaderSearchHilite').appendTo(
|
|
338
|
-
this.$('.pagediv' + chunk.leafIndex)
|
|
339
|
-
);
|
|
340
|
-
|
|
341
|
-
$(div).css({
|
|
342
|
-
width: (r - l) / this.reduce + 'px',
|
|
343
|
-
height: (b - t) / this.reduce + 'px',
|
|
344
|
-
left: l / this.reduce + 'px',
|
|
345
|
-
top: t / this.reduce + 'px'
|
|
346
|
-
});
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* @param {PageChunk} chunk
|
|
353
|
-
*/
|
|
354
|
-
BookReader.prototype.ttsHilite2UP = function (chunk) {
|
|
355
|
-
for (let i = 0; i < chunk.lineRects.length; i++) {
|
|
356
|
-
//each rect is an array of l,b,r,t coords (djvu.xml ordering...)
|
|
357
|
-
const l = chunk.lineRects[i][0];
|
|
358
|
-
const b = chunk.lineRects[i][1];
|
|
359
|
-
const r = chunk.lineRects[i][2];
|
|
360
|
-
const t = chunk.lineRects[i][3];
|
|
361
|
-
|
|
362
|
-
const div = document.createElement('div');
|
|
363
|
-
this.ttsHilites.push(div);
|
|
364
|
-
$(div)
|
|
365
|
-
.prop('className', 'BookReaderSearchHilite BRReadAloudHilite Leaf-' + chunk.leafIndex)
|
|
366
|
-
.css('zIndex', 3)
|
|
367
|
-
.appendTo(this.refs.$brTwoPageView);
|
|
368
|
-
this.setHilightCss2UP(div, chunk.leafIndex, l, r, t, b);
|
|
369
|
-
}
|
|
334
|
+
$(`.pagediv${chunk.leafIndex} .ttsHiliteLayer rect`)[0]?.scrollIntoView();
|
|
370
335
|
};
|
|
371
336
|
|
|
372
337
|
// ttsRemoveHilites()
|
|
373
338
|
//______________________________________________________________________________
|
|
374
339
|
BookReader.prototype.ttsRemoveHilites = function () {
|
|
375
|
-
$(this.
|
|
376
|
-
this.
|
|
340
|
+
$(this.getActivePageContainerElements()).find('.ttsHiliteLayer').remove();
|
|
341
|
+
this._ttsBoxesByIndex = {};
|
|
377
342
|
};
|
|
378
343
|
|
|
379
344
|
/**
|
|
@@ -0,0 +1,184 @@
|
|
|
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}/${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
|
+
if (hasDeprecatedKey) {
|
|
87
|
+
urlState[schema.deprecated_for] = urlStrSplitSlashObj[schema.name];
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (hasPropertyKey) {
|
|
92
|
+
urlState[schema.name] = urlStrSplitSlashObj[schema.name];
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Add searchParams to urlState
|
|
98
|
+
Object.entries(urlSearchParamsObj).forEach(([key, value]) => {
|
|
99
|
+
urlState[key] = value;
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return urlState;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Add or update key-value to the urlState
|
|
107
|
+
* @param {string} key
|
|
108
|
+
* @param {string} val
|
|
109
|
+
*/
|
|
110
|
+
setUrlParam(key, value) {
|
|
111
|
+
this.urlState[key] = value;
|
|
112
|
+
|
|
113
|
+
this.pushToAddressBar();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Delete key-value to the urlState
|
|
118
|
+
* @param {string} key
|
|
119
|
+
*/
|
|
120
|
+
removeUrlParam(key) {
|
|
121
|
+
delete this.urlState[key];
|
|
122
|
+
|
|
123
|
+
this.pushToAddressBar();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get key-value from the urlState
|
|
128
|
+
* @param {string} key
|
|
129
|
+
* @return {string}
|
|
130
|
+
*/
|
|
131
|
+
getUrlParam(key) {
|
|
132
|
+
return this.urlState[key];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Push URL params to addressbar
|
|
137
|
+
*/
|
|
138
|
+
pushToAddressBar() {
|
|
139
|
+
const urlStrPath = this.urlStateToUrlString(this.urlState);
|
|
140
|
+
const concatenatedPath = urlStrPath !== '/' ? urlStrPath : '';
|
|
141
|
+
if (this.urlMode == 'history') {
|
|
142
|
+
if (window.history && window.history.replaceState) {
|
|
143
|
+
const newUrlPath = `${this.urlHistoryBasePath}${concatenatedPath}`;
|
|
144
|
+
window.history.replaceState({}, null, newUrlPath);
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
window.location.replace('#' + concatenatedPath);
|
|
148
|
+
}
|
|
149
|
+
this.oldLocationHash = urlStrPath;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get the url and check if it has changed
|
|
154
|
+
* If it was changeed, update the urlState
|
|
155
|
+
*/
|
|
156
|
+
listenForHashChanges() {
|
|
157
|
+
this.oldLocationHash = window.location.hash.substr(1);
|
|
158
|
+
if (this.urlLocationPollId) {
|
|
159
|
+
clearInterval(this.urlLocationPollId);
|
|
160
|
+
this.urlLocationPollId = null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// check if the URL changes
|
|
164
|
+
const updateHash = () => {
|
|
165
|
+
const newFragment = window.location.hash.substr(1);
|
|
166
|
+
const hasFragmentChange = newFragment != this.oldLocationHash;
|
|
167
|
+
|
|
168
|
+
if (!hasFragmentChange) { return; }
|
|
169
|
+
|
|
170
|
+
this.urlState = this.urlStringToUrlState(newFragment);
|
|
171
|
+
};
|
|
172
|
+
this.urlLocationPollId = setInterval(updateHash, 500);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Will read either the hash or URL and return the bookreader fragment
|
|
177
|
+
*/
|
|
178
|
+
pullFromAddressBar (location = window.location) {
|
|
179
|
+
const path = this.urlMode === 'history'
|
|
180
|
+
? (location.pathname.substr(this.urlHistoryBasePath.length) + location.search)
|
|
181
|
+
: location.hash.substr(1);
|
|
182
|
+
this.urlState = this.urlStringToUrlState(path);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/* global BookReader */
|
|
2
|
+
|
|
3
|
+
import { UrlPlugin } from "./UrlPlugin";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Plugin for URL management in BookReader
|
|
7
|
+
* Note read more about the url "fragment" here:
|
|
8
|
+
* https://openlibrary.org/dev/docs/bookurls
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
jQuery.extend(BookReader.defaultOptions, {
|
|
12
|
+
enableUrlPlugin: true,
|
|
13
|
+
bookId: '',
|
|
14
|
+
/** @type {string} Defaults can be a urlFragment string */
|
|
15
|
+
defaults: null,
|
|
16
|
+
updateWindowTitle: false,
|
|
17
|
+
|
|
18
|
+
/** @type {'history' | 'hash'} */
|
|
19
|
+
urlMode: 'hash',
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* When using 'history' mode, this part of the URL is kept constant
|
|
23
|
+
* @example /details/plato/
|
|
24
|
+
*/
|
|
25
|
+
urlHistoryBasePath: '/',
|
|
26
|
+
|
|
27
|
+
/** Only these params will be reflected onto the URL */
|
|
28
|
+
urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight', 'view'],
|
|
29
|
+
|
|
30
|
+
/** If true, don't update the URL when `page == n0 (eg "/page/n0")` */
|
|
31
|
+
urlTrackIndex0: false,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/** @override */
|
|
35
|
+
BookReader.prototype.setup = (function(super_) {
|
|
36
|
+
return function(options) {
|
|
37
|
+
super_.call(this, options);
|
|
38
|
+
|
|
39
|
+
this.bookId = options.bookId;
|
|
40
|
+
this.defaults = options.defaults;
|
|
41
|
+
|
|
42
|
+
this.locationPollId = null;
|
|
43
|
+
this.oldLocationHash = null;
|
|
44
|
+
this.oldUserHash = null;
|
|
45
|
+
};
|
|
46
|
+
})(BookReader.prototype.setup);
|
|
47
|
+
|
|
48
|
+
/** @override */
|
|
49
|
+
BookReader.prototype.init = (function(super_) {
|
|
50
|
+
return function() {
|
|
51
|
+
|
|
52
|
+
if (this.options.enableUrlPlugin) {
|
|
53
|
+
this.bind(BookReader.eventNames.PostInit, () => {
|
|
54
|
+
const { updateWindowTitle, urlMode } = this.options;
|
|
55
|
+
if (updateWindowTitle) {
|
|
56
|
+
document.title = this.shortTitle(this.bookTitle, 50);
|
|
57
|
+
}
|
|
58
|
+
if (urlMode === 'hash') {
|
|
59
|
+
this.urlStartLocationPolling();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this.bind(BookReader.eventNames.fragmentChange,
|
|
64
|
+
this.urlUpdateFragment.bind(this)
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
super_.call(this);
|
|
68
|
+
};
|
|
69
|
+
})(BookReader.prototype.init);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Returns a shortened version of the title with the maximum number of characters
|
|
73
|
+
* @param {number} maximumCharacters
|
|
74
|
+
* @return {string}
|
|
75
|
+
*/
|
|
76
|
+
BookReader.prototype.shortTitle = function(maximumCharacters) {
|
|
77
|
+
if (this.bookTitle.length < maximumCharacters) {
|
|
78
|
+
return this.bookTitle;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const title = `${this.bookTitle.substr(0, maximumCharacters - 3)}...`;
|
|
82
|
+
return title;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Starts polling of window.location to see hash fragment changes
|
|
87
|
+
*/
|
|
88
|
+
BookReader.prototype.urlStartLocationPolling = function() {
|
|
89
|
+
this.oldLocationHash = this.urlReadFragment();
|
|
90
|
+
|
|
91
|
+
if (this.locationPollId) {
|
|
92
|
+
clearInterval(this.locationPollId);
|
|
93
|
+
this.locationPollId = null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const updateHash = () => {
|
|
97
|
+
const newFragment = this.urlReadFragment();
|
|
98
|
+
const hasFragmentChange = (newFragment != this.oldLocationHash) && (newFragment != this.oldUserHash);
|
|
99
|
+
|
|
100
|
+
if (!hasFragmentChange) { return; }
|
|
101
|
+
|
|
102
|
+
const params = this.paramsFromFragment(newFragment);
|
|
103
|
+
|
|
104
|
+
const updateParams = () => this.updateFromParams(params);
|
|
105
|
+
|
|
106
|
+
this.trigger(BookReader.eventNames.stop);
|
|
107
|
+
if (this.animating) {
|
|
108
|
+
// Queue change if animating
|
|
109
|
+
if (this.autoStop) this.autoStop();
|
|
110
|
+
this.animationFinishedCallback = updateParams;
|
|
111
|
+
} else {
|
|
112
|
+
// update immediately
|
|
113
|
+
updateParams();
|
|
114
|
+
}
|
|
115
|
+
this.oldUserHash = newFragment;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
this.locationPollId = setInterval(updateHash, 500);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Update URL from the current parameters.
|
|
123
|
+
* Call this instead of manually using window.location.replace
|
|
124
|
+
*/
|
|
125
|
+
BookReader.prototype.urlUpdateFragment = function() {
|
|
126
|
+
const allParams = this.paramsFromCurrent();
|
|
127
|
+
const { urlMode, urlTrackIndex0, urlTrackedParams } = this.options;
|
|
128
|
+
|
|
129
|
+
if (!urlTrackIndex0
|
|
130
|
+
&& (typeof(allParams.index) !== 'undefined')
|
|
131
|
+
&& allParams.index === 0) {
|
|
132
|
+
delete allParams.index;
|
|
133
|
+
delete allParams.page;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const params = urlTrackedParams.reduce((validParams, paramName) => {
|
|
137
|
+
if (paramName in allParams) {
|
|
138
|
+
validParams[paramName] = allParams[paramName];
|
|
139
|
+
}
|
|
140
|
+
return validParams;
|
|
141
|
+
}, {});
|
|
142
|
+
|
|
143
|
+
const newFragment = this.fragmentFromParams(params, urlMode);
|
|
144
|
+
const currFragment = this.urlReadFragment();
|
|
145
|
+
const currQueryString = this.getLocationSearch();
|
|
146
|
+
const newQueryString = this.queryStringFromParams(params, currQueryString, urlMode);
|
|
147
|
+
if (currFragment === newFragment && currQueryString === newQueryString) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (urlMode === 'history') {
|
|
152
|
+
if (window.history && window.history.replaceState) {
|
|
153
|
+
const baseWithoutSlash = this.options.urlHistoryBasePath.replace(/\/+$/, '');
|
|
154
|
+
const newFragmentWithSlash = newFragment === '' ? '' : `/${newFragment}`;
|
|
155
|
+
|
|
156
|
+
const newUrlPath = `${baseWithoutSlash}${newFragmentWithSlash}${newQueryString}`;
|
|
157
|
+
window.history.replaceState({}, null, newUrlPath);
|
|
158
|
+
this.oldLocationHash = newFragment + newQueryString;
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
const newQueryStringSearch = this.urlParamsFiltersOnlySearch(this.readQueryString());
|
|
163
|
+
window.location.replace('#' + newFragment + newQueryStringSearch);
|
|
164
|
+
this.oldLocationHash = newFragment + newQueryStringSearch;
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @private
|
|
171
|
+
* Filtering query parameters to select only book search param (?q=foo)
|
|
172
|
+
This needs to be updated/URL system modified if future query params are to be added
|
|
173
|
+
* @param {string} url
|
|
174
|
+
* @return {string}
|
|
175
|
+
* */
|
|
176
|
+
BookReader.prototype.urlParamsFiltersOnlySearch = function(url) {
|
|
177
|
+
const params = new URLSearchParams(url);
|
|
178
|
+
return params.has('q') ? `?${new URLSearchParams({ q: params.get('q') })}` : '';
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Will read either the hash or URL and return the bookreader fragment
|
|
184
|
+
* @return {string}
|
|
185
|
+
*/
|
|
186
|
+
BookReader.prototype.urlReadFragment = function() {
|
|
187
|
+
const { urlMode, urlHistoryBasePath } = this.options;
|
|
188
|
+
if (urlMode === 'history') {
|
|
189
|
+
return window.location.pathname.substr(urlHistoryBasePath.length);
|
|
190
|
+
} else {
|
|
191
|
+
return window.location.hash.substr(1);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Will read the hash return the bookreader fragment
|
|
197
|
+
* @return {string}
|
|
198
|
+
*/
|
|
199
|
+
BookReader.prototype.urlReadHashFragment = function() {
|
|
200
|
+
return window.location.hash.substr(1);
|
|
201
|
+
};
|
|
202
|
+
export class BookreaderUrlPlugin extends BookReader {
|
|
203
|
+
init() {
|
|
204
|
+
if (this.options.enableUrlPlugin) {
|
|
205
|
+
this.urlPlugin = new UrlPlugin(this.options);
|
|
206
|
+
this.bind(BookReader.eventNames.PostInit, () => {
|
|
207
|
+
const { urlMode } = this.options;
|
|
208
|
+
|
|
209
|
+
if (urlMode === 'hash') {
|
|
210
|
+
this.urlPlugin.listenForHashChanges();
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
super.init();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
window.BookReader = BookreaderUrlPlugin;
|
|
220
|
+
export default BookreaderUrlPlugin;
|
|
File without changes
|