@internetarchive/bookreader 5.0.0-20 → 5.0.0-24

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 (60) hide show
  1. package/BookReader/BookReader.css +0 -55
  2. package/BookReader/BookReader.js +1 -1
  3. package/BookReader/BookReader.js.map +1 -1
  4. package/BookReader/bookreader-component-bundle.js +4 -4
  5. package/BookReader/bookreader-component-bundle.js.map +1 -1
  6. package/BookReader/plugins/plugin.url.js +1 -1
  7. package/BookReader/plugins/plugin.url.js.map +1 -1
  8. package/CHANGELOG.md +15 -0
  9. package/index.html +3 -0
  10. package/package.json +2 -6
  11. package/src/BookNavigator/BookNavigator.js +5 -1
  12. package/src/BookNavigator/bookmarks/bookmarks-provider.js +1 -0
  13. package/src/BookNavigator/bookmarks/ia-bookmarks.js +3 -0
  14. package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +1 -1
  15. package/src/BookReader/Mode1Up.js +10 -2
  16. package/src/BookReader/ModeThumb.js +13 -6
  17. package/src/BookReader/Navbar/Navbar.js +0 -29
  18. package/src/BookReader/options.js +4 -0
  19. package/src/BookReader.js +35 -35
  20. package/src/ItemNavigator/ItemNavigator.js +1 -0
  21. package/src/css/_BRnav.scss +0 -23
  22. package/src/plugins/plugin.url.js +1 -1
  23. package/tests/{BookReader → jest/BookReader}/BookModel.test.js +0 -0
  24. package/tests/{BookReader → jest/BookReader}/BookReaderPublicFunctions.test.js +2 -2
  25. package/tests/{BookReader → jest/BookReader}/DebugConsole.test.js +0 -0
  26. package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +0 -0
  27. package/tests/{BookReader → jest/BookReader}/Mode1UpLit.test.js +0 -0
  28. package/tests/{BookReader → jest/BookReader}/Mode2Up.test.js +0 -0
  29. package/tests/{BookReader → jest/BookReader}/ModeSmoothZoom.test.js +0 -0
  30. package/tests/jest/BookReader/ModeThumb.test.js +71 -0
  31. package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +0 -0
  32. package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +0 -0
  33. package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +0 -0
  34. package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +0 -0
  35. package/tests/{BookReader → jest/BookReader}/utils/HTMLDimensionsCacher.test.js +0 -0
  36. package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +0 -0
  37. package/tests/{BookReader → jest/BookReader}/utils.test.js +0 -0
  38. package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +8 -0
  39. package/tests/{BookReader.test.js → jest/BookReader.test.js} +16 -0
  40. package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +0 -0
  41. package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +0 -0
  42. package/tests/{plugins → jest/plugins}/plugin.chapters.test.js +0 -0
  43. package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +0 -0
  44. package/tests/{plugins → jest/plugins}/plugin.mobile_nav.test.js +0 -0
  45. package/tests/{plugins → jest/plugins}/plugin.resume.test.js +0 -0
  46. package/tests/{plugins → jest/plugins}/plugin.text_selection.test.js +0 -0
  47. package/tests/{plugins → jest/plugins}/plugin.url.test.js +18 -0
  48. /package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +0 -0
  49. /package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +0 -0
  50. /package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +0 -0
  51. /package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +0 -0
  52. /package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +0 -0
  53. /package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +0 -0
  54. /package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +0 -0
  55. /package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +0 -0
  56. /package/tests/{plugins → jest/plugins}/tts/utils.test.js +0 -0
  57. /package/tests/{util → jest/util}/browserSniffing.test.js +0 -0
  58. /package/tests/{util → jest/util}/docCookies.test.js +0 -0
  59. /package/tests/{util → jest/util}/strings.test.js +0 -0
  60. /package/tests/{utils.js → jest/utils.js} +0 -0
@@ -1,2 +1,2 @@
1
- "use strict";(self.webpackChunk_internetarchive_bookreader=self.webpackChunk_internetarchive_bookreader||[]).push([[336],{8837:function(t,o,e){var a;e(5827),e(4916),e(5306),e(2222),e(6992),e(1539),e(8783),e(3948),e(285),e(3609).extend(BookReader.defaultOptions,{enableUrlPlugin:!0,bookId:"",defaults:null,updateWindowTitle:!1,urlMode:"hash",urlHistoryBasePath:"/",urlTrackedParams:["page","search","mode","region","highlight"],urlTrackIndex0:!1}),BookReader.prototype.setup=(a=BookReader.prototype.setup,function(t){a.call(this,t),this.bookId=t.bookId,this.defaults=t.defaults,this.locationPollId=null,this.oldLocationHash=null,this.oldUserHash=null}),BookReader.prototype.init=function(t){return function(){var o=this;this.options.enableUrlPlugin&&(this.bind(BookReader.eventNames.PostInit,(function(){var t=o.options,e=t.updateWindowTitle,a=t.urlMode;e&&(document.title=o.shortTitle(50)),"hash"===a&&o.urlStartLocationPolling()})),this.bind(BookReader.eventNames.fragmentChange,this.urlUpdateFragment.bind(this))),t.call(this)}}(BookReader.prototype.init),BookReader.prototype.shortTitle=function(t){return this.bookTitle.length<t?this.bookTitle:"".concat(this.bookTitle.substr(0,t-3),"...")},BookReader.prototype.urlStartLocationPolling=function(){var t=this;this.oldLocationHash=this.urlReadFragment(),this.locationPollId&&(clearInterval(this.locationPollID),this.locationPollId=null),this.locationPollId=setInterval((function(){var o=t.urlReadFragment();if(o!=t.oldLocationHash&&o!=t.oldUserHash){var e=t.paramsFromFragment(o),a=function(){return t.updateFromParams(e)};t.trigger(BookReader.eventNames.stop),t.animating?(t.autoStop&&t.autoStop(),t.animationFinishedCallback=a):a(),t.oldUserHash=o}}),500)},BookReader.prototype.urlUpdateFragment=function(){var t=this.paramsFromCurrent(),o=this.options,e=o.urlMode,a=o.urlTrackIndex0,r=o.urlTrackedParams;a||void 0===t.index||0!==t.index||(delete t.index,delete t.page);var n=r.reduce((function(o,e){return e in t&&(o[e]=t[e]),o}),{}),i=this.fragmentFromParams(n,e),s=this.urlReadFragment(),l=this.getLocationSearch(),h=this.queryStringFromParams(n,l,e);if(s!==i||l!==h)if("history"===e){if(window.history&&window.history.replaceState){var d=this.options.urlHistoryBasePath.replace(/\/+$/,""),u=""===i?"":"/".concat(i),c="".concat(d).concat(u).concat(h);window.history.replaceState({},null,c),this.oldLocationHash=i+h}}else{var p=this.urlParamsFiltersOnlySearch(this.readQueryString());window.location.replace("#"+i+p),this.oldLocationHash=i+p}},BookReader.prototype.urlParamsFiltersOnlySearch=function(t){var o=new URLSearchParams(t);return o.has("q")?"?".concat(new URLSearchParams({q:o.get("q")})):""},BookReader.prototype.urlReadFragment=function(){var t=this.options,o=t.urlMode,e=t.urlHistoryBasePath;return"history"===o?window.location.pathname.substr(e.length):window.location.hash.substr(1)},BookReader.prototype.urlReadHashFragment=function(){return window.location.hash.substr(1)}}},function(t){t(t.s=8837)}]);
1
+ "use strict";(self.webpackChunk_internetarchive_bookreader=self.webpackChunk_internetarchive_bookreader||[]).push([[336],{8837:function(t,o,e){var a;e(5827),e(4916),e(5306),e(2222),e(6992),e(1539),e(8783),e(3948),e(285),e(3609).extend(BookReader.defaultOptions,{enableUrlPlugin:!0,bookId:"",defaults:null,updateWindowTitle:!1,urlMode:"hash",urlHistoryBasePath:"/",urlTrackedParams:["page","search","mode","region","highlight","view"],urlTrackIndex0:!1}),BookReader.prototype.setup=(a=BookReader.prototype.setup,function(t){a.call(this,t),this.bookId=t.bookId,this.defaults=t.defaults,this.locationPollId=null,this.oldLocationHash=null,this.oldUserHash=null}),BookReader.prototype.init=function(t){return function(){var o=this;this.options.enableUrlPlugin&&(this.bind(BookReader.eventNames.PostInit,(function(){var t=o.options,e=t.updateWindowTitle,a=t.urlMode;e&&(document.title=o.shortTitle(50)),"hash"===a&&o.urlStartLocationPolling()})),this.bind(BookReader.eventNames.fragmentChange,this.urlUpdateFragment.bind(this))),t.call(this)}}(BookReader.prototype.init),BookReader.prototype.shortTitle=function(t){return this.bookTitle.length<t?this.bookTitle:"".concat(this.bookTitle.substr(0,t-3),"...")},BookReader.prototype.urlStartLocationPolling=function(){var t=this;this.oldLocationHash=this.urlReadFragment(),this.locationPollId&&(clearInterval(this.locationPollID),this.locationPollId=null),this.locationPollId=setInterval((function(){var o=t.urlReadFragment();if(o!=t.oldLocationHash&&o!=t.oldUserHash){var e=t.paramsFromFragment(o),a=function(){return t.updateFromParams(e)};t.trigger(BookReader.eventNames.stop),t.animating?(t.autoStop&&t.autoStop(),t.animationFinishedCallback=a):a(),t.oldUserHash=o}}),500)},BookReader.prototype.urlUpdateFragment=function(){var t=this.paramsFromCurrent(),o=this.options,e=o.urlMode,a=o.urlTrackIndex0,r=o.urlTrackedParams;a||void 0===t.index||0!==t.index||(delete t.index,delete t.page);var i=r.reduce((function(o,e){return e in t&&(o[e]=t[e]),o}),{}),n=this.fragmentFromParams(i,e),s=this.urlReadFragment(),l=this.getLocationSearch(),h=this.queryStringFromParams(i,l,e);if(s!==n||l!==h)if("history"===e){if(window.history&&window.history.replaceState){var d=this.options.urlHistoryBasePath.replace(/\/+$/,""),u=""===n?"":"/".concat(n),c="".concat(d).concat(u).concat(h);window.history.replaceState({},null,c),this.oldLocationHash=n+h}}else{var p=this.urlParamsFiltersOnlySearch(this.readQueryString());window.location.replace("#"+n+p),this.oldLocationHash=n+p}},BookReader.prototype.urlParamsFiltersOnlySearch=function(t){var o=new URLSearchParams(t);return o.has("q")?"?".concat(new URLSearchParams({q:o.get("q")})):""},BookReader.prototype.urlReadFragment=function(){var t=this.options,o=t.urlMode,e=t.urlHistoryBasePath;return"history"===o?window.location.pathname.substr(e.length):window.location.hash.substr(1)},BookReader.prototype.urlReadHashFragment=function(){return window.location.hash.substr(1)}}},function(t){t(t.s=8837)}]);
2
2
  //# sourceMappingURL=plugin.url.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugins/plugin.url.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/plugins/plugin.url.js"],"sourcesContent":["/* global BookReader */\n/**\n * Plugin for URL management in BookReader\n * Note read more about the url \"fragment\" here:\n * https://openlibrary.org/dev/docs/bookurls\n */\n\njQuery.extend(BookReader.defaultOptions, {\n enableUrlPlugin: true,\n bookId: '',\n /** @type {string} Defaults can be a urlFragment string */\n defaults: null,\n updateWindowTitle: false,\n\n /** @type {'history' | 'hash'} */\n urlMode: 'hash',\n\n /**\n * When using 'history' mode, this part of the URL is kept constant\n * @example /details/plato/\n */\n urlHistoryBasePath: '/',\n\n /** Only these params will be reflected onto the URL */\n urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight'],\n\n /** If true, don't update the URL when `page == n0 (eg \"/page/n0\")` */\n urlTrackIndex0: false,\n});\n\n/** @override */\nBookReader.prototype.setup = (function(super_) {\n return function(options) {\n super_.call(this, options);\n\n this.bookId = options.bookId;\n this.defaults = options.defaults;\n\n this.locationPollId = null;\n this.oldLocationHash = null;\n this.oldUserHash = null;\n };\n})(BookReader.prototype.setup);\n\n/** @override */\nBookReader.prototype.init = (function(super_) {\n return function() {\n\n if (this.options.enableUrlPlugin) {\n this.bind(BookReader.eventNames.PostInit, () => {\n const { updateWindowTitle, urlMode } = this.options;\n if (updateWindowTitle) {\n document.title = this.shortTitle(50);\n }\n if (urlMode === 'hash') {\n this.urlStartLocationPolling();\n }\n });\n\n this.bind(BookReader.eventNames.fragmentChange,\n this.urlUpdateFragment.bind(this)\n );\n }\n super_.call(this);\n };\n})(BookReader.prototype.init);\n\n/**\n * Returns a shortened version of the title with the maximum number of characters\n * @param {number} maximumCharacters\n * @return {string}\n */\nBookReader.prototype.shortTitle = function(maximumCharacters) {\n if (this.bookTitle.length < maximumCharacters) {\n return this.bookTitle;\n }\n\n const title = `${this.bookTitle.substr(0, maximumCharacters - 3)}...`;\n return title;\n};\n\n/**\n * Starts polling of window.location to see hash fragment changes\n */\nBookReader.prototype.urlStartLocationPolling = function() {\n this.oldLocationHash = this.urlReadFragment();\n\n if (this.locationPollId) {\n clearInterval(this.locationPollID);\n this.locationPollId = null;\n }\n\n const updateHash = () => {\n const newFragment = this.urlReadFragment();\n const hasFragmentChange = (newFragment != this.oldLocationHash) && (newFragment != this.oldUserHash);\n\n if (!hasFragmentChange) { return; }\n\n const params = this.paramsFromFragment(newFragment);\n\n const updateParams = () => this.updateFromParams(params);\n\n this.trigger(BookReader.eventNames.stop);\n if (this.animating) {\n // Queue change if animating\n if (this.autoStop) this.autoStop();\n this.animationFinishedCallback = updateParams;\n } else {\n // update immediately\n updateParams();\n }\n this.oldUserHash = newFragment;\n };\n\n this.locationPollId = setInterval(updateHash, 500);\n};\n\n/**\n * Update URL from the current parameters.\n * Call this instead of manually using window.location.replace\n */\nBookReader.prototype.urlUpdateFragment = function() {\n const allParams = this.paramsFromCurrent();\n const { urlMode, urlTrackIndex0, urlTrackedParams } = this.options;\n\n if (!urlTrackIndex0\n && (typeof(allParams.index) !== 'undefined')\n && allParams.index === 0) {\n delete allParams.index;\n delete allParams.page;\n }\n\n const params = urlTrackedParams.reduce((validParams, paramName) => {\n if (paramName in allParams) {\n validParams[paramName] = allParams[paramName];\n }\n return validParams;\n }, {});\n\n const newFragment = this.fragmentFromParams(params, urlMode);\n const currFragment = this.urlReadFragment();\n const currQueryString = this.getLocationSearch();\n const newQueryString = this.queryStringFromParams(params, currQueryString, urlMode);\n if (currFragment === newFragment && currQueryString === newQueryString) {\n return;\n }\n\n if (urlMode === 'history') {\n if (window.history && window.history.replaceState) {\n const baseWithoutSlash = this.options.urlHistoryBasePath.replace(/\\/+$/, '');\n const newFragmentWithSlash = newFragment === '' ? '' : `/${newFragment}`;\n\n const newUrlPath = `${baseWithoutSlash}${newFragmentWithSlash}${newQueryString}`;\n window.history.replaceState({}, null, newUrlPath);\n this.oldLocationHash = newFragment + newQueryString;\n\n }\n } else {\n const newQueryStringSearch = this.urlParamsFiltersOnlySearch(this.readQueryString());\n window.location.replace('#' + newFragment + newQueryStringSearch);\n this.oldLocationHash = newFragment + newQueryStringSearch;\n\n }\n};\n\n/**\n * @private\n * Filtering query parameters to select only book search param (?q=foo)\n This needs to be updated/URL system modified if future query params are to be added\n * @param {string} url\n * @return {string}\n * */\nBookReader.prototype.urlParamsFiltersOnlySearch = function(url) {\n const params = new URLSearchParams(url);\n return params.has('q') ? `?${new URLSearchParams({ q: params.get('q') })}` : '';\n};\n\n\n/**\n * Will read either the hash or URL and return the bookreader fragment\n * @return {string}\n */\nBookReader.prototype.urlReadFragment = function() {\n const { urlMode, urlHistoryBasePath } = this.options;\n if (urlMode === 'history') {\n return window.location.pathname.substr(urlHistoryBasePath.length);\n } else {\n return window.location.hash.substr(1);\n }\n};\n\n/**\n * Will read the hash return the bookreader fragment\n * @return {string}\n */\nBookReader.prototype.urlReadHashFragment = function() {\n return window.location.hash.substr(1);\n};\n"],"names":["super_","extend","BookReader","defaultOptions","enableUrlPlugin","bookId","defaults","updateWindowTitle","urlMode","urlHistoryBasePath","urlTrackedParams","urlTrackIndex0","prototype","setup","options","call","this","locationPollId","oldLocationHash","oldUserHash","init","bind","eventNames","PostInit","document","title","shortTitle","urlStartLocationPolling","fragmentChange","urlUpdateFragment","maximumCharacters","bookTitle","length","substr","urlReadFragment","clearInterval","locationPollID","setInterval","newFragment","params","paramsFromFragment","updateParams","updateFromParams","trigger","stop","animating","autoStop","animationFinishedCallback","allParams","paramsFromCurrent","index","page","reduce","validParams","paramName","fragmentFromParams","currFragment","currQueryString","getLocationSearch","newQueryString","queryStringFromParams","window","history","replaceState","baseWithoutSlash","replace","newFragmentWithSlash","newUrlPath","newQueryStringSearch","urlParamsFiltersOnlySearch","readQueryString","location","url","URLSearchParams","has","q","get","pathname","hash","urlReadHashFragment"],"sourceRoot":""}
1
+ {"version":3,"file":"plugins/plugin.url.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/plugins/plugin.url.js"],"sourcesContent":["/* global BookReader */\n/**\n * Plugin for URL management in BookReader\n * Note read more about the url \"fragment\" here:\n * https://openlibrary.org/dev/docs/bookurls\n */\n\njQuery.extend(BookReader.defaultOptions, {\n enableUrlPlugin: true,\n bookId: '',\n /** @type {string} Defaults can be a urlFragment string */\n defaults: null,\n updateWindowTitle: false,\n\n /** @type {'history' | 'hash'} */\n urlMode: 'hash',\n\n /**\n * When using 'history' mode, this part of the URL is kept constant\n * @example /details/plato/\n */\n urlHistoryBasePath: '/',\n\n /** Only these params will be reflected onto the URL */\n urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight', 'view'],\n\n /** If true, don't update the URL when `page == n0 (eg \"/page/n0\")` */\n urlTrackIndex0: false,\n});\n\n/** @override */\nBookReader.prototype.setup = (function(super_) {\n return function(options) {\n super_.call(this, options);\n\n this.bookId = options.bookId;\n this.defaults = options.defaults;\n\n this.locationPollId = null;\n this.oldLocationHash = null;\n this.oldUserHash = null;\n };\n})(BookReader.prototype.setup);\n\n/** @override */\nBookReader.prototype.init = (function(super_) {\n return function() {\n\n if (this.options.enableUrlPlugin) {\n this.bind(BookReader.eventNames.PostInit, () => {\n const { updateWindowTitle, urlMode } = this.options;\n if (updateWindowTitle) {\n document.title = this.shortTitle(50);\n }\n if (urlMode === 'hash') {\n this.urlStartLocationPolling();\n }\n });\n\n this.bind(BookReader.eventNames.fragmentChange,\n this.urlUpdateFragment.bind(this)\n );\n }\n super_.call(this);\n };\n})(BookReader.prototype.init);\n\n/**\n * Returns a shortened version of the title with the maximum number of characters\n * @param {number} maximumCharacters\n * @return {string}\n */\nBookReader.prototype.shortTitle = function(maximumCharacters) {\n if (this.bookTitle.length < maximumCharacters) {\n return this.bookTitle;\n }\n\n const title = `${this.bookTitle.substr(0, maximumCharacters - 3)}...`;\n return title;\n};\n\n/**\n * Starts polling of window.location to see hash fragment changes\n */\nBookReader.prototype.urlStartLocationPolling = function() {\n this.oldLocationHash = this.urlReadFragment();\n\n if (this.locationPollId) {\n clearInterval(this.locationPollID);\n this.locationPollId = null;\n }\n\n const updateHash = () => {\n const newFragment = this.urlReadFragment();\n const hasFragmentChange = (newFragment != this.oldLocationHash) && (newFragment != this.oldUserHash);\n\n if (!hasFragmentChange) { return; }\n\n const params = this.paramsFromFragment(newFragment);\n\n const updateParams = () => this.updateFromParams(params);\n\n this.trigger(BookReader.eventNames.stop);\n if (this.animating) {\n // Queue change if animating\n if (this.autoStop) this.autoStop();\n this.animationFinishedCallback = updateParams;\n } else {\n // update immediately\n updateParams();\n }\n this.oldUserHash = newFragment;\n };\n\n this.locationPollId = setInterval(updateHash, 500);\n};\n\n/**\n * Update URL from the current parameters.\n * Call this instead of manually using window.location.replace\n */\nBookReader.prototype.urlUpdateFragment = function() {\n const allParams = this.paramsFromCurrent();\n const { urlMode, urlTrackIndex0, urlTrackedParams } = this.options;\n\n if (!urlTrackIndex0\n && (typeof(allParams.index) !== 'undefined')\n && allParams.index === 0) {\n delete allParams.index;\n delete allParams.page;\n }\n\n const params = urlTrackedParams.reduce((validParams, paramName) => {\n if (paramName in allParams) {\n validParams[paramName] = allParams[paramName];\n }\n return validParams;\n }, {});\n\n const newFragment = this.fragmentFromParams(params, urlMode);\n const currFragment = this.urlReadFragment();\n const currQueryString = this.getLocationSearch();\n const newQueryString = this.queryStringFromParams(params, currQueryString, urlMode);\n if (currFragment === newFragment && currQueryString === newQueryString) {\n return;\n }\n\n if (urlMode === 'history') {\n if (window.history && window.history.replaceState) {\n const baseWithoutSlash = this.options.urlHistoryBasePath.replace(/\\/+$/, '');\n const newFragmentWithSlash = newFragment === '' ? '' : `/${newFragment}`;\n\n const newUrlPath = `${baseWithoutSlash}${newFragmentWithSlash}${newQueryString}`;\n window.history.replaceState({}, null, newUrlPath);\n this.oldLocationHash = newFragment + newQueryString;\n\n }\n } else {\n const newQueryStringSearch = this.urlParamsFiltersOnlySearch(this.readQueryString());\n window.location.replace('#' + newFragment + newQueryStringSearch);\n this.oldLocationHash = newFragment + newQueryStringSearch;\n\n }\n};\n\n/**\n * @private\n * Filtering query parameters to select only book search param (?q=foo)\n This needs to be updated/URL system modified if future query params are to be added\n * @param {string} url\n * @return {string}\n * */\nBookReader.prototype.urlParamsFiltersOnlySearch = function(url) {\n const params = new URLSearchParams(url);\n return params.has('q') ? `?${new URLSearchParams({ q: params.get('q') })}` : '';\n};\n\n\n/**\n * Will read either the hash or URL and return the bookreader fragment\n * @return {string}\n */\nBookReader.prototype.urlReadFragment = function() {\n const { urlMode, urlHistoryBasePath } = this.options;\n if (urlMode === 'history') {\n return window.location.pathname.substr(urlHistoryBasePath.length);\n } else {\n return window.location.hash.substr(1);\n }\n};\n\n/**\n * Will read the hash return the bookreader fragment\n * @return {string}\n */\nBookReader.prototype.urlReadHashFragment = function() {\n return window.location.hash.substr(1);\n};\n"],"names":["super_","extend","BookReader","defaultOptions","enableUrlPlugin","bookId","defaults","updateWindowTitle","urlMode","urlHistoryBasePath","urlTrackedParams","urlTrackIndex0","prototype","setup","options","call","this","locationPollId","oldLocationHash","oldUserHash","init","bind","eventNames","PostInit","document","title","shortTitle","urlStartLocationPolling","fragmentChange","urlUpdateFragment","maximumCharacters","bookTitle","length","substr","urlReadFragment","clearInterval","locationPollID","setInterval","newFragment","params","paramsFromFragment","updateParams","updateFromParams","trigger","stop","animating","autoStop","animationFinishedCallback","allParams","paramsFromCurrent","index","page","reduce","validParams","paramName","fragmentFromParams","currFragment","currQueryString","getLocationSearch","newQueryString","queryStringFromParams","window","history","replaceState","baseWithoutSlash","replace","newFragmentWithSlash","newUrlPath","newQueryStringSearch","urlParamsFiltersOnlySearch","readQueryString","location","url","URLSearchParams","has","q","get","pathname","hash","urlReadHashFragment"],"sourceRoot":""}
package/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 5.0.0-24
2
+ Fix: book-nav side panel zoom out @mc2
3
+ Dev: refactor zoom code @mc2
4
+
5
+ # 5.0.0-23
6
+ Fix: Darken scrollbars in Safari @pezvi
7
+ Fix: Bookmarks service calls when reader is logged in @mc2
8
+ Dev: Move jest tests into separate directory @cdrini
9
+
10
+ # 5.0.0-22
11
+ - Dev: remove deprecated embed nav view, use standard default @iisa
12
+
13
+ # 5.0.0-21
14
+ - Dev: Toggle view=theater in fullscreen @mc2
15
+
1
16
  # 5.0.0-20
2
17
  - Feature: Add voice selection dropdown to ReadAloud! @mekarpeles
3
18
  - Dev: Make jest support root-level imports with "@" @cdrini
package/index.html CHANGED
@@ -18,12 +18,15 @@
18
18
  <li><a href="BookReaderDemo/demo-preview-pages.html">Preview Pages</a></li>
19
19
  <li><a href="BookReaderDemo/demo-embed.html">Embed</a></li>
20
20
  <li><a href="BookReaderDemo/demo-multiple.html">Multiple on same page</a></li>
21
+ <!-- plugin.search.js -->
21
22
  <li><a href="BookReaderDemo/demo-internetarchive.html?ocaid=theworksofplato01platiala">From Internet Archive</a></li>
23
+ <!-- plugin.search.js -->
22
24
  <li><a href="BookReaderDemo/demo-internetarchive.html?ocaid=adventuresofoli00dick">From Internet Archive - a book with CHAPTERS</a></li>
23
25
  <li><a href="BookReaderDemo/demo-iiif.html">IIIF</a></li>
24
26
  <li><a href="BookReaderDemo/demo-autoplay.html">Autoplay (kiosk mode)</a></li>
25
27
  <li><a href="BookReaderDemo/demo-plugin-menu-toggle.html">Plugin: Full screen menu toggle</a></li>
26
28
  <li><a href="BookReaderDemo/immersion-mode.html">Start in immersion (fullscreen) mode</a></li>
29
+ <!-- plugin.search.js -->
27
30
  <li><a href="BookReaderDemo/immersion-1up.html">Start in immersion mode on 1up default item</a></li>
28
31
  <li><a href="BookReaderDemo/viewmode-cycle.html">Replace view mode buttons with view mode cycler</a></li>
29
32
  </ul>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@internetarchive/bookreader",
3
- "version": "5.0.0-20",
3
+ "version": "5.0.0-24",
4
4
  "description": "The Internet Archive BookReader.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -94,11 +94,7 @@
94
94
  ],
95
95
  "roots": [
96
96
  "<rootDir>/src/",
97
- "<rootDir>/tests/"
98
- ],
99
- "testPathIgnorePatterns": [
100
- "<rootDir>/tests/e2e/",
101
- "<rootDir>/tests/karma/"
97
+ "<rootDir>/tests/jest/"
102
98
  ],
103
99
  "coverageDirectory": "<rootDir>/coverage-jest"
104
100
  },
@@ -408,7 +408,7 @@ export class BookNavigator extends LitElement {
408
408
 
409
409
  get itemImage() {
410
410
  const url = `https://${this.baseHost}/services/img/${this.book.metadata.identifier}`;
411
- return html`<img src="${url}" alt="cover image for ${this.book.metadata.identifier}">`;
411
+ return html`<img class="cover-img" src="${url}" alt="cover image for ${this.book.metadata.identifier}">`;
412
412
  }
413
413
 
414
414
  render() {
@@ -464,6 +464,10 @@ export class BookNavigator extends LitElement {
464
464
  transform: rotate(-360deg);
465
465
  }
466
466
  }
467
+
468
+ .cover-img {
469
+ max-height: 300px;
470
+ }
467
471
  `;
468
472
  }
469
473
  }
@@ -15,6 +15,7 @@ export default class BookmarksProvider {
15
15
  this.component = document.createElement('ia-bookmarks');
16
16
  this.component.bookreader = bookreader;
17
17
  this.component.options = boundOptions;
18
+ this.component.displayMode = this.component.options.displayMode;
18
19
 
19
20
  this.bindEvents();
20
21
 
@@ -121,6 +121,9 @@ class IABookmarks extends LitElement {
121
121
 
122
122
  setup() {
123
123
  this.api.identifier = this.bookreader.bookId;
124
+ if (this.displayMode === 'login') {
125
+ return;
126
+ }
124
127
  this.fetchBookmarks()
125
128
  .then(() => this.initializeBookmarks())
126
129
  .catch((err) => this.displayMode = 'login');
@@ -60,7 +60,7 @@ export default class {
60
60
  }
61
61
 
62
62
  onZoomOut() {
63
- this.bookreader.zoom();
63
+ this.bookreader.zoom(-1);
64
64
  }
65
65
 
66
66
  onAdjustmentChange(event) {
@@ -79,8 +79,16 @@ export class Mode1Up {
79
79
  * @param {'in' | 'out'} direction
80
80
  */
81
81
  zoom(direction) {
82
- if (direction == 'in') this.mode1UpLit.zoomIn();
83
- else this.mode1UpLit.zoomOut();
82
+ switch (direction) {
83
+ case 'in':
84
+ this.mode1UpLit.zoomIn();
85
+ break;
86
+ case 'out':
87
+ this.mode1UpLit.zoomOut();
88
+ break;
89
+ default:
90
+ console.error(`Unsupported direction: ${direction}`);
91
+ }
84
92
  }
85
93
 
86
94
  /**
@@ -235,20 +235,27 @@ export class ModeThumb {
235
235
  }
236
236
 
237
237
  /**
238
- * @param {1 | -1} direction
238
+ * @param {'in' | 'out'} direction
239
239
  */
240
240
  zoom(direction) {
241
241
  const oldColumns = this.br.thumbColumns;
242
242
  switch (direction) {
243
- case -1:
244
- this.br.thumbColumns += 1;
245
- break;
246
- case 1:
243
+ case 'in':
247
244
  this.br.thumbColumns -= 1;
248
245
  break;
246
+ case 'out':
247
+ this.br.thumbColumns += 1;
248
+ break;
249
+ default:
250
+ console.error(`Unsupported direction: ${direction}`);
249
251
  }
250
252
 
251
- this.br.thumbColumns = clamp(this.br.thumbColumns, 2, 8);
253
+ // Limit zoom in/out columns
254
+ this.br.thumbColumns = clamp(
255
+ this.br.thumbColumns,
256
+ this.br.options.thumbMinZoomColumns,
257
+ this.br.options.thumbMaxZoomColumns
258
+ );
252
259
 
253
260
  if (this.br.thumbColumns != oldColumns) {
254
261
  this.br.displayedRows = []; /* force a gallery redraw */
@@ -240,35 +240,6 @@ export class Navbar {
240
240
  return this.$nav;
241
241
  }
242
242
 
243
- /**
244
- * Initialize the navigation bar when embedded
245
- */
246
- initEmbed() {
247
- const { br } = this;
248
- // IA-specific
249
- const thisLink = (window.location + '')
250
- .replace('?ui=embed','')
251
- .replace('/stream/', '/details/')
252
- .replace('#', '/');
253
- const logoHtml = br.showLogo ? `<a class="logo" href="${br.logoURL}" target="_blank"></a>` : '';
254
-
255
- br.refs.$BRfooter = this.$root = $('<div class="BRfooter"></div>');
256
- br.refs.$BRnav = this.$nav = $(
257
- `<div class="BRnav BRnavEmbed">
258
- ${logoHtml}
259
- <span class="BRembedreturn">
260
- <a href="${thisLink}" target="_blank">${br.bookTitle}</a>
261
- </span>
262
- <span class="BRtoolbarbuttons">
263
- <button class="BRicon book_left"></button>
264
- <button class="BRicon book_right"></button>
265
- <button class="BRicon full"></button>
266
- </span>
267
- </div>`);
268
- this.$root.append(this.$nav);
269
- br.refs.$br.append(this.$root);
270
- }
271
-
272
243
  /**
273
244
  * Returns the textual representation of the current page for the navbar
274
245
  * @param {number} index
@@ -25,6 +25,10 @@ export const DEFAULT_OPTIONS = {
25
25
  thumbMaxLoading: 4,
26
26
  /** spacing between thumbnails */
27
27
  thumbPadding: 10,
28
+ /** min zoom in columns */
29
+ thumbMinZoomColumns: 2,
30
+ /** max zoom out columns */
31
+ thumbMaxZoomColumns: 8,
28
32
 
29
33
  /** @type {number | 'fast' | 'slow'} speed for flip animation */
30
34
  flipSpeed: 'fast',
package/src/BookReader.js CHANGED
@@ -531,15 +531,12 @@ BookReader.prototype.init = function() {
531
531
  // Explicitly ensure this.mode exists for initNavbar() below
532
532
  this.mode = params.mode;
533
533
 
534
- if (this.ui == "embed" && this.options.showNavbar) {
535
- this.initEmbedNavbar();
536
- } else {
537
- if (this.options.showToolbar) {
538
- this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
539
- }
540
- if (this.options.showNavbar) {
541
- this.initNavbar();
542
- }
534
+ // Display Navigation
535
+ if (this.options.showToolbar) {
536
+ this.initToolbar(this.mode, this.ui); // Build inside of toolbar div
537
+ }
538
+ if (this.options.showNavbar) { // default navigation
539
+ this.initNavbar();
543
540
  }
544
541
 
545
542
  // Switch navbar controls on mobile/desktop
@@ -832,29 +829,11 @@ BookReader.prototype.drawLeafsThrottled = utils.throttle(
832
829
  * @param {number} direction Pass 1 to zoom in, anything else to zoom out
833
830
  */
834
831
  BookReader.prototype.zoom = function(direction) {
835
- switch (this.mode) {
836
- case this.constMode1up:
837
- if (direction == 1) {
838
- // XXX other cases
839
- this.zoom1up('in');
840
- } else {
841
- this.zoom1up('out');
842
- }
843
- break;
844
- case this.constMode2up:
845
- if (direction == 1) {
846
- // XXX other cases
847
- this.zoom2up('in');
848
- } else {
849
- this.zoom2up('out');
850
- }
851
- break;
852
- case this.constModeThumb:
853
- // XXX update zoomThumb for named directions
854
- this.zoomThumb(direction);
855
- break;
832
+ if (direction == 1) {
833
+ this.activeMode.zoom('in');
834
+ } else {
835
+ this.activeMode.zoom('out');
856
836
  }
857
-
858
837
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
859
838
  return;
860
839
  };
@@ -1179,6 +1158,8 @@ BookReader.prototype.enterFullscreen = async function(bindKeyboardControls = tru
1179
1158
  this.animating = false;
1180
1159
 
1181
1160
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1161
+ // Add "?view=theater"
1162
+ this.trigger(BookReader.eventNames.fragmentChange);
1182
1163
  this.trigger(BookReader.eventNames.fullscreenToggled);
1183
1164
  };
1184
1165
 
@@ -1215,6 +1196,8 @@ BookReader.prototype.exitFullScreen = async function () {
1215
1196
  this.animating = false;
1216
1197
 
1217
1198
  this.textSelectionPlugin?.stopPageFlip(this.refs.$brContainer);
1199
+ // Remove "?view=theater"
1200
+ this.trigger(BookReader.eventNames.fragmentChange);
1218
1201
  this.trigger(BookReader.eventNames.fullscreenToggled);
1219
1202
  };
1220
1203
 
@@ -1579,9 +1562,6 @@ BookReader.prototype.updateViewModeButton = Navbar.prototype.updateViewModeButto
1579
1562
  exposeOverrideableMethod(Navbar, '_components.navbar', 'updateViewModeButton');
1580
1563
  BookReader.prototype.getNavPageNumString = Navbar.prototype.getNavPageNumString;
1581
1564
  exposeOverrideableMethod(Navbar, '_components.navbar', 'getNavPageNumString');
1582
- /** @deprecated */
1583
- BookReader.prototype.initEmbedNavbar = Navbar.prototype.initEmbed;
1584
- exposeOverrideableMethod(Navbar, '_components.navbar', 'initEmbed', 'initEmbedNavbar');
1585
1565
  /** @deprecated unused */
1586
1566
  BookReader.prototype.getNavPageNumHtml = getNavPageNumHtml;
1587
1567
  /** @deprecated unused outside this file */
@@ -2373,6 +2353,7 @@ BookReader.prototype.getFooterHeight = function() {
2373
2353
  BookReader.prototype.paramsFromCurrent = function() {
2374
2354
  var params = {};
2375
2355
 
2356
+ // Path params
2376
2357
  var index = this.currentIndex();
2377
2358
  var pageNum = this._models.book.getPageNum(index);
2378
2359
  if ((pageNum === 0) || pageNum) {
@@ -2382,10 +2363,17 @@ BookReader.prototype.paramsFromCurrent = function() {
2382
2363
  params.index = index;
2383
2364
  params.mode = this.mode;
2384
2365
 
2366
+ // Unused params
2385
2367
  // $$$ highlight
2386
2368
  // $$$ region
2387
2369
 
2388
- // search
2370
+ // Querystring params
2371
+ // View
2372
+ const fullscreenView = 'theater';
2373
+ if (this.isFullscreenActive) {
2374
+ params.view = fullscreenView;
2375
+ }
2376
+ // Search
2389
2377
  if (this.enableSearch) {
2390
2378
  params.search = this.searchTerm;
2391
2379
  }
@@ -2513,6 +2501,9 @@ BookReader.prototype.fragmentFromParams = function(params, urlMode = 'hash') {
2513
2501
  /**
2514
2502
  * Create, update querystring from the params object
2515
2503
  *
2504
+ * Handles:
2505
+ * view=
2506
+ * q=
2516
2507
  * @param {Object} params
2517
2508
  * @param {string} currQueryString
2518
2509
  * @param {string} [urlMode]
@@ -2524,6 +2515,15 @@ BookReader.prototype.queryStringFromParams = function(
2524
2515
  urlMode = 'hash'
2525
2516
  ) {
2526
2517
  const newParams = new URLSearchParams(currQueryString);
2518
+
2519
+ if (params.view) {
2520
+ // Set ?view=theater when fullscreen
2521
+ newParams.set('view', params.view);
2522
+ } else {
2523
+ // Remove
2524
+ newParams.delete('view');
2525
+ }
2526
+
2527
2527
  if (params.search && urlMode === 'history') {
2528
2528
  newParams.set('q', params.search);
2529
2529
  }
@@ -267,6 +267,7 @@ export default class ItemNavigator extends LitElement {
267
267
  #frame {
268
268
  position: relative;
269
269
  overflow: hidden;
270
+ color-scheme: dark;
270
271
  }
271
272
 
272
273
  #frame.fullscreen,
@@ -127,10 +127,6 @@
127
127
  // Default
128
128
  @include brNavDark;
129
129
 
130
- &.BRnavEmbed {
131
- @include brNavLight;
132
- }
133
-
134
130
  /* Full mobile styles */
135
131
  @media (max-width: $brBreakPointMobile) {
136
132
  .BRbodyMobileNavEnabled &,
@@ -223,25 +219,6 @@
223
219
  flex-direction: row;
224
220
  border-top: 1px solid $controlsBorder;
225
221
 
226
- &.BRnavEmbed {
227
- padding-top: 0;
228
- height: auto;
229
- align-items: center;
230
-
231
- .BRembedreturn {
232
- flex: 1 auto;
233
- overflow-x: hidden;
234
- }
235
- .logo {
236
- display: inline-block;
237
- width: 25px;
238
- height: 25px;
239
- margin: 0 10px;
240
- background: transparent url(images/icon_home.svg) no-repeat center center;
241
- background-size: contain;
242
- }
243
- }
244
-
245
222
  /* Theming */
246
223
 
247
224
  // Default
@@ -22,7 +22,7 @@ jQuery.extend(BookReader.defaultOptions, {
22
22
  urlHistoryBasePath: '/',
23
23
 
24
24
  /** Only these params will be reflected onto the URL */
25
- urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight'],
25
+ urlTrackedParams: ['page', 'search', 'mode', 'region', 'highlight', 'view'],
26
26
 
27
27
  /** If true, don't update the URL when `page == n0 (eg "/page/n0")` */
28
28
  urlTrackIndex0: false,
@@ -86,7 +86,7 @@ describe('BookReader.prototype.enterFullscreen', () => {
86
86
  await br.enterFullscreen();
87
87
  expect(br.switchMode).toHaveBeenCalledTimes(1);
88
88
  expect(br.updateBrClasses).toHaveBeenCalledTimes(0); // book nav's fullscreen manager will set these classes
89
- expect(br.trigger).toHaveBeenCalledTimes(1);
89
+ expect(br.trigger).toHaveBeenCalledTimes(2); // fragmentChange, fullscreenToggled
90
90
  expect(br.resize).toHaveBeenCalledTimes(1);
91
91
  expect(br.jumpToIndex).toHaveBeenCalledTimes(1);
92
92
  });
@@ -107,7 +107,7 @@ describe('BookReader.prototype.exitFullScreen', () => {
107
107
  await br.exitFullScreen();
108
108
  expect(br.switchMode).toHaveBeenCalledTimes(1);
109
109
  expect(br.updateBrClasses).toHaveBeenCalledTimes(1);
110
- expect(br.trigger).toHaveBeenCalledTimes(1);
110
+ expect(br.trigger).toHaveBeenCalledTimes(2); // fragmentChange, fullscreenToggled
111
111
  expect(br.resize).toHaveBeenCalledTimes(1);
112
112
  });
113
113
  });
@@ -0,0 +1,71 @@
1
+
2
+ import sinon from 'sinon';
3
+ import BookReader from '@/src/BookReader.js';
4
+ /** @typedef {import('@/src/BookReader/options.js').BookReaderOptions} BookReaderOptions */
5
+
6
+ beforeAll(() => {
7
+ global.alert = jest.fn();
8
+ });
9
+ afterEach(() => {
10
+ jest.restoreAllMocks();
11
+ sinon.restore();
12
+ });
13
+
14
+ /** @type {BookReaderOptions['data']} */
15
+ const SAMPLE_DATA = [
16
+ [
17
+ { width: 123, height: 123, uri: 'https://archive.org/image0.jpg', pageNum: '1' },
18
+ ],
19
+ [
20
+ { width: 123, height: 123, uri: 'https://archive.org/image1.jpg', pageNum: '2' },
21
+ { width: 123, height: 123, uri: 'https://archive.org/image2.jpg', pageNum: '3' },
22
+ ],
23
+ [
24
+ { width: 123, height: 123, uri: 'https://archive.org/image3.jpg', pageNum: '4' },
25
+ { width: 123, height: 123, uri: 'https://archive.org/image4.jpg', pageNum: '5' },
26
+ ],
27
+ [
28
+ { width: 123, height: 123, uri: 'https://archive.org/image5.jpg', pageNum: '6' },
29
+ ],
30
+ ];
31
+
32
+ describe('zoom', () => {
33
+ const br = new BookReader({ data: SAMPLE_DATA });
34
+ br.init();
35
+
36
+ test('initializes with default columns', () => {
37
+ expect(br.thumbColumns).toBe(br.options.thumbColumns);
38
+ });
39
+
40
+ test('removes column and redraws zooming in', () => {
41
+ const prepare = sinon.spy(br._modes.modeThumb, 'prepare');
42
+ const startColumns = br.thumbColumns;
43
+ br._modes.modeThumb.zoom('in');
44
+ expect(br.thumbColumns).toBe(startColumns - 1);
45
+ expect(prepare.callCount).toBe(1);
46
+ });
47
+
48
+ test('adds column and redraws zooming out', () => {
49
+ const prepare = sinon.spy(br._modes.modeThumb, 'prepare');
50
+ const startColumns = br.thumbColumns;
51
+ br._modes.modeThumb.zoom('out');
52
+ expect(br.thumbColumns).toBe(startColumns + 1);
53
+ expect(prepare.callCount).toBe(1);
54
+ });
55
+
56
+ test('keeps columns and no redraw at zooming in limit', () => {
57
+ const prepare = sinon.spy(br._modes.modeThumb, 'prepare');
58
+ br.thumbColumns = br.options.thumbMinZoomColumns;
59
+ br._modes.modeThumb.zoom('in');
60
+ expect(br.thumbColumns).toBe(br.options.thumbMinZoomColumns);
61
+ expect(prepare.callCount).toBe(0);
62
+ });
63
+
64
+ test('keeps columns and no redraw at zooming out limit', () => {
65
+ const prepare = sinon.spy(br._modes.modeThumb, 'prepare');
66
+ br.thumbColumns = br.options.thumbMaxZoomColumns;
67
+ br._modes.modeThumb.zoom('out');
68
+ expect(br.thumbColumns).toBe(br.options.thumbMaxZoomColumns);
69
+ expect(prepare.callCount).toBe(0);
70
+ });
71
+ });
@@ -36,4 +36,12 @@ describe('BookReader options', () => {
36
36
  expect(br.options.autoResize).toBe(true);
37
37
  });
38
38
  });
39
+
40
+ describe('`showNavbar`', () => {
41
+ it('is on by default', () => {
42
+ const br = new BookReader();
43
+ br.init();
44
+ expect(br.options.showNavbar).toBe(true);
45
+ });
46
+ });
39
47
  });
@@ -192,6 +192,22 @@ test('_getPageURISrcset with the most elements in srcset', () => {
192
192
  expect(br._getPageURISrcset(5, 35, undefined)).toBe("correctURL.png&scale=16 2x, correctURL.png&scale=8 4x, correctURL.png&scale=4 8x, correctURL.png&scale=2 16x, correctURL.png&scale=1 32x");
193
193
  });
194
194
 
195
+ describe('Navigation Bars', () => {
196
+ test('Standard navigation is being used by default', () => {
197
+ br.initNavbar = jest.fn();
198
+ br.options.ui = '';
199
+ br.init();
200
+ expect(br.initNavbar).toHaveBeenCalledTimes(1);
201
+ });
202
+ test('Standard navigation is being used by default - when bookreader is embedded', () => {
203
+ br.initNavbar = jest.fn();
204
+ br.options.ui = 'embed';
205
+ br.init();
206
+ expect(br.initNavbar).toHaveBeenCalledTimes(1);
207
+ expect(br.options.ui).toEqual('embed');
208
+ });
209
+ });
210
+
195
211
  describe('quantizeReduce', () => {
196
212
  const quantizeReduce = BookReader.prototype.quantizeReduce;
197
213
  const SAMPLE_FACTORS = [