diff --git a/README.md b/README.md index 8aad3e33..e134da7e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ TIFY is a slim and mobile-friendly [IIIF](https://iiif.io/) document viewer built with [Vue.js](https://vuejs.org/). It supports [IIIF Presentation API and Image API](https://iiif.io/api/) version 2 and 3. -Continue reading to learn how to integrate TIFY into your website or application and about its options and API, [check out the website for usage examples](https://tify.rocks/), or [have a look at the user guide](doc/user-guide.en.md). +Continue reading to learn how to integrate TIFY into your website or application and about its options and API, [check out the website for usage examples](https://tify.rocks/), or [have a look at the documentation](doc). ## Embedding TIFY @@ -66,79 +66,13 @@ Many aspects of the theme can be modified with SCSS variables or CSS custom prop If you are are upgrading from any previous version, [have a look at the upgrading guidelines](UPGRADING.md). -## Options +## Configuration TIFY takes an options object as its only parameter. While optional, you usually want to set `container` and `manifestUrl`. -- **`childManifestAutoloaded`**: boolean, default `true` +See [config.js](src/config.js) for a documentation of all available options. - If the manifest set by `manifestUrl` is a collection (`@type` is `sc:Collection`) and `childManifestUrl` is not set, automatically load the first manifest in the collection. This only works for collections with `manifests` on the first level; when the collection only contains other collections and `childManifestUrl` is not set, only the collection view is shown until the user selects a child manifest to load. - -- **`childManifestUrl`**: string or `null` (default) - - If the manifest set by `manifestUrl` is a collection (`@type` is `sc:Collection`), additionally load another IIIF manifest, whose `@type` must be `sc:Manifest`. Note that TIFY does not check if this additional manifest is actually part of the collection. - -- **`container`**: string or HTMLElement or `null` (default) - - The HTML element into which TIFY is mounted. If set to `null`, TIFY is not mounted at all until `mount` is called (see [API](#api)). - -- **`fallbackLanguage`**: string, default `'en'` - - The language to be used for strings from the IIIF manifest that are not available in the current `language`. If no value matches `language` or `fallbackLanguage`, the first available language is displayed. - -- **`filters`**: object, default `{}` - - Sets the initial image filters. Available properties are `'brightness'`, `'contrast'` (both a floating-point number between `0.5` and `2`) and `'saturation'` (floating-point number between `0` and `3`), all optional. - -- **`language`**: string, default `'en'` - - The interface language, matching the translation filename without extension. [See which translations are available](https://github.com/tify-iiif-viewer/tify/tree/main/dist/translations) or add your own. - -- **`manifestUrl`**: string or `null` (default) - - The URL of the IIIF manifest to load. - -- **`optionsResetOnPageChange`**: array of strings, default `['pan']` - - Viewer options that are reset on page change. Allowed array values are `'filters'`, `'pan'`, `'rotation'` and `'zoom'`. - -- **`pageLabelFormat`**: string, default `'P : L'` - - Defines how page labels are displayed in the page selector and in the thumbnails view. The placeholder `P` is replaced by the physical page number (consecutive numbers starting at `1`) while `L` is replaced by the logical page label, which can be any string, defined by the manifest. - -- **`pages`**: array of 1-based integers or `null` (default) - - The page(s) to display initially. If `null`, the initial page is determined by the manifest’s `startCanvas`, and if that is not set either, the first page is displayed. Page numbers start at 1. - -- **`pan`**: object, default `{}` - - Sets the initial pan. The object has two optional properties `x` and `y`, both floating-point numbers. The higher the value, the more to the left respectively top the image is positioned. By default, the image is centered within the container. - -- **`translationsDirUrl`**: string or `null` (default) - - The URL of the directory where TIFY finds its translations, without trailing `/`. If not set, TIFY tries to determine this URL automatically from its `<script>` element, but this may not work depending on how TIFY is loaded. - -- **`urlQueryKey`**: string or `null` (default), only use characters `A…Z a…z 0…9 - _` - - If set, parameters are read from the URL query and any changes are reflected, using the key provided. This works with multiple concurrent instances, but each instance must use a unique key. Note that when `urlQueryKey` is set, all options defined by `urlQueryParams` can be overridden by changing the URL in the browser’s address bar. - -- **`urlQueryParams`**: array of strings, default `['childManifestUrl', 'filters', 'pages', 'pan', 'rotation', 'view', 'zoom']` - - The parameter keys to be read from and stored in the URL query. Only has effect if `urlQueryKey` is set, in which case parameters read from the URL override options of the same name. - -- **`view`**: string, default `''` - - The initially displayed view (panel); `scan`, `fulltext`, `thumbnails`, `toc`, `info`, `help`, or empty (same as `scan`). On large screens, the scan is always shown next to the selected view. - -- **`viewer`**: object - - An object with options for OpenSeadragon, TIFY’s image rendering component. [See its documentation](https://openseadragon.github.io/docs/OpenSeadragon.html#.Options) for all available options. - -- **`zoom`**: floating-point number, default `null` - - Sets the initial zoom level. The higher the number, the deeper the zoom. By default, zoom is set automatically so that the full image is visible. - -An example with most available options set to non-default values: +An example with most options set to non-default values: ``` js new Tify({ @@ -161,103 +95,7 @@ new Tify({ ## API -With the exception of `mount` and `destroy`, all API functions are only available after TIFY has been mounted and the manifest has been loaded. Then the `ready` promise is fulfilled. There is no API function to load a new manifest; just replace the instance. - -Use the API like this: - -``` js -const tify = new Tify({ manifestUrl: 'https://example.org/iiif-manifest.json' }) - -tify.mount('#tify') - -tify.ready.then(() => { - tify.setPage([1, 12, 13]) - tify.setView('thumbnails') - tify.viewer.viewport.zoomTo(2) -}) -``` - -- **`destroy`** - - Destroys the current instance and removes event listeners. If you are using TIFY in an SPA, this should be called every time a page containing TIFY is unmounted to avoid memory leaks. - - No parameters. - -- **`mount`** - - Mounts TIFY. - - Parameters: - - - `container`: string or HTMLElement, required - - CSS selector pointing to a single HTML node or the node itself into which TIFY is mounted. - -- **`resetScan`** - - Resets the scan display options. - - Parameters: - - - `includingFiltersAndRotation`: boolean, default `false` - - By default, only pan and zoom are reset. If `true`, image filters and rotation are reset, too. - -- **`setPage`** - - Changes the active page or pages. - - Parameters: - - - `pageOrPages`: 1-based integer or array thereof (required) - - Provide a number to display a single page or an array of numbers to display multiple pages at once. If the number (or any of the numbers in the array) is smaller than `1` or greater than the number of pages in the document, the command is ignored. - - Returns an array of the current pages or `false` if `pageOrPages` is invalid. - -- **`setLanguage`** - - Changes the frontend language and loads the associated translation. This function returns a Promise. - - Parameters: - - - `language`: string, default `'en'` - - The language to load. A JSON file containing the translations for this language must be present in `public/translations`. Untranslated strings are displayed in English. - -- **`setView`** - - Changes the active view (panel). - - Parameters: - - - `name`: string (required) - - The view’s name; `'export'`, `'fulltext'`, `'help'`, `'info'`, `'scan'`, `'thumbnails'`, `'toc'`, or an empty string (same as `'scan'`). - -- **`toggleDoublePage`** - - Switches from single to double page (“book view”) and vice versa. - - Parameters: - - - `forced`: boolean, default `false` - - Double page is forced on (`true`) or off (`false`). - -- **`toggleFullscreen`** - - Toggles fullscreen mode. For security reasons, most browsers require a user interaction to enter fullscreen mode; a button calling this function via `onclick` works, but trying to do so automatically does probably not. - - Parameters: - - - `forced`: boolean, default `false` - - Fullscreen is forced on (`true`) or off (`false`). - -### OpenSeadragon API - -The `viewer` object exposes the full [OpenSeadragon API](https://openseadragon.github.io/docs/OpenSeadragon.html). If you want to control the scan view programmatically, the [methods of `viewer.viewport`](https://openseadragon.github.io/docs/OpenSeadragon.Viewport.html) are probably of interest. +TIFY provides an API for controlling most of its features, see [API documentation](doc/api.md). ## Build Setup diff --git a/doc/api.md b/doc/api.md new file mode 100644 index 00000000..4a7244db --- /dev/null +++ b/doc/api.md @@ -0,0 +1,101 @@ +# TIFY API + +TIFY provides an API for controlling most of its features. With the exception of `mount` and `destroy`, all API functions are only available after TIFY has been mounted and the manifest has been loaded. Then the `ready` promise is fulfilled. There is no API function to load a new manifest; just replace the instance. + +Use the API like this: + +``` js +const tify = new Tify({ manifestUrl: 'https://example.org/iiif-manifest.json' }) + +tify.mount('#tify') + +tify.ready.then(() => { + tify.setPage([1, 12, 13]) + tify.setView('thumbnails') + tify.viewer.viewport.zoomTo(2) +}) +``` + +## Functions + +- **`destroy`** + + Destroys the current instance and removes event listeners. If you are using TIFY in an SPA, this should be called every time a page containing TIFY is unmounted to avoid memory leaks. + + No parameters. + +- **`mount`** + + Mounts TIFY. + + Parameters: + + - `container`: string or HTMLElement, required + + CSS selector pointing to a single HTML node or the node itself into which TIFY is mounted. + +- **`resetScan`** + + Resets the scan display options. + + Parameters: + + - `includingFiltersAndRotation`: boolean, default `false` + + By default, only pan and zoom are reset. If `true`, image filters and rotation are reset, too. + +- **`setPage`** + + Changes the active page or pages. + + Parameters: + + - `pageOrPages`: 1-based integer or array thereof (required) + + Provide a number to display a single page or an array of numbers to display multiple pages at once. If the number (or any of the numbers in the array) is smaller than `1` or greater than the number of pages in the document, the command is ignored. + + Returns an array of the current pages or `false` if `pageOrPages` is invalid. + +- **`setLanguage`** + + Changes the frontend language and loads the associated translation. This function returns a Promise. + + Parameters: + + - `language`: string, default `'en'` + + The language to load. A JSON file containing the translations for this language must be present in `public/translations`. Untranslated strings are displayed in English. + +- **`setView`** + + Changes the active view (panel). + + Parameters: + + - `name`: string (required) + + The view’s name; `'export'`, `'fulltext'`, `'help'`, `'info'`, `'thumbnails'`, `'toc'`, or `null` to display (only) the scan. + +- **`toggleDoublePage`** + + Switches from single to double page (“book view”) and vice versa. + + Parameters: + + - `forced`: boolean, default `false` + + Double page is forced on (`true`) or off (`false`). + +- **`toggleFullscreen`** + + Toggles fullscreen mode. For security reasons, most browsers require a user interaction to enter fullscreen mode; a button calling this function via `onclick` works, but trying to do so automatically does probably not. + + Parameters: + + - `forced`: boolean, default `false` + + Fullscreen is forced on (`true`) or off (`false`). + +## OpenSeadragon API + +The `viewer` object exposes the full [OpenSeadragon API](https://openseadragon.github.io/docs/OpenSeadragon.html). If you want to control the scan view programmatically, the [methods of `viewer.viewport`](https://openseadragon.github.io/docs/OpenSeadragon.Viewport.html) are probably of interest. diff --git a/doc/introduction.md b/doc/introduction.md new file mode 100644 index 00000000..ae72eddc --- /dev/null +++ b/doc/introduction.md @@ -0,0 +1,3 @@ +# TIFY Introduction + +See [readme](../README.md). diff --git a/doc/user-guide.de.md b/doc/user-guide.de.md deleted file mode 100644 index c3e516c2..00000000 --- a/doc/user-guide.de.md +++ /dev/null @@ -1,57 +0,0 @@ -# TIFY Kurzanleitung - -## Einführung - -TIFY ist ein schlanker IIIF-Dokumentenbetrachter, der für Mobilgeräte optimiert wurde und eine schnelle und leicht zu bedienende Oberfläche bietet. - -IIIF steht für »International Image Interoperability Framework« und definiert verschiedene <acronym title="application programming interface">API</acronym>s, mit denen Bilddateien zusammen mit Metadaten für Präsentation und Struktur beschrieben und verteilt werden können. Dadurch können Büchern, Zeitungen, Handschriften, Karten, Schriftrollen und Archivmaterial weltweit zwischen Intitutionen und Repositorien mit geringem Aufwand geteilt werden. Diese Bilder und Metadaten lassen sich mit jeder IIIF-kompatiblen Anwendung verarbeiten und anzeigen. [Erfahren Sie mehr über IIIF.](http://iiif.io/about/) - -## Anzeige mehrerer Seiten - -Beliebige Seiten können nebeneinander dargestellt werden. - -Öffnen Sie dazu die Ansicht »Seiten« und wählen Sie mehrere Seiten aus, indem Sie diese mit gedrückter <kbd>Strg</kbd>-Taste anklicken – oder länger berühren, wenn Sie einen Touchscreen verwenden. - -## Tastenbelegung - -TIFY kann vollständig mit der Tastatur bedient werden. - -### Ansicht - -| Aktion | Taste | -| --- | :---: | -| Volltext (wenn verfügbar) | <kbd>1</kbd> | -| Seiten | <kbd>2</kbd> | -| Inhalt (wenn verfügbar) | <kbd>3</kbd> | -| Info | <kbd>4</kbd> | -| Export | <kbd>5</kbd> | -| Sammlung (wenn verfügbar) | <kbd>6</kbd> | -| Hilfe | <kbd>7</kbd> | -| Scan | <kbd>Rücktaste</kbd> | -| Vollbild | <kbd>F</kbd> | - -### Blättern - -| Aktion | Taste | -| --- | :---: | -| Vorige Seite | <kbd>Q</kbd> oder <kbd>,</kbd> | -| Nächste Seite | <kbd>E</kbd> oder <kbd>.</kbd> | -| Erste Seite | <kbd>⇧Q</kbd> | -| Letzte Seite | <kbd>⇧E</kbd> | -| Zu Seite springen | <kbd>X</kbd> | -| Doppelseite umschalten | <kbd>B</kbd> | - -### Scan - -| Aktion | Taste | -| --- | :---: | -| Bewegen | <kbd>W</kbd> <kbd>S</kbd> <kbd>A</kbd> <kbd>D</kbd> | -| Vergrößern | <kbd>⇧W</kbd> oder <kbd>+</kbd> | -| Verkleinern | <kbd>⇧S</kbd> oder <kbd>-</kbd> | -| Drehen (90 Grad im Uhrzeigersinn) | <kbd>R</kbd> | -| Filter umschalten | <kbd>I</kbd> | -| Position und Vergrößerung zurücksetzen | <kbd>0</kbd> | -| Drehung zurücksetzen | <kbd>⇧</kbd> + <kbd>R</kbd> | -| Filter zurücksetzen| <kbd>⇧</kbd> + <kbd>I</kbd> | -| Alles zurücksetzen | <kbd>⇧</kbd> + <kbd>0</kbd> | -| Vollbildschirm umschalten | <kbd>U</kbd> | diff --git a/doc/user-guide.en.md b/doc/user-guide.md similarity index 99% rename from doc/user-guide.en.md rename to doc/user-guide.md index 3d5ddf04..24ad9c9b 100644 --- a/doc/user-guide.en.md +++ b/doc/user-guide.md @@ -1,7 +1,5 @@ # TIFY User Guide -## Introduction - TIFY is a slim and mobile-friendly IIIF document viewer, created with performance and usability in mind. IIIF, which stands for “International Image Interoperability Framework”, defines a set of standardized <acronym title="application programming interface">API</acronym>s for describing and delivering images along with presentational and structural metadata over the web. This allows digitized artworks, books, newspapers, manuscripts, maps, scrolls, and archival materials to be shared between institutions and repositories. Any IIIF-compliant application can consume and display those images and metadata. [Get more information about IIIF.](http://iiif.io/about/) diff --git a/src/components/AppHeader.vue b/src/components/AppHeader.vue index cdd45f8a..d3ced69d 100644 --- a/src/components/AppHeader.vue +++ b/src/components/AppHeader.vue @@ -85,7 +85,7 @@ export default { case 'Backspace': // switchViewSmall is visible, i.e. screen is small if (this.$refs.switchViewSmall.offsetParent) { - this.toggleView('scan'); + this.toggleView(null); } break; case '1': @@ -222,7 +222,7 @@ export default { this.closeControlsPopup(); const view = name === this.$store.options.view && this.$store.manifest && !this.$store.isMobile() - ? '' + ? null : name; this.$store.updateOptions({ view }); return view; @@ -277,7 +277,7 @@ export default { <button type="button" :aria-controls="$store.getId('controls')" - :aria-expanded="controlsVisible ? 'true' : 'false'" + :aria-expanded="controlsVisible" :aria-label="$translate('View')" class="tify-header-button" :title="$translate('View')" @@ -298,10 +298,10 @@ export default { v-if="$store.manifest" type="button" class="tify-header-button -scan" - :class="{ '-active': $store.options.view === 'scan' }" + :class="{ '-active': !$store.options.view }" :aria-controls="$store.getId('scan')" - :aria-expanded="$store.options.view === 'scan' ? 'true' : 'false'" - @click="toggleView('scan')" + :aria-expanded="!$store.options.view" + @click="toggleView(null)" > <IconImage /> {{ $translate('Scan') }} @@ -313,7 +313,7 @@ export default { class="tify-header-button" :class="{ '-active': $store.options.view === 'fulltext' }" :aria-controls="$store.getId('fulltext')" - :aria-expanded="$store.options.view === 'fulltext' ? 'true' : 'false'" + :aria-expanded="$store.options.view === 'fulltext'" @click="toggleView('fulltext')" > <IconTextLong /> @@ -326,7 +326,7 @@ export default { class="tify-header-button" :class="{ '-active': $store.options.view === 'thumbnails' }" :aria-controls="$store.getId('thumbnails')" - :aria-expanded="$store.options.view === 'thumbnails' ? 'true' : 'false'" + :aria-expanded="$store.options.view === 'thumbnails'" @click="toggleView('thumbnails')" > <IconViewModule /> @@ -339,7 +339,7 @@ export default { class="tify-header-button" :class="{ '-active': $store.options.view === 'toc' }" :aria-controls="$store.getId('toc')" - :aria-expanded="$store.options.view === 'toc' ? 'true' : 'false'" + :aria-expanded="$store.options.view === 'toc'" @click="toggleView('toc')" > <IconTableOfContents /> @@ -351,7 +351,7 @@ export default { class="tify-header-button" :class="{ '-active': $store.options.view === 'info' }" :aria-controls="$store.getId('info')" - :aria-expanded="$store.options.view === 'info' ? 'true' : 'false'" + :aria-expanded="$store.options.view === 'info'" @click="toggleView('info')" > <IconInformationVariant /> @@ -364,7 +364,7 @@ export default { class="tify-header-button" :class="{ '-active': $store.options.view === 'export' }" :aria-controls="$store.getId('export')" - :aria-expanded="$store.options.view === 'export' ? 'true' : 'false'" + :aria-expanded="$store.options.view === 'export'" @click="toggleView('export')" > <IconDownloadOutline /> @@ -377,7 +377,7 @@ export default { class="tify-header-button" :class="{ '-active': $store.options.view === 'collection' }" :aria-controls="$store.getId('collection')" - :aria-expanded="$store.options === 'collection' ? 'true' : 'false'" + :aria-expanded="$store.options === 'collection'" @click="toggleView('collection')" > <IconListBoxOutline /> @@ -391,7 +391,7 @@ export default { class="tify-header-button -icon-only" :class="{ '-active': $store.options.view === 'help' }" :aria-controls="$store.getId('help')" - :aria-expanded="$store.options.view === 'help' ? 'true' : 'false'" + :aria-expanded="$store.options.view === 'help'" :title="$translate('Help')" @click="toggleView('help')" > diff --git a/src/components/CollectionNode.vue b/src/components/CollectionNode.vue index 28153e12..a7879862 100644 --- a/src/components/CollectionNode.vue +++ b/src/components/CollectionNode.vue @@ -59,7 +59,7 @@ export default { v-if="item.type === 'Collection'" type="button" :aria-controls="id" - :aria-expanded="expanded ? 'true' : 'false'" + :aria-expanded="expanded" class="tify-collection-link -has-children" @click="toggleChildren()" > diff --git a/src/components/PageSelect.vue b/src/components/PageSelect.vue index 4b5d40c9..eff2d32f 100644 --- a/src/components/PageSelect.vue +++ b/src/components/PageSelect.vue @@ -79,7 +79,7 @@ export default { this.closeDropdown(); this.$store.setPage(page); if (this.$store.isMobile()) { - this.$store.updateOptions({ view: 'scan' }); + this.$store.updateOptions({ view: null }); } }, toggleDropdown() { @@ -134,7 +134,7 @@ export default { type="button" class="tify-page-select-button" :aria-controls="$store.getId('dropdown')" - :aria-expanded="isOpen ? 'true' : 'false'" + :aria-expanded="isOpen" @click="toggleDropdown()" > <span class="tify-sr-only">{{ $translate('Current page:') }}</span> diff --git a/src/components/TocList.vue b/src/components/TocList.vue index 469b1a9e..3845794a 100644 --- a/src/components/TocList.vue +++ b/src/components/TocList.vue @@ -67,7 +67,7 @@ export default { setPage(page) { this.$store.setPage(page); if (this.$store.isMobile()) { - this.$store.updateOptions({ view: 'scan' }); + this.$store.updateOptions({ view: null }); } }, toggleAllChildren(expanded = null) { @@ -113,7 +113,7 @@ export default { class="tify-toc-toggle" :title="$translate(expandedStructures[index] ? 'Collapse' : 'Expand')" :aria-controls="`${id}-${index}`" - :aria-expanded="expandedStructures[index] ? 'true' : 'false'" + :aria-expanded="!!expandedStructures[index]" @click="toggleChildren(index)" > <template v-if="expandedStructures[index]"> diff --git a/src/components/ViewExport.vue b/src/components/ViewExport.vue index 38d135b3..8820c09f 100644 --- a/src/components/ViewExport.vue +++ b/src/components/ViewExport.vue @@ -105,7 +105,7 @@ export default { class="tify-export-toggle" :class="{ '-close': perElementPdfLinksVisible }" :aria-controls="$store.getId('export-pdf-list')" - :aria-expanded="perElementPdfLinksVisible ? 'true' : 'false'" + :aria-expanded="perElementPdfLinksVisible" @click="perElementPdfLinksVisible = !perElementPdfLinksVisible" > <template v-if="!perElementPdfLinksVisible"> diff --git a/src/components/ViewHelp.vue b/src/components/ViewHelp.vue index 7f657a31..db45fbca 100644 --- a/src/components/ViewHelp.vue +++ b/src/components/ViewHelp.vue @@ -15,12 +15,6 @@ export default { return 'TIFY is a slim and mobile-friendly IIIF document viewer, released under the' + ' <a href="https://www.gnu.org/licenses/agpl-3.0.html.en">GNU Affero General Public License 3.0</a>.'; }, - userGuideUrl() { - const lang = this.env.docsLanguages.includes(this.$store.options.language) - ? this.$store.options.language - : 'en'; - return `${this.env.docsUrl}/user-guide.${lang}.md`; - }, }, }; </script> @@ -40,13 +34,13 @@ export default { <ul class="tify-list"> <li> - <a :href="userGuideUrl">{{ $translate('User guide') }}</a> + <a :href="env.repositoryUrl">{{ $translate('Source code') }}</a> </li> <li> - <a :href="env.repositoryUrl">{{ $translate('Source code') }}</a> + <a :href="`${env.blobBaseUrl}/doc`">{{ $translate('Documentation') }}</a> </li> <li> - <a :href="env.contributorsUrl">{{ $translate('Contributors') }}</a> + <a :href="`${env.blobBaseUrl}/CONTRIBUTORS.md`">{{ $translate('Contributors') }}</a> </li> <li> <a :href="env.bugsUrl">{{ $translate('Report a bug') }}</a> diff --git a/src/components/ViewScan.vue b/src/components/ViewScan.vue index ec2855c3..0452a563 100644 --- a/src/components/ViewScan.vue +++ b/src/components/ViewScan.vue @@ -538,7 +538,7 @@ export default { :class="{ '-active': filtersActive }" :title="$translate('Toggle image filters')" :aria-controls="$store.getId('filters')" - :aria-expanded="filtersVisible ? 'true' : 'false'" + :aria-expanded="filtersVisible" @click="filtersVisible = !filtersVisible" > <IconTune /> diff --git a/src/components/ViewThumbnails.vue b/src/components/ViewThumbnails.vue index bf9d3da5..f0a6ed45 100644 --- a/src/components/ViewThumbnails.vue +++ b/src/components/ViewThumbnails.vue @@ -157,7 +157,7 @@ export default { this.$store.setPage(page); if (this.$store.isMobile()) { - this.$store.updateOptions({ view: 'scan' }); + this.$store.updateOptions({ view: null }); } }, touchStartTogglePage(page) { diff --git a/src/config.js b/src/config.js new file mode 100644 index 00000000..88bc19c0 --- /dev/null +++ b/src/config.js @@ -0,0 +1,212 @@ +export default { + /** + * The ID of the annotation to highlight when the fulltext view is active. + * Only has effect for manifests with annotations. + * + * @type {?string} + */ + annotationId: null, + + /** + * When the fulltext view is active (or just the scan view on small screens), + * TIFY displays clickable annotation overlays on the scan, which are linked + * to their corresponding fulltext section. Set to `false` to hide overlays + * by default. Annotation overlays can always be toggled by the user. Only + * has effect for manifests with annotations. + * + * @type {?boolean} + */ + annotationsVisible: null, + + /** + * Breakpoints used for custom media queries, depending on TIFY’s container + * size instead of the viewport. + * + * @type {object} + */ + breakpoints: { + tiny: 359, + small: 719, + medium: 959, + large: 1199, + }, + + /** + * If the manifest set by `manifestUrl` is a collection (`@type` is + * `sc:Collection`) and `childManifestUrl` is not set, automatically load the + * first manifest in the collection. This only works for collections with + * `manifests` on the first level; when the collection only contains other + * collections and `childManifestUrl` is not set, only the collection view is + * shown until the user selects a child manifest to load. + * + * @type {boolean} + */ + childManifestAutoloaded: true, + + /** + * If the manifest set by `manifestUrl` is a collection (`@type` is + * `sc:Collection`), additionally load another IIIF manifest, whose `@type` + * must be `sc:Manifest`. Note that TIFY does not check if this additional + * manifest is actually part of the collection. + * + * @type {?string} + */ + childManifestUrl: null, + + /** + * The HTML element into which TIFY is mounted. If set to `null`, TIFY is not + * mounted at all until `mount` is called (see docs/api.md). + * + * @type {?string|HTMLElement} + */ + container: null, + + /** + * The language to be used for strings from the IIIF manifest that are not + * available in the current `language`. If no value matches `language` or + * `fallbackLanguage`, the first available language is displayed. + * + * @type {string} + */ + fallbackLanguage: 'en', + + /** + * Sets the initial image filters. Available properties are `'brightness'`, + * `'contrast'` (both a floating-point number between `0.5` and `2`) and + * `'saturation'` (floating-point number between `0` and `3`), all optional. + * + * @type {object} + */ + filters: {}, + + /** + * The interface language, matching the translation filename without + * extension. See which translations are available at + * https://github.com/tify-iiif-viewer/tify/tree/main/dist/translations + * or add your own. + * + * @type {string} + */ + language: 'en', + + /** + * The URL of the IIIF manifest to load. + * + * @type {?string} + */ + manifestUrl: null, + + /** + * Viewer options that are reset on page change. Allowed array values are + * `'filters'`, `'pan'`, `'rotation'` and `'zoom'`. + * + * @type {Array.<string>} + */ + optionsResetOnPageChange: [ + 'pan', + ], + + /** + * Defines how page labels are displayed in the page selector and in the + * thumbnails view. The placeholder `P` is replaced by the physical page + * number (consecutive numbers starting at `1`) while `L` is replaced by the + * logical page label, which can be any string, defined by the manifest. + * + * @type {string} + */ + pageLabelFormat: 'P : L', + + /** + * The page(s) to display initially. If `null`, the initial page is + * determined by the manifest’s `startCanvas`, and if that is not set either, + * the first page is displayed. Page numbers start at 1. + * + * @type {?Array.<number>} + */ + pages: null, + + /** + * Sets the initial pan. The object has two optional properties `x` and `y`, + * both floating-point numbers. The higher the value, the more to the left + * respectively top the image is positioned. By default, the image is + * centered within the container. + * + * @type {object} + */ + pan: {}, + + /** + * The initial rotation of the scan in degrees. Should be a multiple of 90. + * + * @type {?number} + */ + rotation: null, + + /** + * The URL of the directory where TIFY finds its translations, without a + * trailing `/`. If not set, TIFY tries to determine this URL automatically + * from its `<script>` element, but this may not work depending on how TIFY + * is loaded. + * + * @type {?string} + */ + translationsDirUrl: null, + + /** + * If set, parameters are read from the URL query and any changes are + * reflected, using the key provided. This works with multiple concurrent + * instances, but each instance must use a unique key. Note that when + * `urlQueryKey` is set, all options defined by `urlQueryParams` can be + * overridden by changing the URL in the browser’s address bar. + * Only use characters `A…Z a…z 0…9 - _`. + * + * @type {?string} + */ + urlQueryKey: null, + + /** + * The parameter keys to be read from and stored in the URL query. Only has + * effect if `urlQueryKey` is set, in which case parameters read from the URL + * override options of the same name. + * + * @type {Array.<string>} + */ + urlQueryParams: [ + 'annotationId', + 'annotationsVisible', + 'childManifestUrl', + 'filters', + 'pages', + 'pan', + 'rotation', + 'view', + 'zoom', + ], + + /** + * The initially displayed view (panel); `fulltext`, `thumbnails`, + * `toc`, `info`, `help`, or `null` to display (only) the scan. + * On large screens, the scan is always shown next to the selected view. + * + * @type {?string} + */ + view: null, + + /** + * An object with options for OpenSeadragon, TIFY’s image rendering + * component. See its documentation at + * https://openseadragon.github.io/docs/OpenSeadragon.html#.Options + * for all available options. + * + * @type {object} + */ + viewer: {}, + + /** + * Sets the initial zoom level. The higher the number, the deeper the zoom. + * By default, zoom is set automatically so that the full image is visible. + * + * @type {?number} + */ + zoom: null, +}; diff --git a/src/main.js b/src/main.js index e849c56c..f5c3b330 100644 --- a/src/main.js +++ b/src/main.js @@ -2,48 +2,13 @@ import { createApp, h } from 'vue'; import App from './App.vue'; +import defaultOptions from './config'; + import api from './plugins/api'; import i18n from './plugins/i18n'; import store from './plugins/store'; window.Tify = function Tify(userOptions = {}) { - const defaultOptions = { - breakpoints: { - tiny: 359, - small: 719, - medium: 959, - large: 1199, - }, - childManifestAutoloaded: true, - childManifestUrl: null, - container: null, - fallbackLanguage: 'en', - filters: {}, - language: 'en', - manifestUrl: null, - optionsResetOnPageChange: [ - 'pan', - ], - pageLabelFormat: 'P : L', - pages: null, - pan: {}, - rotation: null, - translationsDirUrl: null, - urlQueryKey: null, - urlQueryParams: [ - 'childManifestUrl', - 'filters', - 'pages', - 'pan', - 'rotation', - 'view', - 'zoom', - ], - view: '', - viewer: {}, - zoom: null, - }; - this.options = { ...defaultOptions, ...userOptions }; if (!this.options.translationsDirUrl) { diff --git a/src/plugins/store.js b/src/plugins/store.js index 77eba3c2..29c3ac6b 100644 --- a/src/plugins/store.js +++ b/src/plugins/store.js @@ -324,9 +324,9 @@ function Store(args) { } } - // NOTE: params.view can be an empty string (showing only the scan on large screens) - if (params.view === '' && store.isMobile()) { - params.view = 'scan'; + // For backwards compatibility + if (params.view === 'scan') { + params.view = null; } if (params.pages && !isValidPagesArray(params.pages, store.pageCount)) { @@ -382,7 +382,7 @@ function Store(args) { pages: [store.getStartPage()], pan: {}, rotation: null, - view: store.isMobile() ? 'scan' : 'collection', + view: store.isMobile() ? null : 'collection', zoom: null, }); } diff --git a/tests/e2e/scan.spec.js b/tests/e2e/scan.spec.js index b90c9af0..40a7354f 100644 --- a/tests/e2e/scan.spec.js +++ b/tests/e2e/scan.spec.js @@ -34,8 +34,7 @@ describe('Scan', () => { cy.get('.tify').type('{shift}0'); cy.url().should( 'include', - `/?manifest=${encodeURIComponent(`${Cypress.env('iiifApiUrl')}/manifest/gdz-HANS_DE_7_w042081`)}` - + `&tify=${encodeURIComponent('{"view":""}')}`, + `/?manifest=${encodeURIComponent(`${Cypress.env('iiifApiUrl')}/manifest/gdz-HANS_DE_7_w042081`)}`, ); }); diff --git a/vite.config.js b/vite.config.js index e8a9d06d..26c293d6 100644 --- a/vite.config.js +++ b/vite.config.js @@ -29,15 +29,11 @@ export default defineConfig({ // https://vitejs.dev/config/#environment-variables define: { ENV: { - version: pkg.version, - license: pkg.license, + blobBaseUrl: `${pkg.repository.url}/blob/v${pkg.version}`, bugsUrl: pkg.bugs.url, - contributorsUrl: `${pkg.repository.url}/blob/v${pkg.version}/CONTRIBUTORS.md`, - docsUrl: `${pkg.repository.url}/blob/v${pkg.version}/doc`, - docsLanguages: [ - ...new Set(readdirSync('./doc').map((file) => file.split('.')[1])), - ], + license: pkg.license, repositoryUrl: pkg.repository.url, + version: pkg.version, }, }, plugins: [