@internetarchive/bookreader 5.0.0-24-sortingstate-2 → 5.0.0-25
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/BookReader/BookReader.js +2 -32145
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/bookreader-component-bundle.js +1286 -11256
- package/BookReader/bookreader-component-bundle.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -763
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/package.json +1 -1
- package/src/BookNavigator/volumes/volumes-provider.js +9 -40
- package/src/css/_controls.scss +4 -0
- package/src/plugins/plugin.url.js +2 -215
- package/tests/jest/plugins/plugin.url.test.js +1 -160
- package/.nvmrc +0 -1
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"plugins/plugin.url.js","mappings":"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","sources":["webpack://@internetarchive/bookreader/./src/plugins/plugin.url.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.object.entries.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.object.from-entries.js","webpack://@internetarchive/bookreader/./node_modules/core-js/modules/es.string.match.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(this.bookTitle, 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};\nexport class UrlPlugin {\n constructor(options = {}) {\n this.bookReaderOptions = options;\n\n // the canonical order of elements is important in the path and query string\n this.urlSchema = [\n { name: 'page', position: 'path', default: 'n0' },\n { name: 'mode', position: 'path', default: '2up' },\n { name: 'search', position: 'path', deprecated_for: 'q' },\n { name: 'q', position: 'query_param' },\n { name: 'sort', position: 'query_param' },\n { name: 'view', position: 'query_param' },\n { name: 'admin', position: 'query_param' },\n ];\n\n this.urlState = {};\n this.urlMode = 'hash';\n this.urlHistoryBasePath = '/';\n this.urlLocationPollId = null;\n this.oldLocationHash = null;\n this.oldUserHash = null;\n }\n\n /**\n * Parse JSON object URL state to string format\n * Arrange path names in an order that it is positioned on the urlSchema\n * @param {object} urlSchema\n * @param {string} urlState\n * @returns {string}\n */\n urlStateToUrlString(urlSchema, urlState) {\n const searchParams = new URLSearchParams();\n const pathParams = {};\n\n Object.keys(urlState).forEach(key => {\n let schema = urlSchema.find(schema => schema.name === key);\n if (schema?.deprecated_for) {\n schema = urlSchema.find(schemaKey => schemaKey.name === schema.deprecated_for);\n }\n if (schema?.position == 'path') {\n pathParams[schema?.name] = urlState[key];\n } else {\n searchParams.append(schema?.name || key, urlState[key]);\n }\n });\n\n const strPathParams = urlSchema\n .filter(s => s.position == 'path')\n .map(schema => pathParams[schema.name] ? `${schema.name}/${pathParams[schema.name]}` : '')\n .join('/');\n\n const strStrippedTrailingSlash = `${strPathParams.replace(/\\/$/, '')}`;\n const concatenatedPath = `/${strStrippedTrailingSlash}?${searchParams.toString()}`;\n return searchParams.toString() ? concatenatedPath : `/${strStrippedTrailingSlash}`;\n }\n\n /**\n * Parse string URL and add it in the current urlState\n * Example:\n * /page/n7/mode/2up => {page: 'n7', mode: '2up'}\n * /page/n7/mode/2up/search/hello => {page: 'n7', mode: '2up', q: 'hello'}\n * @param {array} urlSchema\n * @param {string} urlString\n * @returns {object}\n */\n urlStringToUrlState(urlSchema, urlString) {\n const urlState = {};\n\n // Fetch searchParams from given {urlString}\n // Note: whole URL path is needed for URLSearchParams\n const urlPath = new URL(urlString, 'http://example.com');\n const urlSearchParamsObj = Object.fromEntries(urlPath.searchParams.entries());\n const urlStrSplitSlashObj = Object.fromEntries(urlPath.pathname\n .match(/[^\\\\/]+\\/[^\\\\/]+/g)\n .map(x => x.split('/'))\n );\n const doesKeyExists = (_object, _key) => {\n return Object.keys(_object).some(value => value == _key);\n };\n\n // Add path objects to urlState\n urlSchema\n .filter(schema => schema.position == 'path')\n .forEach(schema => {\n if (!urlStrSplitSlashObj[schema.name] && schema.default) {\n return urlState[schema.name] = schema.default;\n }\n const hasPropertyKey = doesKeyExists(urlStrSplitSlashObj, schema.name);\n const hasDeprecatedKey = doesKeyExists(schema, 'deprecated_for') && hasPropertyKey;\n\n if (hasDeprecatedKey) {\n urlState[schema.deprecated_for] = urlStrSplitSlashObj[schema.name];\n return;\n }\n\n if (hasPropertyKey) {\n urlState[schema.name] = urlStrSplitSlashObj[schema.name];\n return;\n }\n });\n\n // Add searchParams to urlState\n // Check if Object value is a Boolean and convert value to Boolean\n // Otherwise, return Object value\n const isBooleanValue = value => value === 'true' || (value === 'false' ? false : value);\n Object.entries(urlSearchParamsObj).forEach(([key, value]) => {\n urlState[key] = isBooleanValue(value);\n });\n\n return urlState;\n }\n\n /**\n * Add or update key-value to the urlState\n * @param {string} key\n * @param {string} val\n */\n setUrlParam(key, value) {\n this.urlState[key] = value;\n\n this.pushToAddressBar();\n }\n\n /**\n * Delete key-value to the urlState\n * @param {string} key\n */\n removeUrlParam(key) {\n delete this.urlState[key];\n\n this.pushToAddressBar();\n }\n\n /**\n * Get key-value from the urlState\n * @param {string} key\n * @return {string}\n */\n getUrlParam(key) {\n return this.urlState[key];\n }\n\n /**\n * Push URL params to addressbar\n */\n pushToAddressBar() {\n const urlStrPath = this.urlStateToUrlString(this.urlSchema, this.urlState);\n if (this.urlMode == 'history') {\n if (window.history && window.history.replaceState) {\n const newUrlPath = `${this.urlHistoryBasePath}${urlStrPath}`;\n window.history.replaceState({}, null, newUrlPath);\n }\n } else {\n window.location.replace('#' + urlStrPath);\n }\n this.oldLocationHash = urlStrPath;\n }\n\n /**\n * Get the url and check if it has changed\n * If it was changeed, update the urlState\n */\n listenForHashChanges() {\n this.oldLocationHash = window.location.hash.substr(1);\n if (this.urlLocationPollId) {\n clearInterval(this.urlLocationPollId);\n this.urlLocationPollId = null;\n }\n\n // check if the URL changes\n const updateHash = () => {\n const newFragment = window.location.hash.substr(1);\n const hasFragmentChange = newFragment != this.oldLocationHash;\n\n if (!hasFragmentChange) { return; }\n\n this.urlState = this.urlStringToUrlState(newFragment);\n };\n this.urlLocationPollId = setInterval(updateHash, 500);\n }\n\n /**\n * Will read either the hash or URL and return the bookreader fragment\n */\n pullFromAddressBar (location = window.location) {\n const path = this.urlMode === 'history'\n ? (location.pathname.substr(this.urlHistoryBasePath.length) + location.search)\n : location.hash.substr(1);\n this.urlState = this.urlStringToUrlState(this.urlSchema, path);\n }\n}\n\nexport class BookreaderUrlPlugin extends BookReader {\n\n init() {\n if (this.options.enableUrlPlugin) {\n this.urlPlugin = new UrlPlugin(this.options);\n this.bind(BookReader.eventNames.PostInit, () => {\n const { urlMode } = this.options;\n\n if (urlMode === 'hash') {\n this.urlPlugin.listenForHashChanges();\n }\n });\n }\n\n super.init();\n }\n\n}\n\nwindow.BookReader = BookreaderUrlPlugin;\nexport default BookreaderUrlPlugin;\n","var $ = require('../internals/export');\nvar $entries = require('../internals/object-to-array').entries;\n\n// `Object.entries` method\n// https://tc39.es/ecma262/#sec-object.entries\n$({ target: 'Object', stat: true }, {\n entries: function entries(O) {\n return $entries(O);\n }\n});\n","var $ = require('../internals/export');\nvar iterate = require('../internals/iterate');\nvar createProperty = require('../internals/create-property');\n\n// `Object.fromEntries` method\n// https://github.com/tc39/proposal-object-from-entries\n$({ target: 'Object', stat: true }, {\n fromEntries: function fromEntries(iterable) {\n var obj = {};\n iterate(iterable, function (k, v) {\n createProperty(obj, k, v);\n }, { AS_ENTRIES: true });\n return obj;\n }\n});\n","'use strict';\nvar fixRegExpWellKnownSymbolLogic = require('../internals/fix-regexp-well-known-symbol-logic');\nvar anObject = require('../internals/an-object');\nvar toLength = require('../internals/to-length');\nvar toString = require('../internals/to-string');\nvar requireObjectCoercible = require('../internals/require-object-coercible');\nvar advanceStringIndex = require('../internals/advance-string-index');\nvar regExpExec = require('../internals/regexp-exec-abstract');\n\n// @@match logic\nfixRegExpWellKnownSymbolLogic('match', function (MATCH, nativeMatch, maybeCallNative) {\n return [\n // `String.prototype.match` method\n // https://tc39.es/ecma262/#sec-string.prototype.match\n function match(regexp) {\n var O = requireObjectCoercible(this);\n var matcher = regexp == undefined ? undefined : regexp[MATCH];\n return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](toString(O));\n },\n // `RegExp.prototype[@@match]` method\n // https://tc39.es/ecma262/#sec-regexp.prototype-@@match\n function (string) {\n var rx = anObject(this);\n var S = toString(string);\n var res = maybeCallNative(nativeMatch, rx, S);\n\n if (res.done) return res.value;\n\n if (!rx.global) return regExpExec(rx, S);\n\n var fullUnicode = rx.unicode;\n rx.lastIndex = 0;\n var A = [];\n var n = 0;\n var result;\n while ((result = regExpExec(rx, S)) !== null) {\n var matchStr = toString(result[0]);\n A[n] = matchStr;\n if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);\n n++;\n }\n return n === 0 ? null : A;\n }\n ];\n});\n"],"names":["jQuery","extend","BookReader","defaultOptions","enableUrlPlugin","bookId","defaults","updateWindowTitle","urlMode","urlHistoryBasePath","urlTrackedParams","urlTrackIndex0","prototype","setup","super_","options","call","locationPollId","oldLocationHash","oldUserHash","init","bind","eventNames","PostInit","document","title","shortTitle","bookTitle","urlStartLocationPolling","fragmentChange","urlUpdateFragment","maximumCharacters","length","substr","urlReadFragment","clearInterval","updateHash","newFragment","hasFragmentChange","params","paramsFromFragment","updateParams","updateFromParams","trigger","stop","animating","autoStop","animationFinishedCallback","setInterval","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","UrlPlugin","bookReaderOptions","urlSchema","name","position","default","deprecated_for","urlState","urlLocationPollId","searchParams","pathParams","Object","keys","forEach","key","schema","find","schemaKey","append","strPathParams","filter","s","map","join","strStrippedTrailingSlash","concatenatedPath","toString","urlString","urlPath","URL","urlSearchParamsObj","fromEntries","entries","urlStrSplitSlashObj","match","x","split","doesKeyExists","_object","_key","some","value","hasPropertyKey","hasDeprecatedKey","isBooleanValue","pushToAddressBar","urlStrPath","urlStateToUrlString","urlStringToUrlState","path","search","BookreaderUrlPlugin","urlPlugin","listenForHashChanges"],"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/package.json
CHANGED
@@ -7,16 +7,8 @@ import volumesIcon from '../assets/icon_volumes.js';
|
|
7
7
|
|
8
8
|
import './volumes.js';
|
9
9
|
|
10
|
-
const sortType = {
|
11
|
-
title_asc: 'title_asc',
|
12
|
-
title_desc: 'title_desc',
|
13
|
-
default: 'default'
|
14
|
-
};
|
15
10
|
export default class VolumesProvider {
|
16
11
|
|
17
|
-
/**
|
18
|
-
* @param {import('../../BookReader').default} bookreader
|
19
|
-
*/
|
20
12
|
constructor(baseHost, bookreader, optionChange) {
|
21
13
|
this.optionChange = optionChange;
|
22
14
|
this.component = document.createElement("viewable-files");
|
@@ -25,9 +17,6 @@ export default class VolumesProvider {
|
|
25
17
|
this.viewableFiles = Object.keys(files).map(item => files[item]);
|
26
18
|
this.volumeCount = Object.keys(files).length;
|
27
19
|
|
28
|
-
/** @type {import('../../BookReader').default} */
|
29
|
-
this.bookreader = bookreader;
|
30
|
-
|
31
20
|
this.component.subPrefix = bookreader.options.subPrefix || "";
|
32
21
|
this.component.hostUrl = baseHost;
|
33
22
|
this.component.viewableFiles = this.viewableFiles;
|
@@ -36,28 +25,20 @@ export default class VolumesProvider {
|
|
36
25
|
this.label = `Viewable files (${this.volumeCount})`;
|
37
26
|
this.icon = html`${volumesIcon}`;
|
38
27
|
|
39
|
-
|
40
|
-
this.
|
41
|
-
const urlSortValue = this.bookreader.urlPlugin.getUrlParam('sort');
|
42
|
-
console.log('urlSortValue: ', urlSortValue);
|
43
|
-
if (urlSortValue === sortType.title_asc || urlSortValue === sortType.title_desc) {
|
44
|
-
this.sortOrderBy = urlSortValue;
|
45
|
-
} else {
|
46
|
-
this.sortOrderBy = sortType.default;
|
47
|
-
}
|
48
|
-
this.sortVolumes(this.sortOrderBy);
|
28
|
+
this.sortOrderBy = "orig_sort";
|
29
|
+
this.sortVolumes("orig_sort");
|
49
30
|
}
|
50
31
|
|
51
32
|
get sortButton() {
|
52
33
|
const sortIcons = {
|
53
|
-
|
34
|
+
orig_sort: html`
|
54
35
|
<button class="sort-by neutral-icon" aria-label="Sort volumes in initial order" @click=${() => this.sortVolumes("title_asc")}>${sortNeutralIcon}</button>
|
55
36
|
`,
|
56
37
|
title_asc: html`
|
57
38
|
<button class="sort-by asc-icon" aria-label="Sort volumes in ascending order" @click=${() => this.sortVolumes("title_desc")}>${sortAscIcon}</button>
|
58
39
|
`,
|
59
40
|
title_desc: html`
|
60
|
-
<button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("
|
41
|
+
<button class="sort-by desc-icon" aria-label="Sort volumes in descending order" @click=${() => this.sortVolumes("orig_sort")}>${sortDescIcon}</button>
|
61
42
|
`,
|
62
43
|
};
|
63
44
|
|
@@ -65,40 +46,28 @@ export default class VolumesProvider {
|
|
65
46
|
}
|
66
47
|
|
67
48
|
/**
|
68
|
-
* @param {'
|
49
|
+
* @param {'orig_sort' | 'title_asc' | 'title_desc'} sortByType
|
69
50
|
*/
|
70
51
|
sortVolumes(sortByType) {
|
71
52
|
let sortedFiles = [];
|
72
53
|
|
73
54
|
const files = this.viewableFiles;
|
74
55
|
sortedFiles = files.sort((a, b) => {
|
75
|
-
if (sortByType ===
|
76
|
-
else if (sortByType ===
|
77
|
-
else return a.
|
56
|
+
if (sortByType === 'orig_sort') return a.orig_sort - b.orig_sort;
|
57
|
+
else if (sortByType === 'title_asc') return a.title.localeCompare(b.title);
|
58
|
+
else return b.title.localeCompare(a.title);
|
78
59
|
});
|
79
60
|
|
80
61
|
this.sortOrderBy = sortByType;
|
81
62
|
this.component.viewableFiles = [...sortedFiles];
|
82
63
|
this.actionButton = this.sortButton;
|
83
|
-
|
84
|
-
if (this.sortOrderBy !== sortType.default) {
|
85
|
-
this.bookreader.urlPlugin.setUrlParam('sort', sortByType);
|
86
|
-
} else {
|
87
|
-
this.bookreader.urlPlugin.removeUrlParam('sort');
|
88
|
-
}
|
89
|
-
|
90
|
-
const urlSchema = this.bookreader.urlPlugin.urlSchema;
|
91
|
-
const urlState = this.bookreader.urlPlugin.urlState;
|
92
|
-
this.bookreader.urlPlugin.urlStateToUrlString(urlSchema, urlState);
|
93
|
-
this.bookreader.urlPlugin.pushToAddressBar();
|
94
|
-
|
95
64
|
this.optionChange(this.bookreader);
|
96
65
|
|
97
66
|
this.multipleFilesClicked(sortByType);
|
98
67
|
}
|
99
68
|
|
100
69
|
/**
|
101
|
-
* @param {'
|
70
|
+
* @param {'orig_sort' | 'title_asc' | 'title_desc'} orderBy
|
102
71
|
*/
|
103
72
|
multipleFilesClicked(orderBy) {
|
104
73
|
if (!window.archive_analytics) {
|
package/src/css/_controls.scss
CHANGED
@@ -50,7 +50,7 @@ BookReader.prototype.init = (function(super_) {
|
|
50
50
|
this.bind(BookReader.eventNames.PostInit, () => {
|
51
51
|
const { updateWindowTitle, urlMode } = this.options;
|
52
52
|
if (updateWindowTitle) {
|
53
|
-
document.title = this.shortTitle(
|
53
|
+
document.title = this.shortTitle(50);
|
54
54
|
}
|
55
55
|
if (urlMode === 'hash') {
|
56
56
|
this.urlStartLocationPolling();
|
@@ -86,7 +86,7 @@ BookReader.prototype.urlStartLocationPolling = function() {
|
|
86
86
|
this.oldLocationHash = this.urlReadFragment();
|
87
87
|
|
88
88
|
if (this.locationPollId) {
|
89
|
-
clearInterval(this.
|
89
|
+
clearInterval(this.locationPollID);
|
90
90
|
this.locationPollId = null;
|
91
91
|
}
|
92
92
|
|
@@ -196,216 +196,3 @@ BookReader.prototype.urlReadFragment = function() {
|
|
196
196
|
BookReader.prototype.urlReadHashFragment = function() {
|
197
197
|
return window.location.hash.substr(1);
|
198
198
|
};
|
199
|
-
export class UrlPlugin {
|
200
|
-
constructor(options = {}) {
|
201
|
-
this.bookReaderOptions = options;
|
202
|
-
|
203
|
-
// the canonical order of elements is important in the path and query string
|
204
|
-
this.urlSchema = [
|
205
|
-
{ name: 'page', position: 'path', default: 'n0' },
|
206
|
-
{ name: 'mode', position: 'path', default: '2up' },
|
207
|
-
{ name: 'search', position: 'path', deprecated_for: 'q' },
|
208
|
-
{ name: 'q', position: 'query_param' },
|
209
|
-
{ name: 'sort', position: 'query_param' },
|
210
|
-
{ name: 'view', position: 'query_param' },
|
211
|
-
{ name: 'admin', position: 'query_param' },
|
212
|
-
];
|
213
|
-
|
214
|
-
this.urlState = {};
|
215
|
-
this.urlMode = 'hash';
|
216
|
-
this.urlHistoryBasePath = '/';
|
217
|
-
this.urlLocationPollId = null;
|
218
|
-
this.oldLocationHash = null;
|
219
|
-
this.oldUserHash = null;
|
220
|
-
}
|
221
|
-
|
222
|
-
/**
|
223
|
-
* Parse JSON object URL state to string format
|
224
|
-
* Arrange path names in an order that it is positioned on the urlSchema
|
225
|
-
* @param {object} urlSchema
|
226
|
-
* @param {string} urlState
|
227
|
-
* @returns {string}
|
228
|
-
*/
|
229
|
-
urlStateToUrlString(urlSchema, urlState) {
|
230
|
-
const searchParams = new URLSearchParams();
|
231
|
-
const pathParams = {};
|
232
|
-
|
233
|
-
Object.keys(urlState).forEach(key => {
|
234
|
-
let schema = urlSchema.find(schema => schema.name === key);
|
235
|
-
if (schema?.deprecated_for) {
|
236
|
-
schema = urlSchema.find(schemaKey => schemaKey.name === schema.deprecated_for);
|
237
|
-
}
|
238
|
-
if (schema?.position == 'path') {
|
239
|
-
pathParams[schema?.name] = urlState[key];
|
240
|
-
} else {
|
241
|
-
searchParams.append(schema?.name || key, urlState[key]);
|
242
|
-
}
|
243
|
-
});
|
244
|
-
|
245
|
-
const strPathParams = urlSchema
|
246
|
-
.filter(s => s.position == 'path')
|
247
|
-
.map(schema => pathParams[schema.name] ? `${schema.name}/${pathParams[schema.name]}` : '')
|
248
|
-
.join('/');
|
249
|
-
|
250
|
-
const strStrippedTrailingSlash = `${strPathParams.replace(/\/$/, '')}`;
|
251
|
-
const concatenatedPath = `/${strStrippedTrailingSlash}?${searchParams.toString()}`;
|
252
|
-
return searchParams.toString() ? concatenatedPath : `/${strStrippedTrailingSlash}`;
|
253
|
-
}
|
254
|
-
|
255
|
-
/**
|
256
|
-
* Parse string URL and add it in the current urlState
|
257
|
-
* Example:
|
258
|
-
* /page/n7/mode/2up => {page: 'n7', mode: '2up'}
|
259
|
-
* /page/n7/mode/2up/search/hello => {page: 'n7', mode: '2up', q: 'hello'}
|
260
|
-
* @param {array} urlSchema
|
261
|
-
* @param {string} urlString
|
262
|
-
* @returns {object}
|
263
|
-
*/
|
264
|
-
urlStringToUrlState(urlSchema, urlString) {
|
265
|
-
const urlState = {};
|
266
|
-
|
267
|
-
// Fetch searchParams from given {urlString}
|
268
|
-
// Note: whole URL path is needed for URLSearchParams
|
269
|
-
const urlPath = new URL(urlString, 'http://example.com');
|
270
|
-
const urlSearchParamsObj = Object.fromEntries(urlPath.searchParams.entries());
|
271
|
-
const urlStrSplitSlashObj = Object.fromEntries(urlPath.pathname
|
272
|
-
.match(/[^\\/]+\/[^\\/]+/g)
|
273
|
-
.map(x => x.split('/'))
|
274
|
-
);
|
275
|
-
const doesKeyExists = (_object, _key) => {
|
276
|
-
return Object.keys(_object).some(value => value == _key);
|
277
|
-
};
|
278
|
-
|
279
|
-
// Add path objects to urlState
|
280
|
-
urlSchema
|
281
|
-
.filter(schema => schema.position == 'path')
|
282
|
-
.forEach(schema => {
|
283
|
-
if (!urlStrSplitSlashObj[schema.name] && schema.default) {
|
284
|
-
return urlState[schema.name] = schema.default;
|
285
|
-
}
|
286
|
-
const hasPropertyKey = doesKeyExists(urlStrSplitSlashObj, schema.name);
|
287
|
-
const hasDeprecatedKey = doesKeyExists(schema, 'deprecated_for') && hasPropertyKey;
|
288
|
-
|
289
|
-
if (hasDeprecatedKey) {
|
290
|
-
urlState[schema.deprecated_for] = urlStrSplitSlashObj[schema.name];
|
291
|
-
return;
|
292
|
-
}
|
293
|
-
|
294
|
-
if (hasPropertyKey) {
|
295
|
-
urlState[schema.name] = urlStrSplitSlashObj[schema.name];
|
296
|
-
return;
|
297
|
-
}
|
298
|
-
});
|
299
|
-
|
300
|
-
// Add searchParams to urlState
|
301
|
-
// Check if Object value is a Boolean and convert value to Boolean
|
302
|
-
// Otherwise, return Object value
|
303
|
-
const isBooleanValue = value => value === 'true' || (value === 'false' ? false : value);
|
304
|
-
Object.entries(urlSearchParamsObj).forEach(([key, value]) => {
|
305
|
-
urlState[key] = isBooleanValue(value);
|
306
|
-
});
|
307
|
-
|
308
|
-
return urlState;
|
309
|
-
}
|
310
|
-
|
311
|
-
/**
|
312
|
-
* Add or update key-value to the urlState
|
313
|
-
* @param {string} key
|
314
|
-
* @param {string} val
|
315
|
-
*/
|
316
|
-
setUrlParam(key, value) {
|
317
|
-
this.urlState[key] = value;
|
318
|
-
|
319
|
-
this.pushToAddressBar();
|
320
|
-
}
|
321
|
-
|
322
|
-
/**
|
323
|
-
* Delete key-value to the urlState
|
324
|
-
* @param {string} key
|
325
|
-
*/
|
326
|
-
removeUrlParam(key) {
|
327
|
-
delete this.urlState[key];
|
328
|
-
|
329
|
-
this.pushToAddressBar();
|
330
|
-
}
|
331
|
-
|
332
|
-
/**
|
333
|
-
* Get key-value from the urlState
|
334
|
-
* @param {string} key
|
335
|
-
* @return {string}
|
336
|
-
*/
|
337
|
-
getUrlParam(key) {
|
338
|
-
return this.urlState[key];
|
339
|
-
}
|
340
|
-
|
341
|
-
/**
|
342
|
-
* Push URL params to addressbar
|
343
|
-
*/
|
344
|
-
pushToAddressBar() {
|
345
|
-
const urlStrPath = this.urlStateToUrlString(this.urlSchema, this.urlState);
|
346
|
-
if (this.urlMode == 'history') {
|
347
|
-
if (window.history && window.history.replaceState) {
|
348
|
-
const newUrlPath = `${this.urlHistoryBasePath}${urlStrPath}`;
|
349
|
-
window.history.replaceState({}, null, newUrlPath);
|
350
|
-
}
|
351
|
-
} else {
|
352
|
-
window.location.replace('#' + urlStrPath);
|
353
|
-
}
|
354
|
-
this.oldLocationHash = urlStrPath;
|
355
|
-
}
|
356
|
-
|
357
|
-
/**
|
358
|
-
* Get the url and check if it has changed
|
359
|
-
* If it was changeed, update the urlState
|
360
|
-
*/
|
361
|
-
listenForHashChanges() {
|
362
|
-
this.oldLocationHash = window.location.hash.substr(1);
|
363
|
-
if (this.urlLocationPollId) {
|
364
|
-
clearInterval(this.urlLocationPollId);
|
365
|
-
this.urlLocationPollId = null;
|
366
|
-
}
|
367
|
-
|
368
|
-
// check if the URL changes
|
369
|
-
const updateHash = () => {
|
370
|
-
const newFragment = window.location.hash.substr(1);
|
371
|
-
const hasFragmentChange = newFragment != this.oldLocationHash;
|
372
|
-
|
373
|
-
if (!hasFragmentChange) { return; }
|
374
|
-
|
375
|
-
this.urlState = this.urlStringToUrlState(newFragment);
|
376
|
-
};
|
377
|
-
this.urlLocationPollId = setInterval(updateHash, 500);
|
378
|
-
}
|
379
|
-
|
380
|
-
/**
|
381
|
-
* Will read either the hash or URL and return the bookreader fragment
|
382
|
-
*/
|
383
|
-
pullFromAddressBar (location = window.location) {
|
384
|
-
const path = this.urlMode === 'history'
|
385
|
-
? (location.pathname.substr(this.urlHistoryBasePath.length) + location.search)
|
386
|
-
: location.hash.substr(1);
|
387
|
-
this.urlState = this.urlStringToUrlState(this.urlSchema, path);
|
388
|
-
}
|
389
|
-
}
|
390
|
-
|
391
|
-
export class BookreaderUrlPlugin extends BookReader {
|
392
|
-
|
393
|
-
init() {
|
394
|
-
if (this.options.enableUrlPlugin) {
|
395
|
-
this.urlPlugin = new UrlPlugin(this.options);
|
396
|
-
this.bind(BookReader.eventNames.PostInit, () => {
|
397
|
-
const { urlMode } = this.options;
|
398
|
-
|
399
|
-
if (urlMode === 'hash') {
|
400
|
-
this.urlPlugin.listenForHashChanges();
|
401
|
-
}
|
402
|
-
});
|
403
|
-
}
|
404
|
-
|
405
|
-
super.init();
|
406
|
-
}
|
407
|
-
|
408
|
-
}
|
409
|
-
|
410
|
-
window.BookReader = BookreaderUrlPlugin;
|
411
|
-
export default BookreaderUrlPlugin;
|
@@ -1,7 +1,6 @@
|
|
1
|
+
|
1
2
|
import BookReader from '@/src/BookReader.js';
|
2
3
|
import '@/src/plugins/plugin.url.js';
|
3
|
-
import { UrlPlugin } from '@/src/plugins/plugin.url.js';
|
4
|
-
import sinon from 'sinon';
|
5
4
|
|
6
5
|
let br;
|
7
6
|
beforeAll(() => {
|
@@ -11,164 +10,6 @@ beforeAll(() => {
|
|
11
10
|
|
12
11
|
afterEach(() => {
|
13
12
|
jest.clearAllMocks();
|
14
|
-
sinon.restore();
|
15
|
-
});
|
16
|
-
|
17
|
-
|
18
|
-
describe.only('UrlPlugin tests', () => {
|
19
|
-
const urlPlugin = new UrlPlugin();
|
20
|
-
const urlSchema = [
|
21
|
-
{ name: 'page', position: 'path', default: 'n0' },
|
22
|
-
{ name: 'mode', position: 'path', default: '2up' },
|
23
|
-
{ name: 'search', position: 'path', deprecated_for: 'q' },
|
24
|
-
{ name: 'q', position: 'query_param' },
|
25
|
-
{ name: 'sort', position: 'query_param' },
|
26
|
-
{ name: 'view', position: 'query_param' },
|
27
|
-
{ name: 'admin', position: 'query_param' },
|
28
|
-
];
|
29
|
-
|
30
|
-
describe('urlStateToUrlString tests', () => {
|
31
|
-
test('urlStateToUrlString with known states in schema', () => {
|
32
|
-
const urlState = { page: 'n7', mode: '1up', search: 'foo' };
|
33
|
-
const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', view: 'theater', sort: 'title_asc' };
|
34
|
-
|
35
|
-
const expectedUrlFromState = '/page/n7/mode/1up?q=foo';
|
36
|
-
const expectedUrlFromStateWithQueries = '/page/n7/mode/1up?q=hello&view=theater&sort=title_asc';
|
37
|
-
|
38
|
-
expect(urlPlugin.urlStateToUrlString(urlSchema, urlState)).toBe(expectedUrlFromState);
|
39
|
-
expect(urlPlugin.urlStateToUrlString(urlSchema, urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
|
40
|
-
});
|
41
|
-
|
42
|
-
test('urlStateToUrlString with unknown states in schema', () => {
|
43
|
-
const urlState = { page: 'n7', mode: '1up' };
|
44
|
-
const urlStateWithQueries = { page: 'n7', mode: '1up', q: 'hello', viewer: 'theater', sortBy: 'title_asc' };
|
45
|
-
|
46
|
-
const expectedUrlFromState = '/page/n7/mode/1up';
|
47
|
-
const expectedUrlFromStateWithQueries = '/page/n7/mode/1up?q=hello&viewer=theater&sortBy=title_asc';
|
48
|
-
|
49
|
-
expect(urlPlugin.urlStateToUrlString(urlSchema, urlState)).toBe(expectedUrlFromState);
|
50
|
-
expect(urlPlugin.urlStateToUrlString(urlSchema, urlStateWithQueries)).toBe(expectedUrlFromStateWithQueries);
|
51
|
-
});
|
52
|
-
|
53
|
-
test('urlStateToUrlString with boolean value', () => {
|
54
|
-
const urlState = { page: 'n7', mode: '1up', search: 'foo', view: 'theater', wrapper: false };
|
55
|
-
const expectedUrlFromState = '/page/n7/mode/1up?q=foo&view=theater&wrapper=false';
|
56
|
-
|
57
|
-
expect(urlPlugin.urlStateToUrlString(urlSchema, urlState)).toBe(expectedUrlFromState);
|
58
|
-
});
|
59
|
-
});
|
60
|
-
|
61
|
-
describe('urlStringToUrlState tests', () => {
|
62
|
-
test('urlStringToUrlState without query string', () => {
|
63
|
-
const url = '/page/n7/mode/2up';
|
64
|
-
const url1 = '/page/n7/mode/1up';
|
65
|
-
|
66
|
-
expect(urlPlugin.urlStringToUrlState(urlSchema, url)).toEqual({page: 'n7', mode: '2up'});
|
67
|
-
expect(urlPlugin.urlStringToUrlState(urlSchema, url1)).toEqual({page: 'n7', mode: '1up'});
|
68
|
-
});
|
69
|
-
|
70
|
-
test('urlStringToUrlState with deprecated_for', () => {
|
71
|
-
const url = '/page/n7/mode/2up/search/hello';
|
72
|
-
|
73
|
-
expect(urlPlugin.urlStringToUrlState(urlSchema, url)).toEqual({page: 'n7', mode: '2up', q: 'hello'});
|
74
|
-
});
|
75
|
-
|
76
|
-
test('urlStringToUrlState with query string', () => {
|
77
|
-
const url = '/page/n7/mode/2up/search/hello?view=theather&foo=bar&sort=title_asc';
|
78
|
-
const url1 = '/mode/2up?ref=ol&ui=embed&wrapper=false&view=theater';
|
79
|
-
|
80
|
-
expect(urlPlugin.urlStringToUrlState(urlSchema, url)).toEqual(
|
81
|
-
{page: 'n7', mode: '2up', q: 'hello', view: 'theather', foo: 'bar', sort: 'title_asc'}
|
82
|
-
);
|
83
|
-
expect(urlPlugin.urlStringToUrlState(urlSchema, url1)).toEqual(
|
84
|
-
{page: 'n0', mode: '2up', ref: 'ol', ui: 'embed', wrapper: false, view: 'theater'}
|
85
|
-
);
|
86
|
-
});
|
87
|
-
|
88
|
-
test('urlStringToUrlState compare search and ?q', () => {
|
89
|
-
const url = '/page/n7/mode/2up/search/hello';
|
90
|
-
urlPlugin.urlState = { q: 'hello' };
|
91
|
-
|
92
|
-
expect(urlPlugin.urlStringToUrlState(urlSchema, url)).toEqual({page: 'n7', mode: '2up', q: 'hello'});
|
93
|
-
});
|
94
|
-
});
|
95
|
-
|
96
|
-
describe('url plugin helper functions', () => {
|
97
|
-
test('setUrlParam', () => {
|
98
|
-
urlPlugin.urlState = {};
|
99
|
-
urlPlugin.setUrlParam('page', '20');
|
100
|
-
urlPlugin.setUrlParam('mode', '2up');
|
101
|
-
|
102
|
-
expect(urlPlugin.urlState).toEqual({page: '20', mode: '2up'});
|
103
|
-
});
|
104
|
-
|
105
|
-
test('removeUrlParam', () => {
|
106
|
-
urlPlugin.setUrlParam('page', '20');
|
107
|
-
urlPlugin.setUrlParam('mode', '2up');
|
108
|
-
urlPlugin.removeUrlParam('mode');
|
109
|
-
|
110
|
-
expect(urlPlugin.urlState).toEqual({page: '20'});
|
111
|
-
});
|
112
|
-
|
113
|
-
test('getUrlParam', () => {
|
114
|
-
urlPlugin.setUrlParam('page', '20');
|
115
|
-
urlPlugin.setUrlParam('mode', '2up');
|
116
|
-
expect(urlPlugin.getUrlParam('page')).toEqual('20');
|
117
|
-
expect(urlPlugin.getUrlParam('mode')).toEqual('2up');
|
118
|
-
});
|
119
|
-
});
|
120
|
-
|
121
|
-
describe('pullFromAddressBar and pushToAddressBar - hash mode', () => {
|
122
|
-
test('url without mode state value - use default', () => {
|
123
|
-
urlPlugin.urlState = {};
|
124
|
-
urlPlugin.urlMode = 'hash';
|
125
|
-
|
126
|
-
urlPlugin.pullFromAddressBar({ pathname: '/page/12', search: '', hash: '' });
|
127
|
-
expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up'});
|
128
|
-
|
129
|
-
urlPlugin.pushToAddressBar();
|
130
|
-
expect(window.location.hash).toEqual('#/page/12/mode/2up');
|
131
|
-
});
|
132
|
-
|
133
|
-
test('url with query param', () => {
|
134
|
-
urlPlugin.urlState = {};
|
135
|
-
urlPlugin.urlMode = 'hash';
|
136
|
-
|
137
|
-
urlPlugin.pullFromAddressBar({ pathname: '/page/12', search: '?q=hello&view=theater', hash: '' });
|
138
|
-
expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up', q: 'hello', view: 'theater'});
|
139
|
-
|
140
|
-
urlPlugin.pushToAddressBar();
|
141
|
-
expect(window.location.hash).toEqual('#/page/12/mode/2up?q=hello&view=theater');
|
142
|
-
});
|
143
|
-
});
|
144
|
-
|
145
|
-
describe('pullFromAddressBar and pushToAddressBar - history mode', () => {
|
146
|
-
test('url without mode state value - use default', () => {
|
147
|
-
urlPlugin.urlState = {};
|
148
|
-
urlPlugin.urlHistoryBasePath = '/details/foo';
|
149
|
-
urlPlugin.urlMode = 'history';
|
150
|
-
|
151
|
-
urlPlugin.pullFromAddressBar({ pathname: '/details/foo/page/12', search: '', hash: '' });
|
152
|
-
expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up'});
|
153
|
-
|
154
|
-
urlPlugin.pushToAddressBar();
|
155
|
-
expect(window.location.pathname).toEqual('/details/foo/page/12/mode/2up');
|
156
|
-
});
|
157
|
-
|
158
|
-
test('url with query param', () => {
|
159
|
-
urlPlugin.urlState = {};
|
160
|
-
urlPlugin.urlHistoryBasePath = '/details/foo';
|
161
|
-
urlPlugin.urlMode = 'history';
|
162
|
-
|
163
|
-
urlPlugin.pullFromAddressBar({ pathname: '/details/foo/page/12', search: '?q=hello&view=theater', hash: '' });
|
164
|
-
expect(urlPlugin.urlState).toEqual({page: '12', mode: '2up', q: 'hello', view: 'theater'});
|
165
|
-
|
166
|
-
urlPlugin.pushToAddressBar();
|
167
|
-
const locationUrl = `${window.location.pathname}${window.location.search}`;
|
168
|
-
expect(locationUrl).toEqual('/details/foo/page/12/mode/2up?q=hello&view=theater');
|
169
|
-
});
|
170
|
-
});
|
171
|
-
|
172
13
|
});
|
173
14
|
|
174
15
|
describe('Plugin: URL controller', () => {
|
package/.nvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
14
|