├── dist └── .gitkeep ├── .prettierignore ├── tests ├── settings.json ├── bootstrap.js ├── promise-util.js └── background │ ├── errors-test.js │ ├── direct-link-query-test.js │ ├── detect-content-type-test.js │ ├── help-page-test.js │ ├── chrome-api-test.js │ ├── index-test.js │ └── uri-info-test.js ├── .prettierrc ├── .babelrc ├── images ├── opera.png ├── screenshot.png ├── google-chrome.ico └── mozilla-firefox.ico ├── src ├── images │ ├── icon128.png │ ├── icon16.png │ ├── icon48.png │ ├── browser-icon-active.png │ ├── browser-icon-active@2x.png │ ├── browser-icon-inactive.png │ └── browser-icon-inactive@2x.png ├── vendor │ └── pdfjs │ │ ├── web │ │ ├── cmaps │ │ │ ├── H.bcmap │ │ │ ├── V.bcmap │ │ │ ├── 78-H.bcmap │ │ │ ├── 78-V.bcmap │ │ │ ├── B5-H.bcmap │ │ │ ├── B5-V.bcmap │ │ │ ├── GB-H.bcmap │ │ │ ├── GB-V.bcmap │ │ │ ├── Add-H.bcmap │ │ │ ├── Add-V.bcmap │ │ │ ├── B5pc-H.bcmap │ │ │ ├── B5pc-V.bcmap │ │ │ ├── CNS1-H.bcmap │ │ │ ├── CNS1-V.bcmap │ │ │ ├── CNS2-H.bcmap │ │ │ ├── CNS2-V.bcmap │ │ │ ├── EUC-H.bcmap │ │ │ ├── EUC-V.bcmap │ │ │ ├── Ext-H.bcmap │ │ │ ├── Ext-V.bcmap │ │ │ ├── GBT-H.bcmap │ │ │ ├── GBT-V.bcmap │ │ │ ├── KSC-H.bcmap │ │ │ ├── KSC-V.bcmap │ │ │ ├── NWP-H.bcmap │ │ │ ├── NWP-V.bcmap │ │ │ ├── RKSJ-H.bcmap │ │ │ ├── RKSJ-V.bcmap │ │ │ ├── Roman.bcmap │ │ │ ├── 78-EUC-H.bcmap │ │ │ ├── 78-EUC-V.bcmap │ │ │ ├── 78-RKSJ-H.bcmap │ │ │ ├── 78-RKSJ-V.bcmap │ │ │ ├── CNS-EUC-H.bcmap │ │ │ ├── CNS-EUC-V.bcmap │ │ │ ├── ETHK-B5-H.bcmap │ │ │ ├── ETHK-B5-V.bcmap │ │ │ ├── ETen-B5-H.bcmap │ │ │ ├── ETen-B5-V.bcmap │ │ │ ├── GB-EUC-H.bcmap │ │ │ ├── GB-EUC-V.bcmap │ │ │ ├── GBK-EUC-H.bcmap │ │ │ ├── GBK-EUC-V.bcmap │ │ │ ├── GBK2K-H.bcmap │ │ │ ├── GBK2K-V.bcmap │ │ │ ├── GBT-EUC-H.bcmap │ │ │ ├── GBT-EUC-V.bcmap │ │ │ ├── Hankaku.bcmap │ │ │ ├── Hiragana.bcmap │ │ │ ├── KSC-EUC-H.bcmap │ │ │ ├── KSC-EUC-V.bcmap │ │ │ ├── Katakana.bcmap │ │ │ ├── WP-Symbol.bcmap │ │ │ ├── 78ms-RKSJ-H.bcmap │ │ │ ├── 78ms-RKSJ-V.bcmap │ │ │ ├── 83pv-RKSJ-H.bcmap │ │ │ ├── 90ms-RKSJ-H.bcmap │ │ │ ├── 90ms-RKSJ-V.bcmap │ │ │ ├── 90pv-RKSJ-H.bcmap │ │ │ ├── 90pv-RKSJ-V.bcmap │ │ │ ├── Add-RKSJ-H.bcmap │ │ │ ├── Add-RKSJ-V.bcmap │ │ │ ├── Adobe-GB1-0.bcmap │ │ │ ├── Adobe-GB1-1.bcmap │ │ │ ├── Adobe-GB1-2.bcmap │ │ │ ├── Adobe-GB1-3.bcmap │ │ │ ├── Adobe-GB1-4.bcmap │ │ │ ├── Adobe-GB1-5.bcmap │ │ │ ├── ETenms-B5-H.bcmap │ │ │ ├── ETenms-B5-V.bcmap │ │ │ ├── Ext-RKSJ-H.bcmap │ │ │ ├── Ext-RKSJ-V.bcmap │ │ │ ├── GBKp-EUC-H.bcmap │ │ │ ├── GBKp-EUC-V.bcmap │ │ │ ├── GBTpc-EUC-H.bcmap │ │ │ ├── GBTpc-EUC-V.bcmap │ │ │ ├── GBpc-EUC-H.bcmap │ │ │ ├── GBpc-EUC-V.bcmap │ │ │ ├── HKdla-B5-H.bcmap │ │ │ ├── HKdla-B5-V.bcmap │ │ │ ├── HKdlb-B5-H.bcmap │ │ │ ├── HKdlb-B5-V.bcmap │ │ │ ├── HKgccs-B5-H.bcmap │ │ │ ├── HKgccs-B5-V.bcmap │ │ │ ├── HKm314-B5-H.bcmap │ │ │ ├── HKm314-B5-V.bcmap │ │ │ ├── HKm471-B5-H.bcmap │ │ │ ├── HKm471-B5-V.bcmap │ │ │ ├── HKscs-B5-H.bcmap │ │ │ ├── HKscs-B5-V.bcmap │ │ │ ├── KSC-Johab-H.bcmap │ │ │ ├── KSC-Johab-V.bcmap │ │ │ ├── KSCms-UHC-H.bcmap │ │ │ ├── KSCms-UHC-V.bcmap │ │ │ ├── KSCpc-EUC-H.bcmap │ │ │ ├── KSCpc-EUC-V.bcmap │ │ │ ├── 90msp-RKSJ-H.bcmap │ │ │ ├── 90msp-RKSJ-V.bcmap │ │ │ ├── Adobe-CNS1-0.bcmap │ │ │ ├── Adobe-CNS1-1.bcmap │ │ │ ├── Adobe-CNS1-2.bcmap │ │ │ ├── Adobe-CNS1-3.bcmap │ │ │ ├── Adobe-CNS1-4.bcmap │ │ │ ├── Adobe-CNS1-5.bcmap │ │ │ ├── Adobe-CNS1-6.bcmap │ │ │ ├── Adobe-GB1-UCS2.bcmap │ │ │ ├── Adobe-Japan1-0.bcmap │ │ │ ├── Adobe-Japan1-1.bcmap │ │ │ ├── Adobe-Japan1-2.bcmap │ │ │ ├── Adobe-Japan1-3.bcmap │ │ │ ├── Adobe-Japan1-4.bcmap │ │ │ ├── Adobe-Japan1-5.bcmap │ │ │ ├── Adobe-Japan1-6.bcmap │ │ │ ├── Adobe-Korea1-0.bcmap │ │ │ ├── Adobe-Korea1-1.bcmap │ │ │ ├── Adobe-Korea1-2.bcmap │ │ │ ├── KSCms-UHC-HW-H.bcmap │ │ │ ├── KSCms-UHC-HW-V.bcmap │ │ │ ├── UniCNS-UCS2-H.bcmap │ │ │ ├── UniCNS-UCS2-V.bcmap │ │ │ ├── UniCNS-UTF16-H.bcmap │ │ │ ├── UniCNS-UTF16-V.bcmap │ │ │ ├── UniCNS-UTF32-H.bcmap │ │ │ ├── UniCNS-UTF32-V.bcmap │ │ │ ├── UniCNS-UTF8-H.bcmap │ │ │ ├── UniCNS-UTF8-V.bcmap │ │ │ ├── UniGB-UCS2-H.bcmap │ │ │ ├── UniGB-UCS2-V.bcmap │ │ │ ├── UniGB-UTF16-H.bcmap │ │ │ ├── UniGB-UTF16-V.bcmap │ │ │ ├── UniGB-UTF32-H.bcmap │ │ │ ├── UniGB-UTF32-V.bcmap │ │ │ ├── UniGB-UTF8-H.bcmap │ │ │ ├── UniGB-UTF8-V.bcmap │ │ │ ├── UniJIS-UCS2-H.bcmap │ │ │ ├── UniJIS-UCS2-V.bcmap │ │ │ ├── UniJIS-UTF16-H.bcmap │ │ │ ├── UniJIS-UTF16-V.bcmap │ │ │ ├── UniJIS-UTF32-H.bcmap │ │ │ ├── UniJIS-UTF32-V.bcmap │ │ │ ├── UniJIS-UTF8-H.bcmap │ │ │ ├── UniJIS-UTF8-V.bcmap │ │ │ ├── UniKS-UCS2-H.bcmap │ │ │ ├── UniKS-UCS2-V.bcmap │ │ │ ├── UniKS-UTF16-H.bcmap │ │ │ ├── UniKS-UTF16-V.bcmap │ │ │ ├── UniKS-UTF32-H.bcmap │ │ │ ├── UniKS-UTF32-V.bcmap │ │ │ ├── UniKS-UTF8-H.bcmap │ │ │ ├── UniKS-UTF8-V.bcmap │ │ │ ├── Adobe-CNS1-UCS2.bcmap │ │ │ ├── UniJIS-UCS2-HW-H.bcmap │ │ │ ├── UniJIS-UCS2-HW-V.bcmap │ │ │ ├── UniJISPro-UCS2-V.bcmap │ │ │ ├── UniJISPro-UTF8-V.bcmap │ │ │ ├── Adobe-Japan1-UCS2.bcmap │ │ │ ├── Adobe-Korea1-UCS2.bcmap │ │ │ ├── UniJIS2004-UTF16-H.bcmap │ │ │ ├── UniJIS2004-UTF16-V.bcmap │ │ │ ├── UniJIS2004-UTF32-H.bcmap │ │ │ ├── UniJIS2004-UTF32-V.bcmap │ │ │ ├── UniJIS2004-UTF8-H.bcmap │ │ │ ├── UniJIS2004-UTF8-V.bcmap │ │ │ ├── UniJISPro-UCS2-HW-V.bcmap │ │ │ ├── UniJISX0213-UTF32-H.bcmap │ │ │ ├── UniJISX0213-UTF32-V.bcmap │ │ │ ├── UniJISX02132004-UTF32-H.bcmap │ │ │ ├── UniJISX02132004-UTF32-V.bcmap │ │ │ └── LICENSE │ │ ├── images │ │ │ ├── shadow.png │ │ │ ├── treeitem-collapsed.svg │ │ │ ├── treeitem-expanded.svg │ │ │ ├── loading-icon.gif │ │ │ ├── toolbarButton-bookmark.svg │ │ │ ├── annotation-noicon.svg │ │ │ ├── secondaryToolbarButton-scrollPage.svg │ │ │ ├── secondaryToolbarButton-spreadNone.svg │ │ │ ├── secondaryToolbarButton-rotateCcw.svg │ │ │ ├── toolbarButton-menuArrow.svg │ │ │ ├── secondaryToolbarButton-firstPage.svg │ │ │ ├── secondaryToolbarButton-lastPage.svg │ │ │ ├── secondaryToolbarButton-scrollHorizontal.svg │ │ │ ├── secondaryToolbarButton-scrollVertical.svg │ │ │ ├── secondaryToolbarButton-handTool.svg │ │ │ ├── toolbarButton-viewAttachments.svg │ │ │ ├── toolbarButton-zoomOut.svg │ │ │ ├── toolbarButton-presentationMode.svg │ │ │ ├── toolbarButton-zoomIn.svg │ │ │ ├── findbarButton-next.svg │ │ │ ├── findbarButton-previous.svg │ │ │ ├── annotation-insert.svg │ │ │ ├── toolbarButton-search.svg │ │ │ ├── annotation-check.svg │ │ │ ├── toolbarButton-viewOutline.svg │ │ │ ├── annotation-newparagraph.svg │ │ │ ├── secondaryToolbarButton-scrollWrapped.svg │ │ │ ├── secondaryToolbarButton-selectTool.svg │ │ │ ├── toolbarButton-pageDown.svg │ │ │ ├── secondaryToolbarButton-rotateCw.svg │ │ │ ├── toolbarButton-pageUp.svg │ │ │ ├── toolbarButton-secondaryToolbarToggle.svg │ │ │ ├── toolbarButton-currentOutlineItem.svg │ │ │ ├── toolbarButton-print.svg │ │ │ ├── secondaryToolbarButton-documentProperties.svg │ │ │ ├── toolbarButton-download.svg │ │ │ ├── toolbarButton-viewThumbnail.svg │ │ │ ├── toolbarButton-sidebarToggle.svg │ │ │ ├── toolbarButton-openFile.svg │ │ │ ├── secondaryToolbarButton-spreadOdd.svg │ │ │ ├── toolbarButton-viewLayers.svg │ │ │ ├── annotation-comment.svg │ │ │ ├── secondaryToolbarButton-spreadEven.svg │ │ │ ├── annotation-paragraph.svg │ │ │ ├── annotation-note.svg │ │ │ ├── annotation-key.svg │ │ │ ├── loading.svg │ │ │ ├── loading-dark.svg │ │ │ └── annotation-help.svg │ │ ├── standard_fonts │ │ │ ├── FoxitSans.pfb │ │ │ ├── FoxitFixed.pfb │ │ │ ├── FoxitSerif.pfb │ │ │ ├── FoxitSymbol.pfb │ │ │ ├── FoxitDingbats.pfb │ │ │ ├── FoxitFixedBold.pfb │ │ │ ├── FoxitSansBold.pfb │ │ │ ├── FoxitSerifBold.pfb │ │ │ ├── FoxitFixedItalic.pfb │ │ │ ├── FoxitSansItalic.pfb │ │ │ ├── FoxitSerifItalic.pfb │ │ │ ├── FoxitSansBoldItalic.pfb │ │ │ ├── LiberationSans-Bold.ttf │ │ │ ├── FoxitFixedBoldItalic.pfb │ │ │ ├── FoxitSerifBoldItalic.pfb │ │ │ ├── LiberationSans-Italic.ttf │ │ │ ├── LiberationSans-Regular.ttf │ │ │ ├── LiberationSans-BoldItalic.ttf │ │ │ ├── LICENSE_FOXIT │ │ │ └── LICENSE_LIBERATION │ │ └── locale │ │ │ ├── scn │ │ │ └── viewer.properties │ │ │ ├── wo │ │ │ └── viewer.properties │ │ │ └── meh │ │ │ └── viewer.properties │ │ └── HYPOTHESIS-README.md ├── sidebar-app.html.mustache ├── tsconfig.json ├── help │ ├── index.js │ └── index.html ├── options │ ├── options.js │ └── index.html ├── background │ ├── settings.ts │ ├── messages.ts │ ├── help-page.ts │ ├── direct-link-query.ts │ ├── uri-info.ts │ ├── errors.ts │ ├── index.ts │ ├── browser-action.ts │ └── detect-content-type.ts ├── unload-client.js ├── pdfjs-init.js └── manifest.json.mustache ├── .github ├── stale.yml ├── dependabot.yml └── workflows │ ├── update-client.yml │ ├── release.yml │ └── continuous-integration.yml ├── codecov.yml ├── .yarnrc.yml ├── settings ├── firefox-dev.json ├── chrome-dev.json ├── firefox-prod.json ├── firefox-staging.json ├── chrome-prod.json └── chrome-staging.json ├── .gitignore ├── rollup.config.js ├── tools ├── update-client ├── chrome-webstore-refresh-token ├── template-context-app.js ├── render-boot-template.js ├── settings.js ├── update-pdfjs └── deploy ├── vitest.config.js ├── gulpfile.js ├── eslint.config.js ├── LICENSE ├── docs ├── troubleshooting.md └── building.md ├── rollup-tests.config.js ├── package.json ├── README.md └── Makefile /dist/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .yalc/ 2 | .yarn/ 3 | build/ 4 | coverage/ 5 | src/vendor/ 6 | -------------------------------------------------------------------------------- /tests/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "apiUrl": "http://127.0.0.1:5000/api" 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-typescript", "@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /images/opera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/images/opera.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/images/screenshot.png -------------------------------------------------------------------------------- /src/images/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/images/icon128.png -------------------------------------------------------------------------------- /src/images/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/images/icon16.png -------------------------------------------------------------------------------- /src/images/icon48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/images/icon48.png -------------------------------------------------------------------------------- /images/google-chrome.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/images/google-chrome.ico -------------------------------------------------------------------------------- /images/mozilla-firefox.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/images/mozilla-firefox.ico -------------------------------------------------------------------------------- /src/images/browser-icon-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/images/browser-icon-active.png -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/V.bcmap -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Label to use when marking as stale 2 | staleLabel: stale 3 | # Limit to only `issues` or `pulls` 4 | only: pulls 5 | -------------------------------------------------------------------------------- /src/images/browser-icon-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/images/browser-icon-active@2x.png -------------------------------------------------------------------------------- /src/images/browser-icon-inactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/images/browser-icon-inactive.png -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/78-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/78-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/78-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/78-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GB-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GB-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GB-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GB-V.bcmap -------------------------------------------------------------------------------- /src/images/browser-icon-inactive@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/images/browser-icon-inactive@2x.png -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Add-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Add-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Add-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Add-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/B5pc-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/B5pc-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/B5pc-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/B5pc-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/CNS1-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/CNS1-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/CNS1-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/CNS1-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/CNS2-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/CNS2-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/CNS2-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/CNS2-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Ext-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Ext-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Ext-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Ext-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBT-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBT-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBT-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBT-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/NWP-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/NWP-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/NWP-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/NWP-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/RKSJ-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/RKSJ-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Roman.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Roman.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/images/shadow.png -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/treeitem-collapsed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/treeitem-expanded.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/HYPOTHESIS-README.md: -------------------------------------------------------------------------------- 1 | # Hypothesis README 2 | 3 | This is a build of the PDF.js viewer auto-generated by tools/update-pdfjs. 4 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/78-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/78-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/78-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/78-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/78-RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/78-RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/78-RKSJ-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/78-RKSJ-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/CNS-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/CNS-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/CNS-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/CNS-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/ETHK-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/ETHK-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/ETHK-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/ETHK-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/ETen-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/ETen-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/ETen-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/ETen-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GB-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GB-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GB-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GB-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBK-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBK-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBK-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBK-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBK2K-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBK2K-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBK2K-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBK2K-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBT-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBT-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBT-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBT-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Hankaku.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Hankaku.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Hiragana.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Hiragana.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSC-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSC-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSC-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSC-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Katakana.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Katakana.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/WP-Symbol.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/WP-Symbol.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/78ms-RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/78ms-RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/78ms-RKSJ-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/78ms-RKSJ-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/83pv-RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/83pv-RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/90ms-RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/90ms-RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/90ms-RKSJ-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/90ms-RKSJ-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/90pv-RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/90pv-RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/90pv-RKSJ-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/90pv-RKSJ-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Add-RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Add-RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Add-RKSJ-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Add-RKSJ-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-GB1-0.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-GB1-0.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-GB1-1.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-GB1-1.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-GB1-2.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-GB1-2.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-GB1-3.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-GB1-3.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-GB1-4.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-GB1-4.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-GB1-5.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-GB1-5.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/ETenms-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/ETenms-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/ETenms-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/ETenms-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Ext-RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Ext-RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Ext-RKSJ-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Ext-RKSJ-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBKp-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBKp-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBKp-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBKp-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBTpc-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBTpc-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBTpc-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBTpc-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBpc-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBpc-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/GBpc-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/GBpc-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKdla-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKdla-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKdla-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKdla-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKdlb-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKdlb-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKdlb-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKdlb-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKgccs-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKgccs-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKgccs-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKgccs-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKm314-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKm314-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKm314-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKm314-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKm471-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKm471-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKm471-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKm471-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKscs-B5-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKscs-B5-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/HKscs-B5-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/HKscs-B5-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSC-Johab-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSC-Johab-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSC-Johab-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSC-Johab-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSCms-UHC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSCms-UHC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSCms-UHC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSCms-UHC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSCpc-EUC-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSCpc-EUC-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSCpc-EUC-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSCpc-EUC-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/loading-icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/images/loading-icon.gif -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/90msp-RKSJ-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/90msp-RKSJ-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/90msp-RKSJ-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/90msp-RKSJ-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-CNS1-0.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-CNS1-0.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-CNS1-1.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-CNS1-1.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-CNS1-2.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-CNS1-2.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-CNS1-3.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-CNS1-3.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-CNS1-4.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-CNS1-4.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-CNS1-5.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-CNS1-5.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-CNS1-6.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-CNS1-6.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-GB1-UCS2.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-GB1-UCS2.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Japan1-0.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Japan1-0.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Japan1-1.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Japan1-1.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Japan1-2.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Japan1-2.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Japan1-3.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Japan1-3.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Japan1-4.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Japan1-4.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Japan1-5.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Japan1-5.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Japan1-6.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Japan1-6.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Korea1-0.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Korea1-0.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Korea1-1.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Korea1-1.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Korea1-2.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Korea1-2.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSCms-UHC-HW-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSCms-UHC-HW-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/KSCms-UHC-HW-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/KSCms-UHC-HW-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniCNS-UCS2-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniCNS-UCS2-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniCNS-UCS2-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniCNS-UCS2-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniCNS-UTF16-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniCNS-UTF16-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniCNS-UTF16-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniCNS-UTF16-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniCNS-UTF32-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniCNS-UTF32-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniCNS-UTF32-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniCNS-UTF32-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniCNS-UTF8-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniCNS-UTF8-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniCNS-UTF8-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniCNS-UTF8-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniGB-UCS2-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniGB-UCS2-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniGB-UCS2-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniGB-UCS2-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniGB-UTF16-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniGB-UTF16-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniGB-UTF16-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniGB-UTF16-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniGB-UTF32-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniGB-UTF32-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniGB-UTF32-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniGB-UTF32-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniGB-UTF8-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniGB-UTF8-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniGB-UTF8-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniGB-UTF8-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UCS2-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UCS2-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UCS2-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UCS2-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UTF16-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UTF16-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UTF16-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UTF16-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UTF32-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UTF32-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UTF32-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UTF32-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UTF8-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UTF8-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UTF8-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UTF8-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniKS-UCS2-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniKS-UCS2-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniKS-UCS2-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniKS-UCS2-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniKS-UTF16-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniKS-UTF16-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniKS-UTF16-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniKS-UTF16-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniKS-UTF32-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniKS-UTF32-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniKS-UTF32-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniKS-UTF32-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniKS-UTF8-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniKS-UTF8-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniKS-UTF8-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniKS-UTF8-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-CNS1-UCS2.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-CNS1-UCS2.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UCS2-HW-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UCS2-HW-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS-UCS2-HW-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS-UCS2-HW-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJISPro-UCS2-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJISPro-UCS2-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJISPro-UTF8-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJISPro-UTF8-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSans.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSans.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Japan1-UCS2.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Japan1-UCS2.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/Adobe-Korea1-UCS2.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/Adobe-Korea1-UCS2.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF16-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF16-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF16-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF16-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF32-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF32-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF32-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF32-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF8-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF8-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF8-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJIS2004-UTF8-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJISPro-UCS2-HW-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJISPro-UCS2-HW-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJISX0213-UTF32-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJISX0213-UTF32-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJISX0213-UTF32-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJISX0213-UTF32-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitFixed.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitFixed.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSerif.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSerif.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSymbol.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSymbol.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-bookmark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitDingbats.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitDingbats.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitFixedBold.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitFixedBold.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSansBold.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSansBold.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSerifBold.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSerifBold.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJISX02132004-UTF32-H.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJISX02132004-UTF32-H.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/UniJISX02132004-UTF32-V.bcmap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/cmaps/UniJISX02132004-UTF32-V.bcmap -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitFixedItalic.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitFixedItalic.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSansItalic.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSansItalic.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSerifItalic.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSerifItalic.pfb -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | # prevent spurious codecov errors resulting from tiny fluctuations 6 | threshold: 0.1% 7 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSansBoldItalic.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSansBoldItalic.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/LiberationSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/LiberationSans-Bold.ttf -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitFixedBoldItalic.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitFixedBoldItalic.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/FoxitSerifBoldItalic.pfb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/FoxitSerifBoldItalic.pfb -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/LiberationSans-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/LiberationSans-Italic.ttf -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/LiberationSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/LiberationSans-Regular.ttf -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/LiberationSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hypothesis/browser-extension/HEAD/src/vendor/pdfjs/web/standard_fonts/LiberationSans-BoldItalic.ttf -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | plugins: 4 | - path: .yarn/plugins/@yarnpkg/plugin-version.cjs 5 | spec: "@yarnpkg/plugin-version" 6 | 7 | yarnPath: .yarn/releases/yarn-3.6.1.cjs 8 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-noicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-scrollPage.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-spreadNone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-rotateCcw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /settings/firefox-dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildType": "dev", 3 | 4 | "apiUrl": "http://localhost:5000/api/", 5 | "authDomain": "localhost", 6 | "serviceUrl": "http://localhost:5000/", 7 | 8 | "browserIsFirefox": true, 9 | "appType": "firefox-extension" 10 | } 11 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-menuArrow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-firstPage.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-lastPage.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /settings/chrome-dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildType": "dev", 3 | 4 | "apiUrl": "http://localhost:5000/api/", 5 | "authDomain": "localhost", 6 | "bouncerUrl": "http://localhost:8000/", 7 | "serviceUrl": "http://localhost:5000/", 8 | 9 | "browserIsChrome": true, 10 | "appType": "chrome-extension" 11 | } 12 | -------------------------------------------------------------------------------- /tests/bootstrap.js: -------------------------------------------------------------------------------- 1 | import { assert } from 'chai'; 2 | import sinon from 'sinon'; 3 | 4 | // Expose the sinon assertions. 5 | sinon.assert.expose(assert, { prefix: null }); 6 | 7 | // Expose these globally 8 | globalThis.assert = assert; 9 | globalThis.sinon = sinon; 10 | globalThis.context ??= globalThis.describe; 11 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-scrollHorizontal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-scrollVertical.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-handTool.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sidebar-app.html.mustache: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-viewAttachments.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-zoomOut.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "checkJs": true, 5 | "lib": ["es2018", "dom"], 6 | "module": "commonjs", 7 | "noEmit": true, 8 | "strict": true, 9 | "target": "ES2020", 10 | "allowSyntheticDefaultImports": true, 11 | "resolveJsonModule": true 12 | }, 13 | "include": ["**/*.js", "**/*.ts", "../gulpfile.js"], 14 | "exclude": ["vendor/"] 15 | } 16 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-presentationMode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-zoomIn.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /tests/promise-util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Takes a Promise and returns a Promise 3 | * where Result = { result: T } | { error: any }. 4 | * 5 | * This is useful for testing that promises are rejected 6 | * as expected in tests. 7 | */ 8 | export function toResult(promise) { 9 | return promise 10 | .then(result => { 11 | return { result }; 12 | }) 13 | .catch(err => { 14 | return { error: err }; 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /settings/firefox-prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildType": "production", 3 | 4 | "apiUrl": "https://hypothes.is/api/", 5 | "authDomain": "hypothes.is", 6 | "bouncerUrl": "https://hyp.is/", 7 | "serviceUrl": "https://hypothes.is/", 8 | 9 | "oauthClientId": "7fb28342-7793-11e7-90b5-7fed4053f592", 10 | 11 | "sentryPublicDSN": "https://934d4f62912b47d8bb03c28ae6670cf8@app.getsentry.com/69811", 12 | 13 | "browserIsFirefox": true, 14 | "appType": "firefox-extension" 15 | } 16 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/findbarButton-next.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/findbarButton-previous.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-insert.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-search.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /settings/firefox-staging.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildType": "staging", 3 | 4 | "apiUrl": "https://staging.hypothes.is/api/", 5 | "authDomain": "hypothes.is", 6 | "bouncerUrl": "https://staging.hyp.is/", 7 | "serviceUrl": "https://staging.hypothes.is/", 8 | 9 | "oauthClientId": "92b42e3c-7793-11e7-8e17-cb2151436a1f", 10 | 11 | "sentryPublicDSN": "https://934d4f62912b47d8bb03c28ae6670cf8@app.getsentry.com/69811", 12 | 13 | "browserIsFirefox": true, 14 | "appType": "firefox-extension" 15 | } 16 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-check.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-viewOutline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-newparagraph.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-scrollWrapped.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-selectTool.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-pageDown.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-rotateCw.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | node_modules/ 4 | coverage/ 5 | 6 | .eslintcache 7 | 8 | # The client uses yarn rather than npm to manage the lockfile. 9 | package-lock.json 10 | 11 | # Local settings for dev and test 12 | settings/*custom*.json 13 | 14 | # See https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored. 15 | # This is the "If you're not using Zero-Installs" list. 16 | .pnp.* 17 | .yarn/* 18 | !.yarn/patches 19 | !.yarn/plugins 20 | !.yarn/releases 21 | !.yarn/sdks 22 | !.yarn/versions 23 | 24 | # TypeScript cache 25 | *.tsbuildinfo 26 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-pageUp.svg: -------------------------------------------------------------------------------- 1 | 4 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-secondaryToolbarToggle.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-currentOutlineItem.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-print.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-documentProperties.svg: -------------------------------------------------------------------------------- 1 | 4 | 6 | 8 | 9 | 11 | 12 | 14 | 15 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-download.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | time: "10:00" 8 | open-pull-requests-limit: 10 9 | groups: 10 | babel: 11 | patterns: 12 | - '@babel/*' 13 | eslint: 14 | patterns: 15 | - 'eslint*' 16 | - 'typescript-eslint' 17 | rollup: 18 | patterns: 19 | - 'rollup' 20 | - '@rollup/*' 21 | sentry: 22 | patterns: 23 | - '@sentry/*' 24 | typescript-types: 25 | patterns: 26 | - '@types/*' 27 | vitest: 28 | patterns: 29 | - 'vitest' 30 | - '@vitest/*' 31 | -------------------------------------------------------------------------------- /src/help/index.js: -------------------------------------------------------------------------------- 1 | // Detect the current OS and show approprite help. 2 | chrome.runtime.getPlatformInfo(info => { 3 | const opts = /** @type {NodeListOf} */ ( 4 | document.querySelectorAll('[data-extension-path]') 5 | ); 6 | opts.forEach(opt => { 7 | if (opt.dataset.extensionPath !== info.os) { 8 | opt.hidden = true; 9 | } 10 | }); 11 | }); 12 | 13 | const query = new URLSearchParams(window.location.search); 14 | const message = query.get('message'); 15 | 16 | if (message) { 17 | const errorTextEl = /** @type {HTMLElement} */ ( 18 | document.querySelector('.js-error-message') 19 | ); 20 | errorTextEl.textContent = message; 21 | } 22 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-viewThumbnail.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/options/options.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Return the checkbox that toggles whether badge requests are sent. 3 | */ 4 | function badgeCheckbox() { 5 | return /** @type {HTMLInputElement} */ (document.getElementById('badge')); 6 | } 7 | 8 | function saveOptions() { 9 | chrome.storage.sync.set({ 10 | badge: badgeCheckbox().checked, 11 | }); 12 | } 13 | 14 | function loadOptions() { 15 | chrome.storage.sync.get( 16 | { 17 | badge: true, 18 | }, 19 | items => { 20 | badgeCheckbox().checked = !!items.badge; 21 | }, 22 | ); 23 | } 24 | 25 | document.addEventListener('DOMContentLoaded', loadOptions); 26 | badgeCheckbox().addEventListener('click', saveOptions); 27 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-sidebarToggle.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-openFile.svg: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /settings/chrome-prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildType": "production", 3 | "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq7XsXE/uakq4aKMG5Smz2nc8VSaandriziGorxX08py3mTkab79GpWYu7j/hA3Yf7fkCLQnX8QoZGj7WdaMX6+b+eHxF7vYpOhEW/Bam7TOlb+5AVmL1KReG9PPTLz4dp+xA4WfK2dqFM+XN40FTbm2G/SNk3GRP3gQOxgy3ZKwIDAQAB", 4 | 5 | 6 | "apiUrl": "https://hypothes.is/api/", 7 | "authDomain": "hypothes.is", 8 | "bouncerUrl": "https://hyp.is/", 9 | "serviceUrl": "https://hypothes.is/", 10 | 11 | "oauthClientId": "fd23fe2e-7792-11e7-8e16-23e47a1799d4", 12 | 13 | "sentryPublicDSN": "https://934d4f62912b47d8bb03c28ae6670cf8@app.getsentry.com/69811", 14 | 15 | "browserIsChrome": true, 16 | "appType": "chrome-extension" 17 | } 18 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-spreadOdd.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/toolbarButton-viewLayers.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/background/settings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Incomplete type for settings in the `settings.json` file. 3 | * 4 | * This contains only the settings that the background script uses. Other 5 | * settings are used when generating the `manifest.json` file. 6 | */ 7 | export type Settings = { 8 | apiUrl: string; 9 | buildType: string; 10 | serviceUrl: string; 11 | }; 12 | 13 | // nb. This will error if the build has not been run yet. 14 | import rawSettings from '../../build/settings.json'; 15 | 16 | /** 17 | * Configuration data for the extension. 18 | */ 19 | const settings: Settings = { 20 | ...rawSettings, 21 | 22 | // Ensure API url does not end with '/' 23 | apiUrl: rawSettings.apiUrl.replace(/\/$/, ''), 24 | }; 25 | 26 | export default settings; 27 | -------------------------------------------------------------------------------- /src/unload-client.js: -------------------------------------------------------------------------------- 1 | // Script injected into the page to trigger removal of any existing instances 2 | // of the Hypothesis client. 3 | 4 | 'use strict'; 5 | 6 | // This wrapper function ensures that variables declared within `unloadClient` 7 | // are not visible to any scripts that are subsequently run by the JS extension. 8 | function unloadClient() { 9 | const annotatorLink = document.querySelector( 10 | 'link[type="application/annotator+html"]', 11 | ); 12 | 13 | if (annotatorLink) { 14 | // Dispatch a 'destroy' event which is handled by the code in 15 | // annotator/main.js to remove the client. 16 | const destroyEvent = new Event('destroy'); 17 | annotatorLink.dispatchEvent(destroyEvent); 18 | } 19 | } 20 | 21 | unloadClient(); 22 | -------------------------------------------------------------------------------- /src/options/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hypothesis Extension Settings 5 | 10 | 11 | 12 | 13 |
14 | 15 | 16 |

17 | By default, the extension button displays the number of annotations found 18 | on the pages you visit. Disable this if you find the badge distracting or 19 | if you do not wish the extension to make requests to the Hypothesis 20 | service for this data. 21 |

22 | 23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { babel } from '@rollup/plugin-babel'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import json from '@rollup/plugin-json'; 4 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 5 | 6 | export default { 7 | input: 'src/background/index.ts', 8 | output: { 9 | file: 'build/extension.bundle.js', 10 | format: 'iife', 11 | 12 | // Global variable used for entry point exports. This is not actually used, 13 | // but it suppresses a warning from Rollup about accessing exports of an 14 | // IIFE bundle. 15 | name: 'hypothesis', 16 | }, 17 | plugins: [ 18 | babel({ 19 | babelHelpers: 'bundled', 20 | exclude: 'node_modules/**', 21 | extensions: ['.js', '.ts'], 22 | }), 23 | nodeResolve({ extensions: ['.js', '.ts'] }), 24 | commonjs(), 25 | json(), 26 | ], 27 | }; 28 | -------------------------------------------------------------------------------- /.github/workflows/update-client.yml: -------------------------------------------------------------------------------- 1 | name: Update client 2 | on: 3 | workflow_dispatch: 4 | jobs: 5 | update-client: 6 | runs-on: ubuntu-latest 7 | outputs: 8 | ref: ${{ steps.update-client.outputs.ref }} 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v4 12 | - name: Cache the node_modules dir 13 | uses: actions/cache@v4 14 | with: 15 | path: node_modules 16 | key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock') }} 17 | - name: Install 18 | run: yarn install --immutable 19 | - name: Update client 20 | id: update-client 21 | run: | 22 | git config --global user.name "Hypothesis GitHub Actions" 23 | git config --global user.email "hypothesis@users.noreply.github.com" 24 | tools/update-client 25 | echo "ref=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT 26 | -------------------------------------------------------------------------------- /settings/chrome-staging.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildType": "staging", 3 | "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqjbEOhG+ZCl2Bl17m2ltNC+3uw0Fqv3Dzuja5vLnH1MLBRQG7L77pXtKCZgVgFJ2K+Kn0L0OqnMDcKEi5pUpNTi39b8twp1imDsoLO+L5XgpKYBtUgfR+T8OO2INjEgz0LDth0l26WmHNS377KZjSTsfPWNnLozXHHkETgug1lt9VzgcvSboiyZuwk23xHmiqnVpZtuqVAv4HdqFofHiNQn2fF7awsQxEYYNfuSk0Jp33XJkkadyrJ/dQ7vVFi0F0O//Oyaw3s4TD58frABxznusmKkjHZorJUrm2OaYbn/7TSUcG5fReQC08fXiMsFGUKxK01HfAwdmVUAmASL+NwIDAQAB", 4 | 5 | "apiUrl": "https://staging.hypothes.is/api/", 6 | "authDomain": "staging.hypothes.is", 7 | "bouncerUrl": "https://staging.hyp.is/", 8 | "serviceUrl": "https://staging.hypothes.is/", 9 | 10 | "oauthClientId": "ca0ef8b2-bc24-11ee-b317-433c505e7e42", 11 | 12 | "sentryPublicDSN": "https://934d4f62912b47d8bb03c28ae6670cf8@app.getsentry.com/69811", 13 | 14 | "browserIsChrome": true, 15 | "appType": "chrome-extension" 16 | } 17 | -------------------------------------------------------------------------------- /tools/update-client: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | CURRENT_BRANCH=$(git branch --show-current) 6 | 7 | if [ "$CURRENT_BRANCH" != "main" ]; then 8 | echo "This command should only be run on the main branch" 9 | exit 1 10 | fi 11 | 12 | # Update Hypothesis client and set the version of the extension to match the 13 | # client release. 14 | yarn add hypothesis --dev 15 | 16 | NEW_CLIENT_VERSION=$(node -p 'require("./package.json").devDependencies.hypothesis.match(/[0-9.]+/)[0]') 17 | TAG_NAME="v$NEW_CLIENT_VERSION" 18 | 19 | yarn version "$NEW_CLIENT_VERSION" 20 | git commit -a -m "Update Hypothesis client to $NEW_CLIENT_VERSION" 21 | git tag "$TAG_NAME" 22 | 23 | # Push the new commit to the source branch as well as the tag. Make the push 24 | # atomic so that both will fail if the source branch has been updated since 25 | # the current checkout. 26 | git push --atomic origin HEAD:main "$TAG_NAME" 27 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-comment.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /vitest.config.js: -------------------------------------------------------------------------------- 1 | import { SummaryReporter } from '@hypothesis/frontend-testing/vitest'; 2 | import { playwright } from '@vitest/browser-playwright'; 3 | import { defineConfig } from 'vitest/config'; 4 | import { excludeFromCoverage } from './rollup-tests.config.js'; 5 | 6 | export default defineConfig({ 7 | test: { 8 | globals: true, 9 | reporters: [new SummaryReporter()], 10 | 11 | browser: { 12 | provider: playwright(), 13 | enabled: true, 14 | headless: true, 15 | screenshotFailures: false, 16 | instances: [{ browser: 'chromium' }], 17 | viewport: { width: 1024, height: 768 }, 18 | }, 19 | 20 | include: [ 21 | // Test bundle 22 | './build/tests.bundle.js', 23 | ], 24 | 25 | coverage: { 26 | enabled: true, 27 | provider: 'istanbul', 28 | reportsDirectory: './coverage', 29 | reporter: ['json', 'html'], 30 | include: ['src/**/*.{ts,tsx}'], 31 | exclude: excludeFromCoverage, 32 | }, 33 | }, 34 | }); 35 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import { runTests } from '@hypothesis/frontend-build/tests'; 3 | 4 | import { spawn } from 'node:child_process'; 5 | 6 | import * as gulp from 'gulp'; 7 | 8 | function build(cb) { 9 | const make = spawn('make', ['build'], { stdio: 'inherit' }); 10 | make.on('close', code => { 11 | if (code !== 0) { 12 | cb(new Error(`make exited with status ${code}`)); 13 | } else { 14 | cb(null); 15 | } 16 | }); 17 | } 18 | 19 | function watchClient() { 20 | gulp.watch('node_modules/hypothesis', { events: 'all' }, build); 21 | } 22 | 23 | function watchSrc() { 24 | gulp.watch('src', { events: 'all' }, build); 25 | } 26 | 27 | export const watch = gulp.parallel(build, watchClient, watchSrc); 28 | 29 | // Unit and integration testing tasks. 30 | gulp.task('test', () => 31 | runTests({ 32 | bootstrapFile: 'tests/bootstrap.js', 33 | vitestConfig: 'vitest.config.js', 34 | rollupConfig: 'rollup-tests.config.js', 35 | testsPattern: 'tests/**/*-test.js', 36 | }), 37 | ); 38 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/secondaryToolbarButton-spreadEven.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-paragraph.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /tools/chrome-webstore-refresh-token: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | # This script is a helper for generating the refresh token used to automate 6 | # upload and publishing of Chrome extensions to the Chrome Web Store. 7 | # 8 | # 1. Read the guide at https://github.com/DrewML/chrome-webstore-upload/blob/master/How%20to%20generate%20Google%20API%20keys.md 9 | # 10 | # The Client ID and Client Secret can be found/generated under the 'Client 11 | # Chrome Extension' project in the 'hypothes.is' organization at 12 | # https://console.developers.google.com 13 | # 14 | # 2. After the step in the above guide that gives you an auth code in the 15 | # browser, run this script with the auth code to get a refresh token: 16 | # 17 | # ./tools/chrome-webstore-refresh-token $AUTH_CODE 18 | # 19 | # 3. Copy the 'refresh_token' value and update the corresponding environment 20 | # secrets in GitHub 21 | 22 | AUTH_CODE=$1 23 | 24 | if [ -z "$AUTH_CODE" ]; then 25 | echo "Auth code not specified." 26 | fi 27 | 28 | curl "https://accounts.google.com/o/oauth2/token" -d "client_id=$CHROME_WEBSTORE_CLIENT_ID&client_secret=$CHROME_WEBSTORE_CLIENT_SECRET&code=$AUTH_CODE&grant_type=authorization_code&redirect_uri=urn:ietf:wg:oauth:2.0:oob" 29 | 30 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-note.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 14 | 21 | 28 | 35 | 42 | 43 | -------------------------------------------------------------------------------- /tools/template-context-app.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Outputs a JSON object representing the appropriate template context for the 5 | * `app.html` file. 6 | */ 7 | 8 | import * as fs from 'node:fs'; 9 | import * as path from 'node:path'; 10 | 11 | function appSettings(settings) { 12 | const result = {}; 13 | result.apiUrl = settings.apiUrl; 14 | result.assetRoot = '/client/'; 15 | result.authDomain = settings.authDomain; 16 | result.serviceUrl = settings.serviceUrl; 17 | result.release = settings.version; 18 | result.appType = settings.appType || ''; 19 | 20 | if (settings.sentryPublicDSN) { 21 | result.raven = { 22 | dsn: settings.sentryPublicDSN, 23 | release: settings.version, 24 | }; 25 | } 26 | 27 | if (settings.oauthClientId) { 28 | result.oauthClientId = settings.oauthClientId; 29 | } 30 | 31 | return result; 32 | } 33 | 34 | if (process.argv.length !== 3) { 35 | console.error('Usage: %s ', path.basename(process.argv[1])); 36 | process.exit(1); 37 | } 38 | 39 | const settings = JSON.parse( 40 | fs.readFileSync(path.join(process.cwd(), process.argv[2])), 41 | ); 42 | 43 | console.log( 44 | JSON.stringify({ 45 | settings: JSON.stringify(appSettings(settings)), 46 | }), 47 | ); 48 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import hypothesisBase from 'eslint-config-hypothesis/base'; 2 | import hypothesisTS from 'eslint-config-hypothesis/ts'; 3 | import globals from 'globals'; 4 | import { globalIgnores, defineConfig } from 'eslint/config'; 5 | 6 | export default defineConfig( 7 | globalIgnores([ 8 | '.yalc/**/*', 9 | '.yarn/**/*', 10 | 'build/**/*', 11 | 'dist/**/*', 12 | '**/vendor/**/*.js', 13 | '**/coverage/**/*', 14 | 'docs/_build/*', 15 | // TODO - Lint these files 16 | 'rollup*.config.js', 17 | ]), 18 | 19 | hypothesisBase, 20 | hypothesisTS, 21 | 22 | { 23 | languageOptions: { 24 | globals: { 25 | chrome: false, 26 | }, 27 | }, 28 | }, 29 | 30 | // Entry points which get loaded as non-module scripts. 31 | { 32 | files: ['src/unload-client.js'], 33 | rules: { 34 | strict: ['error', 'global'], 35 | }, 36 | languageOptions: { 37 | parserOptions: { 38 | sourceType: 'script', 39 | }, 40 | }, 41 | }, 42 | 43 | // ESM scripts which run in Node 44 | { 45 | files: ['tools/*.js'], 46 | rules: { 47 | 'no-console': 'off', 48 | }, 49 | languageOptions: { 50 | globals: { 51 | ...globals.node, 52 | }, 53 | }, 54 | }, 55 | ); 56 | -------------------------------------------------------------------------------- /src/background/messages.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Activate the extension on the tab sending the message. 3 | * 4 | * The extension can optionally redirect the tab to a new URL first, and can 5 | * also configure the client to focus on a specific annotation or group. 6 | */ 7 | export type ActivateMessage = { 8 | type: 'activate'; 9 | 10 | /** URL to navigate tab to, before activating extension. */ 11 | url?: string; 12 | 13 | /** 14 | * Fragment indicating the annotations or groups that the client should 15 | * focus on after loading. 16 | * 17 | * The format of this is the same as the `#annotations:` and related fragments 18 | * understood by the client. 19 | */ 20 | query?: string; 21 | }; 22 | 23 | /** 24 | * Query whether the extension is installed and what features it supports. 25 | */ 26 | export type PingMessage = { 27 | type: 'ping'; 28 | 29 | /** 30 | * List of features to test for. 31 | * 32 | * If a feature is supported, it will be present in a `features` array 33 | * in the response. Note this field is missing from the response of older 34 | * extension versions. 35 | */ 36 | queryFeatures?: string[]; 37 | }; 38 | 39 | /** 40 | * Type of a request sent to the extension from an external website, 41 | * such as the bouncer (hyp.is) service. 42 | */ 43 | export type ExternalMessage = PingMessage | ActivateMessage; 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2020 Hypothes.is Project and contributors 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /tools/render-boot-template.js: -------------------------------------------------------------------------------- 1 | import { readFileSync, writeFileSync } from 'node:fs'; 2 | 3 | /** 4 | * Replace placeholders in the client's boot script with real URLs. 5 | * 6 | * Placeholders are single or double-quoted string literals of the form 7 | * `"__VARIABLE_NAME__"`. 8 | */ 9 | export function renderBootTemplate(src, dest) { 10 | const getURLCode = path => `chrome.runtime.getURL("${path}")`; 11 | 12 | const assetRoot = getURLCode('/client/'); 13 | const notebookAppUrl = getURLCode('/client/notebook.html'); 14 | const profileAppUrl = getURLCode('/client/profile.html'); 15 | const sidebarAppUrl = getURLCode('/client/app.html'); 16 | 17 | const replacements = { 18 | __ASSET_ROOT__: assetRoot, 19 | __NOTEBOOK_APP_URL__: notebookAppUrl, 20 | __PROFILE_APP_URL__: profileAppUrl, 21 | __SIDEBAR_APP_URL__: sidebarAppUrl, 22 | }; 23 | const template = readFileSync(src, { encoding: 'utf8' }); 24 | const bootScript = template.replaceAll( 25 | /"(__[A-Z_0-9]+__)"|'(__[A-Z_0-9]+__)'/g, 26 | (match, doubleQuoted, singleQuoted) => { 27 | const name = doubleQuoted || singleQuoted; 28 | if (!Object.hasOwn(replacements, name)) { 29 | throw new Error(`Unknown placeholder "${name}" in boot template`); 30 | } 31 | return replacements[name]; 32 | }, 33 | ); 34 | writeFileSync(dest, bootScript); 35 | } 36 | 37 | const src = process.argv[2]; 38 | const dest = process.argv[3]; 39 | renderBootTemplate(src, dest); 40 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-key.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/loading.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/background/help-page.ts: -------------------------------------------------------------------------------- 1 | import { chromeAPI } from './chrome-api'; 2 | import { 3 | BlockedSiteError, 4 | LocalFileError, 5 | NoFileAccessError, 6 | RestrictedProtocolError, 7 | } from './errors'; 8 | 9 | /** 10 | * A controller for displaying help pages. These are bound to extension 11 | * specific errors (found in errors.js) but can also be triggered manually. 12 | */ 13 | export class HelpPage { 14 | /** 15 | * Accepts an instance of errors.ExtensionError and displays an appropriate 16 | * help page if one exists. 17 | * 18 | * @param tab - The tab where the error occurred 19 | * @param error - The error to display, usually an instance of {@link ExtensionError} 20 | */ 21 | showHelpForError(tab: chrome.tabs.Tab, error: Error) { 22 | let section; 23 | if (error instanceof LocalFileError) { 24 | section = 'local-file'; 25 | } else if (error instanceof NoFileAccessError) { 26 | section = 'no-file-access'; 27 | } else if (error instanceof RestrictedProtocolError) { 28 | section = 'restricted-protocol'; 29 | } else if (error instanceof BlockedSiteError) { 30 | section = 'blocked-site'; 31 | } else { 32 | section = 'other-error'; 33 | } 34 | 35 | const url = new URL(chromeAPI.runtime.getURL('/help/index.html')); 36 | if (error) { 37 | url.searchParams.append('message', error.message); 38 | } 39 | url.hash = section; 40 | 41 | chromeAPI.tabs.create({ 42 | index: tab.index + 1, 43 | url: url.toString(), 44 | openerTabId: tab.id, 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | Troubleshooting 2 | --------------- 3 | 4 | Here are some errors you might encounter while developing the extension, and 5 | some explanations and solutions for them. 6 | 7 | ### Mixed Content errors in the console 8 | 9 | The extension fails to load and you see `Mixed Content` errors in the console. 10 | When using the extension on sites served over HTTPS, the extension must be 11 | configured to use a HTTPS `serviceUrl` in its settings file. 12 | 13 | ### Insecure Response errors in the console 14 | 15 | You've built the extension with an HTTPS `serviceUrl`, the extension fails to 16 | load and you see `net::ERR_INSECURE_RESPONSE` errors in the console. You need to 17 | open (or whatever `serviceUrl` you provided) and tell 18 | the browser to allow access to the site even though the certificate isn't known. 19 | 20 | ### Empty Response errors in the console 21 | 22 | The extension fails to load and you see `GET http://localhost:5000/... 23 | net::ERR_EMPTY_RESPONSE` errors in the console. This can happen if you're 24 | running an HTTPS-only service but you've built the extension with an HTTP 25 | `serviceUrl`. Either run the service on HTTP or rebuild the extension with the 26 | correct settings. 27 | 28 | ### Connection Refused errors in the console 29 | 30 | The extension fails to load and you see `GET https://localhost:5000/... 31 | net::ERR_CONNECTION_REFUSED` errors in the console. This can happen if you're 32 | running an HTTP-only service but you've built the extension with an HTTPS 33 | `serviceUrl`. Either run the service on HTTPS or rebuild the extension with the 34 | correct settings. 35 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | concurrency: 4 | group: ${{ github.event.repository.name }}-deploy 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_call: 9 | inputs: 10 | ref: 11 | description: 'Git commit to release' 12 | required: false 13 | type: string 14 | workflow_dispatch: 15 | 16 | jobs: 17 | continuous-integration: 18 | uses: ./.github/workflows/continuous-integration.yml 19 | name: continuous integration 20 | with: 21 | ref: ${{ inputs.ref }} 22 | 23 | upload-packages: 24 | needs: continuous-integration 25 | runs-on: ubuntu-latest 26 | environment: production 27 | 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | with: 32 | ref: ${{ inputs.ref }} 33 | - name: Cache the node_modules dir 34 | uses: actions/cache@v4 35 | with: 36 | path: node_modules 37 | key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock') }} 38 | - name: Install 39 | run: yarn install --immutable 40 | - name: Fetch packages 41 | uses: actions/download-artifact@v4 42 | with: 43 | name: packages 44 | path: dist/ 45 | - name: Upload packages 46 | env: 47 | CHROME_WEBSTORE_CLIENT_ID: ${{ secrets.CHROME_WEBSTORE_CLIENT_ID }} 48 | CHROME_WEBSTORE_CLIENT_SECRET: ${{ secrets.CHROME_WEBSTORE_CLIENT_SECRET }} 49 | CHROME_WEBSTORE_REFRESH_TOKEN: ${{ secrets.CHROME_WEBSTORE_REFRESH_TOKEN }} 50 | FIREFOX_AMO_KEY: ${{ secrets.FIREFOX_AMO_KEY }} 51 | FIREFOX_AMO_SECRET: ${{ secrets.FIREFOX_AMO_SECRET }} 52 | run: tools/deploy 53 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/LICENSE_FOXIT: -------------------------------------------------------------------------------- 1 | // Copyright 2014 PDFium Authors. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above 10 | // copyright notice, this list of conditions and the following disclaimer 11 | // in the documentation and/or other materials provided with the 12 | // distribution. 13 | // * Neither the name of Google Inc. nor the names of its 14 | // contributors may be used to endorse or promote products derived from 15 | // this software without specific prior written permission. 16 | // 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/loading-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/pdfjs-init.js: -------------------------------------------------------------------------------- 1 | /* global PDFViewerApplication */ 2 | 3 | // This script is run once PDF.js has loaded and it configures the viewer 4 | // and injects the Hypothesis client. 5 | 6 | async function init() { 7 | const configPromise = chrome.runtime.sendMessage(chrome.runtime.id, { 8 | type: 'getConfigForTab', 9 | }); 10 | 11 | const viewerLoaded = new Promise(resolve => { 12 | // See https://github.com/mozilla/pdf.js/wiki/Third-party-viewer-usage 13 | document.addEventListener('webviewerloaded', () => { 14 | // Wait for the PDF viewer to be fully initialized before loading the client. 15 | // Note that the PDF may still be loading after initialization. 16 | // 17 | // @ts-expect-error - PDFViewerApplication is missing from types. 18 | PDFViewerApplication.initializedPromise.then(resolve); 19 | }); 20 | }); 21 | 22 | // Concurrently request Hypothesis client config and listen for PDF.js 23 | // to finish initializing. 24 | const [config] = await Promise.all([configPromise, viewerLoaded]); 25 | 26 | const configScript = document.createElement('script'); 27 | configScript.type = 'application/json'; 28 | configScript.className = 'js-hypothesis-config'; 29 | configScript.textContent = JSON.stringify(config); 30 | 31 | // This ensures the client removes the script when the extension is deactivated 32 | configScript.setAttribute('data-remove-on-unload', ''); 33 | // The boot script expects this attribute when running from the browser extension 34 | configScript.setAttribute('data-extension-id', chrome.runtime.id); 35 | 36 | document.head.appendChild(configScript); 37 | 38 | const embedScript = document.createElement('script'); 39 | embedScript.src = '/client/build/boot.js'; 40 | document.body.appendChild(embedScript); 41 | } 42 | 43 | init(); 44 | -------------------------------------------------------------------------------- /rollup-tests.config.js: -------------------------------------------------------------------------------- 1 | import glob from 'glob'; 2 | import alias from '@rollup/plugin-alias'; 3 | import { babel } from '@rollup/plugin-babel'; 4 | import commonjs from '@rollup/plugin-commonjs'; 5 | import json from '@rollup/plugin-json'; 6 | import multi from '@rollup/plugin-multi-entry'; 7 | import replace from '@rollup/plugin-replace'; 8 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 9 | import { vitestCoverageOptions } from '@hypothesis/frontend-testing/vitest'; 10 | 11 | export const excludeFromCoverage = [ 12 | '**/node_modules/**', 13 | '**/test/**/*.js', 14 | '**/test-util/**', 15 | ]; 16 | 17 | export default { 18 | input: ['tests/bootstrap.js', ...glob.sync('tests/**/*-test.js')], 19 | output: { 20 | file: 'build/tests.bundle.js', 21 | format: 'es', 22 | sourcemap: true, 23 | }, 24 | treeshake: false, // Disabled for build performance 25 | plugins: [ 26 | alias({ 27 | entries: [ 28 | { 29 | find: '../../build/settings.json', 30 | replacement: '../../tests/settings.json', 31 | }, 32 | ], 33 | }), 34 | babel({ 35 | babelHelpers: 'bundled', 36 | exclude: 'node_modules/**', 37 | extensions: ['.js', '.ts'], 38 | plugins: [ 39 | [ 40 | 'mockable-imports', 41 | { 42 | excludeDirs: ['tests'], 43 | }, 44 | ], 45 | [ 46 | 'babel-plugin-istanbul', 47 | { 48 | ...vitestCoverageOptions, 49 | exclude: excludeFromCoverage, 50 | }, 51 | ], 52 | ], 53 | }), 54 | replace({ 55 | preventAssignment: true, 56 | EXTENSION_TESTS: 'true', 57 | }), 58 | nodeResolve({ extensions: ['.js', '.ts'] }), 59 | commonjs(), 60 | json(), 61 | multi(), 62 | ], 63 | }; 64 | -------------------------------------------------------------------------------- /tests/background/errors-test.js: -------------------------------------------------------------------------------- 1 | import * as errors from '../../src/background/errors'; 2 | 3 | describe('errors', () => { 4 | beforeEach(() => { 5 | sinon.stub(console, 'error'); 6 | }); 7 | 8 | afterEach(() => { 9 | console.error.restore(); 10 | }); 11 | 12 | describe('#shouldIgnoreInjectionError', () => { 13 | const ignoredErrors = [ 14 | 'The tab was closed', 15 | 'No tab with id 42', 16 | 'Cannot access contents of url "file:///C:/t/cpp.pdf". ' + 17 | 'Extension manifest must request permission to access this host.', 18 | 'Cannot access contents of page', 19 | 'The extensions gallery cannot be scripted.', 20 | ]; 21 | 22 | const unexpectedErrors = ['SyntaxError: A typo']; 23 | 24 | it('should be true for "expected" errors', () => { 25 | ignoredErrors.forEach(message => { 26 | const error = { message }; 27 | assert.isTrue(errors.shouldIgnoreInjectionError(error)); 28 | }); 29 | }); 30 | 31 | it('should be false for unexpected errors', () => { 32 | unexpectedErrors.forEach(message => { 33 | const error = { message }; 34 | assert.isFalse(errors.shouldIgnoreInjectionError(error)); 35 | }); 36 | }); 37 | 38 | it("should be true for the extension's custom error classes", () => { 39 | const error = new errors.LocalFileError('some message'); 40 | assert.isTrue(errors.shouldIgnoreInjectionError(error)); 41 | }); 42 | }); 43 | 44 | describe('#report', () => { 45 | it('logs errors', () => { 46 | const error = new Error('A most unexpected error'); 47 | errors.report(error, 'injecting the sidebar', { foo: 'bar' }); 48 | assert.calledWith(console.error, 'injecting the sidebar', error, { 49 | foo: 'bar', 50 | }); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /src/background/direct-link-query.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Subset of the client configuration which causes the client to show a 3 | * particular set of annotations automatically after it loads. 4 | * 5 | * See https://h-client.readthedocs.io/en/latest/publishers/config/#config-settings 6 | */ 7 | export type Query = { 8 | /** ID of the direct-linked annotation. */ 9 | annotations?: string; 10 | /** Filter query for the sidebar. */ 11 | query?: string; 12 | /** ID of the direct-linked group. */ 13 | group?: string; 14 | }; 15 | 16 | /** 17 | * Extracts the direct-linking query from the URL if any. 18 | * 19 | * If present, the query causes the extension to activate automatically and 20 | * show the matching set of annotations. 21 | * 22 | * @param url - 23 | * The URL which may contain a '#annotations:' fragment specifying which 24 | * annotations to show. 25 | * @return - The direct link query translated into client configuration settings. 26 | */ 27 | export function directLinkQuery(url: string): Query | null { 28 | // Annotation IDs are url-safe-base64 identifiers 29 | // See https://tools.ietf.org/html/rfc4648#page-7 30 | const idMatch = url.match(/#annotations:([A-Za-z0-9_-]+)$/); 31 | if (idMatch) { 32 | return { annotations: idMatch[1] }; 33 | } 34 | 35 | const queryMatch = url.match(/#annotations:query:(.*)$/); 36 | if (queryMatch) { 37 | const query = decodeURIComponent(queryMatch[1]); 38 | return { query }; 39 | } 40 | 41 | // Group IDs (and other "pubids" in h) are a subset of ASCII letters and 42 | // digits. As a special exception, the "Public" group has underscores in its 43 | // ID ("__world__"). 44 | const groupMatch = url.match(/#annotations:group:([A-Za-z0-9_]+)$/); 45 | if (groupMatch) { 46 | return { group: groupMatch[1] }; 47 | } 48 | 49 | return null; 50 | } 51 | -------------------------------------------------------------------------------- /tests/background/direct-link-query-test.js: -------------------------------------------------------------------------------- 1 | import { directLinkQuery } from '../../src/background/direct-link-query'; 2 | 3 | describe('common.direct-link-query', () => { 4 | it('returns `null` if the URL contains no #annotations fragment', () => { 5 | const url = 'https://example.com'; 6 | assert.equal(directLinkQuery(url), null); 7 | }); 8 | 9 | it('returns the annotation ID if the URL contains a #annotations: fragment', () => { 10 | const url = 'https://example.com/#annotations:1234'; 11 | assert.deepEqual(directLinkQuery(url), { 12 | annotations: '1234', 13 | }); 14 | }); 15 | 16 | it('does not return annotation ID if it is invalid', () => { 17 | // "invalid" here refers only to the character set, not whether the annotation 18 | // actually exists. 19 | const url = 'https://example.com/#annotations:[foo]'; 20 | assert.equal(directLinkQuery(url), null); 21 | }); 22 | 23 | it('returns the query if the URL contains a #annotations:query: fragment', () => { 24 | const url = 'https://example.com/#annotations:query:user%3Ajsmith'; 25 | assert.deepEqual(directLinkQuery(url), { 26 | query: 'user:jsmith', 27 | }); 28 | }); 29 | 30 | ['123', 'abcDEF456', '__world__'].forEach(groupId => { 31 | it('returns the group ID if the URL contains a #annotations:group: fragment', () => { 32 | const url = `https://example.com/#annotations:group:${groupId}`; 33 | assert.deepEqual(directLinkQuery(url), { 34 | group: groupId, 35 | }); 36 | }); 37 | }); 38 | 39 | it('does not return group ID if it is invalid', () => { 40 | // "invalid" here refers only to the character set, not whether the group 41 | // actually exists. 42 | const url = 'https://example.com/#annotations:group:%%%'; 43 | assert.deepEqual(directLinkQuery(url), null); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /tests/background/detect-content-type-test.js: -------------------------------------------------------------------------------- 1 | import { detectContentType } from '../../src/background/detect-content-type'; 2 | 3 | describe('detectContentType', () => { 4 | const sandbox = sinon.createSandbox(); 5 | 6 | let el; 7 | beforeEach(() => { 8 | el = document.createElement('div'); 9 | document.body.appendChild(el); 10 | }); 11 | 12 | afterEach(() => { 13 | el.parentElement.removeChild(el); 14 | 15 | sandbox.restore(); 16 | }); 17 | 18 | it('returns HTML by default', () => { 19 | el.innerHTML = '
'; 20 | assert.deepEqual(detectContentType(), { type: 'HTML' }); 21 | }); 22 | 23 | it('returns "PDF" if Google Chrome PDF viewer is present', () => { 24 | el.innerHTML = ''; 25 | assert.deepEqual(detectContentType(), { type: 'PDF' }); 26 | }); 27 | 28 | it('returns "PDF" if Chrome\'s OOPIF PDF viewer is present', () => { 29 | const fakeOpenOrClosedShadowRoot = sinon.stub(); 30 | vi.stubGlobal('chrome', { 31 | dom: { 32 | openOrClosedShadowRoot: fakeOpenOrClosedShadowRoot, 33 | }, 34 | }); 35 | 36 | try { 37 | const dummyElement = document.createElement('div'); 38 | const pdfViewer = document.createElement('iframe'); 39 | pdfViewer.setAttribute('type', 'application/pdf'); 40 | const fakeBodyShadowRoot = dummyElement.attachShadow({ mode: 'open' }); 41 | fakeBodyShadowRoot.append(pdfViewer); 42 | 43 | fakeOpenOrClosedShadowRoot 44 | .withArgs(document.body) 45 | .returns(fakeBodyShadowRoot); 46 | 47 | assert.deepEqual(detectContentType(), { type: 'PDF' }); 48 | } finally { 49 | vi.unstubAllGlobals(); 50 | } 51 | }); 52 | 53 | it('returns "PDF" if Firefox PDF viewer is present', () => { 54 | const fakeDocument = { 55 | querySelector: function () { 56 | return null; 57 | }, 58 | baseURI: 'resource://pdf.js', 59 | }; 60 | assert.deepEqual(detectContentType(fakeDocument), { type: 'PDF' }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hypothesis-browser-extension", 3 | "version": "1.1734.0", 4 | "private": true, 5 | "type": "module", 6 | "description": "Annotate with anyone, anywhere.", 7 | "license": "BSD-2-Clause", 8 | "homepage": "https://hypothes.is", 9 | "bugs": "https://github.com/hypothesis/browser-extension/issues", 10 | "repository": "hypothesis/browser-extension", 11 | "devDependencies": { 12 | "@babel/core": "^7.28.5", 13 | "@babel/preset-env": "^7.28.5", 14 | "@babel/preset-typescript": "^7.28.5", 15 | "@hypothesis/frontend-build": "^5.1.0", 16 | "@hypothesis/frontend-testing": "^1.8.0", 17 | "@rollup/plugin-alias": "^6.0.0", 18 | "@rollup/plugin-babel": "^6.1.0", 19 | "@rollup/plugin-commonjs": "^29.0.0", 20 | "@rollup/plugin-json": "^6.1.0", 21 | "@rollup/plugin-multi-entry": "^7.1.0", 22 | "@rollup/plugin-node-resolve": "^16.0.3", 23 | "@rollup/plugin-replace": "^6.0.3", 24 | "@types/chrome": "^0.1.32", 25 | "@vitest/browser": "^4.0.15", 26 | "@vitest/browser-playwright": "^4.0.15", 27 | "@vitest/coverage-istanbul": "^4.0.15", 28 | "@vitest/eslint-plugin": "^1.5.2", 29 | "babel-plugin-istanbul": "^7.0.1", 30 | "babel-plugin-mockable-imports": "^2.0.1", 31 | "chai": "^6.2.1", 32 | "chrome-webstore-upload-cli": "^3.5.0", 33 | "eslint": "^9.39.1", 34 | "eslint-config-hypothesis": "^3.3.1", 35 | "git-describe": "^4.1.1", 36 | "globals": "^16.5.0", 37 | "gulp": "^5.0.1", 38 | "hypothesis": "^1.1734.0", 39 | "is-equal-shallow": "^0.1.3", 40 | "mustache": "^4.2.0", 41 | "playwright": "^1.57.0", 42 | "prettier": "3.7.4", 43 | "rollup": "^4.53.3", 44 | "sinon": "^21.0.0", 45 | "typescript": "^5.9.3", 46 | "typescript-eslint": "^8.48.1", 47 | "vitest": "^4.0.15", 48 | "web-ext": "^9.2.0" 49 | }, 50 | "browserslist": "chrome 85, firefox 75", 51 | "scripts": { 52 | "lint": "eslint --cache .", 53 | "test": "gulp test", 54 | "typecheck": "tsc --build src/tsconfig.json" 55 | }, 56 | "packageManager": "yarn@3.6.1" 57 | } 58 | -------------------------------------------------------------------------------- /tools/settings.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Outputs a JSON object representing the extension settings based on a settings 5 | * file and the package environment. 6 | */ 7 | 8 | import * as fs from 'node:fs'; 9 | import * as path from 'node:path'; 10 | 11 | import gitDescribe from 'git-describe'; 12 | const { gitDescribeSync } = gitDescribe; 13 | 14 | // Suppress (expected) EPIPE errors on STDOUT 15 | process.stdout.on('error', err => { 16 | if (err.code === 'EPIPE') { 17 | process.exit(); 18 | } 19 | }); 20 | 21 | /** 22 | * getVersion fetches the current version from git, applying the following 23 | * rules: 24 | * 25 | * - If buildType is 'production' and the git state is not clean, throw an error 26 | * - Set the version number to X.Y.Z.W, where X.Y.Z is the last tagged release 27 | * and W is the number of commits since that release. 28 | * - If the buildType is 'production', set the version name to "Official Build", 29 | * otherwise set it to a string of the form "gXXXXXXX[.dirty]" to reflect the 30 | * exact commit and state of the repository. 31 | */ 32 | function getVersion(buildType) { 33 | const gitInfo = gitDescribeSync(); 34 | 35 | if (buildType === 'production' && gitInfo.dirty) { 36 | throw new Error('cannot create production build with dirty git state!'); 37 | } 38 | 39 | const version = `${gitInfo.semver}.${gitInfo.distance}`; 40 | let versionName = 'Official Build'; 41 | 42 | if (buildType !== 'production') { 43 | versionName = `${gitInfo.hash}${gitInfo.dirty ? '.dirty' : ''}`; 44 | } 45 | 46 | return { version, versionName }; 47 | } 48 | 49 | if (process.argv.length !== 3) { 50 | console.error('Usage: %s ', path.basename(process.argv[1])); 51 | process.exit(1); 52 | } 53 | 54 | const settings = JSON.parse( 55 | fs.readFileSync(path.join(process.cwd(), process.argv[2])), 56 | ); 57 | const settingsOut = { 58 | ...settings, 59 | ...getVersion(settings.buildType), 60 | }; 61 | 62 | if (settingsOut.sentryPublicDSN) { 63 | settingsOut.raven = { 64 | dsn: settingsOut.sentryPublicDSN, 65 | release: settingsOut.version, 66 | }; 67 | } 68 | 69 | console.log(JSON.stringify(settingsOut)); 70 | -------------------------------------------------------------------------------- /.github/workflows/continuous-integration.yml: -------------------------------------------------------------------------------- 1 | name: Continuous integration 2 | on: 3 | pull_request: 4 | workflow_call: 5 | inputs: 6 | ref: 7 | description: 'Git commit to build and test' 8 | required: false 9 | type: string 10 | jobs: 11 | ci: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | with: 17 | ref: ${{ inputs.ref }} 18 | - name: Cache the node_modules dir 19 | uses: actions/cache@v4 20 | with: 21 | path: node_modules 22 | key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock') }} 23 | - name: Install 24 | run: yarn install --immutable && yarn playwright install chromium 25 | - name: Format 26 | run: make checkformatting 27 | - name: Lint & typecheck 28 | run: make lint 29 | - name: Test 30 | run: make test 31 | - name: Fetch git tags 32 | run: | 33 | # Fetch tags because `git describe` uses them and the output from `git describe` 34 | # is in turn used to produce the extension version number in `build/manifest.json`. 35 | # 36 | # GitHub does a shallow clone by default, so we have to un-shallow it for 37 | # `git describe` to work. 38 | git fetch --quiet --tags --unshallow 39 | 40 | # Show version information in the build logs. This command will also be 41 | # used by `tools/settings.js` to generate the extension version. 42 | git describe --tags 43 | - name: Build packages 44 | run: | 45 | make clean # Remove assets from test step 46 | make build SETTINGS_FILE=settings/chrome-staging.json dist/ci-chrome-staging.zip 47 | make build SETTINGS_FILE=settings/chrome-prod.json dist/ci-chrome-prod.zip 48 | make build SETTINGS_FILE=settings/firefox-staging.json dist/ci-firefox-staging.xpi 49 | make build SETTINGS_FILE=settings/firefox-prod.json dist/ci-firefox-prod.xpi 50 | - name: Archive packages 51 | uses: actions/upload-artifact@v4 52 | with: 53 | name: packages 54 | path: | 55 | dist/*.zip 56 | dist/*.xpi 57 | retention-days: 30 58 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/cmaps/LICENSE: -------------------------------------------------------------------------------- 1 | %%Copyright: ----------------------------------------------------------- 2 | %%Copyright: Copyright 1990-2009 Adobe Systems Incorporated. 3 | %%Copyright: All rights reserved. 4 | %%Copyright: 5 | %%Copyright: Redistribution and use in source and binary forms, with or 6 | %%Copyright: without modification, are permitted provided that the 7 | %%Copyright: following conditions are met: 8 | %%Copyright: 9 | %%Copyright: Redistributions of source code must retain the above 10 | %%Copyright: copyright notice, this list of conditions and the following 11 | %%Copyright: disclaimer. 12 | %%Copyright: 13 | %%Copyright: Redistributions in binary form must reproduce the above 14 | %%Copyright: copyright notice, this list of conditions and the following 15 | %%Copyright: disclaimer in the documentation and/or other materials 16 | %%Copyright: provided with the distribution. 17 | %%Copyright: 18 | %%Copyright: Neither the name of Adobe Systems Incorporated nor the names 19 | %%Copyright: of its contributors may be used to endorse or promote 20 | %%Copyright: products derived from this software without specific prior 21 | %%Copyright: written permission. 22 | %%Copyright: 23 | %%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 24 | %%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 25 | %%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26 | %%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 27 | %%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 28 | %%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | %%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 | %%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | %%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 | %%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | %%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 34 | %%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | %%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | %%Copyright: ----------------------------------------------------------- 37 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/images/annotation-help.svg: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 16 | 18 | 21 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/background/help-page-test.js: -------------------------------------------------------------------------------- 1 | import * as errors from '../../src/background/errors'; 2 | import { HelpPage, $imports } from '../../src/background/help-page'; 3 | 4 | describe('HelpPage', () => { 5 | let fakeChromeTabs; 6 | let fakeExtensionURL; 7 | let help; 8 | 9 | beforeEach(() => { 10 | fakeChromeTabs = { create: sinon.stub() }; 11 | fakeExtensionURL = path => `chrome://abcd${path}`; 12 | 13 | $imports.$mock({ 14 | './chrome-api': { 15 | chromeAPI: { 16 | runtime: { getURL: fakeExtensionURL }, 17 | tabs: fakeChromeTabs, 18 | }, 19 | }, 20 | }); 21 | 22 | help = new HelpPage(); 23 | }); 24 | 25 | afterEach(() => { 26 | $imports.$restore(); 27 | }); 28 | 29 | describe('showHelpForError', () => { 30 | [ 31 | { 32 | getError: () => new errors.LocalFileError('msg'), 33 | helpSection: 'local-file', 34 | }, 35 | { 36 | getError: () => new errors.NoFileAccessError('msg'), 37 | helpSection: 'no-file-access', 38 | }, 39 | { 40 | getError: () => new errors.RestrictedProtocolError('msg'), 41 | helpSection: 'restricted-protocol', 42 | }, 43 | { 44 | getError: () => new errors.BlockedSiteError('msg'), 45 | helpSection: 'blocked-site', 46 | }, 47 | ].forEach(({ getError, helpSection }) => { 48 | it('shows appropriate page for the error', () => { 49 | help.showHelpForError({ id: 1, index: 1 }, getError()); 50 | assert.called(fakeChromeTabs.create); 51 | assert.calledWith(fakeChromeTabs.create, { 52 | index: 2, 53 | openerTabId: 1, 54 | url: fakeExtensionURL(`/help/index.html?message=msg#${helpSection}`), 55 | }); 56 | }); 57 | }); 58 | 59 | it('renders the "other-error" page for unknown errors', () => { 60 | help.showHelpForError({ id: 1, index: 1 }, new Error('Unexpected Error')); 61 | assert.called(fakeChromeTabs.create); 62 | assert.calledWith(fakeChromeTabs.create, { 63 | index: 2, 64 | openerTabId: 1, 65 | url: fakeExtensionURL( 66 | '/help/index.html?message=Unexpected+Error#other-error', 67 | ), 68 | }); 69 | }); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /src/manifest.json.mustache: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hypothesis - Web & PDF Annotation", 3 | "short_name": "Hypothesis", 4 | "version": "{{ version }}", 5 | {{#browserIsChrome}} 6 | "version_name": "{{ version }} ({{ versionName }})", 7 | {{/browserIsChrome}} 8 | "manifest_version": 3, 9 | 10 | {{#browserIsChrome}} 11 | "minimum_chrome_version": "88", 12 | {{/browserIsChrome}} 13 | 14 | {{#key}} 15 | "key": "{{{ key }}}", 16 | {{/key}} 17 | 18 | {{#browserIsFirefox}} 19 | "applications": { 20 | "gecko": { 21 | "strict_min_version": "68.0" 22 | } 23 | }, 24 | {{/browserIsFirefox}} 25 | 26 | "description": "Collaboratively annotate, highlight, and tag web pages and PDF documents.", 27 | "icons": { 28 | "16": "images/icon16.png", 29 | "48": "images/icon48.png", 30 | "128": "images/icon128.png" 31 | }, 32 | 33 | "homepage_url": "https://hypothes.is/", 34 | 35 | {{! Firefox does not support the "split" mode. 36 | See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/incognito 37 | }} 38 | {{#browserIsChrome}} 39 | "incognito": "split", 40 | {{/browserIsChrome}} 41 | 42 | "options_ui": { 43 | "page": "options/index.html" 44 | }, 45 | 46 | {{#browserIsChrome}} 47 | "offline_enabled": false, 48 | {{/browserIsChrome}} 49 | 50 | "permissions": [ 51 | "scripting", 52 | "storage", 53 | "tabs" 54 | ], 55 | 56 | "host_permissions": [""], 57 | 58 | "optional_permissions": [ 59 | {{! Used to enumerate frames on certain websites. }} 60 | "webNavigation" 61 | ], 62 | 63 | "background": { 64 | "service_worker": "extension.bundle.js" 65 | }, 66 | 67 | "action": { 68 | "default_icon": { 69 | "19": "images/browser-icon-inactive.png", 70 | "38": "images/browser-icon-inactive@2x.png" 71 | } 72 | }, 73 | 74 | {{#browserIsChrome}} 75 | "externally_connectable": { 76 | {{#bouncerUrl}}"matches": ["{{&bouncerUrl}}*"]{{/bouncerUrl}} 77 | }, 78 | {{/browserIsChrome}} 79 | 80 | "web_accessible_resources": [ 81 | { 82 | "resources": [ 83 | "client/*", 84 | "help/*", 85 | "pdfjs/*", 86 | "pdfjs/web/viewer.html" 87 | ], 88 | "matches": [""] 89 | } 90 | ] 91 | } 92 | -------------------------------------------------------------------------------- /src/background/uri-info.ts: -------------------------------------------------------------------------------- 1 | import settings from './settings'; 2 | import { BadgeUriError } from './errors'; 3 | 4 | const ALLOWED_PROTOCOLS = new Set(['http:', 'https:']); 5 | 6 | // The following sites are personal in nature, high potential traffic 7 | // and URLs don't correspond to identifiable content 8 | const BLOCKED_HOSTNAMES = new Set([ 9 | 'facebook.com', 10 | 'www.facebook.com', 11 | 'mail.google.com', 12 | ]); 13 | 14 | /** 15 | * Encodes a string for use in a query parameter. 16 | */ 17 | function encodeUriQuery(val: string) { 18 | return encodeURIComponent(val).replace(/%20/g, '+'); 19 | } 20 | 21 | /** 22 | * Returns a normalized version of URI for use in badge requests, or throws BadgeUrlError 23 | * if badge requests cannot be made for the given URL 24 | * 25 | * The normalization consist on (1) adding a final '/' at the end of the URL and 26 | * (2) removing the fragment from the URL. The URL fragment can be ignored as it 27 | * will result the same badge count. 28 | * 29 | * In addition, this normalization facilitates the identification of unique URLs. 30 | * 31 | * @return URL without fragment 32 | * @throws Will throw if URL is invalid or should not be sent to the 'badge' request endpoint 33 | */ 34 | export function uriForBadgeRequest(uri: string) { 35 | const url = new URL(uri); 36 | 37 | if (!ALLOWED_PROTOCOLS.has(url.protocol)) { 38 | throw new BadgeUriError('Blocked protocol'); 39 | } 40 | 41 | if (BLOCKED_HOSTNAMES.has(url.hostname)) { 42 | throw new BadgeUriError('Blocked hostname'); 43 | } 44 | 45 | url.hash = ''; 46 | 47 | return url.toString(); 48 | } 49 | 50 | /** 51 | * Queries the Hypothesis service that provides statistics about the annotations 52 | * for a given URL. 53 | * 54 | * @throws Will throw a variety of errors: network, json parsing, or wrong format errors. 55 | */ 56 | export async function fetchAnnotationCount(uri: string): Promise { 57 | const response = await fetch( 58 | settings.apiUrl + '/badge?uri=' + encodeUriQuery(uri), 59 | { 60 | credentials: 'include', 61 | }, 62 | ); 63 | 64 | const data = await response.json(); 65 | 66 | if (data && typeof data.total === 'number') { 67 | return data.total; 68 | } 69 | 70 | throw new Error('Unable to parse badge response'); 71 | } 72 | -------------------------------------------------------------------------------- /src/background/errors.ts: -------------------------------------------------------------------------------- 1 | export class ExtensionError extends Error {} 2 | 3 | export class LocalFileError extends ExtensionError {} 4 | 5 | export class NoFileAccessError extends ExtensionError {} 6 | 7 | export class RestrictedProtocolError extends ExtensionError {} 8 | 9 | export class BlockedSiteError extends ExtensionError {} 10 | 11 | export class AlreadyInjectedError extends ExtensionError {} 12 | 13 | export class RequestCanceledError extends Error {} 14 | 15 | export class BadgeUriError extends Error {} 16 | 17 | /** 18 | * Returns true if `err` is a recognized 'expected' error. 19 | */ 20 | function isKnownError(err: unknown) { 21 | return err instanceof ExtensionError; 22 | } 23 | 24 | const IGNORED_ERRORS = [ 25 | // Errors that can happen when the tab is closed during injection 26 | /The tab was closed/, 27 | /No tab with id.*/, 28 | // Attempts to access pages for which Chrome does not allow scripting 29 | /Cannot access contents of.*/, 30 | /The extensions gallery cannot be scripted/, 31 | // The extension is disabled on LMS assignments to avoid confusion with the 32 | // embedded Hypothesis instance. The user can still use the extension on other 33 | // pages hosted in the LMS itself. 34 | /Hypothesis extension can't be used on Hypothesis LMS assignments/, 35 | ]; 36 | 37 | /** 38 | * Returns true if a given `err` is anticipated during sidebar injection, such 39 | * as the tab being closed by the user, and should not be reported to Sentry. 40 | * 41 | * @param err - The Error-like object 42 | */ 43 | export function shouldIgnoreInjectionError(err: { message: string }) { 44 | if (IGNORED_ERRORS.some(pattern => err.message.match(pattern))) { 45 | return true; 46 | } 47 | if (isKnownError(err)) { 48 | return true; 49 | } 50 | return false; 51 | } 52 | 53 | /** 54 | * Report an error. 55 | * 56 | * All errors are logged to the console. Additionally unexpected errors, 57 | * ie. those which are not instances of ExtensionError, are reported to 58 | * Sentry. 59 | * 60 | * @param error - The error which happened. 61 | * @param when - Describes the context in which the error occurred. 62 | * @param context - Additional context for the error. 63 | */ 64 | export function report(error: Error, when: string, context?: object) { 65 | console.error(when, error, context); 66 | } 67 | -------------------------------------------------------------------------------- /tools/update-pdfjs: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | # This script fetches the latest build of PDF.js from the viewer demo 6 | # page. 7 | # 8 | # See https://github.com/mozilla/pdf.js/wiki/Setup-pdf.js-in-a-website#from-examples 9 | # 10 | # To update PDF.js to the latest version: 11 | # 12 | # 1. Create a new branch and run this script. 13 | # 2. Rebuild the extension and verify that PDFs work as expected in Chrome 14 | # 3. Commit the changes to the `src/vendor/` directory 15 | 16 | DEST_DIR=src/vendor/pdfjs 17 | PREFIX=pdf.js-gh-pages 18 | COMPONENTS="$PREFIX/build $PREFIX/web $PREFIX/LICENSE" 19 | 20 | # Check for uncommitted git changes. See https://stackoverflow.com/a/3879077/434243 21 | git update-index --refresh 22 | git diff-index --quiet HEAD -- 23 | if [[ $? -ne 0 ]]; then 24 | echo "Cannot update PDF.js when there are uncommitted changes in working tree." 25 | exit 1 26 | fi 27 | 28 | # Download the latest version of the PDF.js library and viewer. 29 | rm -rf $DEST_DIR 30 | mkdir -p $DEST_DIR 31 | 32 | # Get the latest build of the viewer 33 | curl -L https://github.com/mozilla/pdf.js/archive/gh-pages.tar.gz \ 34 | | tar -xz --directory $DEST_DIR --strip-components=1 $COMPONENTS 35 | 36 | # Remove example content from viewer 37 | rm $DEST_DIR/web/*.pdf 38 | 39 | # Remove sourcemaps. These increase the size of the extension significantly. 40 | find $DEST_DIR/ -name '*.map' -delete 41 | 42 | # Remove the check that the PDF being loaded is from the same origin as the 43 | # viewer. 44 | sed -i '' -e 's/HOSTED_VIEWER_ORIGINS.includes(viewerOrigin)/true \/* Hypothesis *\//' $DEST_DIR/web/viewer.js 45 | 46 | # Modify the viewer HTML page to load the Hypothesis client. 47 | sed -i '' -e 's/<\/head>/ 121 | 122 | 123 | -------------------------------------------------------------------------------- /tests/background/chrome-api-test.js: -------------------------------------------------------------------------------- 1 | import { getChromeAPI, getExtensionId } from '../../src/background/chrome-api'; 2 | 3 | describe('chrome-api', () => { 4 | describe('getChromeAPI', () => { 5 | function fakeListener() { 6 | return { addListener: sinon.stub() }; 7 | } 8 | 9 | let fakeChrome; 10 | 11 | beforeEach(() => { 12 | fakeChrome = { 13 | browserAction: { 14 | onClicked: fakeListener(), 15 | setBadgeBackgroundColor: sinon.stub(), 16 | setBadgeText: sinon.stub(), 17 | setIcon: sinon.stub(), 18 | setTitle: sinon.stub(), 19 | }, 20 | 21 | extension: { 22 | isAllowedFileSchemeAccess: sinon.stub(), 23 | }, 24 | 25 | management: { 26 | getSelf: sinon.stub(), 27 | }, 28 | 29 | runtime: { 30 | lastError: null, 31 | getURL: sinon.stub(), 32 | }, 33 | 34 | permissions: { 35 | getAll: sinon.stub(), 36 | request: sinon.stub(), 37 | }, 38 | 39 | tabs: { 40 | create: sinon.stub(), 41 | get: sinon.stub(), 42 | onCreated: fakeListener(), 43 | onReplaced: fakeListener(), 44 | onRemoved: fakeListener(), 45 | onUpdated: fakeListener(), 46 | query: sinon.stub(), 47 | update: sinon.stub(), 48 | }, 49 | 50 | scripting: { 51 | executeScript: sinon.stub(), 52 | }, 53 | 54 | storage: { 55 | sync: { 56 | get: sinon.stub(), 57 | }, 58 | }, 59 | }; 60 | }); 61 | 62 | it('wrapped methods call browser API', async () => { 63 | const syncAPIs = new Set([fakeChrome.runtime.getURL]); 64 | 65 | const chromeAPI = getChromeAPI(fakeChrome); 66 | 67 | for (const namespace of Object.keys(fakeChrome)) { 68 | for (const methodName of Object.keys(fakeChrome[namespace])) { 69 | const method = fakeChrome[namespace][methodName]; 70 | if (typeof method !== 'function') { 71 | // Skip listeners `on` and nested namespaces (eg. `storage.sync.get`). 72 | continue; 73 | } 74 | 75 | const expectedResult = {}; 76 | if (!syncAPIs.has(method)) { 77 | method.resolves(expectedResult); 78 | } 79 | 80 | const arg = {}; 81 | const result = chromeAPI[namespace][methodName](arg); 82 | assert.calledWith(method, arg); 83 | 84 | if (!syncAPIs.has(method)) { 85 | assert.equal(await result, expectedResult); 86 | } 87 | } 88 | } 89 | }); 90 | 91 | it('wrapped methods reject if an error occurs', async () => { 92 | const chromeAPI = getChromeAPI(fakeChrome); 93 | 94 | const expectedError = new Error('Something went wrong'); 95 | fakeChrome.tabs.get.rejects(expectedError); 96 | 97 | let error; 98 | try { 99 | await chromeAPI.tabs.get(1); 100 | } catch (e) { 101 | error = e; 102 | } 103 | 104 | assert.equal(error, expectedError); 105 | }); 106 | 107 | describe('APIs that require optional permissions', () => { 108 | it('rejects if permission has not been granted', async () => { 109 | const chromeAPI = getChromeAPI(fakeChrome); 110 | 111 | let error; 112 | try { 113 | await chromeAPI.webNavigation.getAllFrames(); 114 | } catch (e) { 115 | error = e; 116 | } 117 | 118 | assert.ok(error); 119 | }); 120 | 121 | it('succeeds if permission has been granted', async () => { 122 | const chromeAPI = getChromeAPI(fakeChrome); 123 | 124 | const frames = []; 125 | 126 | // Simulate the "webNavigation" permission being granted, which will 127 | // make the `chrome.webNavigation` property accessible. 128 | fakeChrome.webNavigation = { 129 | getAllFrames: sinon.stub().resolves(frames), 130 | }; 131 | 132 | const actualFrames = await chromeAPI.webNavigation.getAllFrames(); 133 | 134 | assert.equal(actualFrames, frames); 135 | }); 136 | }); 137 | }); 138 | 139 | describe('getExtensionId', () => { 140 | let fakeChromeAPI; 141 | const id = 'hypothesisId'; 142 | 143 | beforeEach(() => { 144 | fakeChromeAPI = { 145 | runtime: { id }, 146 | }; 147 | }); 148 | 149 | it('gets ID from `chrome.runtime.id`', () => { 150 | assert.equal(getExtensionId(fakeChromeAPI), id); 151 | }); 152 | }); 153 | }); 154 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/standard_fonts/LICENSE_LIBERATION: -------------------------------------------------------------------------------- 1 | Digitized data copyright (c) 2010 Google Corporation 2 | with Reserved Font Arimo, Tinos and Cousine. 3 | Copyright (c) 2012 Red Hat, Inc. 4 | with Reserved Font Name Liberation. 5 | 6 | This Font Software is licensed under the SIL Open Font License, 7 | Version 1.1. 8 | 9 | This license is copied below, and is also available with a FAQ at: 10 | http://scripts.sil.org/OFL 11 | 12 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 13 | 14 | PREAMBLE The goals of the Open Font License (OFL) are to stimulate 15 | worldwide development of collaborative font projects, to support the font 16 | creation efforts of academic and linguistic communities, and to provide 17 | a free and open framework in which fonts may be shared and improved in 18 | partnership with others. 19 | 20 | The OFL allows the licensed fonts to be used, studied, modified and 21 | redistributed freely as long as they are not sold by themselves. 22 | The fonts, including any derivative works, can be bundled, embedded, 23 | redistributed and/or sold with any software provided that any reserved 24 | names are not used by derivative works. The fonts and derivatives, 25 | however, cannot be released under any other type of license. The 26 | requirement for fonts to remain under this license does not apply to 27 | any document created using the fonts or their derivatives. 28 | 29 | 30 | 31 | DEFINITIONS 32 | "Font Software" refers to the set of files released by the Copyright 33 | Holder(s) under this license and clearly marked as such. 34 | This may include source files, build scripts and documentation. 35 | 36 | "Reserved Font Name" refers to any names specified as such after the 37 | copyright statement(s). 38 | 39 | "Original Version" refers to the collection of Font Software components 40 | as distributed by the Copyright Holder(s). 41 | 42 | "Modified Version" refers to any derivative made by adding to, deleting, 43 | or substituting ? in part or in whole ? 44 | any of the components of the Original Version, by changing formats or 45 | by porting the Font Software to a new environment. 46 | 47 | "Author" refers to any designer, engineer, programmer, technical writer 48 | or other person who contributed to the Font Software. 49 | 50 | 51 | PERMISSION & CONDITIONS 52 | 53 | Permission is hereby granted, free of charge, to any person obtaining a 54 | copy of the Font Software, to use, study, copy, merge, embed, modify, 55 | redistribute, and sell modified and unmodified copies of the Font 56 | Software, subject to the following conditions: 57 | 58 | 1) Neither the Font Software nor any of its individual components,in 59 | Original or Modified Versions, may be sold by itself. 60 | 61 | 2) Original or Modified Versions of the Font Software may be bundled, 62 | redistributed and/or sold with any software, provided that each copy 63 | contains the above copyright notice and this license. These can be 64 | included either as stand-alone text files, human-readable headers or 65 | in the appropriate machine-readable metadata fields within text or 66 | binary files as long as those fields can be easily viewed by the user. 67 | 68 | 3) No Modified Version of the Font Software may use the Reserved Font 69 | Name(s) unless explicit written permission is granted by the 70 | corresponding Copyright Holder. This restriction only applies to the 71 | primary font name as presented to the users. 72 | 73 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 74 | Software shall not be used to promote, endorse or advertise any 75 | Modified Version, except to acknowledge the contribution(s) of the 76 | Copyright Holder(s) and the Author(s) or with their explicit written 77 | permission. 78 | 79 | 5) The Font Software, modified or unmodified, in part or in whole, must 80 | be distributed entirely under this license, and must not be distributed 81 | under any other license. The requirement for fonts to remain under 82 | this license does not apply to any document created using the Font 83 | Software. 84 | 85 | 86 | 87 | TERMINATION 88 | This license becomes null and void if any of the above conditions are not met. 89 | 90 | 91 | 92 | DISCLAIMER 93 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 94 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 95 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 96 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 97 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 98 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 99 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 100 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER 101 | DEALINGS IN THE FONT SOFTWARE. 102 | 103 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/locale/scn/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | 17 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 18 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 19 | # representing the total number of pages in the document. 20 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 21 | # will be replaced by a number representing the currently visible page, 22 | # respectively a number representing the total number of pages in the document. 23 | 24 | zoom_out.title=Cchiù nicu 25 | zoom_out_label=Cchiù nicu 26 | zoom_in.title=Cchiù granni 27 | zoom_in_label=Cchiù granni 28 | 29 | # Secondary toolbar and context menu 30 | 31 | 32 | 33 | 34 | # Document properties dialog box 35 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 36 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 37 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 38 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 39 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 40 | # will be replaced by the creation/modification date, and time, of the PDF file. 41 | # LOCALIZATION NOTE (document_properties_page_size_dimension_string): 42 | # "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by 43 | # the size, respectively their unit of measurement and orientation, of the (current) page. 44 | # LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): 45 | # "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by 46 | # the size, respectively their unit of measurement, name, and orientation, of the (current) page. 47 | # LOCALIZATION NOTE (document_properties_linearized): The linearization status of 48 | # the document; usually called "Fast Web View" in English locales of Adobe software. 49 | document_properties_linearized=Vista web lesta: 50 | document_properties_linearized_yes=Se 51 | 52 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 53 | # a numerical per cent value. 54 | print_progress_close=Sfai 55 | 56 | # Tooltips and alt text for side panel toolbar buttons 57 | # (the _label strings are alt text for the buttons, the .title strings are 58 | # tooltips) 59 | 60 | # Thumbnails panel item (tooltip and alt text for images) 61 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 62 | # number. 63 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 64 | # number. 65 | 66 | # Find panel button title and messages 67 | # LOCALIZATION NOTE (find_match_count): The supported plural forms are 68 | # [one|two|few|many|other], with [other] as the default value. 69 | # "{{current}}" and "{{total}}" will be replaced by a number representing the 70 | # index of the currently active find result, respectively a number representing 71 | # the total number of matches in the document. 72 | # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are 73 | # [zero|one|two|few|many|other], with [other] as the default value. 74 | # "{{limit}}" will be replaced by a numerical value. 75 | 76 | # Error panel labels 77 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 78 | # replaced by the PDF.JS version and build ID. 79 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 80 | # english string describing the error. 81 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 82 | # trace. 83 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 84 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 85 | 86 | # Predefined zoom values 87 | page_scale_width=Larghizza dâ pàggina 88 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 89 | # numerical scale value. 90 | 91 | # Loading indicator messages 92 | 93 | # LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be 94 | # replaced by the modification date, and time, of the annotation. 95 | 96 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 97 | # "{{type}}" will be replaced with an annotation type from a list defined in 98 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 99 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 100 | password_cancel=Sfai 101 | 102 | -------------------------------------------------------------------------------- /tests/background/index-test.js: -------------------------------------------------------------------------------- 1 | import { init, uninstallURL, $imports } from '../../src/background'; 2 | 3 | let extension; 4 | 5 | function FakeExtension() { 6 | extension = this; // eslint-disable-line consistent-this 7 | 8 | this.activate = sinon.stub(); 9 | this.init = sinon.stub().resolves(); 10 | this.install = sinon.stub(); 11 | this.firstRun = sinon.stub(); 12 | } 13 | 14 | function eventListenerStub() { 15 | return { 16 | addListener: sinon.stub(), 17 | }; 18 | } 19 | 20 | describe('background/index', () => { 21 | let fakeChromeAPI; 22 | 23 | beforeEach(() => { 24 | fakeChromeAPI = { 25 | runtime: { 26 | getURL: sinon.stub(), 27 | requestUpdateCheck: sinon.stub().resolves(), 28 | onInstalled: eventListenerStub(), 29 | onMessageExternal: eventListenerStub(), 30 | onUpdateAvailable: eventListenerStub(), 31 | setUninstallURL: sinon.stub().resolves(), 32 | }, 33 | management: { 34 | getSelf: sinon.stub().resolves({ installType: 'normal', id: '1234' }), 35 | }, 36 | tabs: { 37 | update: sinon.stub(), 38 | }, 39 | }; 40 | 41 | $imports.$mock({ 42 | './chrome-api': { chromeAPI: fakeChromeAPI }, 43 | './extension': { Extension: FakeExtension }, 44 | }); 45 | init(); 46 | }); 47 | 48 | afterEach(() => { 49 | $imports.$restore(); 50 | }); 51 | 52 | /** 53 | * Simulate an external request being sent to the extension from a web page, 54 | * such as the bouncer (hyp.is) service, via the `chrome.runtime.sendMessage` 55 | * API. 56 | */ 57 | function simulateExternalMessage(request, sender, sendResponse) { 58 | const cb = fakeChromeAPI.runtime.onMessageExternal.addListener.args[0][0]; 59 | return cb(request, sender, sendResponse); 60 | } 61 | 62 | context('when the extension is installed', () => { 63 | function triggerInstallEvent() { 64 | const cb = fakeChromeAPI.runtime.onInstalled.addListener.args[0][0]; 65 | return cb({ reason: 'install' }); 66 | } 67 | 68 | it("calls the extension's first run hook", async () => { 69 | await triggerInstallEvent(); 70 | assert.calledWith(extension.firstRun, { 71 | id: '1234', 72 | installType: 'normal', 73 | }); 74 | }); 75 | }); 76 | 77 | it('shows survey to users after extension is uninstalled', () => { 78 | assert.calledWith(fakeChromeAPI.runtime.setUninstallURL, uninstallURL); 79 | }); 80 | 81 | describe('bouncer (hyp.is) message handling', () => { 82 | it('responds to basic "ping" message', () => { 83 | const sender = {}; 84 | const sendResponse = sinon.stub(); 85 | simulateExternalMessage({ type: 'ping' }, sender, sendResponse); 86 | assert.calledWith(sendResponse, { type: 'pong', features: [] }); 87 | }); 88 | 89 | it('responds to "ping" message with `queryFeatures`', () => { 90 | const sender = {}; 91 | const sendResponse = sinon.stub(); 92 | simulateExternalMessage( 93 | { type: 'ping', queryFeatures: ['activate'] }, 94 | sender, 95 | sendResponse, 96 | ); 97 | assert.calledWith(sendResponse, { type: 'pong', features: ['activate'] }); 98 | }); 99 | 100 | it('responds to "activate" message with URL', () => { 101 | const sender = { tab: { id: 123 } }; 102 | const sendResponse = sinon.stub(); 103 | 104 | simulateExternalMessage( 105 | { 106 | type: 'activate', 107 | url: 'https://example.com', 108 | query: '#annotations:1234', 109 | }, 110 | sender, 111 | sendResponse, 112 | ); 113 | 114 | assert.calledWith(fakeChromeAPI.tabs.update, 123, { 115 | url: 'https://example.com', 116 | }); 117 | assert.calledWith(extension.activate, 123, { 118 | afterNavigationTo: 'https://example.com', 119 | query: '#annotations:1234', 120 | }); 121 | assert.calledWith(sendResponse, { active: true }); 122 | }); 123 | 124 | it('responds to "activate" message without URL', () => { 125 | const sender = { tab: { id: 123 } }; 126 | const sendResponse = sinon.stub(); 127 | 128 | simulateExternalMessage( 129 | { 130 | type: 'activate', 131 | query: '#annotations:1234', 132 | }, 133 | sender, 134 | sendResponse, 135 | ); 136 | 137 | assert.notCalled(fakeChromeAPI.tabs.update); 138 | assert.calledWith( 139 | extension.activate, 140 | 123, 141 | sinon.match({ 142 | query: '#annotations:1234', 143 | }), 144 | ); 145 | assert.calledWith(sendResponse, { active: true }); 146 | }); 147 | 148 | it('ignores "activate" message that did not come from a tab', () => { 149 | const sender = {}; 150 | const sendResponse = sinon.stub(); 151 | 152 | simulateExternalMessage( 153 | { 154 | type: 'activate', 155 | query: '#annotations:1234', 156 | }, 157 | sender, 158 | sendResponse, 159 | ); 160 | 161 | assert.notCalled(fakeChromeAPI.tabs.update); 162 | }); 163 | }); 164 | }); 165 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/locale/wo/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | previous.title=Xët wi jiitu 17 | previous_label=Bi jiitu 18 | next.title=Xët wi ci topp 19 | next_label=Bi ci topp 20 | 21 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 22 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 23 | # representing the total number of pages in the document. 24 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 25 | # will be replaced by a number representing the currently visible page, 26 | # respectively a number representing the total number of pages in the document. 27 | 28 | zoom_out.title=Wàññi 29 | zoom_out_label=Wàññi 30 | zoom_in.title=Yaatal 31 | zoom_in_label=Yaatal 32 | zoom.title=Yambalaŋ 33 | presentation_mode.title=Wañarñil ci anamu wone 34 | presentation_mode_label=Anamu Wone 35 | open_file.title=Ubbi benn dencukaay 36 | open_file_label=Ubbi 37 | print.title=Móol 38 | print_label=Móol 39 | download.title=Yeb yi 40 | download_label=Yeb yi 41 | bookmark.title=Wone bi taxaw (duppi walla ubbi palanteer bu bees) 42 | bookmark_label=Wone bi feeñ 43 | 44 | # Secondary toolbar and context menu 45 | 46 | 47 | # Document properties dialog box 48 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 49 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 50 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 51 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 52 | document_properties_title=Bopp: 53 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 54 | # will be replaced by the creation/modification date, and time, of the PDF file. 55 | 56 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 57 | # a numerical per cent value. 58 | 59 | # Tooltips and alt text for side panel toolbar buttons 60 | # (the _label strings are alt text for the buttons, the .title strings are 61 | # tooltips) 62 | thumbs.title=Wone nataal yu ndaw yi 63 | thumbs_label=Nataal yu ndaw yi 64 | findbar.title=Gis ci biir jukki bi 65 | findbar_label=Wut 66 | 67 | # Thumbnails panel item (tooltip and alt text for images) 68 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 69 | # number. 70 | thumb_page_title=Xët {{page}} 71 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 72 | # number. 73 | thumb_page_canvas=Wiñet bu xët {{page}} 74 | 75 | # Find panel button title and messages 76 | find_previous.title=Seet beneen kaddu bu ni mel te jiitu 77 | find_previous_label=Bi jiitu 78 | find_next.title=Seet beneen kaddu bu ni mel 79 | find_next_label=Bi ci topp 80 | find_highlight=Melaxal lépp 81 | find_match_case_label=Sàmm jëmmalin wi 82 | find_reached_top=Jot nañu ndorteel xët wi, kontine dale ko ci suuf 83 | find_reached_bottom=Jot nañu jeexitalu xët wi, kontine ci ndorte 84 | find_not_found=Gisiñu kaddu gi 85 | 86 | # Error panel labels 87 | error_more_info=Xibaar yu gën bari 88 | error_less_info=Xibaar yu gën bari 89 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 90 | # replaced by the PDF.JS version and build ID. 91 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 92 | # english string describing the error. 93 | error_message=Bataaxal: {{message}} 94 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 95 | # trace. 96 | error_stack=Juug: {{stack}} 97 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 98 | error_file=Dencukaay: {{file}} 99 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 100 | error_line=Rëdd : {{line}} 101 | rendering_error=Am njumte bu am bi xët bi di wonewu. 102 | 103 | # Predefined zoom values 104 | page_scale_width=Yaatuwaay bu mët 105 | page_scale_fit=Xët lëmm 106 | page_scale_auto=Yambalaŋ ci saa si 107 | page_scale_actual=Dayo bi am 108 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 109 | # numerical scale value. 110 | 111 | loading_error=Am na njumte ci yebum dencukaay PDF bi. 112 | invalid_file_error=Dencukaay PDF bi baaxul walla mu sankar. 113 | 114 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 115 | # "{{type}}" will be replaced with an annotation type from a list defined in 116 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 117 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 118 | text_annotation_type.alt=[Karmat {{type}}] 119 | password_ok=OK 120 | password_cancel=Neenal 121 | 122 | printing_not_supported=Artu: Joowkat bii nanguwul lool mool. 123 | -------------------------------------------------------------------------------- /tests/background/uri-info-test.js: -------------------------------------------------------------------------------- 1 | import { BadgeUriError } from '../../src/background/errors'; 2 | import * as uriInfo from '../../src/background/uri-info'; 3 | import settings from '../settings.json'; 4 | 5 | describe('background/uri-info', () => { 6 | describe('uriForBadgeRequest', () => { 7 | ['http://.com', 'https://', 'dummy.com'].forEach(badURI => { 8 | it('throws for invalid URL', () => { 9 | try { 10 | uriInfo.uriForBadgeRequest(badURI); 11 | } catch (error) { 12 | assert.instanceOf(error, TypeError); 13 | } 14 | }); 15 | }); 16 | 17 | [ 18 | 'http://www.facebook.com', 19 | 'https://facebook.com', 20 | 'https://mail.google.com', 21 | 'http://www.facebook.com/some/page/', 22 | ].forEach(blockedHostname => { 23 | it('throws for blocked hostnames', () => { 24 | try { 25 | uriInfo.uriForBadgeRequest(blockedHostname); 26 | } catch (error) { 27 | assert.instanceOf(error, BadgeUriError); 28 | assert.equal(error.message, 'Blocked hostname'); 29 | } 30 | }); 31 | }); 32 | 33 | [ 34 | 'chrome://extensions', 35 | 'chrome://newtab', 36 | 'chrome-extension://fadpmhkjbfijelnpfnjmnghgokbppplf/pdfjs/web/viewer.html?file=http%3A%2F%2Fwww.pdf995.com%2Fsamples%2Fpdf.pdf', 37 | 'file://whatever', 38 | ].forEach(blockedProtocol => { 39 | it('throws for blocked protocol', () => { 40 | try { 41 | uriInfo.uriForBadgeRequest(blockedProtocol); 42 | } catch (error) { 43 | assert.instanceOf(error, BadgeUriError); 44 | assert.equal(error.message, 'Blocked protocol'); 45 | } 46 | }); 47 | }); 48 | 49 | ['https://www.google.com', 'http://www.example.com'].forEach(okURI => { 50 | it('returns a URI with final slash added', () => { 51 | assert.strictEqual(uriInfo.uriForBadgeRequest(okURI), `${okURI}/`); 52 | }); 53 | }); 54 | 55 | [ 56 | 'https://www.google.com#1', 57 | 'https://www.google.com#', 58 | 'https://www.google.com', 59 | ].forEach(okURI => { 60 | it('removes the fragment', () => { 61 | assert.strictEqual( 62 | uriInfo.uriForBadgeRequest(okURI), 63 | 'https://www.google.com/', 64 | ); 65 | }); 66 | }); 67 | }); 68 | 69 | describe('fetchAnnotationCount', () => { 70 | const badgeURL = `${settings.apiUrl}/badge`; 71 | let fetchStub; 72 | 73 | beforeEach(() => { 74 | fetchStub = sinon.stub(window, 'fetch').resolves( 75 | new Response('{"total": 1}', { 76 | status: 200, 77 | headers: {}, 78 | }), 79 | ); 80 | }); 81 | 82 | afterEach(() => { 83 | window.fetch.restore(); 84 | }); 85 | 86 | it('returns value from API service', async () => { 87 | const result = await uriInfo.fetchAnnotationCount( 88 | 'http://www.example.com', 89 | ); 90 | assert.equal(result, 1); 91 | }); 92 | 93 | it('sends the correct fetch request', async () => { 94 | await uriInfo.fetchAnnotationCount('http://tabUrl.com'); 95 | assert.equal(fetchStub.callCount, 1); 96 | assert.deepEqual(fetchStub.lastCall.args, [ 97 | badgeURL + '?uri=http%3A%2F%2FtabUrl.com', 98 | { credentials: 'include' }, 99 | ]); 100 | }); 101 | 102 | it('URL-encodes the URL appropriately', async () => { 103 | await uriInfo.fetchAnnotationCount('http://foo.com?bar=baz qüx'); 104 | assert.equal(fetchStub.callCount, 1); 105 | assert.equal( 106 | fetchStub.lastCall.args[0], 107 | badgeURL + '?uri=http%3A%2F%2Ffoo.com%3Fbar%3Dbaz+q%C3%BCx', 108 | ); 109 | }); 110 | 111 | ['{"total": "not a valid number"}', '{"rows": []}', '{"foop": 5}'].forEach( 112 | badBody => { 113 | it('throws an error if the response has an incorrect format', () => { 114 | fetchStub.resolves( 115 | new Response(badBody, { 116 | status: 200, 117 | headers: {}, 118 | }), 119 | ); 120 | return uriInfo 121 | .fetchAnnotationCount('http://www.example.com') 122 | .catch(error => { 123 | assert.strictEqual( 124 | error.message, 125 | 'Unable to parse badge response', 126 | ); 127 | }); 128 | }); 129 | }, 130 | ); 131 | 132 | it('throws an error if the response is not valid JSON', async () => { 133 | fetchStub.resolves( 134 | new Response('this is not valid json', { 135 | status: 200, 136 | headers: {}, 137 | }), 138 | ); 139 | 140 | let error; 141 | try { 142 | await uriInfo.fetchAnnotationCount('http://www.example.com'); 143 | } catch (e) { 144 | error = e; 145 | } 146 | assert.instanceOf(error, SyntaxError); 147 | }); 148 | 149 | it('throws errors for other fetch failures', async () => { 150 | fetchStub.rejects('Network error'); 151 | 152 | let error; 153 | try { 154 | await uriInfo.fetchAnnotationCount('http://www.example.com'); 155 | } catch (e) { 156 | error = e; 157 | } 158 | assert.strictEqual(error.name, 'Network error'); 159 | }); 160 | }); 161 | }); 162 | -------------------------------------------------------------------------------- /src/vendor/pdfjs/web/locale/meh/viewer.properties: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Mozilla Foundation 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Main toolbar buttons (tooltips and alt text for images) 16 | previous.title=Página yata 17 | 18 | # LOCALIZATION NOTE (page.title): The tooltip for the pageNumber input. 19 | # LOCALIZATION NOTE (of_pages): "{{pagesCount}}" will be replaced by a number 20 | # representing the total number of pages in the document. 21 | # LOCALIZATION NOTE (page_of_pages): "{{pageNumber}}" and "{{pagesCount}}" 22 | # will be replaced by a number representing the currently visible page, 23 | # respectively a number representing the total number of pages in the document. 24 | 25 | zoom.title=Nasa´a ka´nu/Nasa´a luli 26 | open_file_label=Síne 27 | 28 | # Secondary toolbar and context menu 29 | 30 | 31 | 32 | 33 | # Document properties dialog box 34 | # LOCALIZATION NOTE (document_properties_kb): "{{size_kb}}" and "{{size_b}}" 35 | # will be replaced by the PDF file size in kilobytes, respectively in bytes. 36 | # LOCALIZATION NOTE (document_properties_mb): "{{size_mb}}" and "{{size_b}}" 37 | # will be replaced by the PDF file size in megabytes, respectively in bytes. 38 | # LOCALIZATION NOTE (document_properties_date_string): "{{date}}" and "{{time}}" 39 | # will be replaced by the creation/modification date, and time, of the PDF file. 40 | document_properties_date_string={{date}}, {{time}} 41 | # LOCALIZATION NOTE (document_properties_page_size_dimension_string): 42 | # "{{width}}", "{{height}}", {{unit}}, and {{orientation}} will be replaced by 43 | # the size, respectively their unit of measurement and orientation, of the (current) page. 44 | document_properties_page_size_dimension_string={{width}} × {{height}} {{unit}} ({{orientation}}) 45 | # LOCALIZATION NOTE (document_properties_page_size_dimension_name_string): 46 | # "{{width}}", "{{height}}", {{unit}}, {{name}}, and {{orientation}} will be replaced by 47 | # the size, respectively their unit of measurement, name, and orientation, of the (current) page. 48 | document_properties_page_size_dimension_name_string={{width}} × {{height}} {{unit}} ({{name}}, {{orientation}}) 49 | # LOCALIZATION NOTE (document_properties_linearized): The linearization status of 50 | # the document; usually called "Fast Web View" in English locales of Adobe software. 51 | document_properties_linearized_yes=Kuvi 52 | document_properties_close=Nakasɨ 53 | 54 | # LOCALIZATION NOTE (print_progress_percent): "{{progress}}" will be replaced by 55 | # a numerical per cent value. 56 | print_progress_percent={{progress}}% 57 | print_progress_close=Nkuvi-ka 58 | 59 | # Tooltips and alt text for side panel toolbar buttons 60 | # (the _label strings are alt text for the buttons, the .title strings are 61 | # tooltips) 62 | findbar_label=Nánuku 63 | 64 | # Thumbnails panel item (tooltip and alt text for images) 65 | # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page 66 | # number. 67 | # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page 68 | # number. 69 | 70 | # Find panel button title and messages 71 | find_input.title=Nánuku 72 | # LOCALIZATION NOTE (find_match_count): The supported plural forms are 73 | # [one|two|few|many|other], with [other] as the default value. 74 | # "{{current}}" and "{{total}}" will be replaced by a number representing the 75 | # index of the currently active find result, respectively a number representing 76 | # the total number of matches in the document. 77 | find_match_count={[ plural(total) ]} 78 | # LOCALIZATION NOTE (find_match_count_limit): The supported plural forms are 79 | # [zero|one|two|few|many|other], with [other] as the default value. 80 | # "{{limit}}" will be replaced by a numerical value. 81 | find_match_count_limit={[ plural(limit) ]} 82 | 83 | # Error panel labels 84 | error_close=Nakasɨ 85 | # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be 86 | # replaced by the PDF.JS version and build ID. 87 | error_version_info=PDF.js v{{version}} (build: {{build}}) 88 | # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an 89 | # english string describing the error. 90 | # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack 91 | # trace. 92 | # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename 93 | # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number 94 | 95 | # Predefined zoom values 96 | # LOCALIZATION NOTE (page_scale_percent): "{{scale}}" will be replaced by a 97 | # numerical scale value. 98 | page_scale_percent={{scale}}% 99 | 100 | # Loading indicator messages 101 | 102 | # LOCALIZATION NOTE (annotation_date_string): "{{date}}" and "{{time}}" will be 103 | # replaced by the modification date, and time, of the annotation. 104 | annotation_date_string={{date}}, {{time}} 105 | 106 | # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. 107 | # "{{type}}" will be replaced with an annotation type from a list defined in 108 | # the PDF spec (32000-1:2008 Table 169 – Annotation types). 109 | # Some common types are e.g.: "Check", "Text", "Comment", "Note" 110 | password_cancel=Nkuvi-ka 111 | 112 | --------------------------------------------------------------------------------