├── README.md ├── docs ├── github-markdown.css ├── index.html ├── open_in_iiif_viewer.xpi └── updates.json └── src ├── background.js ├── browser-polyfill.min.js ├── content.js ├── icon.svg ├── icon_off.svg ├── manifest.json ├── options.html └── options.js /README.md: -------------------------------------------------------------------------------- 1 | # Open in IIIF Viewer 2 | 3 | A Firefox/Chrome extension to open IIIF manifest link in your favorite IIIF viewer. 4 | 5 | (This browser extension is formerly named “Open IIIF Manifest Link in Favorite Viewer.”) 6 | 7 | ## Install 8 | 9 | - Firefox 10 | - [Install](https://2sc1815j.net/open-in-iiif-viewer/open_in_iiif_viewer.xpi) (signed by Mozilla) 11 | - If you use Firefox ESR 52, please set `webextensions.storage.sync.enabled` to `true` in about:config. 12 | - Google Chrome 13 | - [Chrome Web Store](https://chrome.google.com/webstore/detail/pdkbceoglenaneaoebcagpbkocpkhajl) 14 | 15 | ## Usage 16 | 17 | When the web page you are browsing contains a link to a IIIF manifest, by clicking on the toolbar button of this extension, you can open the link in the IIIF viewer specified on the options page. 18 | 19 | ![screenshot_toolbar](https://lh3.googleusercontent.com/aBce0Qk59V2pNzZr_dfMwKvAze5TaqfiSQWl6oQPKRUH0MkGq4wcsEsZtjRK9POlWlBrVxt7) 20 | 21 | By right-clicking on a link to the IIIF manifest, a context menu item “Open link in IIIF viewer” appears, which allows you to open the link in your preferred IIIF viewer. 22 | 23 | ![screenshot_contextmenu](https://lh3.googleusercontent.com/naIzec7cR6iWnClg435Efj5QnEXKhC8ZTKokMdDFi0vDOtErEaizrcPPjuf6pkvzHQKmucz3) 24 | 25 | ## Options 26 | 27 | On the options page, set the URL field depending on the particular IIIF viewer you want to use. 28 | 29 | Note that IIIF viewers hosted on HTTPS servers cannot display IIIF manifests hosted on HTTP servers. 30 | 31 | For example: 32 | - Open in IIIF Curation Viewer (default) 33 | - `http://codh.rois.ac.jp/software/iiif-curation-viewer/demo/?manifest=` 34 | - Open in Mirador 2 (thanks to Kiyonori Nagasaki) 35 | - `http://candra.dhii.jp/nagasaki/mirador_if.php?manifest=` 36 | - Open in Mirador 3 37 | - `https://projectmirador.org/embed/?manifest=` 38 | - Open in Universal Viewer v2 39 | - `http://universalviewer.io/uv.html?manifest=` 40 | - Open in Universal Viewer v3 41 | - `https://uv-v3.netlify.app/#?manifest=` 42 | - Open in Universal Viewer v4 43 | - `https://uv-v4.netlify.app/#?manifest=` 44 | - Open as JSON 45 | - Leave the URL setting field blank. 46 | 47 | ![screenshot_options](https://lh3.googleusercontent.com/hUIP21cmt6LWpJFnvKnHIzUC5Wf4ZTc9QC1vUq50Ook8XGBkUs6GYvJ6DSO5C2zMOtfjKU7lQp0) 48 | 49 | Also, you can set a more complex pattern containing placeholders `{manifest_URI}` and `{canvas_URI}`. 50 | 51 | For example: 52 | - Open in IIIF Curation Viewer 53 | - `http://codh.rois.ac.jp/software/iiif-curation-viewer/demo/?manifest={manifest_URI}&canvas={canvas_URI}&lang=en` 54 | - Open in Mirador 55 | - `http://2sc1815j.net/mirador-loader/?manifest={manifest_URI}&canvas={canvas_URI}` 56 | - Open in Universal Viewer 57 | - `http://2sc1815j.net/uv-loader/?manifest={manifest_URI}&canvas={canvas_URI}` 58 | 59 | ## Notes 60 | 61 | On some web pages, the extension cannot recognize links to IIIF manifests or may misrecognize links to non-IIIF manifests. 62 | 63 | This uncertainty is reduced if the IIIF community specifies (or recommends) the machine-readable patterns for a link to a IIIF manifest. See a [proposal](https://github.com/2SC1815J/open-in-iiif-viewer/issues/1). 64 | 65 | The brief list of IIIF websites on which the extension works or not is as follows. 66 | 67 | |Website|Works?|Example| 68 | |---|---|---| 69 | |Biblissima|Yes|[test](http://beta.biblissima.fr/en/ark:/43093/mdata1939ea3de23cd3b1231f26ba9bdc012c34a76569)| 70 | |Bodleian Libraries|~~Yes[1](#note1)~~[4](#note4)|[test](https://digital.bodleian.ox.ac.uk/objects/acd9492e-25fa-4286-9fe6-e0cf2fc28106/)| 71 | |Cambridge University Library|Yes|[test](https://cudl.lib.cam.ac.uk/view/MS-SPR-ECTOPLASM/1)| 72 | |Digital Vatican Library|Yes|[test](https://digi.vatlib.it/view/MSS_Reg.lat.1896.pt.A)| 73 | |e-codices|Yes|[test](http://www.e-codices.unifr.ch/en/searchresult/list/one/fmb/cb-0601a)| 74 | |Europeana|Yes[3](#note3)|[test](http://www.europeana.eu/portal/en/record/9200365/BibliographicResource_3000149266571.html)| 75 | |Gallica|Yes[3](#note3)|[test](http://gallica.bnf.fr/ark:/12148/btv1b525033083/)| 76 | |Harvard Art Museums|Yes|[test](https://www.harvardartmuseums.org/collections/object/199194)| 77 | |Heidelberg University Library|Yes|[test](http://digi.ub.uni-heidelberg.de/diglit/ia00032100)| 78 | |Internet Archive|Yes[3](#note3)|[test](https://archive.org/details/mma_irises_436528)| 79 | |J. Paul Getty Museum|Yes|[test](http://www.getty.edu/art/collection/objects/287186/)| 80 | |Qatar Digital Library|Yes|[test](https://www.qdl.qa/en/archive/81055/vdc_100023867439.0x000027)| 81 | |Stanford Libraries|Yes/Yes|[test](https://exhibits.stanford.edu/epl/catalog/yc385kr0856)/[test](https://searchworks.stanford.edu/view/vb267mw8946)| 82 | |UCLA Library|Yes|[test](https://digital.library.ucla.edu/catalog/ark:/21198/n12k6g)| 83 | |University of Illinois at Urbana-Champaign Library|Yes|[test](https://digital.library.illinois.edu/items/a73d5ee0-994e-0134-2096-0050569601ca-b)| 84 | |Wellcome Library|~~Yes~~[4](#note4)|[test](https://wellcomelibrary.org/item/b12029348)| 85 | |World Digital Library|Yes|[test](https://www.wdl.org/en/item/19477/)| 86 | |Yale Center for British Art|Yes|[test](http://collections.britishart.yale.edu/vufind/Record/1665464)| 87 | 88 | ([more...](https://github.com/2SC1815J/open-in-iiif-viewer/wiki/Test-Cases)) 89 | 90 | #### IIIF Websites in Japan 91 | 92 | |Website|Works?|Example| 93 | |---|---|---| 94 | |National Diet Library Digital Collections (NDL)|Yes|[test](http://dl.ndl.go.jp/info:ndljp/pid/1287963)| 95 | |Database of Pre-modern Japanese Text (CODH)|Yes|[test](http://codh.rois.ac.jp/pmjt/book/200014778/)| 96 | |Database of Pre-Modern Japanese Works (NIJL)|Yes|[test](https://kotenseki.nijl.ac.jp/biblio/200010512/viewer/?ln=en)| 97 | |Collection for Study of the Japanese Language History (NINJAL)|Yes[2](#note2)|[test](http://dglb01.ninjal.ac.jp/ninjaldl/bunken.php?title=wajisyoransyo)| 98 | |Digital Collections of Keio University Libraries|Yes|[test](http://dcollections.lib.keio.ac.jp/sites/all/libraries/uv/uv.php?archive=NRE&id=132X-200-3-1)| 99 | |Kyoto University Rare Materials Digital Archive|Yes|[test](https://rmda.kulib.kyoto-u.ac.jp/en/item/rb00013599)| 100 | |University of Tokyo Library System|Yes|[test](https://iiif.dl.itc.u-tokyo.ac.jp/repo/s/hyakki/document/fbd0479b-dbb4-4eaa-95b8-f27e1c423e4b)| 101 | |Shimane University Library Digital Archive Collection|Yes|[test](http://da.lib.shimane-u.ac.jp/content/ja/2294)| 102 | |Kyushu University Collections|Yes|[test](http://hdl.handle.net/2324/411796)| 103 | 104 | ([more...](https://github.com/2SC1815J/open-in-iiif-viewer/wiki/Test-Cases-(in-Japan))) 105 | 106 | 1: Though the tooltip of the toolbar button is not updated in real-time, clicking on the button will open the correct manifest. 107 | 108 | 2: Use a context menu item “Open link in IIIF viewer” as needed. 109 | 110 | 3: Ad-hoc support. 111 | 112 | 4: It used to work, but as of July 2022, it no longer works due to changes on the site. -------------------------------------------------------------------------------- /docs/github-markdown.css: -------------------------------------------------------------------------------- 1 | /* github-markdown-css v5.1.0 2 | * https://github.com/sindresorhus/github-markdown-css 3 | * 4 | * MIT License 5 | * Copyright (c) Sindre Sorhus (https://sindresorhus.com) 6 | */ 7 | @media (prefers-color-scheme: dark) { 8 | .markdown-body { 9 | color-scheme: dark; 10 | --color-prettylights-syntax-comment: #8b949e; 11 | --color-prettylights-syntax-constant: #79c0ff; 12 | --color-prettylights-syntax-entity: #d2a8ff; 13 | --color-prettylights-syntax-storage-modifier-import: #c9d1d9; 14 | --color-prettylights-syntax-entity-tag: #7ee787; 15 | --color-prettylights-syntax-keyword: #ff7b72; 16 | --color-prettylights-syntax-string: #a5d6ff; 17 | --color-prettylights-syntax-variable: #ffa657; 18 | --color-prettylights-syntax-brackethighlighter-unmatched: #f85149; 19 | --color-prettylights-syntax-invalid-illegal-text: #f0f6fc; 20 | --color-prettylights-syntax-invalid-illegal-bg: #8e1519; 21 | --color-prettylights-syntax-carriage-return-text: #f0f6fc; 22 | --color-prettylights-syntax-carriage-return-bg: #b62324; 23 | --color-prettylights-syntax-string-regexp: #7ee787; 24 | --color-prettylights-syntax-markup-list: #f2cc60; 25 | --color-prettylights-syntax-markup-heading: #1f6feb; 26 | --color-prettylights-syntax-markup-italic: #c9d1d9; 27 | --color-prettylights-syntax-markup-bold: #c9d1d9; 28 | --color-prettylights-syntax-markup-deleted-text: #ffdcd7; 29 | --color-prettylights-syntax-markup-deleted-bg: #67060c; 30 | --color-prettylights-syntax-markup-inserted-text: #aff5b4; 31 | --color-prettylights-syntax-markup-inserted-bg: #033a16; 32 | --color-prettylights-syntax-markup-changed-text: #ffdfb6; 33 | --color-prettylights-syntax-markup-changed-bg: #5a1e02; 34 | --color-prettylights-syntax-markup-ignored-text: #c9d1d9; 35 | --color-prettylights-syntax-markup-ignored-bg: #1158c7; 36 | --color-prettylights-syntax-meta-diff-range: #d2a8ff; 37 | --color-prettylights-syntax-brackethighlighter-angle: #8b949e; 38 | --color-prettylights-syntax-sublimelinter-gutter-mark: #484f58; 39 | --color-prettylights-syntax-constant-other-reference-link: #a5d6ff; 40 | --color-fg-default: #c9d1d9; 41 | --color-fg-muted: #8b949e; 42 | --color-fg-subtle: #484f58; 43 | --color-canvas-default: #0d1117; 44 | --color-canvas-subtle: #161b22; 45 | --color-border-default: #30363d; 46 | --color-border-muted: #21262d; 47 | --color-neutral-muted: rgba(110,118,129,0.4); 48 | --color-accent-fg: #58a6ff; 49 | --color-accent-emphasis: #1f6feb; 50 | --color-attention-subtle: rgba(187,128,9,0.15); 51 | --color-danger-fg: #f85149; 52 | } 53 | } 54 | 55 | @media (prefers-color-scheme: light) { 56 | .markdown-body { 57 | color-scheme: light; 58 | --color-prettylights-syntax-comment: #6e7781; 59 | --color-prettylights-syntax-constant: #0550ae; 60 | --color-prettylights-syntax-entity: #8250df; 61 | --color-prettylights-syntax-storage-modifier-import: #24292f; 62 | --color-prettylights-syntax-entity-tag: #116329; 63 | --color-prettylights-syntax-keyword: #cf222e; 64 | --color-prettylights-syntax-string: #0a3069; 65 | --color-prettylights-syntax-variable: #953800; 66 | --color-prettylights-syntax-brackethighlighter-unmatched: #82071e; 67 | --color-prettylights-syntax-invalid-illegal-text: #f6f8fa; 68 | --color-prettylights-syntax-invalid-illegal-bg: #82071e; 69 | --color-prettylights-syntax-carriage-return-text: #f6f8fa; 70 | --color-prettylights-syntax-carriage-return-bg: #cf222e; 71 | --color-prettylights-syntax-string-regexp: #116329; 72 | --color-prettylights-syntax-markup-list: #3b2300; 73 | --color-prettylights-syntax-markup-heading: #0550ae; 74 | --color-prettylights-syntax-markup-italic: #24292f; 75 | --color-prettylights-syntax-markup-bold: #24292f; 76 | --color-prettylights-syntax-markup-deleted-text: #82071e; 77 | --color-prettylights-syntax-markup-deleted-bg: #FFEBE9; 78 | --color-prettylights-syntax-markup-inserted-text: #116329; 79 | --color-prettylights-syntax-markup-inserted-bg: #dafbe1; 80 | --color-prettylights-syntax-markup-changed-text: #953800; 81 | --color-prettylights-syntax-markup-changed-bg: #ffd8b5; 82 | --color-prettylights-syntax-markup-ignored-text: #eaeef2; 83 | --color-prettylights-syntax-markup-ignored-bg: #0550ae; 84 | --color-prettylights-syntax-meta-diff-range: #8250df; 85 | --color-prettylights-syntax-brackethighlighter-angle: #57606a; 86 | --color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f; 87 | --color-prettylights-syntax-constant-other-reference-link: #0a3069; 88 | --color-fg-default: #24292f; 89 | --color-fg-muted: #57606a; 90 | --color-fg-subtle: #6e7781; 91 | --color-canvas-default: #ffffff; 92 | --color-canvas-subtle: #f6f8fa; 93 | --color-border-default: #d0d7de; 94 | --color-border-muted: hsla(210,18%,87%,1); 95 | --color-neutral-muted: rgba(175,184,193,0.2); 96 | --color-accent-fg: #0969da; 97 | --color-accent-emphasis: #0969da; 98 | --color-attention-subtle: #fff8c5; 99 | --color-danger-fg: #cf222e; 100 | } 101 | } 102 | 103 | .markdown-body { 104 | -ms-text-size-adjust: 100%; 105 | -webkit-text-size-adjust: 100%; 106 | margin: 0; 107 | color: var(--color-fg-default); 108 | background-color: var(--color-canvas-default); 109 | font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; 110 | font-size: 16px; 111 | line-height: 1.5; 112 | word-wrap: break-word; 113 | } 114 | 115 | .markdown-body .octicon { 116 | display: inline-block; 117 | fill: currentColor; 118 | vertical-align: text-bottom; 119 | } 120 | 121 | .markdown-body h1:hover .anchor .octicon-link:before, 122 | .markdown-body h2:hover .anchor .octicon-link:before, 123 | .markdown-body h3:hover .anchor .octicon-link:before, 124 | .markdown-body h4:hover .anchor .octicon-link:before, 125 | .markdown-body h5:hover .anchor .octicon-link:before, 126 | .markdown-body h6:hover .anchor .octicon-link:before { 127 | width: 16px; 128 | height: 16px; 129 | content: ' '; 130 | display: inline-block; 131 | background-color: currentColor; 132 | -webkit-mask-image: url("data:image/svg+xml,"); 133 | mask-image: url("data:image/svg+xml,"); 134 | } 135 | 136 | .markdown-body details, 137 | .markdown-body figcaption, 138 | .markdown-body figure { 139 | display: block; 140 | } 141 | 142 | .markdown-body summary { 143 | display: list-item; 144 | } 145 | 146 | .markdown-body [hidden] { 147 | display: none !important; 148 | } 149 | 150 | .markdown-body a { 151 | background-color: transparent; 152 | color: var(--color-accent-fg); 153 | text-decoration: none; 154 | } 155 | 156 | .markdown-body a:active, 157 | .markdown-body a:hover { 158 | outline-width: 0; 159 | } 160 | 161 | .markdown-body abbr[title] { 162 | border-bottom: none; 163 | text-decoration: underline dotted; 164 | } 165 | 166 | .markdown-body b, 167 | .markdown-body strong { 168 | font-weight: 600; 169 | } 170 | 171 | .markdown-body dfn { 172 | font-style: italic; 173 | } 174 | 175 | .markdown-body h1 { 176 | margin: .67em 0; 177 | font-weight: 600; 178 | padding-bottom: .3em; 179 | font-size: 2em; 180 | border-bottom: 1px solid var(--color-border-muted); 181 | } 182 | 183 | .markdown-body mark { 184 | background-color: var(--color-attention-subtle); 185 | color: var(--color-text-primary); 186 | } 187 | 188 | .markdown-body small { 189 | font-size: 90%; 190 | } 191 | 192 | .markdown-body sub, 193 | .markdown-body sup { 194 | font-size: 75%; 195 | line-height: 0; 196 | position: relative; 197 | vertical-align: baseline; 198 | } 199 | 200 | .markdown-body sub { 201 | bottom: -0.25em; 202 | } 203 | 204 | .markdown-body sup { 205 | top: -0.5em; 206 | } 207 | 208 | .markdown-body img { 209 | border-style: none; 210 | max-width: 100%; 211 | box-sizing: content-box; 212 | background-color: var(--color-canvas-default); 213 | } 214 | 215 | .markdown-body code, 216 | .markdown-body kbd, 217 | .markdown-body pre, 218 | .markdown-body samp { 219 | font-family: monospace,monospace; 220 | font-size: 1em; 221 | } 222 | 223 | .markdown-body figure { 224 | margin: 1em 40px; 225 | } 226 | 227 | .markdown-body hr { 228 | box-sizing: content-box; 229 | overflow: hidden; 230 | background: transparent; 231 | border-bottom: 1px solid var(--color-border-muted); 232 | height: .25em; 233 | padding: 0; 234 | margin: 24px 0; 235 | background-color: var(--color-border-default); 236 | border: 0; 237 | } 238 | 239 | .markdown-body input { 240 | font: inherit; 241 | margin: 0; 242 | overflow: visible; 243 | font-family: inherit; 244 | font-size: inherit; 245 | line-height: inherit; 246 | } 247 | 248 | .markdown-body [type=button], 249 | .markdown-body [type=reset], 250 | .markdown-body [type=submit] { 251 | -webkit-appearance: button; 252 | } 253 | 254 | .markdown-body [type=button]::-moz-focus-inner, 255 | .markdown-body [type=reset]::-moz-focus-inner, 256 | .markdown-body [type=submit]::-moz-focus-inner { 257 | border-style: none; 258 | padding: 0; 259 | } 260 | 261 | .markdown-body [type=button]:-moz-focusring, 262 | .markdown-body [type=reset]:-moz-focusring, 263 | .markdown-body [type=submit]:-moz-focusring { 264 | outline: 1px dotted ButtonText; 265 | } 266 | 267 | .markdown-body [type=checkbox], 268 | .markdown-body [type=radio] { 269 | box-sizing: border-box; 270 | padding: 0; 271 | } 272 | 273 | .markdown-body [type=number]::-webkit-inner-spin-button, 274 | .markdown-body [type=number]::-webkit-outer-spin-button { 275 | height: auto; 276 | } 277 | 278 | .markdown-body [type=search] { 279 | -webkit-appearance: textfield; 280 | outline-offset: -2px; 281 | } 282 | 283 | .markdown-body [type=search]::-webkit-search-cancel-button, 284 | .markdown-body [type=search]::-webkit-search-decoration { 285 | -webkit-appearance: none; 286 | } 287 | 288 | .markdown-body ::-webkit-input-placeholder { 289 | color: inherit; 290 | opacity: .54; 291 | } 292 | 293 | .markdown-body ::-webkit-file-upload-button { 294 | -webkit-appearance: button; 295 | font: inherit; 296 | } 297 | 298 | .markdown-body a:hover { 299 | text-decoration: underline; 300 | } 301 | 302 | .markdown-body hr::before { 303 | display: table; 304 | content: ""; 305 | } 306 | 307 | .markdown-body hr::after { 308 | display: table; 309 | clear: both; 310 | content: ""; 311 | } 312 | 313 | .markdown-body table { 314 | border-spacing: 0; 315 | border-collapse: collapse; 316 | display: block; 317 | width: max-content; 318 | max-width: 100%; 319 | overflow: auto; 320 | } 321 | 322 | .markdown-body td, 323 | .markdown-body th { 324 | padding: 0; 325 | } 326 | 327 | .markdown-body details summary { 328 | cursor: pointer; 329 | } 330 | 331 | .markdown-body details:not([open])>*:not(summary) { 332 | display: none !important; 333 | } 334 | 335 | .markdown-body kbd { 336 | display: inline-block; 337 | padding: 3px 5px; 338 | font: 11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; 339 | line-height: 10px; 340 | color: var(--color-fg-default); 341 | vertical-align: middle; 342 | background-color: var(--color-canvas-subtle); 343 | border: solid 1px var(--color-neutral-muted); 344 | border-bottom-color: var(--color-neutral-muted); 345 | border-radius: 6px; 346 | box-shadow: inset 0 -1px 0 var(--color-neutral-muted); 347 | } 348 | 349 | .markdown-body h1, 350 | .markdown-body h2, 351 | .markdown-body h3, 352 | .markdown-body h4, 353 | .markdown-body h5, 354 | .markdown-body h6 { 355 | margin-top: 24px; 356 | margin-bottom: 16px; 357 | font-weight: 600; 358 | line-height: 1.25; 359 | } 360 | 361 | .markdown-body h2 { 362 | font-weight: 600; 363 | padding-bottom: .3em; 364 | font-size: 1.5em; 365 | border-bottom: 1px solid var(--color-border-muted); 366 | } 367 | 368 | .markdown-body h3 { 369 | font-weight: 600; 370 | font-size: 1.25em; 371 | } 372 | 373 | .markdown-body h4 { 374 | font-weight: 600; 375 | font-size: 1em; 376 | } 377 | 378 | .markdown-body h5 { 379 | font-weight: 600; 380 | font-size: .875em; 381 | } 382 | 383 | .markdown-body h6 { 384 | font-weight: 600; 385 | font-size: .85em; 386 | color: var(--color-fg-muted); 387 | } 388 | 389 | .markdown-body p { 390 | margin-top: 0; 391 | margin-bottom: 10px; 392 | } 393 | 394 | .markdown-body blockquote { 395 | margin: 0; 396 | padding: 0 1em; 397 | color: var(--color-fg-muted); 398 | border-left: .25em solid var(--color-border-default); 399 | } 400 | 401 | .markdown-body ul, 402 | .markdown-body ol { 403 | margin-top: 0; 404 | margin-bottom: 0; 405 | padding-left: 2em; 406 | } 407 | 408 | .markdown-body ol ol, 409 | .markdown-body ul ol { 410 | list-style-type: lower-roman; 411 | } 412 | 413 | .markdown-body ul ul ol, 414 | .markdown-body ul ol ol, 415 | .markdown-body ol ul ol, 416 | .markdown-body ol ol ol { 417 | list-style-type: lower-alpha; 418 | } 419 | 420 | .markdown-body dd { 421 | margin-left: 0; 422 | } 423 | 424 | .markdown-body tt, 425 | .markdown-body code { 426 | font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; 427 | font-size: 12px; 428 | } 429 | 430 | .markdown-body pre { 431 | margin-top: 0; 432 | margin-bottom: 0; 433 | font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; 434 | font-size: 12px; 435 | word-wrap: normal; 436 | } 437 | 438 | .markdown-body .octicon { 439 | display: inline-block; 440 | overflow: visible !important; 441 | vertical-align: text-bottom; 442 | fill: currentColor; 443 | } 444 | 445 | .markdown-body ::placeholder { 446 | color: var(--color-fg-subtle); 447 | opacity: 1; 448 | } 449 | 450 | .markdown-body input::-webkit-outer-spin-button, 451 | .markdown-body input::-webkit-inner-spin-button { 452 | margin: 0; 453 | -webkit-appearance: none; 454 | appearance: none; 455 | } 456 | 457 | .markdown-body .pl-c { 458 | color: var(--color-prettylights-syntax-comment); 459 | } 460 | 461 | .markdown-body .pl-c1, 462 | .markdown-body .pl-s .pl-v { 463 | color: var(--color-prettylights-syntax-constant); 464 | } 465 | 466 | .markdown-body .pl-e, 467 | .markdown-body .pl-en { 468 | color: var(--color-prettylights-syntax-entity); 469 | } 470 | 471 | .markdown-body .pl-smi, 472 | .markdown-body .pl-s .pl-s1 { 473 | color: var(--color-prettylights-syntax-storage-modifier-import); 474 | } 475 | 476 | .markdown-body .pl-ent { 477 | color: var(--color-prettylights-syntax-entity-tag); 478 | } 479 | 480 | .markdown-body .pl-k { 481 | color: var(--color-prettylights-syntax-keyword); 482 | } 483 | 484 | .markdown-body .pl-s, 485 | .markdown-body .pl-pds, 486 | .markdown-body .pl-s .pl-pse .pl-s1, 487 | .markdown-body .pl-sr, 488 | .markdown-body .pl-sr .pl-cce, 489 | .markdown-body .pl-sr .pl-sre, 490 | .markdown-body .pl-sr .pl-sra { 491 | color: var(--color-prettylights-syntax-string); 492 | } 493 | 494 | .markdown-body .pl-v, 495 | .markdown-body .pl-smw { 496 | color: var(--color-prettylights-syntax-variable); 497 | } 498 | 499 | .markdown-body .pl-bu { 500 | color: var(--color-prettylights-syntax-brackethighlighter-unmatched); 501 | } 502 | 503 | .markdown-body .pl-ii { 504 | color: var(--color-prettylights-syntax-invalid-illegal-text); 505 | background-color: var(--color-prettylights-syntax-invalid-illegal-bg); 506 | } 507 | 508 | .markdown-body .pl-c2 { 509 | color: var(--color-prettylights-syntax-carriage-return-text); 510 | background-color: var(--color-prettylights-syntax-carriage-return-bg); 511 | } 512 | 513 | .markdown-body .pl-sr .pl-cce { 514 | font-weight: bold; 515 | color: var(--color-prettylights-syntax-string-regexp); 516 | } 517 | 518 | .markdown-body .pl-ml { 519 | color: var(--color-prettylights-syntax-markup-list); 520 | } 521 | 522 | .markdown-body .pl-mh, 523 | .markdown-body .pl-mh .pl-en, 524 | .markdown-body .pl-ms { 525 | font-weight: bold; 526 | color: var(--color-prettylights-syntax-markup-heading); 527 | } 528 | 529 | .markdown-body .pl-mi { 530 | font-style: italic; 531 | color: var(--color-prettylights-syntax-markup-italic); 532 | } 533 | 534 | .markdown-body .pl-mb { 535 | font-weight: bold; 536 | color: var(--color-prettylights-syntax-markup-bold); 537 | } 538 | 539 | .markdown-body .pl-md { 540 | color: var(--color-prettylights-syntax-markup-deleted-text); 541 | background-color: var(--color-prettylights-syntax-markup-deleted-bg); 542 | } 543 | 544 | .markdown-body .pl-mi1 { 545 | color: var(--color-prettylights-syntax-markup-inserted-text); 546 | background-color: var(--color-prettylights-syntax-markup-inserted-bg); 547 | } 548 | 549 | .markdown-body .pl-mc { 550 | color: var(--color-prettylights-syntax-markup-changed-text); 551 | background-color: var(--color-prettylights-syntax-markup-changed-bg); 552 | } 553 | 554 | .markdown-body .pl-mi2 { 555 | color: var(--color-prettylights-syntax-markup-ignored-text); 556 | background-color: var(--color-prettylights-syntax-markup-ignored-bg); 557 | } 558 | 559 | .markdown-body .pl-mdr { 560 | font-weight: bold; 561 | color: var(--color-prettylights-syntax-meta-diff-range); 562 | } 563 | 564 | .markdown-body .pl-ba { 565 | color: var(--color-prettylights-syntax-brackethighlighter-angle); 566 | } 567 | 568 | .markdown-body .pl-sg { 569 | color: var(--color-prettylights-syntax-sublimelinter-gutter-mark); 570 | } 571 | 572 | .markdown-body .pl-corl { 573 | text-decoration: underline; 574 | color: var(--color-prettylights-syntax-constant-other-reference-link); 575 | } 576 | 577 | .markdown-body [data-catalyst] { 578 | display: block; 579 | } 580 | 581 | .markdown-body g-emoji { 582 | font-family: "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; 583 | font-size: 1em; 584 | font-style: normal !important; 585 | font-weight: 400; 586 | line-height: 1; 587 | vertical-align: -0.075em; 588 | } 589 | 590 | .markdown-body g-emoji img { 591 | width: 1em; 592 | height: 1em; 593 | } 594 | 595 | .markdown-body::before { 596 | display: table; 597 | content: ""; 598 | } 599 | 600 | .markdown-body::after { 601 | display: table; 602 | clear: both; 603 | content: ""; 604 | } 605 | 606 | .markdown-body>*:first-child { 607 | margin-top: 0 !important; 608 | } 609 | 610 | .markdown-body>*:last-child { 611 | margin-bottom: 0 !important; 612 | } 613 | 614 | .markdown-body a:not([href]) { 615 | color: inherit; 616 | text-decoration: none; 617 | } 618 | 619 | .markdown-body .absent { 620 | color: var(--color-danger-fg); 621 | } 622 | 623 | .markdown-body .anchor { 624 | float: left; 625 | padding-right: 4px; 626 | margin-left: -20px; 627 | line-height: 1; 628 | } 629 | 630 | .markdown-body .anchor:focus { 631 | outline: none; 632 | } 633 | 634 | .markdown-body p, 635 | .markdown-body blockquote, 636 | .markdown-body ul, 637 | .markdown-body ol, 638 | .markdown-body dl, 639 | .markdown-body table, 640 | .markdown-body pre, 641 | .markdown-body details { 642 | margin-top: 0; 643 | margin-bottom: 16px; 644 | } 645 | 646 | .markdown-body blockquote>:first-child { 647 | margin-top: 0; 648 | } 649 | 650 | .markdown-body blockquote>:last-child { 651 | margin-bottom: 0; 652 | } 653 | 654 | .markdown-body sup>a::before { 655 | content: "["; 656 | } 657 | 658 | .markdown-body sup>a::after { 659 | content: "]"; 660 | } 661 | 662 | .markdown-body h1 .octicon-link, 663 | .markdown-body h2 .octicon-link, 664 | .markdown-body h3 .octicon-link, 665 | .markdown-body h4 .octicon-link, 666 | .markdown-body h5 .octicon-link, 667 | .markdown-body h6 .octicon-link { 668 | color: var(--color-fg-default); 669 | vertical-align: middle; 670 | visibility: hidden; 671 | } 672 | 673 | .markdown-body h1:hover .anchor, 674 | .markdown-body h2:hover .anchor, 675 | .markdown-body h3:hover .anchor, 676 | .markdown-body h4:hover .anchor, 677 | .markdown-body h5:hover .anchor, 678 | .markdown-body h6:hover .anchor { 679 | text-decoration: none; 680 | } 681 | 682 | .markdown-body h1:hover .anchor .octicon-link, 683 | .markdown-body h2:hover .anchor .octicon-link, 684 | .markdown-body h3:hover .anchor .octicon-link, 685 | .markdown-body h4:hover .anchor .octicon-link, 686 | .markdown-body h5:hover .anchor .octicon-link, 687 | .markdown-body h6:hover .anchor .octicon-link { 688 | visibility: visible; 689 | } 690 | 691 | .markdown-body h1 tt, 692 | .markdown-body h1 code, 693 | .markdown-body h2 tt, 694 | .markdown-body h2 code, 695 | .markdown-body h3 tt, 696 | .markdown-body h3 code, 697 | .markdown-body h4 tt, 698 | .markdown-body h4 code, 699 | .markdown-body h5 tt, 700 | .markdown-body h5 code, 701 | .markdown-body h6 tt, 702 | .markdown-body h6 code { 703 | padding: 0 .2em; 704 | font-size: inherit; 705 | } 706 | 707 | .markdown-body ul.no-list, 708 | .markdown-body ol.no-list { 709 | padding: 0; 710 | list-style-type: none; 711 | } 712 | 713 | .markdown-body ol[type="1"] { 714 | list-style-type: decimal; 715 | } 716 | 717 | .markdown-body ol[type=a] { 718 | list-style-type: lower-alpha; 719 | } 720 | 721 | .markdown-body ol[type=i] { 722 | list-style-type: lower-roman; 723 | } 724 | 725 | .markdown-body div>ol:not([type]) { 726 | list-style-type: decimal; 727 | } 728 | 729 | .markdown-body ul ul, 730 | .markdown-body ul ol, 731 | .markdown-body ol ol, 732 | .markdown-body ol ul { 733 | margin-top: 0; 734 | margin-bottom: 0; 735 | } 736 | 737 | .markdown-body li>p { 738 | margin-top: 16px; 739 | } 740 | 741 | .markdown-body li+li { 742 | margin-top: .25em; 743 | } 744 | 745 | .markdown-body dl { 746 | padding: 0; 747 | } 748 | 749 | .markdown-body dl dt { 750 | padding: 0; 751 | margin-top: 16px; 752 | font-size: 1em; 753 | font-style: italic; 754 | font-weight: 600; 755 | } 756 | 757 | .markdown-body dl dd { 758 | padding: 0 16px; 759 | margin-bottom: 16px; 760 | } 761 | 762 | .markdown-body table th { 763 | font-weight: 600; 764 | } 765 | 766 | .markdown-body table th, 767 | .markdown-body table td { 768 | padding: 6px 13px; 769 | border: 1px solid var(--color-border-default); 770 | } 771 | 772 | .markdown-body table tr { 773 | background-color: var(--color-canvas-default); 774 | border-top: 1px solid var(--color-border-muted); 775 | } 776 | 777 | .markdown-body table tr:nth-child(2n) { 778 | background-color: var(--color-canvas-subtle); 779 | } 780 | 781 | .markdown-body table img { 782 | background-color: transparent; 783 | } 784 | 785 | .markdown-body img[align=right] { 786 | padding-left: 20px; 787 | } 788 | 789 | .markdown-body img[align=left] { 790 | padding-right: 20px; 791 | } 792 | 793 | .markdown-body .emoji { 794 | max-width: none; 795 | vertical-align: text-top; 796 | background-color: transparent; 797 | } 798 | 799 | .markdown-body span.frame { 800 | display: block; 801 | overflow: hidden; 802 | } 803 | 804 | .markdown-body span.frame>span { 805 | display: block; 806 | float: left; 807 | width: auto; 808 | padding: 7px; 809 | margin: 13px 0 0; 810 | overflow: hidden; 811 | border: 1px solid var(--color-border-default); 812 | } 813 | 814 | .markdown-body span.frame span img { 815 | display: block; 816 | float: left; 817 | } 818 | 819 | .markdown-body span.frame span span { 820 | display: block; 821 | padding: 5px 0 0; 822 | clear: both; 823 | color: var(--color-fg-default); 824 | } 825 | 826 | .markdown-body span.align-center { 827 | display: block; 828 | overflow: hidden; 829 | clear: both; 830 | } 831 | 832 | .markdown-body span.align-center>span { 833 | display: block; 834 | margin: 13px auto 0; 835 | overflow: hidden; 836 | text-align: center; 837 | } 838 | 839 | .markdown-body span.align-center span img { 840 | margin: 0 auto; 841 | text-align: center; 842 | } 843 | 844 | .markdown-body span.align-right { 845 | display: block; 846 | overflow: hidden; 847 | clear: both; 848 | } 849 | 850 | .markdown-body span.align-right>span { 851 | display: block; 852 | margin: 13px 0 0; 853 | overflow: hidden; 854 | text-align: right; 855 | } 856 | 857 | .markdown-body span.align-right span img { 858 | margin: 0; 859 | text-align: right; 860 | } 861 | 862 | .markdown-body span.float-left { 863 | display: block; 864 | float: left; 865 | margin-right: 13px; 866 | overflow: hidden; 867 | } 868 | 869 | .markdown-body span.float-left span { 870 | margin: 13px 0 0; 871 | } 872 | 873 | .markdown-body span.float-right { 874 | display: block; 875 | float: right; 876 | margin-left: 13px; 877 | overflow: hidden; 878 | } 879 | 880 | .markdown-body span.float-right>span { 881 | display: block; 882 | margin: 13px auto 0; 883 | overflow: hidden; 884 | text-align: right; 885 | } 886 | 887 | .markdown-body code, 888 | .markdown-body tt { 889 | padding: .2em .4em; 890 | margin: 0; 891 | font-size: 85%; 892 | background-color: var(--color-neutral-muted); 893 | border-radius: 6px; 894 | } 895 | 896 | .markdown-body code br, 897 | .markdown-body tt br { 898 | display: none; 899 | } 900 | 901 | .markdown-body del code { 902 | text-decoration: inherit; 903 | } 904 | 905 | .markdown-body pre code { 906 | font-size: 100%; 907 | } 908 | 909 | .markdown-body pre>code { 910 | padding: 0; 911 | margin: 0; 912 | word-break: normal; 913 | white-space: pre; 914 | background: transparent; 915 | border: 0; 916 | } 917 | 918 | .markdown-body .highlight { 919 | margin-bottom: 16px; 920 | } 921 | 922 | .markdown-body .highlight pre { 923 | margin-bottom: 0; 924 | word-break: normal; 925 | } 926 | 927 | .markdown-body .highlight pre, 928 | .markdown-body pre { 929 | padding: 16px; 930 | overflow: auto; 931 | font-size: 85%; 932 | line-height: 1.45; 933 | background-color: var(--color-canvas-subtle); 934 | border-radius: 6px; 935 | } 936 | 937 | .markdown-body pre code, 938 | .markdown-body pre tt { 939 | display: inline; 940 | max-width: auto; 941 | padding: 0; 942 | margin: 0; 943 | overflow: visible; 944 | line-height: inherit; 945 | word-wrap: normal; 946 | background-color: transparent; 947 | border: 0; 948 | } 949 | 950 | .markdown-body .csv-data td, 951 | .markdown-body .csv-data th { 952 | padding: 5px; 953 | overflow: hidden; 954 | font-size: 12px; 955 | line-height: 1; 956 | text-align: left; 957 | white-space: nowrap; 958 | } 959 | 960 | .markdown-body .csv-data .blob-num { 961 | padding: 10px 8px 9px; 962 | text-align: right; 963 | background: var(--color-canvas-default); 964 | border: 0; 965 | } 966 | 967 | .markdown-body .csv-data tr { 968 | border-top: 0; 969 | } 970 | 971 | .markdown-body .csv-data th { 972 | font-weight: 600; 973 | background: var(--color-canvas-subtle); 974 | border-top: 0; 975 | } 976 | 977 | .markdown-body .footnotes { 978 | font-size: 12px; 979 | color: var(--color-fg-muted); 980 | border-top: 1px solid var(--color-border-default); 981 | } 982 | 983 | .markdown-body .footnotes ol { 984 | padding-left: 16px; 985 | } 986 | 987 | .markdown-body .footnotes li { 988 | position: relative; 989 | } 990 | 991 | .markdown-body .footnotes li:target::before { 992 | position: absolute; 993 | top: -8px; 994 | right: -8px; 995 | bottom: -8px; 996 | left: -24px; 997 | pointer-events: none; 998 | content: ""; 999 | border: 2px solid var(--color-accent-emphasis); 1000 | border-radius: 6px; 1001 | } 1002 | 1003 | .markdown-body .footnotes li:target { 1004 | color: var(--color-fg-default); 1005 | } 1006 | 1007 | .markdown-body .footnotes .data-footnote-backref g-emoji { 1008 | font-family: monospace; 1009 | } 1010 | 1011 | .markdown-body .task-list-item { 1012 | list-style-type: none; 1013 | } 1014 | 1015 | .markdown-body .task-list-item label { 1016 | font-weight: 400; 1017 | } 1018 | 1019 | .markdown-body .task-list-item.enabled label { 1020 | cursor: pointer; 1021 | } 1022 | 1023 | .markdown-body .task-list-item+.task-list-item { 1024 | margin-top: 3px; 1025 | } 1026 | 1027 | .markdown-body .task-list-item .handle { 1028 | display: none; 1029 | } 1030 | 1031 | .markdown-body .task-list-item-checkbox { 1032 | margin: 0 .2em .25em -1.6em; 1033 | vertical-align: middle; 1034 | } 1035 | 1036 | .markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox { 1037 | margin: 0 -1.6em .25em .2em; 1038 | } 1039 | 1040 | .markdown-body ::-webkit-calendar-picker-indicator { 1041 | filter: invert(50%); 1042 | } 1043 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Open in IIIF Viewer 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |

Open in IIIF Viewer

20 |

A Firefox/Chrome extension to open IIIF manifest link in your favorite IIIF viewer.

21 |

(This browser extension is formerly named “Open IIIF Manifest Link in Favorite Viewer.”)

22 |

Install

23 |

v0.1.13 (2022-07-10: For details, see the GitHub repo.)

24 | 41 |

Usage

42 |

When the web page you are browsing contains a link to a IIIF manifest, by clicking on the toolbar button of this extension, you can open the link in the IIIF viewer specified on the options page.

43 |

screenshot_toolbar

44 |

By right-clicking on a link to the IIIF manifest, a context menu item “Open link in IIIF viewer” appears, which allows you to open the link in your preferred IIIF viewer.

45 |

screenshot_contextmenu

46 |

Options

47 |

On the options page, set the URL field depending on the particular IIIF viewer you want to use.

48 |

Note that IIIF viewers hosted on HTTPS servers cannot display IIIF manifests hosted on HTTP servers.

49 |

For example:

50 | 87 |

screenshot_options

88 |

Also, you can set a more complex pattern containing placeholders {manifest_URI} and {canvas_URI}.

89 |

For example:

90 | 107 |

Notes

108 |

On some web pages, the extension cannot recognize links to IIIF manifests or may misrecognize links to non-IIIF manifests.

109 |

This uncertainty is reduced if the IIIF community specifies (or recommends) the machine-readable patterns for a link to a IIIF manifest. See a proposal.

110 |

The brief list of IIIF websites on which the extension works or not is as follows.

111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 126 | 127 | 128 | 129 | 130 | 133 | 134 | 135 | 136 | 137 | 140 | 141 | 142 | 143 | 144 | 147 | 148 | 149 | 150 | 151 | 154 | 155 | 156 | 157 | 158 | 161 | 162 | 163 | 164 | 165 | 168 | 169 | 170 | 171 | 172 | 175 | 176 | 177 | 178 | 179 | 182 | 183 | 184 | 185 | 186 | 189 | 190 | 191 | 192 | 193 | 196 | 197 | 198 | 199 | 200 | 203 | 204 | 205 | 206 | 207 | 210 | 211 | 212 | 213 | 214 | 217 | 218 | 219 | 220 | 221 | 224 | 225 | 226 | 227 | 228 | 231 | 232 | 233 | 234 | 235 | 238 | 239 | 240 | 241 | 242 | 245 | 246 | 247 |
WebsiteWorks?Example
BiblissimaYes 124 | test 125 |
Bodleian LibrariesYes14 131 | test 132 |
Cambridge University LibraryYes 138 | test 139 |
Digital Vatican LibraryYes 145 | test 146 |
e-codicesYes 152 | test 153 |
EuropeanaYes3 159 | test 160 |
GallicaYes3 166 | test 167 |
Harvard Art MuseumsYes 173 | test 174 |
Heidelberg University LibraryYes 180 | test 181 |
Internet ArchiveYes3 187 | test 188 |
J. Paul Getty MuseumYes 194 | test 195 |
Qatar Digital LibraryYes 201 | test 202 |
Stanford LibrariesYes/Yes 208 | test/test 209 |
UCLA LibraryYes 215 | test 216 |
University of Illinois at Urbana-Champaign LibraryYes 222 | test 223 |
Wellcome LibraryYes4 229 | test 230 |
World Digital LibraryYes 236 | test 237 |
Yale Center for British ArtYes 243 | test 244 |
248 |

(more...)

249 |

IIIF Websites in Japan

250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 265 | 266 | 267 | 268 | 269 | 272 | 273 | 274 | 275 | 276 | 279 | 280 | 281 | 282 | 283 | 286 | 287 | 288 | 289 | 290 | 293 | 294 | 295 | 296 | 297 | 300 | 301 | 302 | 303 | 304 | 307 | 308 | 309 | 310 | 311 | 314 | 315 | 316 | 317 | 318 | 321 | 322 | 323 |
WebsiteWorks?Example
National Diet Library Digital Collections (NDL)Yes 263 | test 264 |
Database of Pre-modern Japanese Text (CODH)Yes 270 | test 271 |
Database of Pre-Modern Japanese Works (NIJL)Yes 277 | test 278 |
Collection for Study of the Japanese Language History (NINJAL)Yes2 284 | test 285 |
Digital Collections of Keio University LibrariesYes 291 | test 292 |
Kyoto University Rare Materials Digital ArchiveYes 298 | test 299 |
University of Tokyo Library SystemYes 305 | test 306 |
Shimane University Library Digital Archive CollectionYes 312 | test 313 |
Kyushu University CollectionsYes 319 | test 320 |
324 |

(more...)

325 |

1: Though the tooltip of the toolbar button is not updated in real-time, clicking on the button will open the correct manifest.

326 |

2: Use a context menu item “Open link in IIIF viewer” as needed.

327 |

3: Ad-hoc support.

328 |

4: It used to work, but as of July 2022, it no longer works due to changes on the site.

329 |

Author

330 |

@2SC1815J

331 |
332 | 333 | -------------------------------------------------------------------------------- /docs/open_in_iiif_viewer.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2SC1815J/open-in-iiif-viewer/d50b0d677f89d513f98bff5cf8b918ecfa68c3fc/docs/open_in_iiif_viewer.xpi -------------------------------------------------------------------------------- /docs/updates.json: -------------------------------------------------------------------------------- 1 | { 2 | "addons": { 3 | "openiiifmanifestlink@example.com": { 4 | "updates": [ 5 | { 6 | "version": "0.1.13", 7 | "update_link": "https://2sc1815j.net/open-in-iiif-viewer/open_in_iiif_viewer.xpi" 8 | } 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/background.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Open in IIIF Viewer 3 | * https://github.com/2sc1815j/open-in-iiif-viewer 4 | * 5 | * Copyright 2017 2SC1815J 6 | * Released under the MIT license 7 | */ 8 | (function() { 9 | 'use strict'; 10 | 11 | let timeoutHandle = null; 12 | 13 | // ref. 14 | // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/sendMessage 15 | // https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses 16 | // Code samples added on or after August 20, 2010 are in the public domain. 17 | 18 | function sendMessageToActiveTab(message, function_) { 19 | browser.tabs.query({ 20 | currentWindow: true, 21 | active: true 22 | }).then(tabs => { 23 | for (let tab of tabs) { 24 | browser.tabs.sendMessage( 25 | tab.id, 26 | message 27 | ).then(response => { 28 | function_(response.url); 29 | }).catch(onError); 30 | } 31 | }).catch(onError); 32 | } 33 | 34 | function onError() { 35 | browserActionButtonOff(); 36 | } 37 | 38 | function encodeURIComponentForQuery(str) { 39 | // This function is taken from 'IIIF Curation Viewer' released under the MIT license, 40 | // Copyright 2016 Center for Open Data in the Humanities, Research Organization of Information and Systems 41 | var result = encodeURIComponent(str).replace(/%(?:3A|2F|2C)/g, function(c) { 42 | return decodeURIComponent(c); 43 | }); 44 | return result; 45 | } 46 | 47 | function openInViewer(url) { 48 | if (url && url.manifest) { 49 | const openInBaseUrlWithoutPlaceholderDefault = 'http://codh.rois.ac.jp/software/iiif-curation-viewer/demo/?manifest='; 50 | browser.storage.sync.get({ 51 | openInBaseUrl: openInBaseUrlWithoutPlaceholderDefault 52 | }).then(options => { 53 | var viewerUrl; 54 | const placeholderManifest = '{manifest_URI}'; 55 | const placeholderCanvas = '{canvas_URI}'; 56 | var manifestUrl = encodeURIComponentForQuery(url.manifest); 57 | var canvasUrl; 58 | if (url.canvas) { 59 | canvasUrl = encodeURIComponentForQuery(url.canvas); 60 | } 61 | if (options.openInBaseUrl.indexOf(placeholderManifest) !== -1) { 62 | //Placeholder format (v0.1.9-) 63 | //eg. 'http://codh.rois.ac.jp/software/iiif-curation-viewer/demo/?manifest={manifest_URI}&canvas={canvas_URI}' 64 | viewerUrl = options.openInBaseUrl.replace(placeholderManifest, manifestUrl); 65 | if (options.openInBaseUrl.indexOf(placeholderCanvas) !== -1) { 66 | viewerUrl = viewerUrl.replace(placeholderCanvas, canvasUrl ? canvasUrl : ''); 67 | } 68 | } else { 69 | //Append format (-v0.1.8) 70 | viewerUrl = options.openInBaseUrl + manifestUrl; 71 | if (canvasUrl && options.openInBaseUrl === openInBaseUrlWithoutPlaceholderDefault) { 72 | viewerUrl += '&canvas=' + canvasUrl; 73 | } 74 | } 75 | browser.tabs.create({ url: viewerUrl }); 76 | }); 77 | } 78 | } 79 | 80 | function openNewTab() { 81 | sendMessageToActiveTab({ message: 'getManifestUrl' }, openInViewer); 82 | } 83 | browser.browserAction.onClicked.addListener(openNewTab); 84 | 85 | // icons: 'Ligature Symbols' (by Kazuyuki Motoyama) under the SIL Open Font License. 86 | // http://kudakurage.com/ligature_symbols/ 87 | function browserActionButtonOff() { 88 | browser.browserAction.setTitle({ title: 'IIIF manifest not found' }); 89 | browser.browserAction.setIcon({ path: 'icon_off.svg' }); 90 | } 91 | function updateBrowserActionButton() { 92 | sendMessageToActiveTab({ message: 'getManifestUrl' }, url => { 93 | if (url && url.manifest) { 94 | stopTimer(); 95 | browser.browserAction.setTitle({ title: url.manifest }); 96 | browser.browserAction.setIcon({ path: 'icon.svg' }); 97 | } else { 98 | browserActionButtonOff(); 99 | } 100 | }); 101 | } 102 | function stopTimer() { 103 | if (timeoutHandle !== null) { 104 | clearTimeout(timeoutHandle); 105 | timeoutHandle = null; 106 | } 107 | } 108 | browserActionButtonOff(); //initial state 109 | browser.tabs.onUpdated.addListener((tabId, changeInfo) => { 110 | if (changeInfo && changeInfo.status === 'complete') { 111 | //check twice 112 | const delay = 1000; //ms 113 | const delay2 = 5000; //ms 114 | stopTimer(); 115 | timeoutHandle = setTimeout(() => { 116 | updateBrowserActionButton(); 117 | timeoutHandle = setTimeout(updateBrowserActionButton, delay2); 118 | }, delay); 119 | } 120 | }); 121 | browser.tabs.onActivated.addListener(updateBrowserActionButton); 122 | 123 | browser.contextMenus.create({ 124 | id: 'open-link-in-iiif-viewer', 125 | title: 'Open link in IIIF viewer', 126 | contexts: ['link'], 127 | targetUrlPatterns: ['*://*/*/manifest.json', '*://*/*/manifest', '*://*/*?manifest=*', '*://*/*&manifest=*'] 128 | }); 129 | browser.contextMenus.onClicked.addListener(info => { 130 | if (info.menuItemId === 'open-link-in-iiif-viewer') { 131 | if (info.linkUrl) { 132 | var manifestUrl = info.linkUrl; //linkUrl is an absolute URL 133 | var canvasUrl; 134 | if (manifestUrl.indexOf('?') !== -1) { 135 | try { 136 | var match = manifestUrl.match(/(?:&|\?)manifest=([^&]+?)(?:&|$)/); 137 | if (match) { 138 | var val = decodeURIComponent(match[1]); 139 | if (val) { 140 | manifestUrl = (new URL(val, info.linkUrl)).href; 141 | match = info.linkUrl.match(/(?:&|\?)canvas=([^&]+?)(?:&|$)/); 142 | if (match) { 143 | val = decodeURIComponent(match[1]); 144 | if (val) { 145 | canvasUrl = (new URL(val, info.linkUrl)).href; 146 | } 147 | } 148 | } 149 | } 150 | } catch(e) { 151 | // 152 | } 153 | } 154 | if (manifestUrl) { 155 | var url = {}; 156 | url.manifest = manifestUrl; 157 | url.canvas = canvasUrl; 158 | openInViewer(url); 159 | } 160 | } 161 | } 162 | }); 163 | })(); -------------------------------------------------------------------------------- /src/browser-polyfill.min.js: -------------------------------------------------------------------------------- 1 | // webextension-polyfill v.0.2.1 (https://github.com/mozilla/webextension-polyfill) 2 | /* This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | (function(a,b){if("function"==typeof define&&define.amd)define("webextension-polyfill",["module"],b);else if("undefined"!=typeof exports)b(module);else{var c={exports:{}};b(c),a.browser=c.exports}})(this,function(a){"use strict";if("undefined"==typeof browser){a.exports=(()=>{const c={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},export:{minArgs:0,maxArgs:0},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},getSubTree:{minArgs:1,maxArgs:1},import:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},setIcon:{minArgs:1,maxArgs:1}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{update:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0}}},downloads:{download:{minArgs:1,maxArgs:1},cancel:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:0,maxArgs:0},setIcon:{minArgs:1,maxArgs:1},show:{minArgs:0,maxArgs:0}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getBrowserInfo:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{create:{minArgs:1,maxArgs:1},captureVisibleTab:{minArgs:0,maxArgs:2},detectLanguage:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},query:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(0===Object.keys(c).length)throw new Error("api-metadata.json has not been included in browser-polyfill");class d extends WeakMap{constructor(o,p=void 0){super(p),this.createItem=o}get(o){return this.has(o)||this.set(o,this.createItem(o)),super.get(o)}}const e=o=>{return o&&"object"==typeof o&&"function"==typeof o.then},f=(o,p)=>{return(...q)=>{chrome.runtime.lastError?o.reject(chrome.runtime.lastError):p.singleCallbackArg||1===q.length?o.resolve(q[0]):o.resolve(q)}},g=(o,p)=>{const q=r=>1==r?"argument":"arguments";return function(s,...t){if(t.lengthp.maxArgs)throw new Error(`Expected at most ${p.maxArgs} ${q(p.maxArgs)} for ${o}(), got ${t.length}`);return new Promise((u,v)=>{s[o](...t,f({resolve:u,reject:v},p))})}},h=(o,p,q)=>{return new Proxy(p,{apply(r,s,t){return q.call(s,o,...t)}})};let i=Function.call.bind(Object.prototype.hasOwnProperty);const j=(o,p={},q={})=>{let r=Object.create(null),s={has(t,u){return u in t||u in r},get(t,u){if(u in r)return r[u];if(u in t){let w=t[u];if("function"==typeof w){if("function"==typeof p[u])w=h(t,t[u],p[u]);else if(i(q,u)){let x=g(u,q[u]);w=h(t,t[u],x)}else w=w.bind(t);}else if("object"==typeof w&&null!==w&&(i(p,u)||i(q,u)))w=j(w,p[u],q[u]);else return Object.defineProperty(r,u,{configurable:!0,enumerable:!0,get(){return t[u]},set(x){t[u]=x}}),w;return r[u]=w,w}},set(t,u,v){return u in r?r[u]=v:t[u]=v,!0},defineProperty(t,u,v){return Reflect.defineProperty(r,u,v)},deleteProperty(t,u){return Reflect.deleteProperty(r,u)}};return new Proxy(o,s)},l=new d(o=>{return"function"==typeof o?function(q,r,s){let t=o(q,r);return e(t)?(t.then(s,u=>{console.error(u),s(u)}),!0):void(void 0!==t&&s(t))}:o}),m={runtime:{onMessage:(o=>({addListener(p,q,...r){p.addListener(o.get(q),...r)},hasListener(p,q){return p.hasListener(o.get(q))},removeListener(p,q){p.removeListener(o.get(q))}}))(l)}},n=Object.assign({},chrome);return j(n,m,c)})()}else a.exports=browser}); -------------------------------------------------------------------------------- /src/content.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Open in IIIF Viewer 3 | * https://github.com/2sc1815j/open-in-iiif-viewer 4 | * 5 | * Copyright 2017 2SC1815J 6 | * Released under the MIT license 7 | */ 8 | (function() { 9 | 'use strict'; 10 | 11 | function getManifestUrl() { 12 | function getManifestUrlFromUrlPart(urlPart, href) { 13 | //urlPart must not be a full URL; href must be an absolute URL 14 | var manifestUrl; 15 | var canvasUrl; 16 | if (urlPart) { 17 | var params = new URLSearchParams(urlPart); 18 | //IIIF Drag and drop 19 | //http://zimeon.github.io/iiif-dragndrop/ 20 | var val = params.get('manifest'); 21 | if (val) { 22 | var baseUrl = href || location.href; 23 | manifestUrl = (new URL(val, baseUrl)).href; 24 | val = params.get('canvas'); 25 | if (val) { 26 | canvasUrl = (new URL(val, baseUrl)).href; 27 | } 28 | } else { 29 | //IIIF Content State API 30 | //https://iiif.io/api/content-state/1.0/ 31 | val = params.get('iiif-content'); 32 | if (val && val.startsWith('http')) { 33 | //This criterion does not work correctly with a relative URL. 34 | manifestUrl = val; 35 | } 36 | } 37 | } 38 | return manifestUrl ? { manifestUrl: manifestUrl, canvasUrl: canvasUrl } : null; 39 | } 40 | function getManifestUrlFromQueryParam(href) { 41 | if (href && href.indexOf('?') !== -1) { 42 | var url = new URL(href); 43 | return getManifestUrlFromUrlPart(url.search, url.href); 44 | } 45 | return null; 46 | } 47 | function getManifestUrlFromFragment(href) { 48 | if (href && href.indexOf('#') !== -1) { 49 | var url = new URL(href); 50 | return getManifestUrlFromUrlPart(url.hash.substring(1), url.href); 51 | } 52 | return null; 53 | } 54 | 55 | var manifestUrl; 56 | var canvasUrl; 57 | try { 58 | var links = document.links; 59 | var linksLen = links.length; 60 | var i; 61 | //Find a link to something like a IIIF Manifest URL heuristically.... 62 | //First priority 63 | for (i = 0; i < linksLen; i++) { 64 | if (/manifest\.json$/.test(links[i].pathname)) { 65 | manifestUrl = links[i].href; //href is an absolute URL 66 | break; 67 | } 68 | } 69 | //Second priority 70 | if (!manifestUrl) { 71 | for (i = 0; i < linksLen; i++) { 72 | if (/manifest$/.test(links[i].pathname)) { 73 | manifestUrl = links[i].href; //href is an absolute URL 74 | break; 75 | } 76 | } 77 | } 78 | if (!manifestUrl || manifestUrl.indexOf('?') !== -1) { 79 | var result; 80 | //Find a IIIF Manifest URL in query parameters. 81 | for (i = 0; i < linksLen; i++) { 82 | result = getManifestUrlFromQueryParam(links[i].href); 83 | if (result) { 84 | manifestUrl = result.manifestUrl; 85 | canvasUrl = result.canvasUrl; 86 | break; 87 | } 88 | } 89 | if (!manifestUrl) { 90 | result = getManifestUrlFromQueryParam(location.href); 91 | if (result) { 92 | manifestUrl = result.manifestUrl; 93 | canvasUrl = result.canvasUrl; 94 | } 95 | } 96 | if (!manifestUrl) { 97 | //Embedded Universal Viewer v2 98 | //https://github.com/UniversalViewer/universalviewer/wiki/Embedding 99 | var elements = document.getElementsByClassName('uv'); 100 | for (i = 0; i < elements.length; i++) { 101 | if (elements[i].dataset.uri) { 102 | manifestUrl = elements[i].dataset.uri; 103 | if (manifestUrl) { 104 | manifestUrl = (new URL(manifestUrl, location.href)).href; 105 | } 106 | break; 107 | } 108 | } 109 | } 110 | if (!manifestUrl) { 111 | //hope someday these ad-hoc codes will be unnecessary... 112 | //ref. https://github.com/2SC1815J/open-in-iiif-viewer/issues/1 113 | var match; 114 | if (location.hostname === 'gallica.bnf.fr') { 115 | //ad-hoc support for Gallica 116 | //http://api.bnf.fr/api-iiif-de-r%C3%A9cup%C3%A9ration-des-images-de-gallica 117 | //http://www.bnf.fr/fr/professionnels/issn_isbn_autres_numeros/a.ark.html 118 | //http://www.cdlib.org/uc3/naan_registry.txt 119 | match = location.pathname.match(/^\/ark:\/12148\/([a-z0-9]+)(?:\/|$)/); 120 | if (match) { 121 | //20180620: Gallica switched to HTTPS 122 | var identifier = 'ark:/12148/' + match[1]; 123 | manifestUrl = 'https://gallica.bnf.fr/iiif/' + identifier + '/manifest.json'; 124 | } 125 | } else if (location.hostname === 'www.europeana.eu') { 126 | //ad-hoc support for Europeana 127 | result = (function() { 128 | var iframes = document.getElementsByTagName('iframe'); 129 | for (var i = 0; i < iframes.length; i++) { 130 | if (iframes[i].src) { 131 | var url = new URL(iframes[i].src, location.href); 132 | if (/iiif/.test(url.pathname)) { 133 | var params = url.searchParams; 134 | var manifestUrl = params.get('uri'); 135 | if (manifestUrl) { 136 | manifestUrl = (new URL(manifestUrl, url.href)).href; 137 | return manifestUrl; 138 | } 139 | } 140 | } 141 | } 142 | return null; 143 | })(); 144 | if (result) { 145 | manifestUrl = result; 146 | } 147 | } else if (location.hostname === 'archive.org') { 148 | //ad-hoc support for Internet Archive 149 | //https://archive.readme.io/docs/ia-iiif-faqs 150 | //Some manifests cannot load images in a IIIF viewer. 151 | var mediatype = document.querySelector('meta[property="mediatype"]'); 152 | if (mediatype) { 153 | var mediaContent = mediatype.getAttribute('content'); 154 | if (mediaContent === 'texts' || mediaContent === 'image') { 155 | match = location.pathname.match(/^\/details\/([^/]+)(?:\/|$)/); 156 | if (match) { 157 | manifestUrl = 'https://iiif.archivelab.org/iiif/' + match[1] + '/manifest.json'; 158 | } 159 | } 160 | } 161 | } 162 | } 163 | if (!manifestUrl) { 164 | //Embedded Universal Viewer v4 165 | //https://codesandbox.io/s/uv-embed-example-wyus9 166 | //Find a IIIF Manifest URL from the fragment part of an iframe's src. 167 | var iframes = document.getElementsByTagName('iframe'); 168 | for (i = 0; i < iframes.length; i++) { 169 | if (iframes[i].src) { 170 | var iframeHref = (new URL(iframes[i].src, location.href)).href; 171 | result = getManifestUrlFromFragment(iframeHref) || getManifestUrlFromQueryParam(iframeHref); 172 | if (result) { 173 | manifestUrl = result.manifestUrl; 174 | canvasUrl = result.canvasUrl; 175 | break; 176 | } 177 | } 178 | } 179 | } 180 | } 181 | //Allow only http/https. 182 | if (manifestUrl && !/^https?:\/\//.test(manifestUrl)) { 183 | manifestUrl = undefined; 184 | } 185 | if (canvasUrl && !/^https?:\/\//.test(canvasUrl)) { 186 | canvasUrl = undefined; 187 | } 188 | } catch(e) { 189 | // 190 | } 191 | return { manifest: manifestUrl, canvas: canvasUrl }; 192 | } 193 | 194 | // https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/sendMessage 195 | // https://developer.mozilla.org/en-US/docs/MDN/About#Copyrights_and_licenses 196 | // Code samples added on or after August 20, 2010 are in the public domain. 197 | browser.runtime.onMessage.addListener(request => { 198 | if (request.message === 'getManifestUrl') { 199 | return Promise.resolve({ url: getManifestUrl() }); 200 | } 201 | }); 202 | })(); -------------------------------------------------------------------------------- /src/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/icon_off.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "name": "Open in IIIF Viewer", 4 | "version": "0.1.13", 5 | "description": "A Firefox/Chrome extension to open IIIF manifest link in your favorite IIIF viewer.", 6 | "author": "2SC1815J", 7 | "homepage_url": "https://github.com/2SC1815J/open-in-iiif-viewer", 8 | "applications": { 9 | "gecko": { 10 | "id": "openiiifmanifestlink@example.com", 11 | "update_url": "https://2sc1815j.net/open-in-iiif-viewer/updates.json" 12 | } 13 | }, 14 | "icons": { 15 | "48": "icon.svg", 16 | "96": "icon.svg" 17 | }, 18 | "permissions": [ 19 | "activeTab", 20 | "contextMenus", 21 | "storage" 22 | ], 23 | "background": { 24 | "scripts": [ 25 | "browser-polyfill.min.js", 26 | "background.js" 27 | ] 28 | }, 29 | "content_scripts": [ 30 | { 31 | "matches": [ 32 | "*://*/*", 33 | "file:///*" 34 | ], 35 | "js": [ 36 | "browser-polyfill.min.js", 37 | "content.js" 38 | ], 39 | "run_at": "document_end", 40 | "all_frames": false 41 | } 42 | ], 43 | "browser_action": { 44 | "default_icon": "icon.svg" 45 | }, 46 | "options_ui": { 47 | "page": "options.html", 48 | "chrome_style": true 49 | } 50 | } -------------------------------------------------------------------------------- /src/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Options 6 | 7 | 8 |
9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/options.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Open in IIIF Viewer 3 | * https://github.com/2sc1815j/open-in-iiif-viewer 4 | * 5 | * Copyright 2017 2SC1815J 6 | * Released under the MIT license 7 | */ 8 | (function() { 9 | 'use strict'; 10 | 11 | browser.storage.sync.get({ 12 | openInBaseUrl: 'http://codh.rois.ac.jp/software/iiif-curation-viewer/demo/?manifest=' 13 | }).then((options) => { 14 | const openInBaseUrlTextInput = document.getElementById('openInBaseUrl'); 15 | openInBaseUrlTextInput.value = options.openInBaseUrl; 16 | openInBaseUrlTextInput.addEventListener('input', () => { 17 | browser.storage.sync.set({ 18 | openInBaseUrl: openInBaseUrlTextInput.value 19 | }); 20 | }); 21 | }); 22 | })(); --------------------------------------------------------------------------------