Compare commits
No commits in common. "master" and "v2.3.200" have entirely different histories.
@ -1,6 +1,6 @@
|
|||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*.{js,jsm,mjs,json,html,css,pdf.link}]
|
[*.{js,jsm,html,css}]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
end_of_line = lf
|
end_of_line = lf
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
@ -9,12 +9,9 @@ insert_final_newline = true
|
|||||||
max_line_length = 80
|
max_line_length = 80
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
[*.{json,pdf.link}]
|
|
||||||
max_line_length = off
|
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
max_line_length = off
|
max_line_length = 0
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
[COMMIT_EDITMSG]
|
[COMMIT_EDITMSG]
|
||||||
max_line_length = off
|
max_line_length = 0
|
||||||
|
@ -3,10 +3,15 @@ l10n/
|
|||||||
docs/
|
docs/
|
||||||
node_modules/
|
node_modules/
|
||||||
external/bcmaps/
|
external/bcmaps/
|
||||||
|
external/webL10n/
|
||||||
|
external/cmapscompress/
|
||||||
external/builder/fixtures/
|
external/builder/fixtures/
|
||||||
external/builder/fixtures_esprima/
|
external/builder/fixtures_esprima/
|
||||||
external/quickjs/
|
src/shared/cffStandardStrings.js
|
||||||
|
src/shared/fonts_utils.js
|
||||||
test/tmp/
|
test/tmp/
|
||||||
|
test/features/
|
||||||
test/pdfs/
|
test/pdfs/
|
||||||
web/locale/
|
test/resources/
|
||||||
|
test/font/*_spec.js
|
||||||
*~/
|
*~/
|
||||||
|
197
.eslintrc
197
.eslintrc
@ -1,132 +1,69 @@
|
|||||||
{
|
{
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2022,
|
"ecmaVersion": 8,
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
},
|
},
|
||||||
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"import",
|
"import",
|
||||||
"json",
|
|
||||||
"mozilla",
|
"mozilla",
|
||||||
"no-unsanitized",
|
"no-unsanitized",
|
||||||
"sort-exports",
|
|
||||||
"unicorn",
|
"unicorn",
|
||||||
],
|
],
|
||||||
|
|
||||||
"extends": [
|
|
||||||
"plugin:json/recommended",
|
|
||||||
"plugin:prettier/recommended"
|
|
||||||
],
|
|
||||||
|
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es2022": true,
|
"es6": true,
|
||||||
"worker": true,
|
"worker": true,
|
||||||
|
"amd": true,
|
||||||
},
|
},
|
||||||
|
|
||||||
"globals": {
|
"globals": {
|
||||||
"PDFJSDev": "readonly",
|
"PDFJSDev": false,
|
||||||
"__non_webpack_import__": "readonly",
|
"exports": false,
|
||||||
|
"SystemJS": false,
|
||||||
},
|
},
|
||||||
|
|
||||||
"rules": {
|
"rules": {
|
||||||
// Plugins
|
// Plugins
|
||||||
"import/export": "error",
|
"import/no-unresolved": "error",
|
||||||
"import/exports-last": "error",
|
|
||||||
"import/extensions": ["error", "always", { "ignorePackages": true, }],
|
|
||||||
"import/first": "error",
|
|
||||||
"import/named": "error",
|
|
||||||
"import/no-cycle": "error",
|
|
||||||
"import/no-empty-named-blocks": "error",
|
|
||||||
"import/no-commonjs": "error",
|
|
||||||
"import/no-mutable-exports": "error",
|
|
||||||
"import/no-self-import": "error",
|
|
||||||
"import/no-unresolved": ["error", {
|
|
||||||
"ignore": ["display", "pdfjs", "pdfjs-lib", "pdfjs-web", "web", "fluent-bundle", "fluent-dom"],
|
|
||||||
}],
|
|
||||||
"mozilla/avoid-removeChild": "error",
|
"mozilla/avoid-removeChild": "error",
|
||||||
"mozilla/use-includes-instead-of-indexOf": "error",
|
"mozilla/use-includes-instead-of-indexOf": "error",
|
||||||
"no-unsanitized/method": "error",
|
"no-unsanitized/method": "error",
|
||||||
"no-unsanitized/property": "error",
|
"no-unsanitized/property": "error",
|
||||||
"sort-exports/sort-exports": ["error", {
|
"unicorn/no-array-instanceof": "error",
|
||||||
"ignoreCase": true,
|
|
||||||
}],
|
|
||||||
"unicorn/no-abusive-eslint-disable": "error",
|
|
||||||
"unicorn/no-array-push-push": "error",
|
|
||||||
"unicorn/no-instanceof-array": "error",
|
|
||||||
"unicorn/no-invalid-remove-event-listener": "error",
|
|
||||||
"unicorn/no-new-buffer": "error",
|
|
||||||
"unicorn/no-typeof-undefined": ["error", {
|
|
||||||
"checkGlobalVariables": false,
|
|
||||||
}],
|
|
||||||
"unicorn/no-useless-promise-resolve-reject": "error",
|
|
||||||
"unicorn/no-useless-spread": "error",
|
|
||||||
"unicorn/prefer-array-find": "error",
|
|
||||||
"unicorn/prefer-array-flat": "error",
|
|
||||||
"unicorn/prefer-array-flat-map": "error",
|
|
||||||
"unicorn/prefer-array-index-of": "error",
|
|
||||||
"unicorn/prefer-array-some": "error",
|
|
||||||
"unicorn/prefer-at": "error",
|
|
||||||
"unicorn/prefer-date-now": "error",
|
|
||||||
"unicorn/prefer-dom-node-append": "error",
|
|
||||||
"unicorn/prefer-dom-node-remove": "error",
|
|
||||||
"unicorn/prefer-logical-operator-over-ternary": "error",
|
|
||||||
"unicorn/prefer-modern-dom-apis": "error",
|
|
||||||
"unicorn/prefer-modern-math-apis": "error",
|
|
||||||
"unicorn/prefer-negative-index": "error",
|
|
||||||
"unicorn/prefer-optional-catch-binding": "error",
|
|
||||||
"unicorn/prefer-regexp-test": "error",
|
|
||||||
"unicorn/prefer-string-replace-all": "error",
|
|
||||||
"unicorn/prefer-string-starts-ends-with": "error",
|
|
||||||
"unicorn/prefer-ternary": ["error", "only-single-line"],
|
|
||||||
|
|
||||||
// Possible errors
|
// Possible errors
|
||||||
"for-direction": "error",
|
"for-direction": "error",
|
||||||
"getter-return": "error",
|
|
||||||
"no-async-promise-executor": "error",
|
"no-async-promise-executor": "error",
|
||||||
"no-cond-assign": ["error", "except-parens"],
|
"no-cond-assign": ["error", "except-parens"],
|
||||||
"no-constant-condition": ["error", { "checkLoops": false, }],
|
"no-constant-condition": ["error", { "checkLoops": false, }],
|
||||||
"no-debugger": "error",
|
|
||||||
"no-dupe-args": "error",
|
"no-dupe-args": "error",
|
||||||
"no-dupe-else-if": "error",
|
|
||||||
"no-dupe-keys": "error",
|
"no-dupe-keys": "error",
|
||||||
"no-duplicate-case": "error",
|
"no-duplicate-case": "error",
|
||||||
"no-empty": ["error", { "allowEmptyCatch": true, }],
|
"no-empty": ["error", { "allowEmptyCatch": true, }],
|
||||||
"no-empty-character-class": "error",
|
|
||||||
"no-ex-assign": "error",
|
"no-ex-assign": "error",
|
||||||
"no-extra-boolean-cast": "error",
|
"no-extra-boolean-cast": "error",
|
||||||
|
"no-extra-semi": "error",
|
||||||
"no-func-assign": "error",
|
"no-func-assign": "error",
|
||||||
"no-inner-declarations": ["error", "functions"],
|
"no-inner-declarations": ["error", "functions"],
|
||||||
"no-invalid-regexp": "error",
|
"no-invalid-regexp": "error",
|
||||||
"no-irregular-whitespace": "error",
|
"no-irregular-whitespace": "error",
|
||||||
"no-loss-of-precision": "error",
|
|
||||||
"no-obj-calls": "error",
|
"no-obj-calls": "error",
|
||||||
"no-promise-executor-return": "error",
|
|
||||||
"no-regex-spaces": "error",
|
"no-regex-spaces": "error",
|
||||||
"no-setter-return": "error",
|
|
||||||
"no-sparse-arrays": "error",
|
"no-sparse-arrays": "error",
|
||||||
"no-template-curly-in-string": "error",
|
|
||||||
"no-unexpected-multiline": "error",
|
"no-unexpected-multiline": "error",
|
||||||
"no-unreachable": "error",
|
"no-unreachable": "error",
|
||||||
"no-unsafe-finally": "error",
|
"no-unsafe-finally": "error",
|
||||||
"no-unsafe-negation": "error",
|
"no-unsafe-negation": "error",
|
||||||
"no-unsafe-optional-chaining": ["error", { "disallowArithmeticOperators": true }],
|
"use-isnan": "error",
|
||||||
"no-unused-private-class-members": "error",
|
|
||||||
"use-isnan": ["error", { "enforceForIndexOf": true, }],
|
|
||||||
"valid-typeof": ["error", { "requireStringLiterals": true, }],
|
"valid-typeof": ["error", { "requireStringLiterals": true, }],
|
||||||
|
|
||||||
// Best Practices
|
// Best Practices
|
||||||
"accessor-pairs": ["error", {
|
"accessor-pairs": ["error", { "setWithoutGet": true, }],
|
||||||
"setWithoutGet": true,
|
|
||||||
"enforceForClassMembers": true,
|
|
||||||
}],
|
|
||||||
"consistent-return": "error",
|
"consistent-return": "error",
|
||||||
"curly": ["error", "all"],
|
"curly": ["error", "all"],
|
||||||
"default-case-last": "error",
|
|
||||||
"dot-notation": "error",
|
|
||||||
"eqeqeq": ["error", "always"],
|
"eqeqeq": ["error", "always"],
|
||||||
"grouped-accessor-pairs": ["error", "getBeforeSet"],
|
|
||||||
"no-alert": "error",
|
|
||||||
"no-caller": "error",
|
"no-caller": "error",
|
||||||
"no-else-return": "error",
|
"no-else-return": "error",
|
||||||
"no-empty-pattern": "error",
|
"no-empty-pattern": "error",
|
||||||
@ -140,12 +77,13 @@
|
|||||||
"no-implied-eval": "error",
|
"no-implied-eval": "error",
|
||||||
"no-iterator": "error",
|
"no-iterator": "error",
|
||||||
"no-lone-blocks": "error",
|
"no-lone-blocks": "error",
|
||||||
"no-lonely-if": "error",
|
"no-multi-spaces": ["error", {
|
||||||
|
"ignoreEOLComments": true,
|
||||||
|
}],
|
||||||
"no-multi-str": "error",
|
"no-multi-str": "error",
|
||||||
"no-new": "error",
|
|
||||||
"no-new-func": "error",
|
"no-new-func": "error",
|
||||||
"no-new-symbol": "error",
|
|
||||||
"no-new-wrappers": "error",
|
"no-new-wrappers": "error",
|
||||||
|
"no-new": "error",
|
||||||
"no-octal-escape": "error",
|
"no-octal-escape": "error",
|
||||||
"no-octal": "error",
|
"no-octal": "error",
|
||||||
"no-redeclare": "error",
|
"no-redeclare": "error",
|
||||||
@ -158,10 +96,8 @@
|
|||||||
"no-useless-call": "error",
|
"no-useless-call": "error",
|
||||||
"no-useless-catch": "error",
|
"no-useless-catch": "error",
|
||||||
"no-useless-concat": "error",
|
"no-useless-concat": "error",
|
||||||
"no-useless-escape": "error",
|
|
||||||
"no-useless-return": "error",
|
"no-useless-return": "error",
|
||||||
"prefer-promise-reject-errors": "error",
|
"prefer-promise-reject-errors": "error",
|
||||||
"prefer-spread": "error",
|
|
||||||
"wrap-iife": ["error", "any"],
|
"wrap-iife": ["error", "any"],
|
||||||
"yoda": ["error", "never", {
|
"yoda": ["error", "never", {
|
||||||
"exceptRange": true,
|
"exceptRange": true,
|
||||||
@ -171,71 +107,67 @@
|
|||||||
"strict": ["off", "global"],
|
"strict": ["off", "global"],
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
|
"no-catch-shadow": "error",
|
||||||
"no-delete-var": "error",
|
"no-delete-var": "error",
|
||||||
"no-label-var": "error",
|
"no-label-var": "error",
|
||||||
"no-shadow": "error",
|
"no-restricted-globals": ["error",
|
||||||
|
{
|
||||||
|
"name": "ReadableStream",
|
||||||
|
"message": "Import it from `src/shared/util.js` or `pdfjsLib` instead; outside of the `/src` and `/web` folders, the rule may be disabled as needed. ",
|
||||||
|
},
|
||||||
|
],
|
||||||
"no-shadow-restricted-names": "error",
|
"no-shadow-restricted-names": "error",
|
||||||
|
"no-shadow": "off",
|
||||||
"no-undef-init": "error",
|
"no-undef-init": "error",
|
||||||
"no-undef": ["error", { "typeof": true, }],
|
"no-undef": ["error", { "typeof": true, }],
|
||||||
"no-unused-vars": ["error", {
|
"no-unused-vars": ["error", {
|
||||||
"vars": "all",
|
"vars": "local",
|
||||||
"args": "none",
|
"args": "none",
|
||||||
}],
|
}],
|
||||||
"no-use-before-define": ["error", {
|
|
||||||
"functions": false,
|
|
||||||
"classes": false,
|
|
||||||
"variables": false,
|
|
||||||
}],
|
|
||||||
|
|
||||||
// Stylistic Issues
|
// Stylistic Issues
|
||||||
|
"array-bracket-spacing": ["error", "never"],
|
||||||
|
"block-spacing": ["error", "always"],
|
||||||
|
"brace-style": ["error", "1tbs", {
|
||||||
|
"allowSingleLine": false,
|
||||||
|
}],
|
||||||
|
"comma-dangle": ["error", {
|
||||||
|
"arrays": "ignore",
|
||||||
|
"objects": "always",
|
||||||
|
"imports": "never",
|
||||||
|
"exports": "always",
|
||||||
|
"functions": "never",
|
||||||
|
}],
|
||||||
|
"comma-spacing": ["error", { "before": false, "after": true, }],
|
||||||
|
"comma-style": ["error", "last"],
|
||||||
|
"eol-last": "error",
|
||||||
|
"func-call-spacing": ["error", "never"],
|
||||||
|
"key-spacing": ["error", { "beforeColon": false, "afterColon": true, "mode": "strict", }],
|
||||||
|
"keyword-spacing": ["error", { "before": true, "after": true, }],
|
||||||
|
"linebreak-style": ["error", "unix"],
|
||||||
"lines-between-class-members": ["error", "always"],
|
"lines-between-class-members": ["error", "always"],
|
||||||
"max-len": ["error", {
|
"max-len": ["error", {
|
||||||
"code": 1000,
|
"code": 80,
|
||||||
"comments": 80,
|
|
||||||
"ignoreUrls": true
|
"ignoreUrls": true
|
||||||
}],
|
}],
|
||||||
"new-cap": ["error", { "newIsCap": true, "capIsNew": false, }],
|
"new-cap": ["error", { "newIsCap": true, "capIsNew": false, }],
|
||||||
|
"new-parens": "error",
|
||||||
"no-array-constructor": "error",
|
"no-array-constructor": "error",
|
||||||
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0, "maxBOF": 1, }],
|
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0, "maxBOF": 1, }],
|
||||||
"no-nested-ternary": "error",
|
|
||||||
"no-new-object": "error",
|
"no-new-object": "error",
|
||||||
"no-restricted-syntax": ["error",
|
"no-tabs": "error",
|
||||||
{
|
"no-trailing-spaces": ["error", { "skipBlankLines": false, }],
|
||||||
"selector": "BinaryExpression[operator='instanceof'][right.name='Object']",
|
"no-whitespace-before-property": "error",
|
||||||
"message": "Use `typeof` rather than `instanceof Object`.",
|
"object-curly-spacing": ["error", "always"],
|
||||||
},
|
"operator-linebreak": ["error", "after", { "overrides": { ":": "ignore", } }],
|
||||||
{
|
"quotes": ["error", "single"],
|
||||||
"selector": "CallExpression[callee.name='assert'][arguments.length!=2]",
|
"semi-spacing": ["error", { "before": false, "after": true, }],
|
||||||
"message": "`assert()` must always be invoked with two arguments.",
|
"semi": ["error", "always"],
|
||||||
},
|
"space-before-blocks": ["error", "always"],
|
||||||
{
|
"space-before-function-paren": ["error", { "anonymous": "ignore", "named": "never", }],
|
||||||
"selector": "CallExpression[callee.name='isCmd'][arguments.length<2]",
|
"space-in-parens": ["error", "never"],
|
||||||
"message": "Use `instanceof Cmd` rather than `isCmd()` with one argument.",
|
"space-infix-ops": ["error", { "int32Hint": false }],
|
||||||
},
|
"space-unary-ops": ["error", { "words": true, "nonwords": false, }],
|
||||||
{
|
|
||||||
"selector": "CallExpression[callee.name='isDict'][arguments.length<2]",
|
|
||||||
"message": "Use `instanceof Dict` rather than `isDict()` with one argument.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "CallExpression[callee.name='isName'][arguments.length<2]",
|
|
||||||
"message": "Use `instanceof Name` rather than `isName()` with one argument.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "NewExpression[callee.name='Cmd']",
|
|
||||||
"message": "Use `Cmd.get()` rather than `new Cmd()`.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "NewExpression[callee.name='Name']",
|
|
||||||
"message": "Use `Name.get()` rather than `new Name()`.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"selector": "NewExpression[callee.name='Ref']",
|
|
||||||
"message": "Use `Ref.get()` rather than `new Ref()`.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-unneeded-ternary": "error",
|
|
||||||
"operator-assignment": "error",
|
|
||||||
"prefer-exponentiation-operator": "error",
|
|
||||||
"spaced-comment": ["error", "always", {
|
"spaced-comment": ["error", "always", {
|
||||||
"block": {
|
"block": {
|
||||||
"balanced": true,
|
"balanced": true,
|
||||||
@ -243,9 +175,15 @@
|
|||||||
}],
|
}],
|
||||||
|
|
||||||
// ECMAScript 6
|
// ECMAScript 6
|
||||||
"arrow-body-style": ["error", "as-needed"],
|
"arrow-body-style": ["error", "always"],
|
||||||
|
"arrow-parens": ["error", "always"],
|
||||||
|
"arrow-spacing": ["error", {
|
||||||
|
"before": true,
|
||||||
|
"after": true,
|
||||||
|
}],
|
||||||
"constructor-super": "error",
|
"constructor-super": "error",
|
||||||
"no-class-assign": "error",
|
"no-class-assign": "error",
|
||||||
|
"no-confusing-arrow": "error",
|
||||||
"no-const-assign": "error",
|
"no-const-assign": "error",
|
||||||
"no-dupe-class-members": "error",
|
"no-dupe-class-members": "error",
|
||||||
"no-duplicate-imports": "error",
|
"no-duplicate-imports": "error",
|
||||||
@ -253,12 +191,11 @@
|
|||||||
"no-useless-computed-key": "error",
|
"no-useless-computed-key": "error",
|
||||||
"no-useless-constructor": "error",
|
"no-useless-constructor": "error",
|
||||||
"no-useless-rename": "error",
|
"no-useless-rename": "error",
|
||||||
"no-var": "error",
|
"no-var": "off",
|
||||||
"object-shorthand": ["error", "always", {
|
"object-shorthand": ["error", "always", {
|
||||||
"avoidQuotes": true,
|
"avoidQuotes": true,
|
||||||
}],
|
}],
|
||||||
"prefer-const": "error",
|
"rest-spread-spacing": ["error", "never"],
|
||||||
"require-yield": "error",
|
|
||||||
"sort-imports": ["error", {
|
"sort-imports": ["error", {
|
||||||
"ignoreCase": true,
|
"ignoreCase": true,
|
||||||
}],
|
}],
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
# Auto-format `.js` files with ESLint/Prettier
|
|
||||||
de36b2aabab2b7fd647d9591f959c4540129541d
|
|
||||||
# Auto-format `.css` files with Stylelint/Prettier
|
|
||||||
8aa2718d225ad701a5b8a2788b42d221f1e4327d
|
|
||||||
# Auto-format `.json` files with Prettier
|
|
||||||
29de9bdce6c9785574994fda0e51533d796a9bb4
|
|
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -4,7 +4,7 @@
|
|||||||
*.css text eol=lf
|
*.css text eol=lf
|
||||||
*.html text eol=lf
|
*.html text eol=lf
|
||||||
*.md text eol=lf
|
*.md text eol=lf
|
||||||
*.ftl text eol=lf
|
*.properties text eol=lf
|
||||||
*.yml text eol=lf
|
*.yml text eol=lf
|
||||||
*.json text eol=lf
|
*.json text eol=lf
|
||||||
*.config text eol=lf
|
*.config text eol=lf
|
||||||
|
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -1 +0,0 @@
|
|||||||
l10n/en-US/*.ftl @mozilla/pdfjs-l10n
|
|
4
.github/CONTRIBUTING.md
vendored
4
.github/CONTRIBUTING.md
vendored
@ -4,9 +4,9 @@ The issues are used to track both bugs filed by users and specific work items fo
|
|||||||
|
|
||||||
If the issue is related to errors produced by a specific PDF, please always include the PDF by providing a URL where contributors can download it. Without a PDF for reproduction, such issues will be closed. We understand that many PDFs contain sensitive information, however having a PDF is essential to resolving the issue and building our regression testing suite. If possible, try creating a reduced example exhibiting the problem but not containing sensitive data. Also small PDFs are best suited for our regression testing. If an important issue only shows on sensitive PDFs, contributors might be willing to accept these PDFs via a secure exchange.
|
If the issue is related to errors produced by a specific PDF, please always include the PDF by providing a URL where contributors can download it. Without a PDF for reproduction, such issues will be closed. We understand that many PDFs contain sensitive information, however having a PDF is essential to resolving the issue and building our regression testing suite. If possible, try creating a reduced example exhibiting the problem but not containing sensitive data. Also small PDFs are best suited for our regression testing. If an important issue only shows on sensitive PDFs, contributors might be willing to accept these PDFs via a secure exchange.
|
||||||
|
|
||||||
The issue tracking system is designed to record a single technical problem. A bug report is something where a developer/contributor can work on. The GitHub issue tracker is not a good place for general, not well thought out or unworkable ideas. Most likely a discussion-type issue will not be addressed for a long time or closed as invalid. The best place for general discussions is our Matrix room at https://chat.mozilla.org/#/room/#pdfjs:mozilla.org.
|
The issue tracking system is designed to record a single technical problem. A bug report is something where a developer/contributor can work on. The GitHub issue tracker is not a good place for general, not well thought out or unworkable ideas. Most likely a discussion-type issue will not be addressed for a long time or closed as invalid. The best place for general discussions is our #pdfjs IRC channel on irc.mozilla.org.
|
||||||
|
|
||||||
If you are developing a custom solution, first check the examples at https://github.com/mozilla/pdf.js#learning and search existing issues. If this does not help, please prepare a short well-documented example that demonstrates the problem and make it accessible online on your website, JS Bin, GitHub, etc. before opening a new issue or contacting us in the Matrix room -- keep in mind that just code snippets won't help us troubleshoot the problem.
|
If you are developing a custom solution, first check the examples at https://github.com/mozilla/pdf.js#learning and search existing issues. If this does not help, please prepare a short well-documented example that demonstrates the problem and make it accessible online on your website, JS Bin, GitHub, etc. before opening a new issue or contacting us on the IRC channel -- keep in mind that just code snippets won't help us troubleshoot the problem.
|
||||||
|
|
||||||
Note that the translations for PDF.js in the `l10n` folder are imported from the Nightly channel of Mozilla Firefox, such that we don't have to maintain them ourselves. This means that we will not accept pull requests that add new languages and/or modify existing translations, unless the corresponding changes have been made in Mozilla Firefox first.
|
Note that the translations for PDF.js in the `l10n` folder are imported from the Nightly channel of Mozilla Firefox, such that we don't have to maintain them ourselves. This means that we will not accept pull requests that add new languages and/or modify existing translations, unless the corresponding changes have been made in Mozilla Firefox first.
|
||||||
|
|
||||||
|
8
.github/dependabot.yml
vendored
8
.github/dependabot.yml
vendored
@ -1,8 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
labels:
|
|
||||||
- "dependencies"
|
|
27
.github/fluent_linter_config.yml
vendored
27
.github/fluent_linter_config.yml
vendored
@ -1,27 +0,0 @@
|
|||||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
|
|
||||||
# See https://github.com/mozilla-l10n/moz-fluent-linter/blob/main/src/fluent_linter/config.yml
|
|
||||||
# for details
|
|
||||||
|
|
||||||
---
|
|
||||||
ID01:
|
|
||||||
enabled: true
|
|
||||||
exclusions:
|
|
||||||
messages: []
|
|
||||||
files: []
|
|
||||||
ID02:
|
|
||||||
enabled: true
|
|
||||||
min_length: 9
|
|
||||||
exclusions:
|
|
||||||
messages: []
|
|
||||||
files: []
|
|
||||||
CO01:
|
|
||||||
enabled: true
|
|
||||||
brands:
|
|
||||||
- Firefox
|
|
||||||
- Mozilla
|
|
||||||
exclusions:
|
|
||||||
files: []
|
|
||||||
messages: []
|
|
1
.github/requirements.txt
vendored
1
.github/requirements.txt
vendored
@ -1 +0,0 @@
|
|||||||
moz-fluent-linter==0.4.*
|
|
37
.github/workflows/ci.yml
vendored
37
.github/workflows/ci.yml
vendored
@ -1,37 +0,0 @@
|
|||||||
name: CI
|
|
||||||
on: [push, pull_request]
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
node-version: [18, lts/*, latest]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
- name: Install Gulp
|
|
||||||
run: npm install -g gulp-cli
|
|
||||||
|
|
||||||
- name: Install other dependencies
|
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: Run external tests
|
|
||||||
run: gulp externaltest
|
|
||||||
|
|
||||||
- name: Run CLI unit tests
|
|
||||||
run: gulp unittestcli
|
|
35
.github/workflows/codeql.yml
vendored
35
.github/workflows/codeql.yml
vendored
@ -1,35 +0,0 @@
|
|||||||
name: CodeQL
|
|
||||||
on: [push, pull_request]
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [javascript]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v3
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
queries: security-and-quality
|
|
||||||
|
|
||||||
- name: Autobuild CodeQL
|
|
||||||
uses: github/codeql-action/autobuild@v3
|
|
||||||
|
|
||||||
- name: Perform CodeQL analysis
|
|
||||||
uses: github/codeql-action/analyze@v3
|
|
42
.github/workflows/fluent_linter.yml
vendored
42
.github/workflows/fluent_linter.yml
vendored
@ -1,42 +0,0 @@
|
|||||||
name: Lint Fluent Reference Files
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'l10n/en-US/**.ftl'
|
|
||||||
- '.github/fluent_linter_config.yml'
|
|
||||||
- '.github/workflows/fluent_linter.yml'
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'l10n/en-US/**.ftl'
|
|
||||||
- '.github/fluent_linter_config.yml'
|
|
||||||
- '.github/workflows/fluent_linter.yml'
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
workflow_dispatch:
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
name: Lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Use Python 3.12
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.12'
|
|
||||||
cache: 'pip'
|
|
||||||
|
|
||||||
- name: Install Fluent dependencies
|
|
||||||
run: |
|
|
||||||
pip install -r .github/requirements.txt
|
|
||||||
|
|
||||||
- name: Lint Fluent reference files
|
|
||||||
run: |
|
|
||||||
moz-fluent-lint ./l10n/en-US --config .github/fluent_linter_config.yml
|
|
64
.github/workflows/font_tests.yml
vendored
64
.github/workflows/font_tests.yml
vendored
@ -1,64 +0,0 @@
|
|||||||
name: Font tests
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
paths:
|
|
||||||
- 'gulpfile.mjs'
|
|
||||||
- 'src/**'
|
|
||||||
- 'test/test.mjs'
|
|
||||||
- 'test/font/**'
|
|
||||||
- '.github/workflows/font_tests.yml'
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- 'gulpfile.mjs'
|
|
||||||
- 'src/**'
|
|
||||||
- 'test/test.mjs'
|
|
||||||
- 'test/font/**'
|
|
||||||
- '.github/workflows/font_tests.yml'
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
workflow_dispatch:
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: Test
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
node-version: [lts/*]
|
|
||||||
os: [windows-latest, ubuntu-latest]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
- name: Install Gulp
|
|
||||||
run: npm install -g gulp-cli
|
|
||||||
|
|
||||||
- name: Install other dependencies
|
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: Use Python 3.12
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.12'
|
|
||||||
cache: 'pip'
|
|
||||||
|
|
||||||
- name: Install Fonttools
|
|
||||||
run: pip install fonttools
|
|
||||||
|
|
||||||
- name: Run font tests
|
|
||||||
run: gulp fonttest --headless
|
|
37
.github/workflows/lint.yml
vendored
37
.github/workflows/lint.yml
vendored
@ -1,37 +0,0 @@
|
|||||||
name: Lint
|
|
||||||
on: [push, pull_request]
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
name: Lint
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
node-version: [lts/*]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
- name: Install Gulp
|
|
||||||
run: npm install -g gulp-cli
|
|
||||||
|
|
||||||
- name: Install other dependencies
|
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: Run lint
|
|
||||||
run: gulp lint
|
|
||||||
|
|
||||||
- name: Run lint-chromium
|
|
||||||
run: gulp lint-chromium
|
|
72
.github/workflows/publish_website.yml
vendored
72
.github/workflows/publish_website.yml
vendored
@ -1,72 +0,0 @@
|
|||||||
name: Publish website
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
name: Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node-version: [lts/*]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
- name: Install Gulp
|
|
||||||
run: npm install -g gulp-cli
|
|
||||||
|
|
||||||
- name: Install other dependencies
|
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: Build the website
|
|
||||||
run: gulp web
|
|
||||||
|
|
||||||
- name: Archive the website
|
|
||||||
shell: sh
|
|
||||||
run: |
|
|
||||||
chmod -c -R +rX "$INPUT_PATH" | while read line; do
|
|
||||||
echo "::warning title=Invalid file permissions automatically fixed::$line"
|
|
||||||
done
|
|
||||||
tar \
|
|
||||||
--dereference --hard-dereference \
|
|
||||||
--directory "$INPUT_PATH" \
|
|
||||||
-cvf "$RUNNER_TEMP/website.tar" \
|
|
||||||
--exclude=.git \
|
|
||||||
--exclude=.github \
|
|
||||||
.
|
|
||||||
env:
|
|
||||||
INPUT_PATH: build/gh-pages
|
|
||||||
|
|
||||||
- name: Upload the website
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: github-pages
|
|
||||||
path: ${{ runner.temp }}/website.tar
|
|
||||||
retention-days: 1
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
name: Deploy
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
permissions:
|
|
||||||
pages: write # Required to deploy to GitHub Pages.
|
|
||||||
id-token: write # Required to verify that the deployment originates from this workflow.
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Deploy the website
|
|
||||||
uses: actions/deploy-pages@v4
|
|
34
.github/workflows/types_tests.yml
vendored
34
.github/workflows/types_tests.yml
vendored
@ -1,34 +0,0 @@
|
|||||||
name: Types tests
|
|
||||||
on: [push, pull_request]
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: Test
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
node-version: [lts/*]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: ${{ matrix.node-version }}
|
|
||||||
|
|
||||||
- name: Install Gulp
|
|
||||||
run: npm install -g gulp-cli
|
|
||||||
|
|
||||||
- name: Install other dependencies
|
|
||||||
run: npm install
|
|
||||||
|
|
||||||
- name: Run types tests
|
|
||||||
run: gulp typestest
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "test/ttx/fonttools-code"]
|
||||||
|
path = test/ttx/fonttools-code
|
||||||
|
url = https://github.com/behdad/fonttools.git
|
7
.gitpod.Dockerfile
vendored
7
.gitpod.Dockerfile
vendored
@ -1,7 +0,0 @@
|
|||||||
FROM gitpod/workspace-full-vnc
|
|
||||||
|
|
||||||
USER gitpod
|
|
||||||
|
|
||||||
RUN sudo apt-get update && \
|
|
||||||
sudo apt-get install -yq firefox && \
|
|
||||||
sudo rm -rf /var/lib/apt/lists/*
|
|
13
.gitpod.yml
13
.gitpod.yml
@ -1,13 +0,0 @@
|
|||||||
image:
|
|
||||||
file: .gitpod.Dockerfile
|
|
||||||
tasks:
|
|
||||||
- command: |
|
|
||||||
gp await-port 8888 && gp preview $(gp url 8888)/web/viewer.html && echo '[{"name": "Firefox","path": "/usr/bin/firefox"}]' | jq '.' > test/resources/browser_manifests/browser_manifest.json
|
|
||||||
|
|
||||||
- init: npm install -g gulp-cli && npm install
|
|
||||||
command: gulp server
|
|
||||||
ports:
|
|
||||||
- port: 8888
|
|
||||||
onOpen: ignore
|
|
||||||
- port: 6080
|
|
||||||
onOpen: ignore
|
|
@ -1,12 +0,0 @@
|
|||||||
build/
|
|
||||||
l10n/
|
|
||||||
docs/
|
|
||||||
node_modules/
|
|
||||||
external/bcmaps/
|
|
||||||
external/builder/fixtures/
|
|
||||||
external/builder/fixtures_esprima/
|
|
||||||
external/quickjs/
|
|
||||||
test/tmp/
|
|
||||||
test/pdfs/
|
|
||||||
web/locale/
|
|
||||||
*~/
|
|
18
.prettierrc
18
.prettierrc
@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"endOfLine": "lf",
|
|
||||||
"printWidth": 80,
|
|
||||||
"semi": true,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"useTabs": false,
|
|
||||||
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
files: ["tsconfig.json"],
|
|
||||||
options: {
|
|
||||||
parser: "json",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
build/
|
|
||||||
l10n/
|
|
||||||
docs/
|
|
||||||
node_modules/
|
|
||||||
external/bcmaps/
|
|
||||||
external/builder/fixtures/
|
|
||||||
external/builder/fixtures_esprima/
|
|
||||||
external/quickjs/
|
|
||||||
test/tmp/
|
|
||||||
test/pdfs/
|
|
||||||
web/locale/
|
|
||||||
*~/
|
|
25
.stylelintrc
25
.stylelintrc
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"stylelint-prettier"
|
|
||||||
],
|
|
||||||
|
|
||||||
"rules": {
|
|
||||||
"prettier/prettier": true,
|
|
||||||
|
|
||||||
"alpha-value-notation": "number",
|
|
||||||
"block-no-empty": true,
|
|
||||||
"color-function-notation": "modern",
|
|
||||||
"color-hex-length": "short",
|
|
||||||
"color-no-invalid-hex": true,
|
|
||||||
"declaration-block-no-duplicate-properties": true,
|
|
||||||
"declaration-block-no-redundant-longhand-properties": true,
|
|
||||||
"declaration-property-value-disallowed-list": {
|
|
||||||
"float": ["inline-start", "inline-end"]
|
|
||||||
},
|
|
||||||
"length-zero-no-unit": [true, {
|
|
||||||
ignore: ["custom-properties"]
|
|
||||||
}],
|
|
||||||
"selector-pseudo-element-colon-notation": "double",
|
|
||||||
"shorthand-property-no-redundant-values": true,
|
|
||||||
},
|
|
||||||
}
|
|
11
.travis.yml
Normal file
11
.travis.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- node
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
||||||
|
install:
|
||||||
|
- npm install -g npm@latest
|
||||||
|
- npm install -g gulp-cli
|
||||||
|
- npm install
|
||||||
|
- npm update
|
40
README.md
40
README.md
@ -1,8 +1,8 @@
|
|||||||
# PDF.js [](https://github.com/mozilla/pdf.js/actions?query=workflow%3ACI+branch%3Amaster)
|
# PDF.js [](https://travis-ci.org/mozilla/pdf.js)
|
||||||
|
|
||||||
[PDF.js](https://mozilla.github.io/pdf.js/) is a Portable Document Format (PDF) viewer that is built with HTML5.
|
[PDF.js](https://mozilla.github.io/pdf.js/) is a Portable Document Format (PDF) viewer that is built with HTML5.
|
||||||
|
|
||||||
PDF.js is community-driven and supported by Mozilla. Our goal is to
|
PDF.js is community-driven and supported by Mozilla Labs. Our goal is to
|
||||||
create a general-purpose, web standards-based platform for parsing and
|
create a general-purpose, web standards-based platform for parsing and
|
||||||
rendering PDFs.
|
rendering PDFs.
|
||||||
|
|
||||||
@ -14,21 +14,16 @@ get involved, visit:
|
|||||||
+ [Issue Reporting Guide](https://github.com/mozilla/pdf.js/blob/master/.github/CONTRIBUTING.md)
|
+ [Issue Reporting Guide](https://github.com/mozilla/pdf.js/blob/master/.github/CONTRIBUTING.md)
|
||||||
+ [Code Contribution Guide](https://github.com/mozilla/pdf.js/wiki/Contributing)
|
+ [Code Contribution Guide](https://github.com/mozilla/pdf.js/wiki/Contributing)
|
||||||
+ [Frequently Asked Questions](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions)
|
+ [Frequently Asked Questions](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions)
|
||||||
+ [Good Beginner Bugs](https://github.com/mozilla/pdf.js/issues?direction=desc&labels=good-beginner-bug&page=1&sort=created&state=open)
|
+ [Good Beginner Bugs](https://github.com/mozilla/pdf.js/issues?direction=desc&labels=5-good-beginner-bug&page=1&sort=created&state=open)
|
||||||
+ [Projects](https://github.com/mozilla/pdf.js/projects)
|
+ [Projects](https://github.com/mozilla/pdf.js/projects)
|
||||||
|
|
||||||
Feel free to stop by our [Matrix room](https://chat.mozilla.org/#/room/#pdfjs:mozilla.org) for questions or guidance.
|
Feel free to stop by #pdfjs on irc.mozilla.org for questions or guidance.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
### Online demo
|
### Online demo
|
||||||
|
|
||||||
Please note that the "Modern browsers" version assumes native support for the
|
+ https://mozilla.github.io/pdf.js/web/viewer.html
|
||||||
latest JavaScript features; please also see [this wiki page](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support).
|
|
||||||
|
|
||||||
+ Modern browsers: https://mozilla.github.io/pdf.js/web/viewer.html
|
|
||||||
|
|
||||||
+ Older browsers: https://mozilla.github.io/pdf.js/legacy/web/viewer.html
|
|
||||||
|
|
||||||
### Browser Extensions
|
### Browser Extensions
|
||||||
|
|
||||||
@ -53,19 +48,14 @@ To get a local copy of the current code, clone it using git:
|
|||||||
|
|
||||||
Next, install Node.js via the [official package](https://nodejs.org) or via
|
Next, install Node.js via the [official package](https://nodejs.org) or via
|
||||||
[nvm](https://github.com/creationix/nvm). You need to install the gulp package
|
[nvm](https://github.com/creationix/nvm). You need to install the gulp package
|
||||||
globally (see also [gulp's getting started](https://github.com/gulpjs/gulp/tree/master/docs/getting-started)):
|
globally (see also [gulp's getting started](https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md#getting-started)):
|
||||||
|
|
||||||
$ npm install -g gulp-cli@^2.3.0
|
$ npm install -g gulp-cli
|
||||||
|
|
||||||
If you prefer to not install `gulp-cli` globally, you have to prefix all the `gulp` commands with `npx` (for example, `npx gulp server` instead of `gulp server`).
|
|
||||||
|
|
||||||
If everything worked out, install all dependencies for PDF.js:
|
If everything worked out, install all dependencies for PDF.js:
|
||||||
|
|
||||||
$ npm install
|
$ npm install
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> On MacOS M1/M2 you may see some `node-gyp`-related errors when running `npm install`. This is because one of our dependencies, `"canvas"`, does not provide pre-built binaries for this platform and instead `npm` will try to build it from source. Please make sure to first install the necessary native dependencies using `brew`: https://github.com/Automattic/node-canvas#compiling.
|
|
||||||
|
|
||||||
Finally, you need to start a local web server as some browsers do not allow opening
|
Finally, you need to start a local web server as some browsers do not allow opening
|
||||||
PDF files using a `file://` URL. Run:
|
PDF files using a `file://` URL. Run:
|
||||||
|
|
||||||
@ -75,7 +65,7 @@ and then you can open:
|
|||||||
|
|
||||||
+ http://localhost:8888/web/viewer.html
|
+ http://localhost:8888/web/viewer.html
|
||||||
|
|
||||||
Please keep in mind that this assumes the latest version of Mozilla Firefox; refer to [Building PDF.js](https://github.com/mozilla/pdf.js/blob/master/README.md#building-pdfjs) for non-development usage of the PDF.js library.
|
Please keep in mind that this requires an ES6 compatible browser; refer to [Building PDF.js](https://github.com/mozilla/pdf.js/blob/master/README.md#building-pdfjs) for usage with older browsers.
|
||||||
|
|
||||||
It is also possible to view all test PDF files on the right side by opening:
|
It is also possible to view all test PDF files on the right side by opening:
|
||||||
|
|
||||||
@ -88,11 +78,7 @@ viewer, run:
|
|||||||
|
|
||||||
$ gulp generic
|
$ gulp generic
|
||||||
|
|
||||||
If you need to support older browsers, run:
|
This will generate `pdf.js` and `pdf.worker.js` in the `build/generic/build/` directory.
|
||||||
|
|
||||||
$ gulp generic-legacy
|
|
||||||
|
|
||||||
This will generate `pdf.js` and `pdf.worker.js` in the `build/generic/build/` directory (respectively `build/generic-legacy/build/`).
|
|
||||||
Both scripts are needed but only `pdf.js` needs to be included since `pdf.worker.js` will
|
Both scripts are needed but only `pdf.js` needs to be included since `pdf.worker.js` will
|
||||||
be loaded by `pdf.js`. The PDF.js files are large and should be minified for production.
|
be loaded by `pdf.js`. The PDF.js files are large and should be minified for production.
|
||||||
|
|
||||||
@ -137,10 +123,14 @@ Check out our FAQs and get answers to common questions:
|
|||||||
|
|
||||||
+ https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions
|
+ https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions
|
||||||
|
|
||||||
Talk to us on Matrix:
|
Talk to us on IRC (Internet Relay Chat):
|
||||||
|
|
||||||
+ https://chat.mozilla.org/#/room/#pdfjs:mozilla.org
|
+ #pdfjs on irc.mozilla.org
|
||||||
|
|
||||||
File an issue:
|
File an issue:
|
||||||
|
|
||||||
+ https://github.com/mozilla/pdf.js/issues/new
|
+ https://github.com/mozilla/pdf.js/issues/new
|
||||||
|
|
||||||
|
Follow us on twitter: @pdfjs
|
||||||
|
|
||||||
|
+ https://twitter.com/pdfjs
|
||||||
|
@ -44,24 +44,14 @@ Each PDF page has its own viewport which defines the size in pixels(72DPI) and i
|
|||||||
```js
|
```js
|
||||||
var scale = 1.5;
|
var scale = 1.5;
|
||||||
var viewport = page.getViewport({ scale: scale, });
|
var viewport = page.getViewport({ scale: scale, });
|
||||||
// Support HiDPI-screens.
|
|
||||||
var outputScale = window.devicePixelRatio || 1;
|
|
||||||
|
|
||||||
var canvas = document.getElementById('the-canvas');
|
var canvas = document.getElementById('the-canvas');
|
||||||
var context = canvas.getContext('2d');
|
var context = canvas.getContext('2d');
|
||||||
|
canvas.height = viewport.height;
|
||||||
canvas.width = Math.floor(viewport.width * outputScale);
|
canvas.width = viewport.width;
|
||||||
canvas.height = Math.floor(viewport.height * outputScale);
|
|
||||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
|
||||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
|
||||||
|
|
||||||
var transform = outputScale !== 1
|
|
||||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
|
||||||
: null;
|
|
||||||
|
|
||||||
var renderContext = {
|
var renderContext = {
|
||||||
canvasContext: context,
|
canvasContext: context,
|
||||||
transform: transform,
|
|
||||||
viewport: viewport
|
viewport: viewport
|
||||||
};
|
};
|
||||||
page.render(renderContext);
|
page.render(renderContext);
|
||||||
@ -81,19 +71,19 @@ var scaledViewport = page.getViewport({ scale: scale, });
|
|||||||
### Hello World with document load error handling
|
### Hello World with document load error handling
|
||||||
|
|
||||||
The example demonstrates how promises can be used to handle errors during loading.
|
The example demonstrates how promises can be used to handle errors during loading.
|
||||||
It also demonstrates how to wait until a page is loaded and rendered.
|
It also demonstrates how to wait until page loaded and rendered.
|
||||||
|
|
||||||
<script async src="//jsfiddle.net/pdfjs/9engc9mw/embed/html,css,result/"></script>
|
<script async src="//jsfiddle.net/pdfjs/9engc9mw/embed/js,html,result/"></script>
|
||||||
|
|
||||||
### Hello World using base64 encoded PDF
|
### Hello World using base64 encoded PDF
|
||||||
|
|
||||||
The PDF.js can accept any decoded base64 data as an array.
|
The PDF.js can accept any decoded base64 data as an array.
|
||||||
|
|
||||||
<script async src="//jsfiddle.net/pdfjs/cq0asLqz/embed/html,css,result/"></script>
|
<script async src="//jsfiddle.net/pdfjs/cq0asLqz/embed/js,html,result/"></script>
|
||||||
|
|
||||||
### Previous/Next example
|
### Previous/Next example
|
||||||
|
|
||||||
The same canvas cannot be used to perform to draw two pages at the same time --
|
The same canvas cannot be used to perform to draw two pages at the same time --
|
||||||
the example demonstrates how to wait on previous operation to be complete.
|
the example demonstrates how to wait on previous operation to be complete.
|
||||||
|
|
||||||
<script async src="//jsfiddle.net/pdfjs/wagvs9Lf/embed/html,css,result/"></script>
|
<script async src="//jsfiddle.net/pdfjs/wagvs9Lf/embed/js,html,result/"></script>
|
||||||
|
@ -37,27 +37,21 @@ Before downloading PDF.js please take a moment to understand the different layer
|
|||||||
|
|
||||||
## Download
|
## Download
|
||||||
|
|
||||||
Please refer to [this wiki page](https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support) for information about supported browsers.
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-6">
|
||||||
<h3>Prebuilt (modern browsers)</h3>
|
<h3>Prebuilt</h3>
|
||||||
<p>
|
<p>
|
||||||
Includes the generic build of PDF.js and the viewer.
|
Includes the generic build of PDF.js and the viewer.
|
||||||
</p>
|
</p>
|
||||||
|
<span class="GROUP_CLASS">
|
||||||
<a type="button" class="btn btn-primary" href="https://github.com/mozilla/pdf.js/releases/download/vSTABLE_VERSION/pdfjs-STABLE_VERSION-dist.zip">Stable (vSTABLE_VERSION)</a>
|
<a type="button" class="btn btn-primary" href="https://github.com/mozilla/pdf.js/releases/download/vSTABLE_VERSION/pdfjs-STABLE_VERSION-dist.zip">Stable (vSTABLE_VERSION)</a>
|
||||||
|
<a type="button" class="btn btn-warning HIDDEN_CLASS" href="https://github.com/mozilla/pdf.js/releases/download/vBETA_VERSION/pdfjs-BETA_VERSION-dist.zip">Beta (vBETA_VERSION)</a>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-6">
|
||||||
<h3>Prebuilt (older browsers)</h3>
|
|
||||||
<p>
|
|
||||||
Includes the generic build of PDF.js and the viewer.
|
|
||||||
</p>
|
|
||||||
<a type="button" class="btn btn-primary" href="https://github.com/mozilla/pdf.js/releases/download/vSTABLE_VERSION/pdfjs-STABLE_VERSION-legacy-dist.zip">Stable (vSTABLE_VERSION)</a>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h3>Source</h3>
|
<h3>Source</h3>
|
||||||
To get a local copy of the current code, clone it using git:
|
To get a local copy of the current code, clone it using git:
|
||||||
<pre><code>$ git clone https://github.com/mozilla/pdf.js.git
|
<pre><code>$ git clone git://github.com/mozilla/pdf.js.git
|
||||||
$ cd pdf.js
|
$ cd pdf.js
|
||||||
</code></pre>
|
</code></pre>
|
||||||
</div>
|
</div>
|
||||||
@ -108,8 +102,9 @@ Note that we only mention the most relevant files and folders.
|
|||||||
│ ├── display/ - display layer
|
│ ├── display/ - display layer
|
||||||
│ ├── shared/ - shared code between the core and display layers
|
│ ├── shared/ - shared code between the core and display layers
|
||||||
│ ├── interfaces.js - interface definitions for the core/display layers
|
│ ├── interfaces.js - interface definitions for the core/display layers
|
||||||
│ └── pdf.*.js - wrapper files for bundling
|
│ ├── pdf.*.js - wrapper files for bundling
|
||||||
├── test/ - unit, font, reference, and integration tests
|
│ └── worker_loader.js - used for developer builds to load worker files
|
||||||
|
├── test/ - unit, font and reference tests
|
||||||
├── web/ - viewer layer
|
├── web/ - viewer layer
|
||||||
├── LICENSE
|
├── LICENSE
|
||||||
├── README.md
|
├── README.md
|
||||||
|
@ -9,6 +9,6 @@ template: layout.jade
|
|||||||
</p>
|
</p>
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<a type="button" class="btn btn-lg btn-default" href="getting_started/#download">Download</a>
|
<a type="button" class="btn btn-lg btn-default" href="getting_started/#download">Download</a>
|
||||||
<a type="button" class="btn btn-lg btn-default" href="https://github.com/mozilla/pdf.js#online-demo">Demo</a>
|
<a type="button" class="btn btn-lg btn-default" href="web/viewer.html">Demo</a>
|
||||||
<a type="button" class="btn btn-lg btn-default" href="https://github.com/mozilla/pdf.js">GitHub Project</a>
|
<a type="button" class="btn btn-lg btn-default" href="https://github.com/mozilla/pdf.js">GitHub Project</a>
|
||||||
</p>
|
</p>
|
||||||
|
@ -3,9 +3,22 @@
|
|||||||
"../.eslintrc"
|
"../.eslintrc"
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 6,
|
||||||
|
},
|
||||||
|
|
||||||
|
"env": {
|
||||||
|
"es6": false,
|
||||||
|
},
|
||||||
|
|
||||||
"globals": {
|
"globals": {
|
||||||
"pdfjsImageDecoders": false,
|
"pdfjsImageDecoders": false,
|
||||||
"pdfjsLib": false,
|
"pdfjsLib": false,
|
||||||
"pdfjsViewer": false,
|
"pdfjsViewer": false,
|
||||||
|
"Uint8Array": false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"rules": {
|
||||||
|
"object-shorthand": ["error", "never"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
11
examples/acroforms/README.md
Normal file
11
examples/acroforms/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
## Overview
|
||||||
|
|
||||||
|
Example to demonstrate PDF.js library usage for rendering files with AcroForms.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Build and install PDF.js using `gulp dist-install` and run `gulp server` to
|
||||||
|
start a web server. You can then work with the example at
|
||||||
|
http://localhost:8888/examples/acroforms/acroforms.html.
|
||||||
|
|
||||||
|
Refer to `acroforms.js` for the source code of the example.
|
44
examples/acroforms/acroforms.html
Normal file
44
examples/acroforms/acroforms.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Copyright 2017 Mozilla Foundation
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<html dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
|
||||||
|
<title>AcroForms example</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||||
|
|
||||||
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
|
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.page {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="pageContainer"></div>
|
||||||
|
|
||||||
|
<script src="acroforms.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
52
examples/acroforms/acroforms.js
Normal file
52
examples/acroforms/acroforms.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* Copyright 2017 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
|
var DEFAULT_URL = '../../test/pdfs/f1040.pdf';
|
||||||
|
var DEFAULT_SCALE = 1.0;
|
||||||
|
|
||||||
|
var container = document.getElementById('pageContainer');
|
||||||
|
|
||||||
|
// Fetch the PDF document from the URL using promises.
|
||||||
|
var loadingTask = pdfjsLib.getDocument(DEFAULT_URL);
|
||||||
|
loadingTask.promise.then(function(doc) {
|
||||||
|
// Use a promise to fetch and render the next page.
|
||||||
|
var promise = Promise.resolve();
|
||||||
|
|
||||||
|
for (var i = 1; i <= doc.numPages; i++) {
|
||||||
|
promise = promise.then(function (pageNum) {
|
||||||
|
return doc.getPage(pageNum).then(function (pdfPage) {
|
||||||
|
// Create the page view.
|
||||||
|
var pdfPageView = new pdfjsViewer.PDFPageView({
|
||||||
|
container: container,
|
||||||
|
id: pageNum,
|
||||||
|
scale: DEFAULT_SCALE,
|
||||||
|
defaultViewport: pdfPage.getViewport({ scale: DEFAULT_SCALE, }),
|
||||||
|
annotationLayerFactory:
|
||||||
|
new pdfjsViewer.DefaultAnnotationLayerFactory(),
|
||||||
|
renderInteractiveForms: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Associate the actual page with the view and draw it.
|
||||||
|
pdfPageView.setPdfPage(pdfPage);
|
||||||
|
return pdfPageView.draw();
|
||||||
|
});
|
||||||
|
}.bind(null, i));
|
||||||
|
}
|
||||||
|
});
|
1
examples/browserify/.gitignore
vendored
Normal file
1
examples/browserify/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules/
|
26
examples/browserify/README.md
Normal file
26
examples/browserify/README.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
## Overview
|
||||||
|
|
||||||
|
Example to demonstrate PDF.js library usage with Browserify.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Build project and install the example dependencies:
|
||||||
|
|
||||||
|
$ gulp dist-install
|
||||||
|
$ cd examples/browserify
|
||||||
|
$ npm install
|
||||||
|
|
||||||
|
To build Browserify bundles, run `gulp build`. If you are running
|
||||||
|
a web server, you can observe the build results at
|
||||||
|
http://localhost:8888/examples/browserify/index.html
|
||||||
|
|
||||||
|
See main.js, worker.js and gulpfile.js files. Please notice that PDF.js
|
||||||
|
packaging requires packaging of the main application and PDF.js worker code,
|
||||||
|
and the `workerSrc` path shall be set to the latter file. The pdf.worker.js file
|
||||||
|
shall be excluded from the main bundle.
|
||||||
|
|
||||||
|
Alternatives to the gulp commands (without compression) are:
|
||||||
|
|
||||||
|
$ mkdir -p ../../build/browserify
|
||||||
|
$ node_modules/.bin/browserify main.js -u ./node_modules/pdfjs-dist/build/pdf.worker.js -o ../../build/browserify/main.bundle.js
|
||||||
|
$ node_modules/.bin/browserify worker.js -o ../../build/browserify/pdf.worker.bundle.js
|
36
examples/browserify/gulpfile.js
Normal file
36
examples/browserify/gulpfile.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
var gulp = require('gulp');
|
||||||
|
var browserify = require('browserify');
|
||||||
|
var streamify = require('gulp-streamify');
|
||||||
|
var rename = require('gulp-rename');
|
||||||
|
var uglify = require('gulp-uglify');
|
||||||
|
var source = require('vinyl-source-stream');
|
||||||
|
|
||||||
|
var OUTPUT_PATH = '../../build/browserify';
|
||||||
|
var TMP_FILE_PREFIX = '../../build/browserify_';
|
||||||
|
|
||||||
|
gulp.task('build-bundle', function() {
|
||||||
|
return browserify('main.js', { output: TMP_FILE_PREFIX + 'main.tmp', })
|
||||||
|
.ignore(require.resolve('pdfjs-dist/build/pdf.worker')) // Reducing size
|
||||||
|
.bundle()
|
||||||
|
.pipe(source(TMP_FILE_PREFIX + 'main.tmp'))
|
||||||
|
.pipe(streamify(uglify()))
|
||||||
|
.pipe(rename('main.bundle.js'))
|
||||||
|
.pipe(gulp.dest(OUTPUT_PATH));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('build-worker', function() {
|
||||||
|
// We can create our own viewer (see worker.js) or use already defined one.
|
||||||
|
var workerSrc = require.resolve('pdfjs-dist/build/pdf.worker.entry');
|
||||||
|
return browserify(workerSrc, { output: TMP_FILE_PREFIX + 'worker.tmp', })
|
||||||
|
.bundle()
|
||||||
|
.pipe(source(TMP_FILE_PREFIX + 'worker.tmp'))
|
||||||
|
.pipe(streamify(uglify({
|
||||||
|
compress: {
|
||||||
|
sequences: false, // Chrome has issue with the generated code if true
|
||||||
|
},
|
||||||
|
})))
|
||||||
|
.pipe(rename('pdf.worker.bundle.js'))
|
||||||
|
.pipe(gulp.dest(OUTPUT_PATH));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('build', gulp.series('build-bundle', 'build-worker'));
|
11
examples/browserify/index.html
Normal file
11
examples/browserify/index.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>browserify example</title>
|
||||||
|
<script src="../../build/browserify/main.bundle.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="theCanvas"></canvas>
|
||||||
|
</body>
|
||||||
|
</html>
|
33
examples/browserify/main.js
Normal file
33
examples/browserify/main.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
|
// Hello world example for browserify.
|
||||||
|
|
||||||
|
var pdfjsLib = require('pdfjs-dist');
|
||||||
|
|
||||||
|
var pdfPath = '../helloworld/helloworld.pdf';
|
||||||
|
|
||||||
|
// Setting worker path to worker bundle.
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../build/browserify/pdf.worker.bundle.js';
|
||||||
|
|
||||||
|
// Loading a document.
|
||||||
|
var loadingTask = pdfjsLib.getDocument(pdfPath);
|
||||||
|
loadingTask.promise.then(function (pdfDocument) {
|
||||||
|
// Request a first page
|
||||||
|
return pdfDocument.getPage(1).then(function (pdfPage) {
|
||||||
|
// Display page on the existing canvas with 100% scale.
|
||||||
|
var viewport = pdfPage.getViewport({ scale: 1.0, });
|
||||||
|
var canvas = document.getElementById('theCanvas');
|
||||||
|
canvas.width = viewport.width;
|
||||||
|
canvas.height = viewport.height;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
var renderTask = pdfPage.render({
|
||||||
|
canvasContext: ctx,
|
||||||
|
viewport: viewport,
|
||||||
|
});
|
||||||
|
return renderTask.promise;
|
||||||
|
});
|
||||||
|
}).catch(function (reason) {
|
||||||
|
console.error('Error: ' + reason);
|
||||||
|
});
|
16
examples/browserify/package.json
Normal file
16
examples/browserify/package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "browserify-pdf.js-example",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"browserify": "^13.0.0",
|
||||||
|
"gulp": "^3.9.1",
|
||||||
|
"gulp-rename": "^1.2.2",
|
||||||
|
"gulp-streamify": "^1.0.2",
|
||||||
|
"gulp-uglify": "^1.5.3",
|
||||||
|
"pdfjs-dist": "../../node_modules/pdfjs-dist",
|
||||||
|
"vinyl-source-stream": "^1.1.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp build"
|
||||||
|
}
|
||||||
|
}
|
7
examples/browserify/worker.js
Normal file
7
examples/browserify/worker.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
|
// Hello world example for browserify: worker bundle.
|
||||||
|
|
||||||
|
(typeof window !== 'undefined' ? window : {}).pdfjsWorker =
|
||||||
|
require('pdfjs-dist/build/pdf.worker');
|
@ -31,13 +31,13 @@ limitations under the License.
|
|||||||
|
|
||||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||||
|
|
||||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body tabindex="1">
|
<body tabindex="1">
|
||||||
<div id="pageContainer" class="pdfViewer singlePageView"></div>
|
<div id="pageContainer" class="pdfViewer singlePageView"></div>
|
||||||
|
|
||||||
<script src="pageviewer.mjs" type="module"></script>
|
<script src="pageviewer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
62
examples/components/pageviewer.js
Normal file
62
examples/components/pageviewer.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/* Copyright 2014 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
|
||||||
|
alert('Please build the pdfjs-dist library using\n' +
|
||||||
|
' `gulp dist-install`');
|
||||||
|
}
|
||||||
|
|
||||||
|
// The workerSrc property shall be specified.
|
||||||
|
//
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
|
// Some PDFs need external cmaps.
|
||||||
|
//
|
||||||
|
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||||
|
var CMAP_PACKED = true;
|
||||||
|
|
||||||
|
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
var PAGE_TO_VIEW = 1;
|
||||||
|
var SCALE = 1.0;
|
||||||
|
|
||||||
|
var container = document.getElementById('pageContainer');
|
||||||
|
|
||||||
|
// Loading document.
|
||||||
|
var loadingTask = pdfjsLib.getDocument({
|
||||||
|
url: DEFAULT_URL,
|
||||||
|
cMapUrl: CMAP_URL,
|
||||||
|
cMapPacked: CMAP_PACKED,
|
||||||
|
});
|
||||||
|
loadingTask.promise.then(function(pdfDocument) {
|
||||||
|
// Document loaded, retrieving the page.
|
||||||
|
return pdfDocument.getPage(PAGE_TO_VIEW).then(function (pdfPage) {
|
||||||
|
// Creating the page view with default parameters.
|
||||||
|
var pdfPageView = new pdfjsViewer.PDFPageView({
|
||||||
|
container: container,
|
||||||
|
id: PAGE_TO_VIEW,
|
||||||
|
scale: SCALE,
|
||||||
|
defaultViewport: pdfPage.getViewport({ scale: SCALE, }),
|
||||||
|
// We can enable text/annotations layers, if needed
|
||||||
|
textLayerFactory: new pdfjsViewer.DefaultTextLayerFactory(),
|
||||||
|
annotationLayerFactory: new pdfjsViewer.DefaultAnnotationLayerFactory(),
|
||||||
|
});
|
||||||
|
// Associates the actual page with the view, and drawing it
|
||||||
|
pdfPageView.setPdfPage(pdfPage);
|
||||||
|
return pdfPageView.draw();
|
||||||
|
});
|
||||||
|
});
|
@ -1,63 +0,0 @@
|
|||||||
/* Copyright 2014 Mozilla Foundation
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFPageView) {
|
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
|
||||||
}
|
|
||||||
|
|
||||||
// The workerSrc property shall be specified.
|
|
||||||
//
|
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
|
||||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
|
||||||
|
|
||||||
// Some PDFs need external cmaps.
|
|
||||||
//
|
|
||||||
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
|
||||||
const CMAP_PACKED = true;
|
|
||||||
|
|
||||||
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
|
||||||
const PAGE_TO_VIEW = 1;
|
|
||||||
const SCALE = 1.0;
|
|
||||||
|
|
||||||
const ENABLE_XFA = true;
|
|
||||||
|
|
||||||
const container = document.getElementById("pageContainer");
|
|
||||||
|
|
||||||
const eventBus = new pdfjsViewer.EventBus();
|
|
||||||
|
|
||||||
// Loading document.
|
|
||||||
const loadingTask = pdfjsLib.getDocument({
|
|
||||||
url: DEFAULT_URL,
|
|
||||||
cMapUrl: CMAP_URL,
|
|
||||||
cMapPacked: CMAP_PACKED,
|
|
||||||
enableXfa: ENABLE_XFA,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pdfDocument = await loadingTask.promise;
|
|
||||||
// Document loaded, retrieving the page.
|
|
||||||
const pdfPage = await pdfDocument.getPage(PAGE_TO_VIEW);
|
|
||||||
|
|
||||||
// Creating the page view with default parameters.
|
|
||||||
const pdfPageView = new pdfjsViewer.PDFPageView({
|
|
||||||
container,
|
|
||||||
id: PAGE_TO_VIEW,
|
|
||||||
scale: SCALE,
|
|
||||||
defaultViewport: pdfPage.getViewport({ scale: SCALE }),
|
|
||||||
eventBus,
|
|
||||||
});
|
|
||||||
// Associate the actual page with the view, and draw it.
|
|
||||||
pdfPageView.setPdfPage(pdfPage);
|
|
||||||
pdfPageView.draw();
|
|
@ -37,8 +37,8 @@ limitations under the License.
|
|||||||
|
|
||||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||||
|
|
||||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body tabindex="1">
|
<body tabindex="1">
|
||||||
@ -46,6 +46,6 @@ limitations under the License.
|
|||||||
<div id="viewer" class="pdfViewer"></div>
|
<div id="viewer" class="pdfViewer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="simpleviewer.mjs" type="module"></script>
|
<script src="simpleviewer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
74
examples/components/simpleviewer.js
Normal file
74
examples/components/simpleviewer.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* Copyright 2014 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
||||||
|
alert('Please build the pdfjs-dist library using\n' +
|
||||||
|
' `gulp dist-install`');
|
||||||
|
}
|
||||||
|
|
||||||
|
// The workerSrc property shall be specified.
|
||||||
|
//
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
|
// Some PDFs need external cmaps.
|
||||||
|
//
|
||||||
|
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||||
|
var CMAP_PACKED = true;
|
||||||
|
|
||||||
|
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
var SEARCH_FOR = ''; // try 'Mozilla';
|
||||||
|
|
||||||
|
var container = document.getElementById('viewerContainer');
|
||||||
|
|
||||||
|
// (Optionally) enable hyperlinks within PDF files.
|
||||||
|
var pdfLinkService = new pdfjsViewer.PDFLinkService();
|
||||||
|
|
||||||
|
// (Optionally) enable find controller.
|
||||||
|
var pdfFindController = new pdfjsViewer.PDFFindController({
|
||||||
|
linkService: pdfLinkService,
|
||||||
|
});
|
||||||
|
|
||||||
|
var pdfViewer = new pdfjsViewer.PDFViewer({
|
||||||
|
container: container,
|
||||||
|
linkService: pdfLinkService,
|
||||||
|
findController: pdfFindController,
|
||||||
|
});
|
||||||
|
pdfLinkService.setViewer(pdfViewer);
|
||||||
|
|
||||||
|
document.addEventListener('pagesinit', function () {
|
||||||
|
// We can use pdfViewer now, e.g. let's change default scale.
|
||||||
|
pdfViewer.currentScaleValue = 'page-width';
|
||||||
|
|
||||||
|
if (SEARCH_FOR) { // We can try search for things
|
||||||
|
pdfFindController.executeCommand('find', { query: SEARCH_FOR, });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Loading document.
|
||||||
|
var loadingTask = pdfjsLib.getDocument({
|
||||||
|
url: DEFAULT_URL,
|
||||||
|
cMapUrl: CMAP_URL,
|
||||||
|
cMapPacked: CMAP_PACKED,
|
||||||
|
});
|
||||||
|
loadingTask.promise.then(function(pdfDocument) {
|
||||||
|
// Document loaded, specifying document for the viewer and
|
||||||
|
// the (optional) linkService.
|
||||||
|
pdfViewer.setDocument(pdfDocument);
|
||||||
|
|
||||||
|
pdfLinkService.setDocument(pdfDocument, null);
|
||||||
|
});
|
@ -1,97 +0,0 @@
|
|||||||
/* Copyright 2014 Mozilla Foundation
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
|
||||||
}
|
|
||||||
|
|
||||||
// The workerSrc property shall be specified.
|
|
||||||
//
|
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
|
||||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
|
||||||
|
|
||||||
// Some PDFs need external cmaps.
|
|
||||||
//
|
|
||||||
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
|
||||||
const CMAP_PACKED = true;
|
|
||||||
|
|
||||||
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
|
||||||
// To test the AcroForm and/or scripting functionality, try e.g. this file:
|
|
||||||
// "../../test/pdfs/160F-2019.pdf"
|
|
||||||
|
|
||||||
const ENABLE_XFA = true;
|
|
||||||
const SEARCH_FOR = ""; // try "Mozilla";
|
|
||||||
|
|
||||||
const SANDBOX_BUNDLE_SRC = new URL(
|
|
||||||
"../../node_modules/pdfjs-dist/build/pdf.sandbox.mjs",
|
|
||||||
window.location
|
|
||||||
);
|
|
||||||
|
|
||||||
const container = document.getElementById("viewerContainer");
|
|
||||||
|
|
||||||
const eventBus = new pdfjsViewer.EventBus();
|
|
||||||
|
|
||||||
// (Optionally) enable hyperlinks within PDF files.
|
|
||||||
const pdfLinkService = new pdfjsViewer.PDFLinkService({
|
|
||||||
eventBus,
|
|
||||||
});
|
|
||||||
|
|
||||||
// (Optionally) enable find controller.
|
|
||||||
const pdfFindController = new pdfjsViewer.PDFFindController({
|
|
||||||
eventBus,
|
|
||||||
linkService: pdfLinkService,
|
|
||||||
});
|
|
||||||
|
|
||||||
// (Optionally) enable scripting support.
|
|
||||||
const pdfScriptingManager = new pdfjsViewer.PDFScriptingManager({
|
|
||||||
eventBus,
|
|
||||||
sandboxBundleSrc: SANDBOX_BUNDLE_SRC,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pdfViewer = new pdfjsViewer.PDFViewer({
|
|
||||||
container,
|
|
||||||
eventBus,
|
|
||||||
linkService: pdfLinkService,
|
|
||||||
findController: pdfFindController,
|
|
||||||
scriptingManager: pdfScriptingManager,
|
|
||||||
});
|
|
||||||
pdfLinkService.setViewer(pdfViewer);
|
|
||||||
pdfScriptingManager.setViewer(pdfViewer);
|
|
||||||
|
|
||||||
eventBus.on("pagesinit", function () {
|
|
||||||
// We can use pdfViewer now, e.g. let's change default scale.
|
|
||||||
pdfViewer.currentScaleValue = "page-width";
|
|
||||||
|
|
||||||
// We can try searching for things.
|
|
||||||
if (SEARCH_FOR) {
|
|
||||||
eventBus.dispatch("find", { type: "", query: SEARCH_FOR });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Loading document.
|
|
||||||
const loadingTask = pdfjsLib.getDocument({
|
|
||||||
url: DEFAULT_URL,
|
|
||||||
cMapUrl: CMAP_URL,
|
|
||||||
cMapPacked: CMAP_PACKED,
|
|
||||||
enableXfa: ENABLE_XFA,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pdfDocument = await loadingTask.promise;
|
|
||||||
// Document loaded, specifying document for the viewer and
|
|
||||||
// the (optional) linkService.
|
|
||||||
pdfViewer.setDocument(pdfDocument);
|
|
||||||
|
|
||||||
pdfLinkService.setDocument(pdfDocument, null);
|
|
@ -37,8 +37,8 @@ limitations under the License.
|
|||||||
|
|
||||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||||
|
|
||||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body tabindex="1">
|
<body tabindex="1">
|
||||||
@ -46,6 +46,6 @@ limitations under the License.
|
|||||||
<div id="viewer" class="pdfViewer"></div>
|
<div id="viewer" class="pdfViewer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="singlepageviewer.mjs" type="module"></script>
|
<script src="singlepageviewer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
74
examples/components/singlepageviewer.js
Normal file
74
examples/components/singlepageviewer.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* Copyright 2014 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFSinglePageViewer) {
|
||||||
|
alert('Please build the pdfjs-dist library using\n' +
|
||||||
|
' `gulp dist-install`');
|
||||||
|
}
|
||||||
|
|
||||||
|
// The workerSrc property shall be specified.
|
||||||
|
//
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
|
// Some PDFs need external cmaps.
|
||||||
|
//
|
||||||
|
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||||
|
var CMAP_PACKED = true;
|
||||||
|
|
||||||
|
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
var SEARCH_FOR = ''; // try 'Mozilla';
|
||||||
|
|
||||||
|
var container = document.getElementById('viewerContainer');
|
||||||
|
|
||||||
|
// (Optionally) enable hyperlinks within PDF files.
|
||||||
|
var pdfLinkService = new pdfjsViewer.PDFLinkService();
|
||||||
|
|
||||||
|
// (Optionally) enable find controller.
|
||||||
|
var pdfFindController = new pdfjsViewer.PDFFindController({
|
||||||
|
linkService: pdfLinkService,
|
||||||
|
});
|
||||||
|
|
||||||
|
var pdfSinglePageViewer = new pdfjsViewer.PDFSinglePageViewer({
|
||||||
|
container: container,
|
||||||
|
linkService: pdfLinkService,
|
||||||
|
findController: pdfFindController,
|
||||||
|
});
|
||||||
|
pdfLinkService.setViewer(pdfSinglePageViewer);
|
||||||
|
|
||||||
|
document.addEventListener('pagesinit', function () {
|
||||||
|
// We can use pdfSinglePageViewer now, e.g. let's change default scale.
|
||||||
|
pdfSinglePageViewer.currentScaleValue = 'page-width';
|
||||||
|
|
||||||
|
if (SEARCH_FOR) { // We can try search for things
|
||||||
|
pdfFindController.executeCommand('find', { query: SEARCH_FOR, });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Loading document.
|
||||||
|
var loadingTask = pdfjsLib.getDocument({
|
||||||
|
url: DEFAULT_URL,
|
||||||
|
cMapUrl: CMAP_URL,
|
||||||
|
cMapPacked: CMAP_PACKED,
|
||||||
|
});
|
||||||
|
loadingTask.promise.then(function(pdfDocument) {
|
||||||
|
// Document loaded, specifying document for the viewer and
|
||||||
|
// the (optional) linkService.
|
||||||
|
pdfSinglePageViewer.setDocument(pdfDocument);
|
||||||
|
|
||||||
|
pdfLinkService.setDocument(pdfDocument, null);
|
||||||
|
});
|
@ -1,97 +0,0 @@
|
|||||||
/* Copyright 2014 Mozilla Foundation
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFSinglePageViewer) {
|
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
|
||||||
}
|
|
||||||
|
|
||||||
// The workerSrc property shall be specified.
|
|
||||||
//
|
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
|
||||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
|
||||||
|
|
||||||
// Some PDFs need external cmaps.
|
|
||||||
//
|
|
||||||
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
|
||||||
const CMAP_PACKED = true;
|
|
||||||
|
|
||||||
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
|
||||||
// To test the AcroForm and/or scripting functionality, try e.g. this file:
|
|
||||||
// "../../test/pdfs/160F-2019.pdf"
|
|
||||||
|
|
||||||
const ENABLE_XFA = true;
|
|
||||||
const SEARCH_FOR = ""; // try "Mozilla";
|
|
||||||
|
|
||||||
const SANDBOX_BUNDLE_SRC = new URL(
|
|
||||||
"../../node_modules/pdfjs-dist/build/pdf.sandbox.mjs",
|
|
||||||
window.location
|
|
||||||
);
|
|
||||||
|
|
||||||
const container = document.getElementById("viewerContainer");
|
|
||||||
|
|
||||||
const eventBus = new pdfjsViewer.EventBus();
|
|
||||||
|
|
||||||
// (Optionally) enable hyperlinks within PDF files.
|
|
||||||
const pdfLinkService = new pdfjsViewer.PDFLinkService({
|
|
||||||
eventBus,
|
|
||||||
});
|
|
||||||
|
|
||||||
// (Optionally) enable find controller.
|
|
||||||
const pdfFindController = new pdfjsViewer.PDFFindController({
|
|
||||||
eventBus,
|
|
||||||
linkService: pdfLinkService,
|
|
||||||
});
|
|
||||||
|
|
||||||
// (Optionally) enable scripting support.
|
|
||||||
const pdfScriptingManager = new pdfjsViewer.PDFScriptingManager({
|
|
||||||
eventBus,
|
|
||||||
sandboxBundleSrc: SANDBOX_BUNDLE_SRC,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pdfSinglePageViewer = new pdfjsViewer.PDFSinglePageViewer({
|
|
||||||
container,
|
|
||||||
eventBus,
|
|
||||||
linkService: pdfLinkService,
|
|
||||||
findController: pdfFindController,
|
|
||||||
scriptingManager: pdfScriptingManager,
|
|
||||||
});
|
|
||||||
pdfLinkService.setViewer(pdfSinglePageViewer);
|
|
||||||
pdfScriptingManager.setViewer(pdfSinglePageViewer);
|
|
||||||
|
|
||||||
eventBus.on("pagesinit", function () {
|
|
||||||
// We can use pdfSinglePageViewer now, e.g. let's change default scale.
|
|
||||||
pdfSinglePageViewer.currentScaleValue = "page-width";
|
|
||||||
|
|
||||||
// We can try searching for things.
|
|
||||||
if (SEARCH_FOR) {
|
|
||||||
eventBus.dispatch("find", { type: "", query: SEARCH_FOR });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Loading document.
|
|
||||||
const loadingTask = pdfjsLib.getDocument({
|
|
||||||
url: DEFAULT_URL,
|
|
||||||
cMapUrl: CMAP_URL,
|
|
||||||
cMapPacked: CMAP_PACKED,
|
|
||||||
enableXfa: ENABLE_XFA,
|
|
||||||
});
|
|
||||||
|
|
||||||
const pdfDocument = await loadingTask.promise;
|
|
||||||
// Document loaded, specifying document for the viewer and
|
|
||||||
// the (optional) linkService.
|
|
||||||
pdfSinglePageViewer.setDocument(pdfDocument);
|
|
||||||
|
|
||||||
pdfLinkService.setDocument(pdfDocument, null);
|
|
@ -29,12 +29,12 @@ limitations under the License.
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script src="../../node_modules/pdfjs-dist/image_decoders/pdf.image_decoders.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/image_decoders/pdf.image_decoders.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body tabindex="1">
|
<body tabindex="1">
|
||||||
<canvas id="jpegCanvas" width="0" height="0"></canvas>
|
<canvas id="jpegCanvas" width="0" height="0"></canvas>
|
||||||
|
|
||||||
<script src="jpeg_viewer.mjs" type="module"></script>
|
<script src="jpeg_viewer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
79
examples/image_decoders/jpeg_viewer.js
Normal file
79
examples/image_decoders/jpeg_viewer.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/* Copyright 2018 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (!pdfjsImageDecoders.JpegImage) {
|
||||||
|
alert('Please build the pdfjs-dist library using `gulp dist-install`');
|
||||||
|
}
|
||||||
|
|
||||||
|
var JPEG_IMAGE = 'fish.jpg';
|
||||||
|
|
||||||
|
var jpegCanvas = document.getElementById('jpegCanvas');
|
||||||
|
var jpegCtx = jpegCanvas.getContext('2d');
|
||||||
|
|
||||||
|
// Load the image data, and convert it to a Uint8Array.
|
||||||
|
//
|
||||||
|
var nonBinaryRequest = false;
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open('GET', JPEG_IMAGE, false);
|
||||||
|
try {
|
||||||
|
request.responseType = 'arraybuffer';
|
||||||
|
nonBinaryRequest = request.responseType !== 'arraybuffer';
|
||||||
|
} catch (e) {
|
||||||
|
nonBinaryRequest = true;
|
||||||
|
}
|
||||||
|
if (nonBinaryRequest && request.overrideMimeType) {
|
||||||
|
request.overrideMimeType('text/plain; charset=x-user-defined');
|
||||||
|
}
|
||||||
|
request.send(null);
|
||||||
|
|
||||||
|
var typedArrayImage;
|
||||||
|
if (nonBinaryRequest) {
|
||||||
|
var str = request.responseText, length = str.length;
|
||||||
|
var bytes = new Uint8Array(length);
|
||||||
|
for (var i = 0; i < length; ++i) {
|
||||||
|
bytes[i] = str.charCodeAt(i) & 0xFF;
|
||||||
|
}
|
||||||
|
typedArrayImage = bytes;
|
||||||
|
} else {
|
||||||
|
typedArrayImage = new Uint8Array(request.response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the image data using `JpegImage`.
|
||||||
|
//
|
||||||
|
var jpegImage = new pdfjsImageDecoders.JpegImage();
|
||||||
|
jpegImage.parse(typedArrayImage);
|
||||||
|
|
||||||
|
var width = jpegImage.width, height = jpegImage.height;
|
||||||
|
var jpegData = jpegImage.getData({
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
forceRGB: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Render the JPEG image on a <canvas>.
|
||||||
|
//
|
||||||
|
var imageData = jpegCtx.createImageData(width, height);
|
||||||
|
var imageBytes = imageData.data;
|
||||||
|
for (var j = 0, k = 0, jj = width * height * 4; j < jj;) {
|
||||||
|
imageBytes[j++] = jpegData[k++];
|
||||||
|
imageBytes[j++] = jpegData[k++];
|
||||||
|
imageBytes[j++] = jpegData[k++];
|
||||||
|
imageBytes[j++] = 255;
|
||||||
|
}
|
||||||
|
jpegCanvas.width = width;
|
||||||
|
jpegCanvas.height = height;
|
||||||
|
jpegCtx.putImageData(imageData, 0, 0);
|
@ -1,59 +0,0 @@
|
|||||||
/* Copyright 2018 Mozilla Foundation
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!pdfjsImageDecoders.JpegImage) {
|
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
alert("Please build the pdfjs-dist library using `gulp dist-install`");
|
|
||||||
}
|
|
||||||
|
|
||||||
const JPEG_IMAGE = "fish.jpg";
|
|
||||||
|
|
||||||
const jpegCanvas = document.getElementById("jpegCanvas");
|
|
||||||
const jpegCtx = jpegCanvas.getContext("2d");
|
|
||||||
|
|
||||||
// Load the image data, and convert it to a Uint8Array.
|
|
||||||
//
|
|
||||||
const response = await fetch(JPEG_IMAGE);
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(response.statusText);
|
|
||||||
}
|
|
||||||
const typedArrayImage = new Uint8Array(await response.arrayBuffer());
|
|
||||||
|
|
||||||
// Parse the image data using `JpegImage`.
|
|
||||||
//
|
|
||||||
const jpegImage = new pdfjsImageDecoders.JpegImage();
|
|
||||||
jpegImage.parse(typedArrayImage);
|
|
||||||
|
|
||||||
const width = jpegImage.width,
|
|
||||||
height = jpegImage.height;
|
|
||||||
const jpegData = jpegImage.getData({
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
forceRGB: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Render the JPEG image on a <canvas>.
|
|
||||||
//
|
|
||||||
const imageData = jpegCtx.createImageData(width, height);
|
|
||||||
const imageBytes = imageData.data;
|
|
||||||
for (let j = 0, k = 0, jj = width * height * 4; j < jj; ) {
|
|
||||||
imageBytes[j++] = jpegData[k++];
|
|
||||||
imageBytes[j++] = jpegData[k++];
|
|
||||||
imageBytes[j++] = jpegData[k++];
|
|
||||||
imageBytes[j++] = 255;
|
|
||||||
}
|
|
||||||
jpegCanvas.width = width;
|
|
||||||
jpegCanvas.height = height;
|
|
||||||
jpegCtx.putImageData(imageData, 0, 0);
|
|
@ -8,61 +8,53 @@
|
|||||||
|
|
||||||
<h1>'Hello, world!' example</h1>
|
<h1>'Hello, world!' example</h1>
|
||||||
|
|
||||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
|
<canvas id="the-canvas" style="border:1px solid black"></canvas>
|
||||||
|
|
||||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
|
|
||||||
<script id="script" type="module">
|
<script id="script">
|
||||||
//
|
//
|
||||||
// If absolute URL from the remote server is provided, configure the CORS
|
// If absolute URL from the remote server is provided, configure the CORS
|
||||||
// header on that server.
|
// header on that server.
|
||||||
//
|
//
|
||||||
const url = './helloworld.pdf';
|
var url = './helloworld.pdf';
|
||||||
|
|
||||||
//
|
//
|
||||||
// The workerSrc property shall be specified.
|
// The workerSrc property shall be specified.
|
||||||
//
|
//
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
//
|
//
|
||||||
// Asynchronous download PDF
|
// Asynchronous download PDF
|
||||||
//
|
//
|
||||||
const loadingTask = pdfjsLib.getDocument(url);
|
var loadingTask = pdfjsLib.getDocument(url);
|
||||||
const pdf = await loadingTask.promise;
|
loadingTask.promise.then(function(pdf) {
|
||||||
//
|
//
|
||||||
// Fetch the first page
|
// Fetch the first page
|
||||||
//
|
//
|
||||||
const page = await pdf.getPage(1);
|
pdf.getPage(1).then(function(page) {
|
||||||
const scale = 1.5;
|
var scale = 1.5;
|
||||||
const viewport = page.getViewport({ scale });
|
var viewport = page.getViewport({ scale: scale, });
|
||||||
// Support HiDPI-screens.
|
|
||||||
const outputScale = window.devicePixelRatio || 1;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Prepare canvas using PDF page dimensions
|
// Prepare canvas using PDF page dimensions
|
||||||
//
|
//
|
||||||
const canvas = document.getElementById("the-canvas");
|
var canvas = document.getElementById('the-canvas');
|
||||||
const context = canvas.getContext("2d");
|
var context = canvas.getContext('2d');
|
||||||
|
canvas.height = viewport.height;
|
||||||
canvas.width = Math.floor(viewport.width * outputScale);
|
canvas.width = viewport.width;
|
||||||
canvas.height = Math.floor(viewport.height * outputScale);
|
|
||||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
|
||||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
|
||||||
|
|
||||||
const transform = outputScale !== 1
|
|
||||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
|
||||||
: null;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render PDF page into canvas context
|
// Render PDF page into canvas context
|
||||||
//
|
//
|
||||||
const renderContext = {
|
var renderContext = {
|
||||||
canvasContext: context,
|
canvasContext: context,
|
||||||
transform,
|
viewport: viewport,
|
||||||
viewport,
|
|
||||||
};
|
};
|
||||||
page.render(renderContext);
|
page.render(renderContext);
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
<h1>'Hello, world!' example</h1>
|
<h1>'Hello, world!' example</h1>
|
||||||
|
|
||||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
|
<canvas id="the-canvas" style="border:1px solid black"></canvas>
|
||||||
|
|
||||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
|
|
||||||
<script id="script" type="module">
|
<script id="script">
|
||||||
// atob() is used to convert base64 encoded PDF to binary-like data.
|
// atob() is used to convert base64 encoded PDF to binary-like data.
|
||||||
// (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/
|
// (See also https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/
|
||||||
// Base64_encoding_and_decoding.)
|
// Base64_encoding_and_decoding.)
|
||||||
@ -35,39 +35,31 @@
|
|||||||
// The workerSrc property shall be specified.
|
// The workerSrc property shall be specified.
|
||||||
//
|
//
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
// Opening PDF by passing its binary data as a string. It is still preferable
|
// Opening PDF by passing its binary data as a string. It is still preferable
|
||||||
// to use Uint8Array, but string or array-like structure will work too.
|
// to use Uint8Array, but string or array-like structure will work too.
|
||||||
var loadingTask = pdfjsLib.getDocument({ data: pdfData, });
|
var loadingTask = pdfjsLib.getDocument({ data: pdfData, });
|
||||||
var pdf = await loadingTask.promise;
|
loadingTask.promise.then(function(pdf) {
|
||||||
// Fetch the first page.
|
// Fetch the first page.
|
||||||
var page = await pdf.getPage(1);
|
pdf.getPage(1).then(function(page) {
|
||||||
var scale = 1.5;
|
var scale = 1.5;
|
||||||
var viewport = page.getViewport({ scale: scale, });
|
var viewport = page.getViewport({ scale: scale, });
|
||||||
// Support HiDPI-screens.
|
|
||||||
var outputScale = window.devicePixelRatio || 1;
|
|
||||||
|
|
||||||
// Prepare canvas using PDF page dimensions.
|
// Prepare canvas using PDF page dimensions.
|
||||||
var canvas = document.getElementById('the-canvas');
|
var canvas = document.getElementById('the-canvas');
|
||||||
var context = canvas.getContext('2d');
|
var context = canvas.getContext('2d');
|
||||||
|
canvas.height = viewport.height;
|
||||||
canvas.width = Math.floor(viewport.width * outputScale);
|
canvas.width = viewport.width;
|
||||||
canvas.height = Math.floor(viewport.height * outputScale);
|
|
||||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
|
||||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
|
||||||
|
|
||||||
var transform = outputScale !== 1
|
|
||||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Render PDF page into canvas context.
|
// Render PDF page into canvas context.
|
||||||
var renderContext = {
|
var renderContext = {
|
||||||
canvasContext: context,
|
canvasContext: context,
|
||||||
transform,
|
viewport: viewport,
|
||||||
viewport,
|
|
||||||
};
|
};
|
||||||
page.render(renderContext);
|
page.render(renderContext);
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -16,12 +16,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
|
<canvas id="the-canvas" style="border:1px solid black"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
|
|
||||||
<script id="script" type="module">
|
<script id="script">
|
||||||
//
|
//
|
||||||
// If absolute URL from the remote server is provided, configure the CORS
|
// If absolute URL from the remote server is provided, configure the CORS
|
||||||
// header on that server.
|
// header on that server.
|
||||||
@ -34,7 +34,7 @@
|
|||||||
// shall be specified.
|
// shall be specified.
|
||||||
//
|
//
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
'../../node_modules/pdfjs-dist/build/pdf.worker.mjs';
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
var pdfDoc = null,
|
var pdfDoc = null,
|
||||||
pageNum = 1,
|
pageNum = 1,
|
||||||
@ -53,22 +53,12 @@
|
|||||||
// Using promise to fetch the page
|
// Using promise to fetch the page
|
||||||
pdfDoc.getPage(num).then(function(page) {
|
pdfDoc.getPage(num).then(function(page) {
|
||||||
var viewport = page.getViewport({ scale: scale, });
|
var viewport = page.getViewport({ scale: scale, });
|
||||||
// Support HiDPI-screens.
|
canvas.height = viewport.height;
|
||||||
var outputScale = window.devicePixelRatio || 1;
|
canvas.width = viewport.width;
|
||||||
|
|
||||||
canvas.width = Math.floor(viewport.width * outputScale);
|
|
||||||
canvas.height = Math.floor(viewport.height * outputScale);
|
|
||||||
canvas.style.width = Math.floor(viewport.width) + "px";
|
|
||||||
canvas.style.height = Math.floor(viewport.height) + "px";
|
|
||||||
|
|
||||||
var transform = outputScale !== 1
|
|
||||||
? [outputScale, 0, 0, outputScale, 0, 0]
|
|
||||||
: null;
|
|
||||||
|
|
||||||
// Render PDF page into canvas context
|
// Render PDF page into canvas context
|
||||||
var renderContext = {
|
var renderContext = {
|
||||||
canvasContext: ctx,
|
canvasContext: ctx,
|
||||||
transform: transform,
|
|
||||||
viewport: viewport,
|
viewport: viewport,
|
||||||
};
|
};
|
||||||
var renderTask = page.render(renderContext);
|
var renderTask = page.render(renderContext);
|
||||||
@ -90,7 +80,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* If another page rendering in progress, waits until the rendering is
|
* If another page rendering in progress, waits until the rendering is
|
||||||
* finished. Otherwise, executes rendering immediately.
|
* finised. Otherwise, executes rendering immediately.
|
||||||
*/
|
*/
|
||||||
function queueRenderPage(num) {
|
function queueRenderPage(num) {
|
||||||
if (pageRendering) {
|
if (pageRendering) {
|
||||||
@ -128,11 +118,13 @@
|
|||||||
* Asynchronously downloads PDF.
|
* Asynchronously downloads PDF.
|
||||||
*/
|
*/
|
||||||
var loadingTask = pdfjsLib.getDocument(url);
|
var loadingTask = pdfjsLib.getDocument(url);
|
||||||
pdfDoc = await loadingTask.promise;
|
loadingTask.promise.then(function(pdfDoc_) {
|
||||||
|
pdfDoc = pdfDoc_;
|
||||||
document.getElementById('page_count').textContent = pdfDoc.numPages;
|
document.getElementById('page_count').textContent = pdfDoc.numPages;
|
||||||
|
|
||||||
// Initial/first page rendering
|
// Initial/first page rendering
|
||||||
renderPage(pageNum);
|
renderPage(pageNum);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@ -26,12 +26,12 @@ html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header {
|
header {
|
||||||
background-color: rgb(244 244 244 / 1);
|
background-color: #f4f4f4;
|
||||||
}
|
}
|
||||||
|
|
||||||
header h1 {
|
header h1 {
|
||||||
border-bottom: 1px solid rgb(216 216 216 / 1);
|
border-bottom: 1px solid #d8d8d8;
|
||||||
color: rgb(133 133 133 / 1);
|
color: #858585;
|
||||||
font-size: 23px;
|
font-size: 23px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
@ -44,7 +44,7 @@ header h1 {
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
background: url(images/document_bg.png);
|
background: url(images/document_bg.png);
|
||||||
color: rgb(255 255 255 / 1);
|
color: #fff;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -71,7 +71,7 @@ footer {
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
box-shadow: 0 -0.2rem 0.5rem rgb(50 50 50 / 0.75);
|
box-shadow: 0 -0.2rem 0.5rem rgba(50, 50, 50, 0.75);
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbarButton {
|
.toolbarButton {
|
||||||
@ -81,7 +81,7 @@ footer {
|
|||||||
border-width: 0;
|
border-width: 0;
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-color: rgb(0 0 0 / 0);
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbarButton.pageUp {
|
.toolbarButton.pageUp {
|
||||||
@ -110,11 +110,10 @@ footer {
|
|||||||
left: 36%;
|
left: 36%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 0;
|
border: 0;
|
||||||
background-color: rgb(0 0 0 / 0);
|
background-color: transparent;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
color: rgb(255 255 255 / 1);
|
color: #FFF;
|
||||||
background-image: url(images/div_line_left.png),
|
background-image: url(images/div_line_left.png), url(images/div_line_right.png);
|
||||||
url(images/div_line_right.png);
|
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: left, right;
|
background-position: left, right;
|
||||||
background-size: 0.2rem, 0.2rem;
|
background-size: 0.2rem, 0.2rem;
|
||||||
@ -139,7 +138,7 @@ footer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.toolbarButton[disabled] {
|
.toolbarButton[disabled] {
|
||||||
opacity: 0.3;
|
opacity: .3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
@ -153,7 +152,10 @@ footer {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
inset: 5rem 0 4rem;
|
top: 5rem;
|
||||||
|
bottom: 4rem;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
@ -164,7 +166,7 @@ canvas {
|
|||||||
.pdfViewer .page .loadingIcon {
|
.pdfViewer .page .loadingIcon {
|
||||||
width: 2.9rem;
|
width: 2.9rem;
|
||||||
height: 2.9rem;
|
height: 2.9rem;
|
||||||
background: url("images/spinner.png") no-repeat left top / 38rem;
|
background: url("images/spinner.png") no-repeat left top / 38rem ;
|
||||||
border: medium none;
|
border: medium none;
|
||||||
animation: 1s steps(10, end) 0s normal none infinite moveDefault;
|
animation: 1s steps(10, end) 0s normal none infinite moveDefault;
|
||||||
display: block;
|
display: block;
|
||||||
@ -184,59 +186,72 @@ canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#loadingBar {
|
#loadingBar {
|
||||||
/* Define this variable here, and not in :root, to avoid reflowing the
|
|
||||||
entire viewer when updating progress (see issue 15958). */
|
|
||||||
--progressBar-percent: 0%;
|
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 0.6rem;
|
height: .6rem;
|
||||||
background-color: rgb(51 51 51 / 1);
|
background-color: #333;
|
||||||
border-bottom: 1px solid rgb(51 51 51 / 1);
|
border-bottom: 1px solid #333;
|
||||||
|
margin-top: 5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loadingBar .progress {
|
#loadingBar .progress {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 0;
|
||||||
transform: scaleX(var(--progressBar-percent));
|
|
||||||
transform-origin: 0 0;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: rgb(221 221 221 / 1);
|
background-color: #ddd;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: transform 200ms;
|
transition: width 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes progressIndeterminate {
|
@keyframes progressIndeterminate {
|
||||||
0% {
|
0% { left: 0; }
|
||||||
transform: translateX(0%);
|
50% { left: 100%; }
|
||||||
}
|
100% { left: 100%; }
|
||||||
50% {
|
|
||||||
transform: translateX(100%);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(100%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#loadingBar.indeterminate .progress {
|
#loadingBar .progress.indeterminate {
|
||||||
transform: none;
|
background-color: #999;
|
||||||
background-color: rgb(153 153 153 / 1);
|
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loadingBar.indeterminate .progress .glimmer {
|
#loadingBar .indeterminate .glimmer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 5rem;
|
width: 5rem;
|
||||||
background-image: linear-gradient(
|
|
||||||
to right,
|
background-image: linear-gradient(to right, #999 0%, #fff 50%, #999 100%);
|
||||||
rgb(153 153 153 / 1) 0%,
|
|
||||||
rgb(255 255 255 / 1) 50%,
|
|
||||||
rgb(153 153 153 / 1) 100%
|
|
||||||
);
|
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
animation: progressIndeterminate 2s linear infinite;
|
animation: progressIndeterminate 2s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#errorWrapper {
|
||||||
|
background: none repeat scroll 0 0 #FF5555;
|
||||||
|
color: white;
|
||||||
|
left: 0;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 3.2rem;
|
||||||
|
z-index: 1000;
|
||||||
|
padding: 0.3rem;
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#errorMessageLeft {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#errorMessageRight {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#errorMoreInfo {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
color: black;
|
||||||
|
padding: 0.3rem;
|
||||||
|
margin: 0.3rem;
|
||||||
|
width: 98%;
|
||||||
|
}
|
||||||
|
@ -24,8 +24,8 @@ limitations under the License.
|
|||||||
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||||
<link rel="stylesheet" type="text/css" href="viewer.css">
|
<link rel="stylesheet" type="text/css" href="viewer.css">
|
||||||
|
|
||||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@ -42,6 +42,25 @@ limitations under the License.
|
|||||||
<div class="glimmer"></div>
|
<div class="glimmer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="errorWrapper" hidden="true">
|
||||||
|
<div id="errorMessageLeft">
|
||||||
|
<span id="errorMessage"></span>
|
||||||
|
<button id="errorShowMore">
|
||||||
|
More Information
|
||||||
|
</button>
|
||||||
|
<button id="errorShowLess">
|
||||||
|
Less Information
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="errorMessageRight">
|
||||||
|
<button id="errorClose">
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="clearBoth"></div>
|
||||||
|
<textarea id="errorMoreInfo" hidden="true" readonly="readonly"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<button class="toolbarButton pageUp" title="Previous Page" id="previous"></button>
|
<button class="toolbarButton pageUp" title="Previous Page" id="previous"></button>
|
||||||
<button class="toolbarButton pageDown" title="Next Page" id="next"></button>
|
<button class="toolbarButton pageDown" title="Next Page" id="next"></button>
|
||||||
@ -52,6 +71,6 @@ limitations under the License.
|
|||||||
<button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn"></button>
|
<button class="toolbarButton zoomIn" title="Zoom In" id="zoomIn"></button>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="viewer.mjs" type="module"></script>
|
<script src="viewer.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
383
examples/mobile-viewer/viewer.js
Normal file
383
examples/mobile-viewer/viewer.js
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
/* Copyright 2016 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
||||||
|
alert('Please build the pdfjs-dist library using\n `gulp dist-install`');
|
||||||
|
}
|
||||||
|
|
||||||
|
var USE_ONLY_CSS_ZOOM = true;
|
||||||
|
var TEXT_LAYER_MODE = 0; // DISABLE
|
||||||
|
var MAX_IMAGE_SIZE = 1024 * 1024;
|
||||||
|
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||||
|
var CMAP_PACKED = true;
|
||||||
|
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
|
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
var DEFAULT_SCALE_DELTA = 1.1;
|
||||||
|
var MIN_SCALE = 0.25;
|
||||||
|
var MAX_SCALE = 10.0;
|
||||||
|
var DEFAULT_SCALE_VALUE = 'auto';
|
||||||
|
|
||||||
|
var PDFViewerApplication = {
|
||||||
|
pdfLoadingTask: null,
|
||||||
|
pdfDocument: null,
|
||||||
|
pdfViewer: null,
|
||||||
|
pdfHistory: null,
|
||||||
|
pdfLinkService: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens PDF document specified by URL.
|
||||||
|
* @returns {Promise} - Returns the promise, which is resolved when document
|
||||||
|
* is opened.
|
||||||
|
*/
|
||||||
|
open: function(params) {
|
||||||
|
if (this.pdfLoadingTask) {
|
||||||
|
// We need to destroy already opened document
|
||||||
|
return this.close().then(function () {
|
||||||
|
// ... and repeat the open() call.
|
||||||
|
return this.open(params);
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
var url = params.url;
|
||||||
|
var self = this;
|
||||||
|
this.setTitleUsingUrl(url);
|
||||||
|
|
||||||
|
// Loading document.
|
||||||
|
var loadingTask = pdfjsLib.getDocument({
|
||||||
|
url: url,
|
||||||
|
maxImageSize: MAX_IMAGE_SIZE,
|
||||||
|
cMapUrl: CMAP_URL,
|
||||||
|
cMapPacked: CMAP_PACKED,
|
||||||
|
});
|
||||||
|
this.pdfLoadingTask = loadingTask;
|
||||||
|
|
||||||
|
loadingTask.onProgress = function (progressData) {
|
||||||
|
self.progress(progressData.loaded / progressData.total);
|
||||||
|
};
|
||||||
|
|
||||||
|
return loadingTask.promise.then(function (pdfDocument) {
|
||||||
|
// Document loaded, specifying document for the viewer.
|
||||||
|
self.pdfDocument = pdfDocument;
|
||||||
|
self.pdfViewer.setDocument(pdfDocument);
|
||||||
|
self.pdfLinkService.setDocument(pdfDocument);
|
||||||
|
self.pdfHistory.initialize({ fingerprint: pdfDocument.fingerprint, });
|
||||||
|
|
||||||
|
self.loadingBar.hide();
|
||||||
|
self.setTitleUsingMetadata(pdfDocument);
|
||||||
|
}, function (exception) {
|
||||||
|
var message = exception && exception.message;
|
||||||
|
var l10n = self.l10n;
|
||||||
|
var loadingErrorMessage;
|
||||||
|
|
||||||
|
if (exception instanceof pdfjsLib.InvalidPDFException) {
|
||||||
|
// change error message also for other builds
|
||||||
|
loadingErrorMessage = l10n.get('invalid_file_error', null,
|
||||||
|
'Invalid or corrupted PDF file.');
|
||||||
|
} else if (exception instanceof pdfjsLib.MissingPDFException) {
|
||||||
|
// special message for missing PDFs
|
||||||
|
loadingErrorMessage = l10n.get('missing_file_error', null,
|
||||||
|
'Missing PDF file.');
|
||||||
|
} else if (exception instanceof pdfjsLib.UnexpectedResponseException) {
|
||||||
|
loadingErrorMessage = l10n.get('unexpected_response_error', null,
|
||||||
|
'Unexpected server response.');
|
||||||
|
} else {
|
||||||
|
loadingErrorMessage = l10n.get('loading_error', null,
|
||||||
|
'An error occurred while loading the PDF.');
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingErrorMessage.then(function (msg) {
|
||||||
|
self.error(msg, { message: message, });
|
||||||
|
});
|
||||||
|
self.loadingBar.hide();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes opened PDF document.
|
||||||
|
* @returns {Promise} - Returns the promise, which is resolved when all
|
||||||
|
* destruction is completed.
|
||||||
|
*/
|
||||||
|
close: function() {
|
||||||
|
var errorWrapper = document.getElementById('errorWrapper');
|
||||||
|
errorWrapper.setAttribute('hidden', 'true');
|
||||||
|
|
||||||
|
if (!this.pdfLoadingTask) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
var promise = this.pdfLoadingTask.destroy();
|
||||||
|
this.pdfLoadingTask = null;
|
||||||
|
|
||||||
|
if (this.pdfDocument) {
|
||||||
|
this.pdfDocument = null;
|
||||||
|
|
||||||
|
this.pdfViewer.setDocument(null);
|
||||||
|
this.pdfLinkService.setDocument(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
},
|
||||||
|
|
||||||
|
get loadingBar() {
|
||||||
|
var bar = new pdfjsViewer.ProgressBar('#loadingBar', {});
|
||||||
|
|
||||||
|
return pdfjsLib.shadow(this, 'loadingBar', bar);
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
|
||||||
|
this.url = url;
|
||||||
|
var title = pdfjsLib.getFilenameFromUrl(url) || url;
|
||||||
|
try {
|
||||||
|
title = decodeURIComponent(title);
|
||||||
|
} catch (e) {
|
||||||
|
// decodeURIComponent may throw URIError,
|
||||||
|
// fall back to using the unprocessed url in that case
|
||||||
|
}
|
||||||
|
this.setTitle(title);
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitleUsingMetadata: function(pdfDocument) {
|
||||||
|
var self = this;
|
||||||
|
pdfDocument.getMetadata().then(function(data) {
|
||||||
|
var info = data.info, metadata = data.metadata;
|
||||||
|
self.documentInfo = info;
|
||||||
|
self.metadata = metadata;
|
||||||
|
|
||||||
|
// Provides some basic debug information
|
||||||
|
console.log('PDF ' + pdfDocument.fingerprint + ' [' +
|
||||||
|
info.PDFFormatVersion + ' ' + (info.Producer || '-').trim() +
|
||||||
|
' / ' + (info.Creator || '-').trim() + ']' +
|
||||||
|
' (PDF.js: ' + (pdfjsLib.version || '-') + ')');
|
||||||
|
|
||||||
|
var pdfTitle;
|
||||||
|
if (metadata && metadata.has('dc:title')) {
|
||||||
|
var title = metadata.get('dc:title');
|
||||||
|
// Ghostscript sometimes returns 'Untitled', so prevent setting the
|
||||||
|
// title to 'Untitled.
|
||||||
|
if (title !== 'Untitled') {
|
||||||
|
pdfTitle = title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pdfTitle && info && info['Title']) {
|
||||||
|
pdfTitle = info['Title'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pdfTitle) {
|
||||||
|
self.setTitle(pdfTitle + ' - ' + document.title);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setTitle: function pdfViewSetTitle(title) {
|
||||||
|
document.title = title;
|
||||||
|
document.getElementById('title').textContent = title;
|
||||||
|
},
|
||||||
|
|
||||||
|
error: function pdfViewError(message, moreInfo) {
|
||||||
|
var l10n = this.l10n;
|
||||||
|
var moreInfoText = [l10n.get('error_version_info',
|
||||||
|
{ version: pdfjsLib.version || '?',
|
||||||
|
build: pdfjsLib.build || '?', },
|
||||||
|
'PDF.js v{{version}} (build: {{build}})')];
|
||||||
|
|
||||||
|
if (moreInfo) {
|
||||||
|
moreInfoText.push(
|
||||||
|
l10n.get('error_message', { message: moreInfo.message, },
|
||||||
|
'Message: {{message}}'));
|
||||||
|
if (moreInfo.stack) {
|
||||||
|
moreInfoText.push(
|
||||||
|
l10n.get('error_stack', { stack: moreInfo.stack, },
|
||||||
|
'Stack: {{stack}}'));
|
||||||
|
} else {
|
||||||
|
if (moreInfo.filename) {
|
||||||
|
moreInfoText.push(
|
||||||
|
l10n.get('error_file', { file: moreInfo.filename, },
|
||||||
|
'File: {{file}}'));
|
||||||
|
}
|
||||||
|
if (moreInfo.lineNumber) {
|
||||||
|
moreInfoText.push(
|
||||||
|
l10n.get('error_line', { line: moreInfo.lineNumber, },
|
||||||
|
'Line: {{line}}'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var errorWrapper = document.getElementById('errorWrapper');
|
||||||
|
errorWrapper.removeAttribute('hidden');
|
||||||
|
|
||||||
|
var errorMessage = document.getElementById('errorMessage');
|
||||||
|
errorMessage.textContent = message;
|
||||||
|
|
||||||
|
var closeButton = document.getElementById('errorClose');
|
||||||
|
closeButton.onclick = function() {
|
||||||
|
errorWrapper.setAttribute('hidden', 'true');
|
||||||
|
};
|
||||||
|
|
||||||
|
var errorMoreInfo = document.getElementById('errorMoreInfo');
|
||||||
|
var moreInfoButton = document.getElementById('errorShowMore');
|
||||||
|
var lessInfoButton = document.getElementById('errorShowLess');
|
||||||
|
moreInfoButton.onclick = function() {
|
||||||
|
errorMoreInfo.removeAttribute('hidden');
|
||||||
|
moreInfoButton.setAttribute('hidden', 'true');
|
||||||
|
lessInfoButton.removeAttribute('hidden');
|
||||||
|
errorMoreInfo.style.height = errorMoreInfo.scrollHeight + 'px';
|
||||||
|
};
|
||||||
|
lessInfoButton.onclick = function() {
|
||||||
|
errorMoreInfo.setAttribute('hidden', 'true');
|
||||||
|
moreInfoButton.removeAttribute('hidden');
|
||||||
|
lessInfoButton.setAttribute('hidden', 'true');
|
||||||
|
};
|
||||||
|
moreInfoButton.removeAttribute('hidden');
|
||||||
|
lessInfoButton.setAttribute('hidden', 'true');
|
||||||
|
Promise.all(moreInfoText).then(function (parts) {
|
||||||
|
errorMoreInfo.value = parts.join('\n');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
progress: function pdfViewProgress(level) {
|
||||||
|
var percent = Math.round(level * 100);
|
||||||
|
// Updating the bar if value increases.
|
||||||
|
if (percent > this.loadingBar.percent || isNaN(percent)) {
|
||||||
|
this.loadingBar.percent = percent;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get pagesCount() {
|
||||||
|
return this.pdfDocument.numPages;
|
||||||
|
},
|
||||||
|
|
||||||
|
set page(val) {
|
||||||
|
this.pdfViewer.currentPageNumber = val;
|
||||||
|
},
|
||||||
|
|
||||||
|
get page() {
|
||||||
|
return this.pdfViewer.currentPageNumber;
|
||||||
|
},
|
||||||
|
|
||||||
|
zoomIn: function pdfViewZoomIn(ticks) {
|
||||||
|
var newScale = this.pdfViewer.currentScale;
|
||||||
|
do {
|
||||||
|
newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2);
|
||||||
|
newScale = Math.ceil(newScale * 10) / 10;
|
||||||
|
newScale = Math.min(MAX_SCALE, newScale);
|
||||||
|
} while (--ticks && newScale < MAX_SCALE);
|
||||||
|
this.pdfViewer.currentScaleValue = newScale;
|
||||||
|
},
|
||||||
|
|
||||||
|
zoomOut: function pdfViewZoomOut(ticks) {
|
||||||
|
var newScale = this.pdfViewer.currentScale;
|
||||||
|
do {
|
||||||
|
newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2);
|
||||||
|
newScale = Math.floor(newScale * 10) / 10;
|
||||||
|
newScale = Math.max(MIN_SCALE, newScale);
|
||||||
|
} while (--ticks && newScale > MIN_SCALE);
|
||||||
|
this.pdfViewer.currentScaleValue = newScale;
|
||||||
|
},
|
||||||
|
|
||||||
|
initUI: function pdfViewInitUI() {
|
||||||
|
var linkService = new pdfjsViewer.PDFLinkService();
|
||||||
|
this.pdfLinkService = linkService;
|
||||||
|
|
||||||
|
this.l10n = pdfjsViewer.NullL10n;
|
||||||
|
|
||||||
|
var container = document.getElementById('viewerContainer');
|
||||||
|
var pdfViewer = new pdfjsViewer.PDFViewer({
|
||||||
|
container: container,
|
||||||
|
linkService: linkService,
|
||||||
|
l10n: this.l10n,
|
||||||
|
useOnlyCssZoom: USE_ONLY_CSS_ZOOM,
|
||||||
|
textLayerMode: TEXT_LAYER_MODE,
|
||||||
|
});
|
||||||
|
this.pdfViewer = pdfViewer;
|
||||||
|
linkService.setViewer(pdfViewer);
|
||||||
|
|
||||||
|
this.pdfHistory = new pdfjsViewer.PDFHistory({
|
||||||
|
linkService: linkService,
|
||||||
|
});
|
||||||
|
linkService.setHistory(this.pdfHistory);
|
||||||
|
|
||||||
|
document.getElementById('previous').addEventListener('click', function() {
|
||||||
|
PDFViewerApplication.page--;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('next').addEventListener('click', function() {
|
||||||
|
PDFViewerApplication.page++;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('zoomIn').addEventListener('click', function() {
|
||||||
|
PDFViewerApplication.zoomIn();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('zoomOut').addEventListener('click', function() {
|
||||||
|
PDFViewerApplication.zoomOut();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('pageNumber').addEventListener('click', function() {
|
||||||
|
this.select();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('pageNumber').addEventListener('change',
|
||||||
|
function() {
|
||||||
|
PDFViewerApplication.page = (this.value | 0);
|
||||||
|
|
||||||
|
// Ensure that the page number input displays the correct value,
|
||||||
|
// even if the value entered by the user was invalid
|
||||||
|
// (e.g. a floating point number).
|
||||||
|
if (this.value !== PDFViewerApplication.page.toString()) {
|
||||||
|
this.value = PDFViewerApplication.page;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('pagesinit', function () {
|
||||||
|
// We can use pdfViewer now, e.g. let's change default scale.
|
||||||
|
pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('pagechanging', function (evt) {
|
||||||
|
var page = evt.detail.pageNumber;
|
||||||
|
var numPages = PDFViewerApplication.pagesCount;
|
||||||
|
|
||||||
|
document.getElementById('pageNumber').value = page;
|
||||||
|
document.getElementById('previous').disabled = (page <= 1);
|
||||||
|
document.getElementById('next').disabled = (page >= numPages);
|
||||||
|
}, true);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
PDFViewerApplication.initUI();
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
(function animationStartedClosure() {
|
||||||
|
// The offsetParent is not set until the PDF.js iframe or object is visible.
|
||||||
|
// Waiting for first animation.
|
||||||
|
PDFViewerApplication.animationStartedPromise = new Promise(
|
||||||
|
function (resolve) {
|
||||||
|
window.requestAnimationFrame(resolve);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
|
// We need to delay opening until all HTML is loaded.
|
||||||
|
PDFViewerApplication.animationStartedPromise.then(function () {
|
||||||
|
PDFViewerApplication.open({
|
||||||
|
url: DEFAULT_URL,
|
||||||
|
});
|
||||||
|
});
|
@ -1,371 +0,0 @@
|
|||||||
/* Copyright 2016 Mozilla Foundation
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_CANVAS_PIXELS = 0; // CSS-only zooming.
|
|
||||||
const TEXT_LAYER_MODE = 0; // DISABLE
|
|
||||||
const MAX_IMAGE_SIZE = 1024 * 1024;
|
|
||||||
const CMAP_URL = "../../node_modules/pdfjs-dist/cmaps/";
|
|
||||||
const CMAP_PACKED = true;
|
|
||||||
|
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
|
||||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
|
||||||
|
|
||||||
const DEFAULT_URL = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
|
||||||
const DEFAULT_SCALE_DELTA = 1.1;
|
|
||||||
const MIN_SCALE = 0.25;
|
|
||||||
const MAX_SCALE = 10.0;
|
|
||||||
const DEFAULT_SCALE_VALUE = "auto";
|
|
||||||
|
|
||||||
const PDFViewerApplication = {
|
|
||||||
pdfLoadingTask: null,
|
|
||||||
pdfDocument: null,
|
|
||||||
pdfViewer: null,
|
|
||||||
pdfHistory: null,
|
|
||||||
pdfLinkService: null,
|
|
||||||
eventBus: null,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens PDF document specified by URL.
|
|
||||||
* @returns {Promise} - Returns the promise, which is resolved when document
|
|
||||||
* is opened.
|
|
||||||
*/
|
|
||||||
open(params) {
|
|
||||||
if (this.pdfLoadingTask) {
|
|
||||||
// We need to destroy already opened document
|
|
||||||
return this.close().then(
|
|
||||||
function () {
|
|
||||||
// ... and repeat the open() call.
|
|
||||||
return this.open(params);
|
|
||||||
}.bind(this)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = params.url;
|
|
||||||
const self = this;
|
|
||||||
this.setTitleUsingUrl(url);
|
|
||||||
|
|
||||||
// Loading document.
|
|
||||||
const loadingTask = pdfjsLib.getDocument({
|
|
||||||
url,
|
|
||||||
maxImageSize: MAX_IMAGE_SIZE,
|
|
||||||
cMapUrl: CMAP_URL,
|
|
||||||
cMapPacked: CMAP_PACKED,
|
|
||||||
});
|
|
||||||
this.pdfLoadingTask = loadingTask;
|
|
||||||
|
|
||||||
loadingTask.onProgress = function (progressData) {
|
|
||||||
self.progress(progressData.loaded / progressData.total);
|
|
||||||
};
|
|
||||||
|
|
||||||
return loadingTask.promise.then(
|
|
||||||
function (pdfDocument) {
|
|
||||||
// Document loaded, specifying document for the viewer.
|
|
||||||
self.pdfDocument = pdfDocument;
|
|
||||||
self.pdfViewer.setDocument(pdfDocument);
|
|
||||||
self.pdfLinkService.setDocument(pdfDocument);
|
|
||||||
self.pdfHistory.initialize({
|
|
||||||
fingerprint: pdfDocument.fingerprints[0],
|
|
||||||
});
|
|
||||||
|
|
||||||
self.loadingBar.hide();
|
|
||||||
self.setTitleUsingMetadata(pdfDocument);
|
|
||||||
},
|
|
||||||
function (reason) {
|
|
||||||
let key = "pdfjs-loading-error";
|
|
||||||
if (reason instanceof pdfjsLib.InvalidPDFException) {
|
|
||||||
key = "pdfjs-invalid-file-error";
|
|
||||||
} else if (reason instanceof pdfjsLib.MissingPDFException) {
|
|
||||||
key = "pdfjs-missing-file-error";
|
|
||||||
} else if (reason instanceof pdfjsLib.UnexpectedResponseException) {
|
|
||||||
key = "pdfjs-unexpected-response-error";
|
|
||||||
}
|
|
||||||
self.l10n.get(key).then(msg => {
|
|
||||||
self.error(msg, { message: reason?.message });
|
|
||||||
});
|
|
||||||
self.loadingBar.hide();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes opened PDF document.
|
|
||||||
* @returns {Promise} - Returns the promise, which is resolved when all
|
|
||||||
* destruction is completed.
|
|
||||||
*/
|
|
||||||
close() {
|
|
||||||
if (!this.pdfLoadingTask) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
const promise = this.pdfLoadingTask.destroy();
|
|
||||||
this.pdfLoadingTask = null;
|
|
||||||
|
|
||||||
if (this.pdfDocument) {
|
|
||||||
this.pdfDocument = null;
|
|
||||||
|
|
||||||
this.pdfViewer.setDocument(null);
|
|
||||||
this.pdfLinkService.setDocument(null, null);
|
|
||||||
|
|
||||||
if (this.pdfHistory) {
|
|
||||||
this.pdfHistory.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
},
|
|
||||||
|
|
||||||
get loadingBar() {
|
|
||||||
const bar = document.getElementById("loadingBar");
|
|
||||||
return pdfjsLib.shadow(
|
|
||||||
this,
|
|
||||||
"loadingBar",
|
|
||||||
new pdfjsViewer.ProgressBar(bar)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) {
|
|
||||||
this.url = url;
|
|
||||||
let title = pdfjsLib.getFilenameFromUrl(url) || url;
|
|
||||||
try {
|
|
||||||
title = decodeURIComponent(title);
|
|
||||||
} catch {
|
|
||||||
// decodeURIComponent may throw URIError,
|
|
||||||
// fall back to using the unprocessed url in that case
|
|
||||||
}
|
|
||||||
this.setTitle(title);
|
|
||||||
},
|
|
||||||
|
|
||||||
setTitleUsingMetadata(pdfDocument) {
|
|
||||||
const self = this;
|
|
||||||
pdfDocument.getMetadata().then(function (data) {
|
|
||||||
const info = data.info,
|
|
||||||
metadata = data.metadata;
|
|
||||||
self.documentInfo = info;
|
|
||||||
self.metadata = metadata;
|
|
||||||
|
|
||||||
// Provides some basic debug information
|
|
||||||
console.log(
|
|
||||||
"PDF " +
|
|
||||||
pdfDocument.fingerprints[0] +
|
|
||||||
" [" +
|
|
||||||
info.PDFFormatVersion +
|
|
||||||
" " +
|
|
||||||
(info.Producer || "-").trim() +
|
|
||||||
" / " +
|
|
||||||
(info.Creator || "-").trim() +
|
|
||||||
"]" +
|
|
||||||
" (PDF.js: " +
|
|
||||||
(pdfjsLib.version || "-") +
|
|
||||||
")"
|
|
||||||
);
|
|
||||||
|
|
||||||
let pdfTitle;
|
|
||||||
if (metadata && metadata.has("dc:title")) {
|
|
||||||
const title = metadata.get("dc:title");
|
|
||||||
// Ghostscript sometimes returns 'Untitled', so prevent setting the
|
|
||||||
// title to 'Untitled.
|
|
||||||
if (title !== "Untitled") {
|
|
||||||
pdfTitle = title;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pdfTitle && info && info.Title) {
|
|
||||||
pdfTitle = info.Title;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdfTitle) {
|
|
||||||
self.setTitle(pdfTitle + " - " + document.title);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setTitle: function pdfViewSetTitle(title) {
|
|
||||||
document.title = title;
|
|
||||||
document.getElementById("title").textContent = title;
|
|
||||||
},
|
|
||||||
|
|
||||||
error: function pdfViewError(message, moreInfo) {
|
|
||||||
const moreInfoText = [
|
|
||||||
`PDF.js v${pdfjsLib.version || "?"} (build: ${pdfjsLib.build || "?"})`,
|
|
||||||
];
|
|
||||||
if (moreInfo) {
|
|
||||||
moreInfoText.push(`Message: ${moreInfo.message}`);
|
|
||||||
|
|
||||||
if (moreInfo.stack) {
|
|
||||||
moreInfoText.push(`Stack: ${moreInfo.stack}`);
|
|
||||||
} else {
|
|
||||||
if (moreInfo.filename) {
|
|
||||||
moreInfoText.push(`File: ${moreInfo.filename}`);
|
|
||||||
}
|
|
||||||
if (moreInfo.lineNumber) {
|
|
||||||
moreInfoText.push(`Line: ${moreInfo.lineNumber}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error(`${message}\n\n${moreInfoText.join("\n")}`);
|
|
||||||
},
|
|
||||||
|
|
||||||
progress: function pdfViewProgress(level) {
|
|
||||||
const percent = Math.round(level * 100);
|
|
||||||
// Updating the bar if value increases.
|
|
||||||
if (percent > this.loadingBar.percent || isNaN(percent)) {
|
|
||||||
this.loadingBar.percent = percent;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
get pagesCount() {
|
|
||||||
return this.pdfDocument.numPages;
|
|
||||||
},
|
|
||||||
|
|
||||||
get page() {
|
|
||||||
return this.pdfViewer.currentPageNumber;
|
|
||||||
},
|
|
||||||
|
|
||||||
set page(val) {
|
|
||||||
this.pdfViewer.currentPageNumber = val;
|
|
||||||
},
|
|
||||||
|
|
||||||
zoomIn: function pdfViewZoomIn(ticks) {
|
|
||||||
let newScale = this.pdfViewer.currentScale;
|
|
||||||
do {
|
|
||||||
newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2);
|
|
||||||
newScale = Math.ceil(newScale * 10) / 10;
|
|
||||||
newScale = Math.min(MAX_SCALE, newScale);
|
|
||||||
} while (--ticks && newScale < MAX_SCALE);
|
|
||||||
this.pdfViewer.currentScaleValue = newScale;
|
|
||||||
},
|
|
||||||
|
|
||||||
zoomOut: function pdfViewZoomOut(ticks) {
|
|
||||||
let newScale = this.pdfViewer.currentScale;
|
|
||||||
do {
|
|
||||||
newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2);
|
|
||||||
newScale = Math.floor(newScale * 10) / 10;
|
|
||||||
newScale = Math.max(MIN_SCALE, newScale);
|
|
||||||
} while (--ticks && newScale > MIN_SCALE);
|
|
||||||
this.pdfViewer.currentScaleValue = newScale;
|
|
||||||
},
|
|
||||||
|
|
||||||
initUI: function pdfViewInitUI() {
|
|
||||||
const eventBus = new pdfjsViewer.EventBus();
|
|
||||||
this.eventBus = eventBus;
|
|
||||||
|
|
||||||
const linkService = new pdfjsViewer.PDFLinkService({
|
|
||||||
eventBus,
|
|
||||||
});
|
|
||||||
this.pdfLinkService = linkService;
|
|
||||||
|
|
||||||
this.l10n = new pdfjsViewer.GenericL10n();
|
|
||||||
|
|
||||||
const container = document.getElementById("viewerContainer");
|
|
||||||
const pdfViewer = new pdfjsViewer.PDFViewer({
|
|
||||||
container,
|
|
||||||
eventBus,
|
|
||||||
linkService,
|
|
||||||
l10n: this.l10n,
|
|
||||||
maxCanvasPixels: MAX_CANVAS_PIXELS,
|
|
||||||
textLayerMode: TEXT_LAYER_MODE,
|
|
||||||
});
|
|
||||||
this.pdfViewer = pdfViewer;
|
|
||||||
linkService.setViewer(pdfViewer);
|
|
||||||
|
|
||||||
this.pdfHistory = new pdfjsViewer.PDFHistory({
|
|
||||||
eventBus,
|
|
||||||
linkService,
|
|
||||||
});
|
|
||||||
linkService.setHistory(this.pdfHistory);
|
|
||||||
|
|
||||||
document.getElementById("previous").addEventListener("click", function () {
|
|
||||||
PDFViewerApplication.page--;
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById("next").addEventListener("click", function () {
|
|
||||||
PDFViewerApplication.page++;
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById("zoomIn").addEventListener("click", function () {
|
|
||||||
PDFViewerApplication.zoomIn();
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById("zoomOut").addEventListener("click", function () {
|
|
||||||
PDFViewerApplication.zoomOut();
|
|
||||||
});
|
|
||||||
|
|
||||||
document
|
|
||||||
.getElementById("pageNumber")
|
|
||||||
.addEventListener("click", function () {
|
|
||||||
this.select();
|
|
||||||
});
|
|
||||||
|
|
||||||
document
|
|
||||||
.getElementById("pageNumber")
|
|
||||||
.addEventListener("change", function () {
|
|
||||||
PDFViewerApplication.page = this.value | 0;
|
|
||||||
|
|
||||||
// Ensure that the page number input displays the correct value,
|
|
||||||
// even if the value entered by the user was invalid
|
|
||||||
// (e.g. a floating point number).
|
|
||||||
if (this.value !== PDFViewerApplication.page.toString()) {
|
|
||||||
this.value = PDFViewerApplication.page;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
eventBus.on("pagesinit", function () {
|
|
||||||
// We can use pdfViewer now, e.g. let's change default scale.
|
|
||||||
pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE;
|
|
||||||
});
|
|
||||||
|
|
||||||
eventBus.on(
|
|
||||||
"pagechanging",
|
|
||||||
function (evt) {
|
|
||||||
const page = evt.pageNumber;
|
|
||||||
const numPages = PDFViewerApplication.pagesCount;
|
|
||||||
|
|
||||||
document.getElementById("pageNumber").value = page;
|
|
||||||
document.getElementById("previous").disabled = page <= 1;
|
|
||||||
document.getElementById("next").disabled = page >= numPages;
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
window.PDFViewerApplication = PDFViewerApplication;
|
|
||||||
|
|
||||||
document.addEventListener(
|
|
||||||
"DOMContentLoaded",
|
|
||||||
function () {
|
|
||||||
PDFViewerApplication.initUI();
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|
||||||
// The offsetParent is not set until the PDF.js iframe or object is visible;
|
|
||||||
// waiting for first animation.
|
|
||||||
const animationStarted = new Promise(function (resolve) {
|
|
||||||
window.requestAnimationFrame(resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
// We need to delay opening until all HTML is loaded.
|
|
||||||
animationStarted.then(function () {
|
|
||||||
PDFViewerApplication.open({
|
|
||||||
url: DEFAULT_URL,
|
|
||||||
});
|
|
||||||
});
|
|
268
examples/node/domstubs.js
Normal file
268
examples/node/domstubs.js
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
function xmlEncode(s) {
|
||||||
|
var i = 0, ch;
|
||||||
|
s = String(s);
|
||||||
|
while (i < s.length && (ch = s[i]) !== '&' && ch !== '<' &&
|
||||||
|
ch !== '\"' && ch !== '\n' && ch !== '\r' && ch !== '\t') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i >= s.length) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
var buf = s.substring(0, i);
|
||||||
|
while (i < s.length) {
|
||||||
|
ch = s[i++];
|
||||||
|
switch (ch) {
|
||||||
|
case '&':
|
||||||
|
buf += '&';
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
buf += '<';
|
||||||
|
break;
|
||||||
|
case '\"':
|
||||||
|
buf += '"';
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
buf += '
';
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
buf += '
';
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
buf += '	';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
buf += ch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
function DOMElement(name) {
|
||||||
|
this.nodeName = name;
|
||||||
|
this.childNodes = [];
|
||||||
|
this.attributes = {};
|
||||||
|
this.textContent = '';
|
||||||
|
|
||||||
|
if (name === 'style') {
|
||||||
|
this.sheet = {
|
||||||
|
cssRules: [],
|
||||||
|
insertRule: function(rule) {
|
||||||
|
this.cssRules.push(rule);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOMElement.prototype = {
|
||||||
|
getAttribute: function DOMElement_getAttribute(name) {
|
||||||
|
if (name in this.attributes) {
|
||||||
|
return this.attributes[name];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getAttributeNS: function DOMElement_getAttributeNS(NS, name) {
|
||||||
|
// Fast path
|
||||||
|
if (name in this.attributes) {
|
||||||
|
return this.attributes[name];
|
||||||
|
}
|
||||||
|
// Slow path - used by test/unit/display_svg_spec.js
|
||||||
|
// Assuming that there is only one matching attribute for a given name,
|
||||||
|
// across all namespaces.
|
||||||
|
if (NS) {
|
||||||
|
var suffix = ':' + name;
|
||||||
|
for (var fullName in this.attributes) {
|
||||||
|
if (fullName.slice(-suffix.length) === suffix) {
|
||||||
|
return this.attributes[fullName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
setAttribute: function DOMElement_setAttribute(name, value) {
|
||||||
|
value = value || '';
|
||||||
|
value = xmlEncode(value);
|
||||||
|
this.attributes[name] = value;
|
||||||
|
},
|
||||||
|
|
||||||
|
setAttributeNS: function DOMElement_setAttributeNS(NS, name, value) {
|
||||||
|
this.setAttribute(name, value);
|
||||||
|
},
|
||||||
|
|
||||||
|
appendChild: function DOMElement_appendChild(element) {
|
||||||
|
var childNodes = this.childNodes;
|
||||||
|
if (!childNodes.includes(element)) {
|
||||||
|
childNodes.push(element);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hasChildNodes: function DOMElement_hasChildNodes() {
|
||||||
|
return this.childNodes.length !== 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
cloneNode: function DOMElement_cloneNode() {
|
||||||
|
var newNode = new DOMElement(this.nodeName);
|
||||||
|
newNode.childNodes = this.childNodes;
|
||||||
|
newNode.attributes = this.attributes;
|
||||||
|
newNode.textContent = this.textContent;
|
||||||
|
return newNode;
|
||||||
|
},
|
||||||
|
|
||||||
|
// This method is offered for convenience. It is recommended to directly use
|
||||||
|
// getSerializer because that allows you to process the chunks as they come
|
||||||
|
// instead of requiring the whole image to fit in memory.
|
||||||
|
toString: function DOMElement_toString() {
|
||||||
|
var buf = [];
|
||||||
|
var serializer = this.getSerializer();
|
||||||
|
var chunk;
|
||||||
|
while ((chunk = serializer.getNext()) !== null) {
|
||||||
|
buf.push(chunk);
|
||||||
|
}
|
||||||
|
return buf.join('');
|
||||||
|
},
|
||||||
|
|
||||||
|
getSerializer: function DOMElement_getSerializer() {
|
||||||
|
return new DOMElementSerializer(this);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function DOMElementSerializer(node) {
|
||||||
|
this._node = node;
|
||||||
|
this._state = 0;
|
||||||
|
this._loopIndex = 0;
|
||||||
|
this._attributeKeys = null;
|
||||||
|
this._childSerializer = null;
|
||||||
|
}
|
||||||
|
DOMElementSerializer.prototype = {
|
||||||
|
/**
|
||||||
|
* Yields the next chunk in the serialization of the element.
|
||||||
|
*
|
||||||
|
* @returns {string|null} null if the element has fully been serialized.
|
||||||
|
*/
|
||||||
|
getNext: function DOMElementSerializer_getNext() {
|
||||||
|
var node = this._node;
|
||||||
|
switch (this._state) {
|
||||||
|
case 0: // Start opening tag.
|
||||||
|
++this._state;
|
||||||
|
return '<' + node.nodeName;
|
||||||
|
case 1: // Add SVG namespace if this is the root element.
|
||||||
|
++this._state;
|
||||||
|
if (node.nodeName === 'svg:svg') {
|
||||||
|
return ' xmlns:xlink="http://www.w3.org/1999/xlink"' +
|
||||||
|
' xmlns:svg="http://www.w3.org/2000/svg"';
|
||||||
|
}
|
||||||
|
/* falls through */
|
||||||
|
case 2: // Initialize variables for looping over attributes.
|
||||||
|
++this._state;
|
||||||
|
this._loopIndex = 0;
|
||||||
|
this._attributeKeys = Object.keys(node.attributes);
|
||||||
|
/* falls through */
|
||||||
|
case 3: // Serialize any attributes and end opening tag.
|
||||||
|
if (this._loopIndex < this._attributeKeys.length) {
|
||||||
|
var name = this._attributeKeys[this._loopIndex++];
|
||||||
|
return ' ' + name + '="' + xmlEncode(node.attributes[name]) + '"';
|
||||||
|
}
|
||||||
|
++this._state;
|
||||||
|
return '>';
|
||||||
|
case 4: // Serialize textContent for tspan/style elements.
|
||||||
|
if (node.nodeName === 'svg:tspan' || node.nodeName === 'svg:style') {
|
||||||
|
this._state = 6;
|
||||||
|
return xmlEncode(node.textContent);
|
||||||
|
}
|
||||||
|
++this._state;
|
||||||
|
this._loopIndex = 0;
|
||||||
|
/* falls through */
|
||||||
|
case 5: // Serialize child nodes (only for non-tspan/style elements).
|
||||||
|
var value;
|
||||||
|
while (true) {
|
||||||
|
value = this._childSerializer && this._childSerializer.getNext();
|
||||||
|
if (value !== null) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
var nextChild = node.childNodes[this._loopIndex++];
|
||||||
|
if (nextChild) {
|
||||||
|
this._childSerializer = new DOMElementSerializer(nextChild);
|
||||||
|
} else {
|
||||||
|
this._childSerializer = null;
|
||||||
|
++this._state;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* falls through */
|
||||||
|
case 6: // Ending tag.
|
||||||
|
++this._state;
|
||||||
|
return '</' + node.nodeName + '>';
|
||||||
|
case 7: // Done.
|
||||||
|
return null;
|
||||||
|
default:
|
||||||
|
throw new Error('Unexpected serialization state: ' + this._state);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const document = {
|
||||||
|
childNodes: [],
|
||||||
|
|
||||||
|
get currentScript() {
|
||||||
|
return { src: '', };
|
||||||
|
},
|
||||||
|
|
||||||
|
get documentElement() {
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
createElementNS: function(NS, element) {
|
||||||
|
var elObject = new DOMElement(element);
|
||||||
|
return elObject;
|
||||||
|
},
|
||||||
|
|
||||||
|
createElement: function(element) {
|
||||||
|
return this.createElementNS('', element);
|
||||||
|
},
|
||||||
|
|
||||||
|
getElementsByTagName: function(element) {
|
||||||
|
if (element === 'head') {
|
||||||
|
return [this.head || (this.head = new DOMElement('head'))];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function Image() {
|
||||||
|
this._src = null;
|
||||||
|
this.onload = null;
|
||||||
|
}
|
||||||
|
Image.prototype = {
|
||||||
|
get src() {
|
||||||
|
return this._src;
|
||||||
|
},
|
||||||
|
set src(value) {
|
||||||
|
this._src = value;
|
||||||
|
if (this.onload) {
|
||||||
|
this.onload();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.document = document;
|
||||||
|
exports.Image = Image;
|
||||||
|
|
||||||
|
var exported_symbols = Object.keys(exports);
|
||||||
|
|
||||||
|
exports.setStubs = function(namespace) {
|
||||||
|
exported_symbols.forEach(function(key) {
|
||||||
|
console.assert(!(key in namespace), 'property should not be set: ' + key);
|
||||||
|
namespace[key] = exports[key];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
exports.unsetStubs = function(namespace) {
|
||||||
|
exported_symbols.forEach(function(key) {
|
||||||
|
console.assert(key in namespace, 'property should be set: ' + key);
|
||||||
|
delete namespace[key];
|
||||||
|
});
|
||||||
|
};
|
67
examples/node/getinfo.js
Normal file
67
examples/node/getinfo.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Basic node example that prints document metadata and text content.
|
||||||
|
// Requires single file built version of PDF.js -- please run
|
||||||
|
// `gulp singlefile` before running the example.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Run `gulp dist-install` to generate 'pdfjs-dist' npm package files.
|
||||||
|
var pdfjsLib = require('pdfjs-dist');
|
||||||
|
|
||||||
|
// Loading file from file system into typed array
|
||||||
|
var pdfPath = process.argv[2] || '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
|
||||||
|
// Will be using promises to load document, pages and misc data instead of
|
||||||
|
// callback.
|
||||||
|
var loadingTask = pdfjsLib.getDocument(pdfPath);
|
||||||
|
loadingTask.promise.then(function(doc) {
|
||||||
|
var numPages = doc.numPages;
|
||||||
|
console.log('# Document Loaded');
|
||||||
|
console.log('Number of Pages: ' + numPages);
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
var lastPromise; // will be used to chain promises
|
||||||
|
lastPromise = doc.getMetadata().then(function (data) {
|
||||||
|
console.log('# Metadata Is Loaded');
|
||||||
|
console.log('## Info');
|
||||||
|
console.log(JSON.stringify(data.info, null, 2));
|
||||||
|
console.log();
|
||||||
|
if (data.metadata) {
|
||||||
|
console.log('## Metadata');
|
||||||
|
console.log(JSON.stringify(data.metadata.getAll(), null, 2));
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var loadPage = function (pageNum) {
|
||||||
|
return doc.getPage(pageNum).then(function (page) {
|
||||||
|
console.log('# Page ' + pageNum);
|
||||||
|
var viewport = page.getViewport({ scale: 1.0, });
|
||||||
|
console.log('Size: ' + viewport.width + 'x' + viewport.height);
|
||||||
|
console.log();
|
||||||
|
return page.getTextContent().then(function (content) {
|
||||||
|
// Content contains lots of information about the text layout and
|
||||||
|
// styles, but we need only strings at the moment
|
||||||
|
var strings = content.items.map(function (item) {
|
||||||
|
return item.str;
|
||||||
|
});
|
||||||
|
console.log('## Text Content');
|
||||||
|
console.log(strings.join(' '));
|
||||||
|
}).then(function () {
|
||||||
|
console.log();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// Loading of the first page will wait on metadata and subsequent loadings
|
||||||
|
// will wait on the previous pages.
|
||||||
|
for (var i = 1; i <= numPages; i++) {
|
||||||
|
lastPromise = lastPromise.then(loadPage.bind(null, i));
|
||||||
|
}
|
||||||
|
return lastPromise;
|
||||||
|
}).then(function () {
|
||||||
|
console.log('# End of Document');
|
||||||
|
}, function (err) {
|
||||||
|
console.error('Error: ' + err);
|
||||||
|
});
|
@ -1,76 +0,0 @@
|
|||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
//
|
|
||||||
// Basic node example that prints document metadata and text content.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Run `gulp dist-install` to generate 'pdfjs-dist' npm package files.
|
|
||||||
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
||||||
|
|
||||||
// Loading file from file system into typed array
|
|
||||||
const pdfPath =
|
|
||||||
process.argv[2] || "../../web/compressed.tracemonkey-pldi-09.pdf";
|
|
||||||
|
|
||||||
// Will be using promises to load document, pages and misc data instead of
|
|
||||||
// callback.
|
|
||||||
const loadingTask = getDocument(pdfPath);
|
|
||||||
loadingTask.promise
|
|
||||||
.then(function (doc) {
|
|
||||||
const numPages = doc.numPages;
|
|
||||||
console.log("# Document Loaded");
|
|
||||||
console.log("Number of Pages: " + numPages);
|
|
||||||
console.log();
|
|
||||||
|
|
||||||
let lastPromise; // will be used to chain promises
|
|
||||||
lastPromise = doc.getMetadata().then(function (data) {
|
|
||||||
console.log("# Metadata Is Loaded");
|
|
||||||
console.log("## Info");
|
|
||||||
console.log(JSON.stringify(data.info, null, 2));
|
|
||||||
console.log();
|
|
||||||
if (data.metadata) {
|
|
||||||
console.log("## Metadata");
|
|
||||||
console.log(JSON.stringify(data.metadata.getAll(), null, 2));
|
|
||||||
console.log();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const loadPage = function (pageNum) {
|
|
||||||
return doc.getPage(pageNum).then(function (page) {
|
|
||||||
console.log("# Page " + pageNum);
|
|
||||||
const viewport = page.getViewport({ scale: 1.0 });
|
|
||||||
console.log("Size: " + viewport.width + "x" + viewport.height);
|
|
||||||
console.log();
|
|
||||||
return page
|
|
||||||
.getTextContent()
|
|
||||||
.then(function (content) {
|
|
||||||
// Content contains lots of information about the text layout and
|
|
||||||
// styles, but we need only strings at the moment
|
|
||||||
const strings = content.items.map(function (item) {
|
|
||||||
return item.str;
|
|
||||||
});
|
|
||||||
console.log("## Text Content");
|
|
||||||
console.log(strings.join(" "));
|
|
||||||
// Release page resources.
|
|
||||||
page.cleanup();
|
|
||||||
})
|
|
||||||
.then(function () {
|
|
||||||
console.log();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// Loading of the first page will wait on metadata and subsequent loadings
|
|
||||||
// will wait on the previous pages.
|
|
||||||
for (let i = 1; i <= numPages; i++) {
|
|
||||||
lastPromise = lastPromise.then(loadPage.bind(null, i));
|
|
||||||
}
|
|
||||||
return lastPromise;
|
|
||||||
})
|
|
||||||
.then(
|
|
||||||
function () {
|
|
||||||
console.log("# End of Document");
|
|
||||||
},
|
|
||||||
function (err) {
|
|
||||||
console.error("Error: " + err);
|
|
||||||
}
|
|
||||||
);
|
|
93
examples/node/pdf2png/pdf2png.js
Normal file
93
examples/node/pdf2png/pdf2png.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/* Copyright 2017 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Canvas = require('canvas');
|
||||||
|
var assert = require('assert');
|
||||||
|
var fs = require('fs');
|
||||||
|
|
||||||
|
function NodeCanvasFactory() {}
|
||||||
|
NodeCanvasFactory.prototype = {
|
||||||
|
create: function NodeCanvasFactory_create(width, height) {
|
||||||
|
assert(width > 0 && height > 0, 'Invalid canvas size');
|
||||||
|
var canvas = Canvas.createCanvas(width, height);
|
||||||
|
var context = canvas.getContext('2d');
|
||||||
|
return {
|
||||||
|
canvas: canvas,
|
||||||
|
context: context,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function NodeCanvasFactory_reset(canvasAndContext, width, height) {
|
||||||
|
assert(canvasAndContext.canvas, 'Canvas is not specified');
|
||||||
|
assert(width > 0 && height > 0, 'Invalid canvas size');
|
||||||
|
canvasAndContext.canvas.width = width;
|
||||||
|
canvasAndContext.canvas.height = height;
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function NodeCanvasFactory_destroy(canvasAndContext) {
|
||||||
|
assert(canvasAndContext.canvas, 'Canvas is not specified');
|
||||||
|
|
||||||
|
// Zeroing the width and height cause Firefox to release graphics
|
||||||
|
// resources immediately, which can greatly reduce memory consumption.
|
||||||
|
canvasAndContext.canvas.width = 0;
|
||||||
|
canvasAndContext.canvas.height = 0;
|
||||||
|
canvasAndContext.canvas = null;
|
||||||
|
canvasAndContext.context = null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var pdfjsLib = require('pdfjs-dist');
|
||||||
|
|
||||||
|
// Relative path of the PDF file.
|
||||||
|
var pdfURL = '../../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
|
||||||
|
// Read the PDF file into a typed array so PDF.js can load it.
|
||||||
|
var rawData = new Uint8Array(fs.readFileSync(pdfURL));
|
||||||
|
|
||||||
|
// Load the PDF file.
|
||||||
|
var loadingTask = pdfjsLib.getDocument(rawData);
|
||||||
|
loadingTask.promise.then(function(pdfDocument) {
|
||||||
|
console.log('# PDF document loaded.');
|
||||||
|
|
||||||
|
// Get the first page.
|
||||||
|
pdfDocument.getPage(1).then(function (page) {
|
||||||
|
// Render the page on a Node canvas with 100% scale.
|
||||||
|
var viewport = page.getViewport({ scale: 1.0, });
|
||||||
|
var canvasFactory = new NodeCanvasFactory();
|
||||||
|
var canvasAndContext =
|
||||||
|
canvasFactory.create(viewport.width, viewport.height);
|
||||||
|
var renderContext = {
|
||||||
|
canvasContext: canvasAndContext.context,
|
||||||
|
viewport: viewport,
|
||||||
|
canvasFactory: canvasFactory,
|
||||||
|
};
|
||||||
|
|
||||||
|
var renderTask = page.render(renderContext);
|
||||||
|
renderTask.promise.then(function() {
|
||||||
|
// Convert the canvas to an image buffer.
|
||||||
|
var image = canvasAndContext.canvas.toBuffer();
|
||||||
|
fs.writeFile('output.png', image, function (error) {
|
||||||
|
if (error) {
|
||||||
|
console.error('Error: ' + error);
|
||||||
|
} else {
|
||||||
|
console.log(
|
||||||
|
'Finished converting first page of PDF file to a PNG image.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).catch(function(reason) {
|
||||||
|
console.log(reason);
|
||||||
|
});
|
@ -1,106 +0,0 @@
|
|||||||
/* Copyright 2017 Mozilla Foundation
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { strict as assert } from "assert";
|
|
||||||
import Canvas from "canvas";
|
|
||||||
import fs from "fs";
|
|
||||||
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
||||||
|
|
||||||
class NodeCanvasFactory {
|
|
||||||
create(width, height) {
|
|
||||||
assert(width > 0 && height > 0, "Invalid canvas size");
|
|
||||||
const canvas = Canvas.createCanvas(width, height);
|
|
||||||
const context = canvas.getContext("2d");
|
|
||||||
return {
|
|
||||||
canvas,
|
|
||||||
context,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
reset(canvasAndContext, width, height) {
|
|
||||||
assert(canvasAndContext.canvas, "Canvas is not specified");
|
|
||||||
assert(width > 0 && height > 0, "Invalid canvas size");
|
|
||||||
canvasAndContext.canvas.width = width;
|
|
||||||
canvasAndContext.canvas.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy(canvasAndContext) {
|
|
||||||
assert(canvasAndContext.canvas, "Canvas is not specified");
|
|
||||||
|
|
||||||
// Zeroing the width and height cause Firefox to release graphics
|
|
||||||
// resources immediately, which can greatly reduce memory consumption.
|
|
||||||
canvasAndContext.canvas.width = 0;
|
|
||||||
canvasAndContext.canvas.height = 0;
|
|
||||||
canvasAndContext.canvas = null;
|
|
||||||
canvasAndContext.context = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some PDFs need external cmaps.
|
|
||||||
const CMAP_URL = "../../../node_modules/pdfjs-dist/cmaps/";
|
|
||||||
const CMAP_PACKED = true;
|
|
||||||
|
|
||||||
// Where the standard fonts are located.
|
|
||||||
const STANDARD_FONT_DATA_URL =
|
|
||||||
"../../../node_modules/pdfjs-dist/standard_fonts/";
|
|
||||||
|
|
||||||
const canvasFactory = new NodeCanvasFactory();
|
|
||||||
|
|
||||||
// Loading file from file system into typed array.
|
|
||||||
const pdfPath =
|
|
||||||
process.argv[2] || "../../../web/compressed.tracemonkey-pldi-09.pdf";
|
|
||||||
const data = new Uint8Array(fs.readFileSync(pdfPath));
|
|
||||||
|
|
||||||
// Load the PDF file.
|
|
||||||
const loadingTask = getDocument({
|
|
||||||
data,
|
|
||||||
cMapUrl: CMAP_URL,
|
|
||||||
cMapPacked: CMAP_PACKED,
|
|
||||||
standardFontDataUrl: STANDARD_FONT_DATA_URL,
|
|
||||||
canvasFactory,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const pdfDocument = await loadingTask.promise;
|
|
||||||
console.log("# PDF document loaded.");
|
|
||||||
// Get the first page.
|
|
||||||
const page = await pdfDocument.getPage(1);
|
|
||||||
// Render the page on a Node canvas with 100% scale.
|
|
||||||
const viewport = page.getViewport({ scale: 1.0 });
|
|
||||||
const canvasAndContext = canvasFactory.create(
|
|
||||||
viewport.width,
|
|
||||||
viewport.height
|
|
||||||
);
|
|
||||||
const renderContext = {
|
|
||||||
canvasContext: canvasAndContext.context,
|
|
||||||
viewport,
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderTask = page.render(renderContext);
|
|
||||||
await renderTask.promise;
|
|
||||||
// Convert the canvas to an image buffer.
|
|
||||||
const image = canvasAndContext.canvas.toBuffer();
|
|
||||||
fs.writeFile("output.png", image, function (error) {
|
|
||||||
if (error) {
|
|
||||||
console.error("Error: " + error);
|
|
||||||
} else {
|
|
||||||
console.log("Finished converting first page of PDF file to a PNG image.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Release page resources.
|
|
||||||
page.cleanup();
|
|
||||||
} catch (reason) {
|
|
||||||
console.log(reason);
|
|
||||||
}
|
|
130
examples/node/pdf2svg.js
Normal file
130
examples/node/pdf2svg.js
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Node tool to dump SVG output into a file.
|
||||||
|
//
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
var util = require('util');
|
||||||
|
var path = require('path');
|
||||||
|
var stream = require('stream');
|
||||||
|
|
||||||
|
// HACK few hacks to let PDF.js be loaded not as a module in global space.
|
||||||
|
require('./domstubs.js').setStubs(global);
|
||||||
|
|
||||||
|
// Run `gulp dist-install` to generate 'pdfjs-dist' npm package files.
|
||||||
|
var pdfjsLib = require('pdfjs-dist');
|
||||||
|
|
||||||
|
// Loading file from file system into typed array
|
||||||
|
var pdfPath = process.argv[2] || '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
var data = new Uint8Array(fs.readFileSync(pdfPath));
|
||||||
|
|
||||||
|
var outputDirectory = './svgdump';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Note: This creates a directory only one level deep. If you want to create
|
||||||
|
// multiple subdirectories on the fly, use the mkdirp module from npm.
|
||||||
|
fs.mkdirSync(outputDirectory);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code !== 'EEXIST') {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dumps svg outputs to a folder called svgdump
|
||||||
|
function getFilePathForPage(pageNum) {
|
||||||
|
var name = path.basename(pdfPath, path.extname(pdfPath));
|
||||||
|
return path.join(outputDirectory, name + '-' + pageNum + '.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A readable stream which offers a stream representing the serialization of a
|
||||||
|
* given DOM element (as defined by domstubs.js).
|
||||||
|
*
|
||||||
|
* @param {object} options
|
||||||
|
* @param {DOMElement} options.svgElement The element to serialize
|
||||||
|
*/
|
||||||
|
function ReadableSVGStream(options) {
|
||||||
|
if (!(this instanceof ReadableSVGStream)) {
|
||||||
|
return new ReadableSVGStream(options);
|
||||||
|
}
|
||||||
|
stream.Readable.call(this, options);
|
||||||
|
this.serializer = options.svgElement.getSerializer();
|
||||||
|
}
|
||||||
|
util.inherits(ReadableSVGStream, stream.Readable);
|
||||||
|
// Implements https://nodejs.org/api/stream.html#stream_readable_read_size_1
|
||||||
|
ReadableSVGStream.prototype._read = function() {
|
||||||
|
var chunk;
|
||||||
|
while ((chunk = this.serializer.getNext()) !== null) {
|
||||||
|
if (!this.push(chunk)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.push(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Streams the SVG element to the given file path.
|
||||||
|
function writeSvgToFile(svgElement, filePath) {
|
||||||
|
var readableSvgStream = new ReadableSVGStream({
|
||||||
|
svgElement: svgElement,
|
||||||
|
});
|
||||||
|
var writableStream = fs.createWriteStream(filePath);
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
readableSvgStream.once('error', reject);
|
||||||
|
writableStream.once('error', reject);
|
||||||
|
writableStream.once('finish', resolve);
|
||||||
|
readableSvgStream.pipe(writableStream);
|
||||||
|
}).catch(function(err) {
|
||||||
|
readableSvgStream = null; // Explicitly null because of v8 bug 6512.
|
||||||
|
writableStream.end();
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Will be using promises to load document, pages and misc data instead of
|
||||||
|
// callback.
|
||||||
|
var loadingTask = pdfjsLib.getDocument({
|
||||||
|
data: data,
|
||||||
|
// Try to export JPEG images directly if they don't need any further
|
||||||
|
// processing.
|
||||||
|
nativeImageDecoderSupport: pdfjsLib.NativeImageDecoding.DISPLAY,
|
||||||
|
});
|
||||||
|
loadingTask.promise.then(function(doc) {
|
||||||
|
var numPages = doc.numPages;
|
||||||
|
console.log('# Document Loaded');
|
||||||
|
console.log('Number of Pages: ' + numPages);
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
var lastPromise = Promise.resolve(); // will be used to chain promises
|
||||||
|
var loadPage = function (pageNum) {
|
||||||
|
return doc.getPage(pageNum).then(function (page) {
|
||||||
|
console.log('# Page ' + pageNum);
|
||||||
|
var viewport = page.getViewport({ scale: 1.0, });
|
||||||
|
console.log('Size: ' + viewport.width + 'x' + viewport.height);
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
return page.getOperatorList().then(function (opList) {
|
||||||
|
var svgGfx = new pdfjsLib.SVGGraphics(page.commonObjs, page.objs);
|
||||||
|
svgGfx.embedFonts = true;
|
||||||
|
return svgGfx.getSVG(opList, viewport).then(function (svg) {
|
||||||
|
return writeSvgToFile(svg, getFilePathForPage(pageNum))
|
||||||
|
.then(function () {
|
||||||
|
console.log('Page: ' + pageNum);
|
||||||
|
}, function(err) {
|
||||||
|
console.log('Error: ' + err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 1; i <= numPages; i++) {
|
||||||
|
lastPromise = lastPromise.then(loadPage.bind(null, i));
|
||||||
|
}
|
||||||
|
return lastPromise;
|
||||||
|
}).then(function () {
|
||||||
|
console.log('# End of Document');
|
||||||
|
}, function (err) {
|
||||||
|
console.error('Error: ' + err);
|
||||||
|
});
|
8
examples/svgviewer/README.md
Normal file
8
examples/svgviewer/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
## PDF.js using SVG
|
||||||
|
|
||||||
|
This is a project for implementing alternate backend for PDF.js using Scalable Vector Graphics. This is still a WIP.
|
||||||
|
Take a look at [proposal](https://docs.google.com/document/d/1k4nPx1RrHbxXi94kSdvW5ay8KMkjwLmBEiCNupyzlwk/pub) for this project.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Take a look at src/display/svg.js to see the SVG rendering code.
|
51
examples/svgviewer/index.html
Normal file
51
examples/svgviewer/index.html
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Copyright 2014 Mozilla Foundation
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<html dir="ltr" mozdisallowselectionprint>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
|
<meta name="google" content="notranslate">
|
||||||
|
<title>PDF.js SVG viewer using built components</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #808080;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#viewerContainer {
|
||||||
|
overflow: auto;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="../../node_modules/pdfjs-dist/web/pdf_viewer.css">
|
||||||
|
|
||||||
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
|
<script src="../../node_modules/pdfjs-dist/web/pdf_viewer.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body tabindex="1">
|
||||||
|
<div id="viewerContainer">
|
||||||
|
<div id="viewer" class="pdfViewer"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="viewer.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
65
examples/svgviewer/viewer.js
Normal file
65
examples/svgviewer/viewer.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/* Copyright 2014 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (!pdfjsLib.getDocument || !pdfjsViewer.PDFViewer) {
|
||||||
|
alert('Please build the pdfjs-dist library using\n' +
|
||||||
|
' `gulp dist-install`');
|
||||||
|
}
|
||||||
|
|
||||||
|
// The workerSrc property shall be specified.
|
||||||
|
//
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
|
// Some PDFs need external cmaps.
|
||||||
|
//
|
||||||
|
var CMAP_URL = '../../node_modules/pdfjs-dist/cmaps/';
|
||||||
|
var CMAP_PACKED = true;
|
||||||
|
|
||||||
|
var DEFAULT_URL = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
|
||||||
|
var container = document.getElementById('viewerContainer');
|
||||||
|
|
||||||
|
// (Optionally) enable hyperlinks within PDF files.
|
||||||
|
var pdfLinkService = new pdfjsViewer.PDFLinkService();
|
||||||
|
|
||||||
|
var pdfViewer = new pdfjsViewer.PDFViewer({
|
||||||
|
container: container,
|
||||||
|
linkService: pdfLinkService,
|
||||||
|
renderer: 'svg',
|
||||||
|
textLayerMode: 0,
|
||||||
|
});
|
||||||
|
pdfLinkService.setViewer(pdfViewer);
|
||||||
|
|
||||||
|
document.addEventListener('pagesinit', function () {
|
||||||
|
// We can use pdfViewer now, e.g. let's change default scale.
|
||||||
|
pdfViewer.currentScaleValue = 'page-width';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Loading document.
|
||||||
|
var loadingTask = pdfjsLib.getDocument({
|
||||||
|
url: DEFAULT_URL,
|
||||||
|
cMapUrl: CMAP_URL,
|
||||||
|
cMapPacked: CMAP_PACKED,
|
||||||
|
});
|
||||||
|
loadingTask.promise.then(function(pdfDocument) {
|
||||||
|
// Document loaded, specifying document for the viewer and
|
||||||
|
// the (optional) linkService.
|
||||||
|
pdfViewer.setDocument(pdfDocument);
|
||||||
|
|
||||||
|
pdfLinkService.setDocument(pdfDocument, null);
|
||||||
|
});
|
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Text-only PDF.js example</title>
|
<title>Text-only PDF.js example</title>
|
||||||
<script src="../../node_modules/pdfjs-dist/build/pdf.mjs" type="module"></script>
|
<script src="../../node_modules/pdfjs-dist/build/pdf.js"></script>
|
||||||
<script src="pdf2svg.mjs" type="module"></script>
|
<script src="pdf2svg.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>Text-only PDF.js example</p>
|
<p>Text-only PDF.js example</p>
|
||||||
|
72
examples/text-only/pdf2svg.js
Normal file
72
examples/text-only/pdf2svg.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/* Copyright 2014 Mozilla Foundation
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var PDF_PATH = '../../web/compressed.tracemonkey-pldi-09.pdf';
|
||||||
|
var PAGE_NUMBER = 1;
|
||||||
|
var PAGE_SCALE = 1.5;
|
||||||
|
var SVG_NS = 'http://www.w3.org/2000/svg';
|
||||||
|
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../node_modules/pdfjs-dist/build/pdf.worker.js';
|
||||||
|
|
||||||
|
function buildSVG(viewport, textContent) {
|
||||||
|
// Building SVG with size of the viewport (for simplicity)
|
||||||
|
var svg = document.createElementNS(SVG_NS, 'svg:svg');
|
||||||
|
svg.setAttribute('width', viewport.width + 'px');
|
||||||
|
svg.setAttribute('height', viewport.height + 'px');
|
||||||
|
// items are transformed to have 1px font size
|
||||||
|
svg.setAttribute('font-size', 1);
|
||||||
|
|
||||||
|
// processing all items
|
||||||
|
textContent.items.forEach(function (textItem) {
|
||||||
|
// we have to take in account viewport transform, which includes scale,
|
||||||
|
// rotation and Y-axis flip, and not forgetting to flip text.
|
||||||
|
var tx = pdfjsLib.Util.transform(
|
||||||
|
pdfjsLib.Util.transform(viewport.transform, textItem.transform),
|
||||||
|
[1, 0, 0, -1, 0, 0]);
|
||||||
|
var style = textContent.styles[textItem.fontName];
|
||||||
|
// adding text element
|
||||||
|
var text = document.createElementNS(SVG_NS, 'svg:text');
|
||||||
|
text.setAttribute('transform', 'matrix(' + tx.join(' ') + ')');
|
||||||
|
text.setAttribute('font-family', style.fontFamily);
|
||||||
|
text.textContent = textItem.str;
|
||||||
|
svg.appendChild(text);
|
||||||
|
});
|
||||||
|
return svg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pageLoaded() {
|
||||||
|
// Loading document and page text content
|
||||||
|
var loadingTask = pdfjsLib.getDocument({ url: PDF_PATH, });
|
||||||
|
loadingTask.promise.then(function(pdfDocument) {
|
||||||
|
pdfDocument.getPage(PAGE_NUMBER).then(function (page) {
|
||||||
|
var viewport = page.getViewport({ scale: PAGE_SCALE, });
|
||||||
|
page.getTextContent().then(function (textContent) {
|
||||||
|
// building SVG and adding that to the DOM
|
||||||
|
var svg = buildSVG(viewport, textContent);
|
||||||
|
document.getElementById('pageContainer').appendChild(svg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
if (typeof pdfjsLib === 'undefined') {
|
||||||
|
alert('Built version of PDF.js was not found.\n' +
|
||||||
|
'Please run `gulp dist-install`.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pageLoaded();
|
||||||
|
});
|
@ -1,72 +0,0 @@
|
|||||||
/* Copyright 2014 Mozilla Foundation
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const PDF_PATH = "../../web/compressed.tracemonkey-pldi-09.pdf";
|
|
||||||
const PAGE_NUMBER = 1;
|
|
||||||
const PAGE_SCALE = 1.5;
|
|
||||||
const SVG_NS = "http://www.w3.org/2000/svg";
|
|
||||||
|
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
|
||||||
"../../node_modules/pdfjs-dist/build/pdf.worker.mjs";
|
|
||||||
|
|
||||||
function buildSVG(viewport, textContent) {
|
|
||||||
// Building SVG with size of the viewport (for simplicity)
|
|
||||||
const svg = document.createElementNS(SVG_NS, "svg:svg");
|
|
||||||
svg.setAttribute("width", viewport.width + "px");
|
|
||||||
svg.setAttribute("height", viewport.height + "px");
|
|
||||||
// items are transformed to have 1px font size
|
|
||||||
svg.setAttribute("font-size", 1);
|
|
||||||
|
|
||||||
// processing all items
|
|
||||||
textContent.items.forEach(function (textItem) {
|
|
||||||
// we have to take in account viewport transform, which includes scale,
|
|
||||||
// rotation and Y-axis flip, and not forgetting to flip text.
|
|
||||||
const tx = pdfjsLib.Util.transform(
|
|
||||||
pdfjsLib.Util.transform(viewport.transform, textItem.transform),
|
|
||||||
[1, 0, 0, -1, 0, 0]
|
|
||||||
);
|
|
||||||
const style = textContent.styles[textItem.fontName];
|
|
||||||
// adding text element
|
|
||||||
const text = document.createElementNS(SVG_NS, "svg:text");
|
|
||||||
text.setAttribute("transform", "matrix(" + tx.join(" ") + ")");
|
|
||||||
text.setAttribute("font-family", style.fontFamily);
|
|
||||||
text.textContent = textItem.str;
|
|
||||||
svg.append(text);
|
|
||||||
});
|
|
||||||
return svg;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function pageLoaded() {
|
|
||||||
// Loading document and page text content
|
|
||||||
const loadingTask = pdfjsLib.getDocument({ url: PDF_PATH });
|
|
||||||
const pdfDocument = await loadingTask.promise;
|
|
||||||
const page = await pdfDocument.getPage(PAGE_NUMBER);
|
|
||||||
const viewport = page.getViewport({ scale: PAGE_SCALE });
|
|
||||||
const textContent = await page.getTextContent();
|
|
||||||
// building SVG and adding that to the DOM
|
|
||||||
const svg = buildSVG(viewport, textContent);
|
|
||||||
document.getElementById("pageContainer").append(svg);
|
|
||||||
// Release page resources.
|
|
||||||
page.cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
if (typeof pdfjsLib === "undefined") {
|
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pageLoaded();
|
|
||||||
});
|
|
@ -18,16 +18,10 @@ Refer to the `main.js` and `webpack.config.js` files for the source code.
|
|||||||
Note that PDF.js packaging requires packaging of the main application and
|
Note that PDF.js packaging requires packaging of the main application and
|
||||||
the worker code, and the `workerSrc` path shall be set to the latter file.
|
the worker code, and the `workerSrc` path shall be set to the latter file.
|
||||||
|
|
||||||
### Minification
|
|
||||||
|
|
||||||
If you are configuring Webpack to output a minified build, please note that you
|
|
||||||
*must* configure the minifier to keep original class/function names intact;
|
|
||||||
otherwise the build is not guaranteed to work correctly.
|
|
||||||
|
|
||||||
## Worker loading
|
## Worker loading
|
||||||
|
|
||||||
If you are getting the `Setting up fake worker` warning, make sure you are
|
If you are getting the `Setting up fake worker` warning, make sure you are importing `pdfjs-dist/webpack` which is the zero-configuration method for Webpack users:
|
||||||
importing `pdfjs-dist/webpack.mjs` which is the zero-configuration method for
|
|
||||||
Webpack users. Installing `worker-loader` is no longer necessary.
|
|
||||||
|
|
||||||
import * as pdfjsLib from 'pdfjs-dist/webpack.mjs';
|
import pdfjsLib from 'pdfjs-dist/webpack';
|
||||||
|
|
||||||
|
For a full working example refer to [this repository](https://github.com/yurydelendik/pdfjs-react).
|
||||||
|
33
examples/webpack/main.js
Normal file
33
examples/webpack/main.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Any copyright is dedicated to the Public Domain.
|
||||||
|
// http://creativecommons.org/licenses/publicdomain/
|
||||||
|
|
||||||
|
// Hello world example for webpack.
|
||||||
|
|
||||||
|
var pdfjsLib = require('pdfjs-dist');
|
||||||
|
|
||||||
|
var pdfPath = '../helloworld/helloworld.pdf';
|
||||||
|
|
||||||
|
// Setting worker path to worker bundle.
|
||||||
|
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
||||||
|
'../../build/webpack/pdf.worker.bundle.js';
|
||||||
|
|
||||||
|
// Loading a document.
|
||||||
|
var loadingTask = pdfjsLib.getDocument(pdfPath);
|
||||||
|
loadingTask.promise.then(function (pdfDocument) {
|
||||||
|
// Request a first page
|
||||||
|
return pdfDocument.getPage(1).then(function (pdfPage) {
|
||||||
|
// Display page on the existing canvas with 100% scale.
|
||||||
|
var viewport = pdfPage.getViewport({ scale: 1.0, });
|
||||||
|
var canvas = document.getElementById('theCanvas');
|
||||||
|
canvas.width = viewport.width;
|
||||||
|
canvas.height = viewport.height;
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
var renderTask = pdfPage.render({
|
||||||
|
canvasContext: ctx,
|
||||||
|
viewport: viewport,
|
||||||
|
});
|
||||||
|
return renderTask.promise;
|
||||||
|
});
|
||||||
|
}).catch(function (reason) {
|
||||||
|
console.error('Error: ' + reason);
|
||||||
|
});
|
@ -1,29 +0,0 @@
|
|||||||
// Any copyright is dedicated to the Public Domain.
|
|
||||||
// http://creativecommons.org/licenses/publicdomain/
|
|
||||||
|
|
||||||
// Hello world example for webpack.
|
|
||||||
|
|
||||||
import * as pdfjsLib from "pdfjs-dist";
|
|
||||||
|
|
||||||
const pdfPath = "../learning/helloworld.pdf";
|
|
||||||
|
|
||||||
// Setting worker path to worker bundle.
|
|
||||||
pdfjsLib.GlobalWorkerOptions.workerSrc =
|
|
||||||
"../../build/webpack/pdf.worker.bundle.js";
|
|
||||||
|
|
||||||
// Loading a document.
|
|
||||||
const loadingTask = pdfjsLib.getDocument(pdfPath);
|
|
||||||
const pdfDocument = await loadingTask.promise;
|
|
||||||
// Request a first page
|
|
||||||
const pdfPage = await pdfDocument.getPage(1);
|
|
||||||
// Display page on the existing canvas with 100% scale.
|
|
||||||
const viewport = pdfPage.getViewport({ scale: 1.0 });
|
|
||||||
const canvas = document.getElementById("theCanvas");
|
|
||||||
canvas.width = viewport.width;
|
|
||||||
canvas.height = viewport.height;
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
const renderTask = pdfPage.render({
|
|
||||||
canvasContext: ctx,
|
|
||||||
viewport,
|
|
||||||
});
|
|
||||||
await renderTask.promise;
|
|
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "webpack-pdf.js-example",
|
"name": "webpack-pdf.js-example",
|
||||||
"version": "0.2.0",
|
"version": "0.1.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack"
|
"build": "webpack"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"webpack": "^5.89.0",
|
"webpack": "4.21.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^3.1.2",
|
||||||
"pdfjs-dist": "../../node_modules/pdfjs-dist"
|
"pdfjs-dist": "../../node_modules/pdfjs-dist"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,16 @@
|
|||||||
/* eslint-disable import/no-commonjs */
|
var webpack = require('webpack'); // eslint-disable-line no-unused-vars
|
||||||
|
var path = require('path');
|
||||||
const webpack = require("webpack"); // eslint-disable-line no-unused-vars
|
|
||||||
const path = require("path");
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
context: __dirname,
|
context: __dirname,
|
||||||
entry: {
|
entry: {
|
||||||
main: "./main.mjs",
|
'main': './main.js',
|
||||||
"pdf.worker": "pdfjs-dist/build/pdf.worker.mjs",
|
'pdf.worker': 'pdfjs-dist/build/pdf.worker.entry',
|
||||||
},
|
},
|
||||||
mode: "none",
|
mode: 'none',
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, "../../build/webpack"),
|
path: path.join(__dirname, '../../build/webpack'),
|
||||||
publicPath: "../../build/webpack/",
|
publicPath: '../../build/webpack/',
|
||||||
filename: "[name].bundle.js",
|
filename: '[name].bundle.js',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
9
extensions/.eslintrc
Normal file
9
extensions/.eslintrc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
../.eslintrc
|
||||||
|
],
|
||||||
|
|
||||||
|
"rules": {
|
||||||
|
"no-restricted-globals": "off",
|
||||||
|
},
|
||||||
|
}
|
@ -17,6 +17,6 @@
|
|||||||
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"mozilla/import-globals": "error",
|
"mozilla/import-globals": "error",
|
||||||
"no-var": "off",
|
"object-shorthand": "off",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -14,18 +14,22 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html');
|
||||||
|
|
||||||
function getViewerURL(pdf_url) {
|
function getViewerURL(pdf_url) {
|
||||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url);
|
return VIEWER_URL + '?file=' + encodeURIComponent(pdf_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("animationstart", onAnimationStart, true);
|
if (CSS.supports('animation', '0s')) {
|
||||||
|
document.addEventListener('animationstart', onAnimationStart, true);
|
||||||
|
} else {
|
||||||
|
document.addEventListener('webkitAnimationStart', onAnimationStart, true);
|
||||||
|
}
|
||||||
|
|
||||||
function onAnimationStart(event) {
|
function onAnimationStart(event) {
|
||||||
if (event.animationName === "pdfjs-detected-object-or-embed") {
|
if (event.animationName === 'pdfjs-detected-object-or-embed') {
|
||||||
watchObjectOrEmbed(event.target);
|
watchObjectOrEmbed(event.target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,23 +40,19 @@ function onAnimationStart(event) {
|
|||||||
// invocations have no effect.
|
// invocations have no effect.
|
||||||
function watchObjectOrEmbed(elem) {
|
function watchObjectOrEmbed(elem) {
|
||||||
var mimeType = elem.type;
|
var mimeType = elem.type;
|
||||||
if (mimeType && mimeType.toLowerCase() !== "application/pdf") {
|
if (mimeType && mimeType.toLowerCase() !== 'application/pdf') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// <embed src> <object data>
|
// <embed src> <object data>
|
||||||
var srcAttribute = "src" in elem ? "src" : "data";
|
var srcAttribute = 'src' in elem ? 'src' : 'data';
|
||||||
var path = elem[srcAttribute];
|
var path = elem[srcAttribute];
|
||||||
if (!mimeType && !/\.pdf($|[?#])/i.test(path)) {
|
if (!mimeType && !/\.pdf($|[?#])/i.test(path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (elem.tagName === 'EMBED' && elem.name === 'plugin' &&
|
||||||
elem.tagName === "EMBED" &&
|
|
||||||
elem.name === "plugin" &&
|
|
||||||
elem.parentNode === document.body &&
|
elem.parentNode === document.body &&
|
||||||
elem.parentNode.childElementCount === 1 &&
|
elem.parentNode.childElementCount === 1 && elem.src === location.href) {
|
||||||
elem.src === location.href
|
|
||||||
) {
|
|
||||||
// This page is most likely Chrome's default page that embeds a PDF file.
|
// This page is most likely Chrome's default page that embeds a PDF file.
|
||||||
// The fact that the extension's background page did not intercept and
|
// The fact that the extension's background page did not intercept and
|
||||||
// redirect this PDF request means that this PDF cannot be opened by PDF.js,
|
// redirect this PDF request means that this PDF cannot be opened by PDF.js,
|
||||||
@ -62,7 +62,7 @@ function watchObjectOrEmbed(elem) {
|
|||||||
// Until #4483 is fixed, POST requests should be ignored.
|
// Until #4483 is fixed, POST requests should be ignored.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (elem.tagName === "EMBED" && elem.src === "about:blank") {
|
if (elem.tagName === 'EMBED' && elem.src === 'about:blank') {
|
||||||
// Starting from Chrome 76, internal embeds do not have the original URL,
|
// Starting from Chrome 76, internal embeds do not have the original URL,
|
||||||
// but "about:blank" instead.
|
// but "about:blank" instead.
|
||||||
// See https://github.com/mozilla/pdf.js/issues/11137
|
// See https://github.com/mozilla/pdf.js/issues/11137
|
||||||
@ -76,9 +76,9 @@ function watchObjectOrEmbed(elem) {
|
|||||||
|
|
||||||
var tagName = elem.tagName.toUpperCase();
|
var tagName = elem.tagName.toUpperCase();
|
||||||
var updateEmbedOrObject;
|
var updateEmbedOrObject;
|
||||||
if (tagName === "EMBED") {
|
if (tagName === 'EMBED') {
|
||||||
updateEmbedOrObject = updateEmbedElement;
|
updateEmbedOrObject = updateEmbedElement;
|
||||||
} else if (tagName === "OBJECT") {
|
} else if (tagName === 'OBJECT') {
|
||||||
updateEmbedOrObject = updateObjectElement;
|
updateEmbedOrObject = updateObjectElement;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
@ -115,7 +115,7 @@ function watchObjectOrEmbed(elem) {
|
|||||||
|
|
||||||
// Display the PDF Viewer in an <embed>.
|
// Display the PDF Viewer in an <embed>.
|
||||||
function updateEmbedElement(elem) {
|
function updateEmbedElement(elem) {
|
||||||
if (elem.type === "text/html" && elem.src.lastIndexOf(VIEWER_URL, 0) === 0) {
|
if (elem.type === 'text/html' && elem.src.lastIndexOf(VIEWER_URL, 0) === 0) {
|
||||||
// The viewer is already shown.
|
// The viewer is already shown.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -124,15 +124,11 @@ function updateEmbedElement(elem) {
|
|||||||
var parentNode = elem.parentNode;
|
var parentNode = elem.parentNode;
|
||||||
var nextSibling = elem.nextSibling;
|
var nextSibling = elem.nextSibling;
|
||||||
if (parentNode) {
|
if (parentNode) {
|
||||||
elem.remove();
|
parentNode.removeChild(elem);
|
||||||
}
|
}
|
||||||
elem.type = "text/html";
|
elem.type = 'text/html';
|
||||||
elem.src = getEmbeddedViewerURL(elem.src);
|
elem.src = getEmbeddedViewerURL(elem.src);
|
||||||
|
|
||||||
if (parentNode) {
|
if (parentNode) {
|
||||||
// Suppress linter warning: insertBefore is preferable to
|
|
||||||
// nextSibling.before(elem) because nextSibling may be null.
|
|
||||||
// eslint-disable-next-line unicorn/prefer-modern-dom-apis
|
|
||||||
parentNode.insertBefore(elem, nextSibling);
|
parentNode.insertBefore(elem, nextSibling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,7 +146,7 @@ function updateObjectElement(elem) {
|
|||||||
// attribute reloads the content (provided that the type was correctly set).
|
// attribute reloads the content (provided that the type was correctly set).
|
||||||
// - When <object type=text/html data="chrome-extension://..."> is used
|
// - When <object type=text/html data="chrome-extension://..."> is used
|
||||||
// (tested with a data-URL, data:text/html,<object...>, the extension's
|
// (tested with a data-URL, data:text/html,<object...>, the extension's
|
||||||
// origin allowlist is not set up, so the viewer can't load the PDF file.
|
// origin whitelist is not set up, so the viewer can't load the PDF file.
|
||||||
// - The content of the <object> tag may be affected by <param> tags.
|
// - The content of the <object> tag may be affected by <param> tags.
|
||||||
//
|
//
|
||||||
// To make sure that our solution works for all cases, we will insert a frame
|
// To make sure that our solution works for all cases, we will insert a frame
|
||||||
@ -159,21 +155,21 @@ function updateObjectElement(elem) {
|
|||||||
var iframe = elem.firstElementChild;
|
var iframe = elem.firstElementChild;
|
||||||
if (!iframe || !iframe.__inserted_by_pdfjs) {
|
if (!iframe || !iframe.__inserted_by_pdfjs) {
|
||||||
iframe = createFullSizeIframe();
|
iframe = createFullSizeIframe();
|
||||||
elem.textContent = "";
|
elem.textContent = '';
|
||||||
elem.append(iframe);
|
elem.appendChild(iframe);
|
||||||
iframe.__inserted_by_pdfjs = true;
|
iframe.__inserted_by_pdfjs = true;
|
||||||
}
|
}
|
||||||
iframe.src = getEmbeddedViewerURL(elem.data);
|
iframe.src = getEmbeddedViewerURL(elem.data);
|
||||||
|
|
||||||
// Some bogus content type that is not handled by any plugin.
|
// Some bogus content type that is not handled by any plugin.
|
||||||
elem.type = "application/not-a-pee-dee-eff-type";
|
elem.type = 'application/not-a-pee-dee-eff-type';
|
||||||
// Force the <object> to reload and render its fallback content.
|
// Force the <object> to reload and render its fallback content.
|
||||||
elem.data += "";
|
elem.data += '';
|
||||||
|
|
||||||
// Usually the browser renders plugin content in this tag, which is completely
|
// Usually the browser renders plugin content in this tag, which is completely
|
||||||
// oblivious of styles such as padding, but we insert and render child nodes,
|
// oblivious of styles such as padding, but we insert and render child nodes,
|
||||||
// so force padding to be zero to avoid undesired dimension changes.
|
// so force padding to be zero to avoid undesired dimension changes.
|
||||||
elem.style.padding = "0";
|
elem.style.padding = '0';
|
||||||
|
|
||||||
// <object> and <embed> elements have a "display:inline" style by default.
|
// <object> and <embed> elements have a "display:inline" style by default.
|
||||||
// Despite this property, when a plugin is loaded in the tag, the tag is
|
// Despite this property, when a plugin is loaded in the tag, the tag is
|
||||||
@ -184,27 +180,27 @@ function updateObjectElement(elem) {
|
|||||||
// web pages is respected.
|
// web pages is respected.
|
||||||
// (<embed> behaves as expected with the default display value, but setting it
|
// (<embed> behaves as expected with the default display value, but setting it
|
||||||
// to display:inline-block doesn't hurt).
|
// to display:inline-block doesn't hurt).
|
||||||
elem.style.display = "inline-block";
|
elem.style.display = 'inline-block';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an <iframe> element without borders that takes the full width and
|
// Create an <iframe> element without borders that takes the full width and
|
||||||
// height.
|
// height.
|
||||||
function createFullSizeIframe() {
|
function createFullSizeIframe() {
|
||||||
var iframe = document.createElement("iframe");
|
var iframe = document.createElement('iframe');
|
||||||
iframe.style.background = "none";
|
iframe.style.background = 'none';
|
||||||
iframe.style.border = "none";
|
iframe.style.border = 'none';
|
||||||
iframe.style.borderRadius = "none";
|
iframe.style.borderRadius = 'none';
|
||||||
iframe.style.boxShadow = "none";
|
iframe.style.boxShadow = 'none';
|
||||||
iframe.style.cssFloat = "none";
|
iframe.style.cssFloat = 'none';
|
||||||
iframe.style.display = "block";
|
iframe.style.display = 'block';
|
||||||
iframe.style.height = "100%";
|
iframe.style.height = '100%';
|
||||||
iframe.style.margin = "0";
|
iframe.style.margin = '0';
|
||||||
iframe.style.maxHeight = "none";
|
iframe.style.maxHeight = 'none';
|
||||||
iframe.style.maxWidth = "none";
|
iframe.style.maxWidth = 'none';
|
||||||
iframe.style.position = "static";
|
iframe.style.position = 'static';
|
||||||
iframe.style.transform = "none";
|
iframe.style.transform = 'none';
|
||||||
iframe.style.visibility = "visible";
|
iframe.style.visibility = 'visible';
|
||||||
iframe.style.width = "100%";
|
iframe.style.width = '100%';
|
||||||
return iframe;
|
return iframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,10 +208,10 @@ function createFullSizeIframe() {
|
|||||||
function getEmbeddedViewerURL(path) {
|
function getEmbeddedViewerURL(path) {
|
||||||
var fragment = /^([^#]*)(#.*)?$/.exec(path);
|
var fragment = /^([^#]*)(#.*)?$/.exec(path);
|
||||||
path = fragment[1];
|
path = fragment[1];
|
||||||
fragment = fragment[2] || "";
|
fragment = fragment[2] || '';
|
||||||
|
|
||||||
// Resolve relative path to document.
|
// Resolve relative path to document.
|
||||||
var a = document.createElement("a");
|
var a = document.createElement('a');
|
||||||
a.href = document.baseURI;
|
a.href = document.baseURI;
|
||||||
a.href = path;
|
a.href = path;
|
||||||
path = a.href;
|
path = a.href;
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Detect creation of <embed> and <object> tags.
|
* Detect creation of <embed> and <object> tags.
|
||||||
*/
|
*/
|
||||||
@keyframes pdfjs-detected-object-or-embed {
|
@-webkit-keyframes pdfjs-detected-object-or-embed { from {} }
|
||||||
from {
|
@keyframes pdfjs-detected-object-or-embed { from {} }
|
||||||
/* empty */
|
object, embed {
|
||||||
}
|
-webkit-animation-delay: 0s !important;
|
||||||
}
|
-webkit-animation-name: pdfjs-detected-object-or-embed !important;
|
||||||
object,
|
-webkit-animation-play-state: running !important;
|
||||||
embed {
|
|
||||||
animation-delay: 0s !important;
|
animation-delay: 0s !important;
|
||||||
animation-name: pdfjs-detected-object-or-embed !important;
|
animation-name: pdfjs-detected-object-or-embed !important;
|
||||||
animation-play-state: running !important;
|
animation-play-state: running !important;
|
||||||
|
@ -14,41 +14,41 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
(function ExtensionRouterClosure() {
|
(function ExtensionRouterClosure() {
|
||||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html');
|
||||||
var CRX_BASE_URL = chrome.extension.getURL("/");
|
var CRX_BASE_URL = chrome.extension.getURL('/');
|
||||||
|
|
||||||
var schemes = [
|
var schemes = [
|
||||||
"http",
|
'http',
|
||||||
"https",
|
'https',
|
||||||
"ftp",
|
'ftp',
|
||||||
"file",
|
'file',
|
||||||
"chrome-extension",
|
'chrome-extension',
|
||||||
"blob",
|
'blob',
|
||||||
"data",
|
'data',
|
||||||
// Chromium OS
|
// Chromium OS
|
||||||
"filesystem",
|
'filesystem',
|
||||||
// Chromium OS, shorthand for filesystem:<origin>/external/
|
// Chromium OS, shorthand for filesystem:<origin>/external/
|
||||||
"drive",
|
'drive'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} url The URL prefixed with chrome-extension://.../
|
* @param {string} url The URL prefixed with chrome-extension://.../
|
||||||
* @returns {string|undefined} The percent-encoded URL of the (PDF) file.
|
* @return {string|undefined} The percent-encoded URL of the (PDF) file.
|
||||||
*/
|
*/
|
||||||
function parseExtensionURL(url) {
|
function parseExtensionURL(url) {
|
||||||
url = url.substring(CRX_BASE_URL.length);
|
url = url.substring(CRX_BASE_URL.length);
|
||||||
// Find the (url-encoded) colon and verify that the scheme is allowed.
|
// Find the (url-encoded) colon and verify that the scheme is whitelisted.
|
||||||
var schemeIndex = url.search(/:|%3A/i);
|
var schemeIndex = url.search(/:|%3A/i);
|
||||||
if (schemeIndex === -1) {
|
if (schemeIndex === -1) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
var scheme = url.slice(0, schemeIndex).toLowerCase();
|
var scheme = url.slice(0, schemeIndex).toLowerCase();
|
||||||
if (schemes.includes(scheme)) {
|
if (schemes.includes(scheme)) {
|
||||||
url = url.split("#", 1)[0];
|
url = url.split('#')[0];
|
||||||
if (url.charAt(schemeIndex) === ":") {
|
if (url.charAt(schemeIndex) === ':') {
|
||||||
url = encodeURIComponent(url);
|
url = encodeURIComponent(url);
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
@ -60,65 +60,55 @@ limitations under the License.
|
|||||||
// supported, see http://crbug.com/273589
|
// supported, see http://crbug.com/273589
|
||||||
// (or rewrite the query string parser in viewer.js to get it to
|
// (or rewrite the query string parser in viewer.js to get it to
|
||||||
// recognize the non-URL-encoded PDF URL.)
|
// recognize the non-URL-encoded PDF URL.)
|
||||||
chrome.webRequest.onBeforeRequest.addListener(
|
chrome.webRequest.onBeforeRequest.addListener(function(details) {
|
||||||
function (details) {
|
|
||||||
// This listener converts chrome-extension://.../http://...pdf to
|
// This listener converts chrome-extension://.../http://...pdf to
|
||||||
// chrome-extension://.../content/web/viewer.html?file=http%3A%2F%2F...pdf
|
// chrome-extension://.../content/web/viewer.html?file=http%3A%2F%2F...pdf
|
||||||
var url = parseExtensionURL(details.url);
|
var url = parseExtensionURL(details.url);
|
||||||
if (url) {
|
if (url) {
|
||||||
url = VIEWER_URL + "?file=" + url;
|
url = VIEWER_URL + '?file=' + url;
|
||||||
var i = details.url.indexOf("#");
|
var i = details.url.indexOf('#');
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
url += details.url.slice(i);
|
url += details.url.slice(i);
|
||||||
}
|
}
|
||||||
console.log("Redirecting " + details.url + " to " + url);
|
console.log('Redirecting ' + details.url + ' to ' + url);
|
||||||
return { redirectUrl: url };
|
return { redirectUrl: url, };
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
}, {
|
||||||
{
|
types: ['main_frame', 'sub_frame'],
|
||||||
types: ["main_frame", "sub_frame"],
|
urls: schemes.map(function(scheme) {
|
||||||
urls: schemes.map(function (scheme) {
|
|
||||||
// Format: "chrome-extension://[EXTENSIONID]/<scheme>*"
|
// Format: "chrome-extension://[EXTENSIONID]/<scheme>*"
|
||||||
return CRX_BASE_URL + scheme + "*";
|
return CRX_BASE_URL + scheme + '*';
|
||||||
}),
|
}),
|
||||||
},
|
}, ['blocking']);
|
||||||
["blocking"]
|
|
||||||
);
|
|
||||||
|
|
||||||
// When session restore is used, viewer pages may be loaded before the
|
// When session restore is used, viewer pages may be loaded before the
|
||||||
// webRequest event listener is attached (= page not found).
|
// webRequest event listener is attached (= page not found).
|
||||||
// Or the extension could have been crashed (OOM), leaving a sad tab behind.
|
// Or the extension could have been crashed (OOM), leaving a sad tab behind.
|
||||||
// Reload these tabs.
|
// Reload these tabs.
|
||||||
chrome.tabs.query(
|
chrome.tabs.query({
|
||||||
{
|
url: CRX_BASE_URL + '*:*',
|
||||||
url: CRX_BASE_URL + "*:*",
|
}, function(tabsFromLastSession) {
|
||||||
},
|
for (var i = 0; i < tabsFromLastSession.length; ++i) {
|
||||||
function (tabsFromLastSession) {
|
chrome.tabs.reload(tabsFromLastSession[i].id);
|
||||||
for (const { id } of tabsFromLastSession) {
|
|
||||||
chrome.tabs.reload(id);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
console.log('Set up extension URL router.');
|
||||||
console.log("Set up extension URL router.");
|
|
||||||
|
|
||||||
Object.keys(localStorage).forEach(function (key) {
|
Object.keys(localStorage).forEach(function(key) {
|
||||||
// The localStorage item is set upon unload by chromecom.js.
|
// The localStorage item is set upon unload by chromecom.js.
|
||||||
var parsedKey = /^unload-(\d+)-(true|false)-(.+)/.exec(key);
|
var parsedKey = /^unload-(\d+)-(true|false)-(.+)/.exec(key);
|
||||||
if (parsedKey) {
|
if (parsedKey) {
|
||||||
var timeStart = parseInt(parsedKey[1], 10);
|
var timeStart = parseInt(parsedKey[1], 10);
|
||||||
var isHidden = parsedKey[2] === "true";
|
var isHidden = parsedKey[2] === 'true';
|
||||||
var url = parsedKey[3];
|
var url = parsedKey[3];
|
||||||
if (Date.now() - timeStart < 3000) {
|
if (Date.now() - timeStart < 3000) {
|
||||||
// Is it a new item (younger than 3 seconds)? Assume that the extension
|
// Is it a new item (younger than 3 seconds)? Assume that the extension
|
||||||
// just reloaded, so restore the tab (work-around for crbug.com/511670).
|
// just reloaded, so restore the tab (work-around for crbug.com/511670).
|
||||||
chrome.tabs.create({
|
chrome.tabs.create({
|
||||||
url:
|
url: chrome.runtime.getURL('restoretab.html') +
|
||||||
chrome.runtime.getURL("restoretab.html") +
|
'?' + encodeURIComponent(url) +
|
||||||
"?" +
|
'#' + encodeURIComponent(localStorage.getItem(key)),
|
||||||
encodeURIComponent(url) +
|
|
||||||
"#" +
|
|
||||||
encodeURIComponent(localStorage.getItem(key)),
|
|
||||||
active: !isHidden,
|
active: !isHidden,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"minimum_chrome_version": "88",
|
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "PDF Viewer",
|
"name": "PDF Viewer",
|
||||||
"version": "PDFJSSCRIPT_VERSION",
|
"version": "PDFJSSCRIPT_VERSION",
|
||||||
@ -11,30 +10,32 @@
|
|||||||
},
|
},
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"fileBrowserHandler",
|
"fileBrowserHandler",
|
||||||
"webRequest",
|
"webRequest", "webRequestBlocking",
|
||||||
"webRequestBlocking",
|
|
||||||
"<all_urls>",
|
"<all_urls>",
|
||||||
"tabs",
|
"tabs",
|
||||||
"webNavigation",
|
"webNavigation",
|
||||||
"storage"
|
"storage"
|
||||||
],
|
],
|
||||||
"content_scripts": [
|
"content_scripts": [{
|
||||||
{
|
"matches": [
|
||||||
"matches": ["http://*/*", "https://*/*", "ftp://*/*", "file://*/*"],
|
"http://*/*",
|
||||||
|
"https://*/*",
|
||||||
|
"ftp://*/*",
|
||||||
|
"file://*/*"
|
||||||
|
],
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true,
|
"all_frames": true,
|
||||||
"css": ["contentstyle.css"],
|
"css": ["contentstyle.css"],
|
||||||
"js": ["contentscript.js"]
|
"js": ["contentscript.js"]
|
||||||
}
|
}],
|
||||||
],
|
|
||||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||||
"file_browser_handlers": [
|
"file_browser_handlers": [{
|
||||||
{
|
|
||||||
"id": "open-as-pdf",
|
"id": "open-as-pdf",
|
||||||
"default_title": "Open with PDF Viewer",
|
"default_title": "Open with PDF Viewer",
|
||||||
"file_filters": ["filesystem:*.pdf"]
|
"file_filters": [
|
||||||
}
|
"filesystem:*.pdf"
|
||||||
],
|
]
|
||||||
|
}],
|
||||||
"storage": {
|
"storage": {
|
||||||
"managed_schema": "preferences_schema.json"
|
"managed_schema": "preferences_schema.json"
|
||||||
},
|
},
|
||||||
|
@ -15,8 +15,8 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
/* eslint strict: ["error", "function"] */
|
/* eslint strict: ["error", "function"] */
|
||||||
|
|
||||||
(function () {
|
(function() {
|
||||||
"use strict";
|
'use strict';
|
||||||
var storageLocal = chrome.storage.local;
|
var storageLocal = chrome.storage.local;
|
||||||
var storageSync = chrome.storage.sync;
|
var storageSync = chrome.storage.sync;
|
||||||
|
|
||||||
@ -25,8 +25,8 @@ limitations under the License.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getStorageNames(function (storageKeys) {
|
getStorageNames(function(storageKeys) {
|
||||||
storageLocal.get(storageKeys, function (values) {
|
storageLocal.get(storageKeys, function(values) {
|
||||||
if (!values || !Object.keys(values).length) {
|
if (!values || !Object.keys(values).length) {
|
||||||
// No local storage - nothing to migrate.
|
// No local storage - nothing to migrate.
|
||||||
// ... except possibly for a renamed preference name.
|
// ... except possibly for a renamed preference name.
|
||||||
@ -40,34 +40,31 @@ limitations under the License.
|
|||||||
function getStorageNames(callback) {
|
function getStorageNames(callback) {
|
||||||
var x = new XMLHttpRequest();
|
var x = new XMLHttpRequest();
|
||||||
var schema_location = chrome.runtime.getManifest().storage.managed_schema;
|
var schema_location = chrome.runtime.getManifest().storage.managed_schema;
|
||||||
x.open("get", chrome.runtime.getURL(schema_location));
|
x.open('get', chrome.runtime.getURL(schema_location));
|
||||||
x.onload = function () {
|
x.onload = function() {
|
||||||
var storageKeys = Object.keys(x.response.properties);
|
var storageKeys = Object.keys(x.response.properties);
|
||||||
callback(storageKeys);
|
callback(storageKeys);
|
||||||
};
|
};
|
||||||
x.responseType = "json";
|
x.responseType = 'json';
|
||||||
x.send();
|
x.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save |values| to storage.sync and delete the values with that key from
|
// Save |values| to storage.sync and delete the values with that key from
|
||||||
// storage.local.
|
// storage.local.
|
||||||
function migrateToSyncStorage(values) {
|
function migrateToSyncStorage(values) {
|
||||||
storageSync.set(values, function () {
|
storageSync.set(values, function() {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
console.error(
|
console.error('Failed to migrate settings due to an error: ' +
|
||||||
"Failed to migrate settings due to an error: " +
|
chrome.runtime.lastError.message);
|
||||||
chrome.runtime.lastError.message
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Migration successful. Delete local settings.
|
// Migration successful. Delete local settings.
|
||||||
storageLocal.remove(Object.keys(values), function () {
|
storageLocal.remove(Object.keys(values), function() {
|
||||||
// In theory remove() could fail (e.g. if the browser's storage
|
// In theory remove() could fail (e.g. if the browser's storage
|
||||||
// backend is corrupt), but since storageSync.set succeeded, consider
|
// backend is corrupt), but since storageSync.set succeeded, consider
|
||||||
// the migration successful.
|
// the migration successful.
|
||||||
console.log(
|
console.log(
|
||||||
"Successfully migrated preferences from local to sync storage."
|
'Successfully migrated preferences from local to sync storage.');
|
||||||
);
|
|
||||||
migrateRenamedStorage();
|
migrateRenamedStorage();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -78,76 +75,61 @@ limitations under the License.
|
|||||||
// Note: We cannot modify managed preferences, so the migration logic is
|
// Note: We cannot modify managed preferences, so the migration logic is
|
||||||
// duplicated in web/chromecom.js too.
|
// duplicated in web/chromecom.js too.
|
||||||
function migrateRenamedStorage() {
|
function migrateRenamedStorage() {
|
||||||
storageSync.get(
|
storageSync.get([
|
||||||
[
|
'enableHandToolOnLoad',
|
||||||
"enableHandToolOnLoad",
|
'cursorToolOnLoad',
|
||||||
"cursorToolOnLoad",
|
'disableTextLayer',
|
||||||
"disableTextLayer",
|
'enhanceTextSelection',
|
||||||
"enhanceTextSelection",
|
'textLayerMode',
|
||||||
"textLayerMode",
|
'showPreviousViewOnLoad',
|
||||||
"showPreviousViewOnLoad",
|
'disablePageMode',
|
||||||
"disablePageMode",
|
'viewOnLoad',
|
||||||
"viewOnLoad",
|
], function(items) {
|
||||||
],
|
|
||||||
function (items) {
|
|
||||||
// Migration code for https://github.com/mozilla/pdf.js/pull/7635.
|
// Migration code for https://github.com/mozilla/pdf.js/pull/7635.
|
||||||
if (typeof items.enableHandToolOnLoad === "boolean") {
|
if (typeof items.enableHandToolOnLoad === 'boolean') {
|
||||||
if (items.enableHandToolOnLoad) {
|
if (items.enableHandToolOnLoad) {
|
||||||
storageSync.set(
|
storageSync.set({
|
||||||
{
|
|
||||||
cursorToolOnLoad: 1,
|
cursorToolOnLoad: 1,
|
||||||
},
|
}, function() {
|
||||||
function () {
|
|
||||||
if (!chrome.runtime.lastError) {
|
if (!chrome.runtime.lastError) {
|
||||||
storageSync.remove("enableHandToolOnLoad");
|
storageSync.remove('enableHandToolOnLoad');
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
storageSync.remove("enableHandToolOnLoad");
|
storageSync.remove('enableHandToolOnLoad');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Migration code for https://github.com/mozilla/pdf.js/pull/9479.
|
// Migration code for https://github.com/mozilla/pdf.js/pull/9479.
|
||||||
if (typeof items.disableTextLayer === "boolean") {
|
if (typeof items.disableTextLayer === 'boolean') {
|
||||||
if (items.disableTextLayer) {
|
var textLayerMode = items.disableTextLayer ? 0 :
|
||||||
storageSync.set(
|
items.enhanceTextSelection ? 2 : 1;
|
||||||
{
|
if (textLayerMode !== 1) {
|
||||||
textLayerMode: 0,
|
// Overwrite if computed textLayerMode is not the default value (1).
|
||||||
},
|
storageSync.set({
|
||||||
function () {
|
textLayerMode: textLayerMode,
|
||||||
|
}, function() {
|
||||||
if (!chrome.runtime.lastError) {
|
if (!chrome.runtime.lastError) {
|
||||||
storageSync.remove([
|
storageSync.remove(['disableTextLayer', 'enhanceTextSelection']);
|
||||||
"disableTextLayer",
|
|
||||||
"enhanceTextSelection",
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
storageSync.remove(["disableTextLayer", "enhanceTextSelection"]);
|
storageSync.remove(['disableTextLayer', 'enhanceTextSelection']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Migration code for https://github.com/mozilla/pdf.js/pull/10502.
|
// Migration code for https://github.com/mozilla/pdf.js/pull/10502.
|
||||||
if (typeof items.showPreviousViewOnLoad === "boolean") {
|
if (typeof items.showPreviousViewOnLoad === 'boolean') {
|
||||||
if (!items.showPreviousViewOnLoad) {
|
if (!items.showPreviousViewOnLoad) {
|
||||||
storageSync.set(
|
storageSync.set({
|
||||||
{
|
|
||||||
viewOnLoad: 1,
|
viewOnLoad: 1,
|
||||||
},
|
}, function() {
|
||||||
function () {
|
|
||||||
if (!chrome.runtime.lastError) {
|
if (!chrome.runtime.lastError) {
|
||||||
storageSync.remove([
|
storageSync.remove(['showPreviousViewOnLoad', 'disablePageMode']);
|
||||||
"showPreviousViewOnLoad",
|
|
||||||
"disablePageMode",
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
storageSync.remove(["showPreviousViewOnLoad", "disablePageMode"]);
|
storageSync.remove(['showPreviousViewOnLoad', 'disablePageMode']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -43,19 +43,6 @@ body {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template id="viewerCssTheme-template">
|
|
||||||
<div class="settings-row">
|
|
||||||
<label>
|
|
||||||
<span></span>
|
|
||||||
<select>
|
|
||||||
<option value="0">Use system theme</option>
|
|
||||||
<option value="1">Light theme</option>
|
|
||||||
<option value="2">Dark theme</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template id="viewOnLoad-template">
|
<template id="viewOnLoad-template">
|
||||||
<div class="settings-row">
|
<div class="settings-row">
|
||||||
<label>
|
<label>
|
||||||
@ -126,6 +113,7 @@ body {
|
|||||||
<select>
|
<select>
|
||||||
<option value="0">Disable text selection</option>
|
<option value="0">Disable text selection</option>
|
||||||
<option value="1">Enable text selection</option>
|
<option value="1">Enable text selection</option>
|
||||||
|
<option value="2">Enable enhanced mode (experimental)</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
@ -152,7 +140,6 @@ body {
|
|||||||
<span></span>
|
<span></span>
|
||||||
<select>
|
<select>
|
||||||
<option value="-1">Default</option>
|
<option value="-1">Default</option>
|
||||||
<option value="3">Page scrolling</option>
|
|
||||||
<option value="0">Vertical scrolling</option>
|
<option value="0">Vertical scrolling</option>
|
||||||
<option value="1">Horizontal scrolling</option>
|
<option value="1">Horizontal scrolling</option>
|
||||||
<option value="2">Wrapped scrolling</option>
|
<option value="2">Wrapped scrolling</option>
|
||||||
|
@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
var storageAreaName = chrome.storage.sync ? "sync" : "local";
|
var storageAreaName = chrome.storage.sync ? 'sync' : 'local';
|
||||||
var storageArea = chrome.storage[storageAreaName];
|
var storageArea = chrome.storage[storageAreaName];
|
||||||
|
|
||||||
Promise.all([
|
Promise.all([
|
||||||
@ -25,13 +25,13 @@ Promise.all([
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get preferences as set by the system administrator.
|
// Get preferences as set by the system administrator.
|
||||||
chrome.storage.managed.get(null, function (prefs) {
|
chrome.storage.managed.get(null, function(prefs) {
|
||||||
// Managed storage may be disabled, e.g. in Opera.
|
// Managed storage may be disabled, e.g. in Opera.
|
||||||
resolve(prefs || {});
|
resolve(prefs || {});
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
new Promise(function getUserPrefs(resolve) {
|
new Promise(function getUserPrefs(resolve) {
|
||||||
storageArea.get(null, function (prefs) {
|
storageArea.get(null, function(prefs) {
|
||||||
resolve(prefs || {});
|
resolve(prefs || {});
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
@ -39,15 +39,14 @@ Promise.all([
|
|||||||
// Get the storage schema - a dictionary of preferences.
|
// Get the storage schema - a dictionary of preferences.
|
||||||
var x = new XMLHttpRequest();
|
var x = new XMLHttpRequest();
|
||||||
var schema_location = chrome.runtime.getManifest().storage.managed_schema;
|
var schema_location = chrome.runtime.getManifest().storage.managed_schema;
|
||||||
x.open("get", chrome.runtime.getURL(schema_location));
|
x.open('get', chrome.runtime.getURL(schema_location));
|
||||||
x.onload = function () {
|
x.onload = function() {
|
||||||
resolve(x.response.properties);
|
resolve(x.response.properties);
|
||||||
};
|
};
|
||||||
x.responseType = "json";
|
x.responseType = 'json';
|
||||||
x.send();
|
x.send();
|
||||||
}),
|
})
|
||||||
])
|
]).then(function(values) {
|
||||||
.then(function (values) {
|
|
||||||
var managedPrefs = values[0];
|
var managedPrefs = values[0];
|
||||||
var userPrefs = values[1];
|
var userPrefs = values[1];
|
||||||
var schema = values[2];
|
var schema = values[2];
|
||||||
@ -62,7 +61,7 @@ Promise.all([
|
|||||||
var prefNames = Object.keys(schema);
|
var prefNames = Object.keys(schema);
|
||||||
var renderPreferenceFunctions = {};
|
var renderPreferenceFunctions = {};
|
||||||
// Render options
|
// Render options
|
||||||
prefNames.forEach(function (prefName) {
|
prefNames.forEach(function(prefName) {
|
||||||
var prefSchema = schema[prefName];
|
var prefSchema = schema[prefName];
|
||||||
if (!prefSchema.title) {
|
if (!prefSchema.title) {
|
||||||
// Don't show preferences if the title is missing.
|
// Don't show preferences if the title is missing.
|
||||||
@ -71,26 +70,24 @@ Promise.all([
|
|||||||
|
|
||||||
// A DOM element with a method renderPreference.
|
// A DOM element with a method renderPreference.
|
||||||
var renderPreference;
|
var renderPreference;
|
||||||
if (prefSchema.type === "boolean") {
|
if (prefSchema.type === 'boolean') {
|
||||||
// Most prefs are booleans, render them in a generic way.
|
// Most prefs are booleans, render them in a generic way.
|
||||||
renderPreference = renderBooleanPref(
|
renderPreference = renderBooleanPref(prefSchema.title,
|
||||||
prefSchema.title,
|
|
||||||
prefSchema.description,
|
prefSchema.description,
|
||||||
prefName
|
prefName);
|
||||||
);
|
} else if (prefSchema.type === 'integer' && prefSchema.enum) {
|
||||||
} else if (prefSchema.type === "integer" && prefSchema.enum) {
|
|
||||||
// Most other prefs are integer-valued enumerations, render them in a
|
// Most other prefs are integer-valued enumerations, render them in a
|
||||||
// generic way too.
|
// generic way too.
|
||||||
// Unlike the renderBooleanPref branch, each preference handled by this
|
// Unlike the renderBooleanPref branch, each preference handled by this
|
||||||
// branch still needs its own template in options.html with
|
// branch still needs its own template in options.html with
|
||||||
// id="$prefName-template".
|
// id="$prefName-template".
|
||||||
renderPreference = renderEnumPref(prefSchema.title, prefName);
|
renderPreference = renderEnumPref(prefSchema.title, prefName);
|
||||||
} else if (prefName === "defaultZoomValue") {
|
} else if (prefName === 'defaultZoomValue') {
|
||||||
renderPreference = renderDefaultZoomValue(prefSchema.title);
|
renderPreference = renderDefaultZoomValue(prefSchema.title);
|
||||||
} else {
|
} else {
|
||||||
// Should NEVER be reached. Only happens if a new type of preference is
|
// Should NEVER be reached. Only happens if a new type of preference is
|
||||||
// added to the storage manifest.
|
// added to the storage manifest.
|
||||||
console.error("Don't know how to handle " + prefName + "!");
|
console.error('Don\'t know how to handle ' + prefName + '!');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,28 +99,24 @@ Promise.all([
|
|||||||
var renderedPrefNames = Object.keys(renderPreferenceFunctions);
|
var renderedPrefNames = Object.keys(renderPreferenceFunctions);
|
||||||
|
|
||||||
// Reset button to restore default settings.
|
// Reset button to restore default settings.
|
||||||
document.getElementById("reset-button").onclick = function () {
|
document.getElementById('reset-button').onclick = function() {
|
||||||
userPrefs = {};
|
userPrefs = {};
|
||||||
storageArea.remove(prefNames, function () {
|
storageArea.remove(prefNames, function() {
|
||||||
renderedPrefNames.forEach(function (prefName) {
|
renderedPrefNames.forEach(function(prefName) {
|
||||||
renderPreferenceFunctions[prefName](getPrefValue(prefName));
|
renderPreferenceFunctions[prefName](getPrefValue(prefName));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Automatically update the UI when the preferences were changed elsewhere.
|
// Automatically update the UI when the preferences were changed elsewhere.
|
||||||
chrome.storage.onChanged.addListener(function (changes, areaName) {
|
chrome.storage.onChanged.addListener(function(changes, areaName) {
|
||||||
var prefs = null;
|
var prefs = areaName === storageAreaName ? userPrefs :
|
||||||
if (areaName === storageAreaName) {
|
areaName === 'managed' ? managedPrefs : null;
|
||||||
prefs = userPrefs;
|
|
||||||
} else if (areaName === "managed") {
|
|
||||||
prefs = managedPrefs;
|
|
||||||
}
|
|
||||||
if (prefs) {
|
if (prefs) {
|
||||||
renderedPrefNames.forEach(function (prefName) {
|
renderedPrefNames.forEach(function(prefName) {
|
||||||
var prefChanges = changes[prefName];
|
var prefChanges = changes[prefName];
|
||||||
if (prefChanges) {
|
if (prefChanges) {
|
||||||
if ("newValue" in prefChanges) {
|
if ('newValue' in prefChanges) {
|
||||||
userPrefs[prefName] = prefChanges.newValue;
|
userPrefs[prefName] = prefChanges.newValue;
|
||||||
} else {
|
} else {
|
||||||
// Otherwise the pref was deleted
|
// Otherwise the pref was deleted
|
||||||
@ -134,8 +127,7 @@ Promise.all([
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
}).then(null, console.error.bind(console));
|
||||||
.then(null, console.error.bind(console));
|
|
||||||
|
|
||||||
function importTemplate(id) {
|
function importTemplate(id) {
|
||||||
return document.importNode(document.getElementById(id).content, true);
|
return document.importNode(document.getElementById(id).content, true);
|
||||||
@ -145,17 +137,17 @@ function importTemplate(id) {
|
|||||||
// function which updates the UI with the preference.
|
// function which updates the UI with the preference.
|
||||||
|
|
||||||
function renderBooleanPref(shortDescription, description, prefName) {
|
function renderBooleanPref(shortDescription, description, prefName) {
|
||||||
var wrapper = importTemplate("checkbox-template");
|
var wrapper = importTemplate('checkbox-template');
|
||||||
wrapper.title = description;
|
wrapper.title = description;
|
||||||
|
|
||||||
var checkbox = wrapper.querySelector('input[type="checkbox"]');
|
var checkbox = wrapper.querySelector('input[type="checkbox"]');
|
||||||
checkbox.onchange = function () {
|
checkbox.onchange = function() {
|
||||||
var pref = {};
|
var pref = {};
|
||||||
pref[prefName] = this.checked;
|
pref[prefName] = this.checked;
|
||||||
storageArea.set(pref);
|
storageArea.set(pref);
|
||||||
};
|
};
|
||||||
wrapper.querySelector("span").textContent = shortDescription;
|
wrapper.querySelector('span').textContent = shortDescription;
|
||||||
document.getElementById("settings-boxes").append(wrapper);
|
document.getElementById('settings-boxes').appendChild(wrapper);
|
||||||
|
|
||||||
function renderPreference(value) {
|
function renderPreference(value) {
|
||||||
checkbox.checked = value;
|
checkbox.checked = value;
|
||||||
@ -164,15 +156,15 @@ function renderBooleanPref(shortDescription, description, prefName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderEnumPref(shortDescription, prefName) {
|
function renderEnumPref(shortDescription, prefName) {
|
||||||
var wrapper = importTemplate(prefName + "-template");
|
var wrapper = importTemplate(prefName + '-template');
|
||||||
var select = wrapper.querySelector("select");
|
var select = wrapper.querySelector('select');
|
||||||
select.onchange = function () {
|
select.onchange = function() {
|
||||||
var pref = {};
|
var pref = {};
|
||||||
pref[prefName] = parseInt(this.value);
|
pref[prefName] = parseInt(this.value);
|
||||||
storageArea.set(pref);
|
storageArea.set(pref);
|
||||||
};
|
};
|
||||||
wrapper.querySelector("span").textContent = shortDescription;
|
wrapper.querySelector('span').textContent = shortDescription;
|
||||||
document.getElementById("settings-boxes").append(wrapper);
|
document.getElementById('settings-boxes').appendChild(wrapper);
|
||||||
|
|
||||||
function renderPreference(value) {
|
function renderPreference(value) {
|
||||||
select.value = value;
|
select.value = value;
|
||||||
@ -181,24 +173,24 @@ function renderEnumPref(shortDescription, prefName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderDefaultZoomValue(shortDescription) {
|
function renderDefaultZoomValue(shortDescription) {
|
||||||
var wrapper = importTemplate("defaultZoomValue-template");
|
var wrapper = importTemplate('defaultZoomValue-template');
|
||||||
var select = wrapper.querySelector("select");
|
var select = wrapper.querySelector('select');
|
||||||
select.onchange = function () {
|
select.onchange = function() {
|
||||||
storageArea.set({
|
storageArea.set({
|
||||||
defaultZoomValue: this.value,
|
defaultZoomValue: this.value,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
wrapper.querySelector("span").textContent = shortDescription;
|
wrapper.querySelector('span').textContent = shortDescription;
|
||||||
document.getElementById("settings-boxes").append(wrapper);
|
document.getElementById('settings-boxes').appendChild(wrapper);
|
||||||
|
|
||||||
function renderPreference(value) {
|
function renderPreference(value) {
|
||||||
value = value || "auto";
|
value = value || 'auto';
|
||||||
select.value = value;
|
select.value = value;
|
||||||
var customOption = select.querySelector("option.custom-zoom");
|
var customOption = select.querySelector('option.custom-zoom');
|
||||||
if (select.selectedIndex === -1 && value) {
|
if (select.selectedIndex === -1 && value) {
|
||||||
// Custom zoom percentage, e.g. set via managed preferences.
|
// Custom zoom percentage, e.g. set via managed preferences.
|
||||||
// [zoom] or [zoom],[left],[top]
|
// [zoom] or [zoom],[left],[top]
|
||||||
customOption.text = value.indexOf(",") > 0 ? value : value + "%";
|
customOption.text = value.indexOf(',') > 0 ? value : value + '%';
|
||||||
customOption.value = value;
|
customOption.value = value;
|
||||||
customOption.hidden = false;
|
customOption.hidden = false;
|
||||||
customOption.selected = true;
|
customOption.selected = true;
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
(function PageActionClosure() {
|
(function PageActionClosure() {
|
||||||
/**
|
/**
|
||||||
@ -28,17 +28,17 @@ limitations under the License.
|
|||||||
if (url) {
|
if (url) {
|
||||||
url = url[1];
|
url = url[1];
|
||||||
chrome.pageAction.setPopup({
|
chrome.pageAction.setPopup({
|
||||||
tabId,
|
tabId: tabId,
|
||||||
popup: "/pageAction/popup.html?file=" + encodeURIComponent(url),
|
popup: '/pageAction/popup.html?file=' + encodeURIComponent(url),
|
||||||
});
|
});
|
||||||
chrome.pageAction.show(tabId);
|
chrome.pageAction.show(tabId);
|
||||||
} else {
|
} else {
|
||||||
console.log("Unable to get PDF url from " + displayUrl);
|
console.log('Unable to get PDF url from ' + displayUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener(function (message, sender) {
|
chrome.runtime.onMessage.addListener(function(message, sender) {
|
||||||
if (message === "showPageAction" && sender.tab) {
|
if (message === 'showPageAction' && sender.tab) {
|
||||||
showPageAction(sender.tab.id, sender.tab.url);
|
showPageAction(sender.tab.id, sender.tab.url);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
var url = location.search.match(/[&?]file=([^&]+)/i);
|
var url = location.search.match(/[&?]file=([^&]+)/i);
|
||||||
if (url) {
|
if (url) {
|
||||||
|
@ -16,8 +16,8 @@ limitations under the License.
|
|||||||
/* eslint strict: ["error", "function"] */
|
/* eslint strict: ["error", "function"] */
|
||||||
/* import-globals-from pdfHandler.js */
|
/* import-globals-from pdfHandler.js */
|
||||||
|
|
||||||
(function () {
|
(function() {
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
if (!chrome.fileBrowserHandler) {
|
if (!chrome.fileBrowserHandler) {
|
||||||
// Not on Chromium OS, bail out
|
// Not on Chromium OS, bail out
|
||||||
@ -28,12 +28,12 @@ limitations under the License.
|
|||||||
/**
|
/**
|
||||||
* Invoked when "Open with PDF Viewer" is chosen in the File browser.
|
* Invoked when "Open with PDF Viewer" is chosen in the File browser.
|
||||||
*
|
*
|
||||||
* @param {string} id File browser action ID as specified in
|
* @param {String} id File browser action ID as specified in
|
||||||
* manifest.json
|
* manifest.json
|
||||||
* @param {Object} details Object of type FileHandlerExecuteEventDetails
|
* @param {Object} details Object of type FileHandlerExecuteEventDetails
|
||||||
*/
|
*/
|
||||||
function onExecuteFileBrowserHandler(id, details) {
|
function onExecuteFileBrowserHandler(id, details) {
|
||||||
if (id !== "open-as-pdf") {
|
if (id !== 'open-as-pdf') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var fileEntries = details.entries;
|
var fileEntries = details.entries;
|
||||||
@ -41,15 +41,15 @@ limitations under the License.
|
|||||||
// the other Chrome APIs that use "tabId" (http://crbug.com/179767)
|
// the other Chrome APIs that use "tabId" (http://crbug.com/179767)
|
||||||
var tabId = details.tab_id || details.tabId;
|
var tabId = details.tab_id || details.tabId;
|
||||||
if (tabId > 0) {
|
if (tabId > 0) {
|
||||||
chrome.tabs.get(tabId, function (tab) {
|
chrome.tabs.get(tabId, function(tab) {
|
||||||
openViewer(tab && tab.windowId, fileEntries);
|
openViewer(tab && tab.windowId, fileEntries);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Re-use existing window, if available.
|
// Re-use existing window, if available.
|
||||||
chrome.windows.getLastFocused(function (chromeWindow) {
|
chrome.windows.getLastFocused(function(chromeWindow) {
|
||||||
var windowId = chromeWindow && chromeWindow.id;
|
var windowId = chromeWindow && chromeWindow.id;
|
||||||
if (windowId) {
|
if (windowId) {
|
||||||
chrome.windows.update(windowId, { focused: true });
|
chrome.windows.update(windowId, { focused: true, });
|
||||||
}
|
}
|
||||||
openViewer(windowId, fileEntries);
|
openViewer(windowId, fileEntries);
|
||||||
});
|
});
|
||||||
@ -69,34 +69,26 @@ limitations under the License.
|
|||||||
var fileEntry = fileEntries.shift();
|
var fileEntry = fileEntries.shift();
|
||||||
var url = fileEntry.toURL();
|
var url = fileEntry.toURL();
|
||||||
// Use drive: alias to get shorter (more human-readable) URLs.
|
// Use drive: alias to get shorter (more human-readable) URLs.
|
||||||
url = url.replace(
|
url = url.replace(/^filesystem:chrome-extension:\/\/[a-p]{32}\/external\//,
|
||||||
/^filesystem:chrome-extension:\/\/[a-p]{32}\/external\//,
|
'drive:');
|
||||||
"drive:"
|
|
||||||
);
|
|
||||||
url = getViewerURL(url);
|
url = getViewerURL(url);
|
||||||
|
|
||||||
if (windowId) {
|
if (windowId) {
|
||||||
chrome.tabs.create(
|
chrome.tabs.create({
|
||||||
{
|
windowId: windowId,
|
||||||
windowId,
|
|
||||||
active: true,
|
active: true,
|
||||||
url,
|
url: url,
|
||||||
},
|
}, function() {
|
||||||
function () {
|
|
||||||
openViewer(windowId, fileEntries);
|
openViewer(windowId, fileEntries);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
chrome.windows.create(
|
chrome.windows.create({
|
||||||
{
|
type: 'normal',
|
||||||
type: "normal",
|
|
||||||
focused: true,
|
focused: true,
|
||||||
url,
|
url: url,
|
||||||
},
|
}, function(chromeWindow) {
|
||||||
function (chromeWindow) {
|
|
||||||
openViewer(chromeWindow.id, fileEntries);
|
openViewer(chromeWindow.id, fileEntries);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
@ -15,29 +15,21 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
/* import-globals-from preserve-referer.js */
|
/* import-globals-from preserve-referer.js */
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
var VIEWER_URL = chrome.extension.getURL("content/web/viewer.html");
|
var VIEWER_URL = chrome.extension.getURL('content/web/viewer.html');
|
||||||
|
|
||||||
function getViewerURL(pdf_url) {
|
function getViewerURL(pdf_url) {
|
||||||
// |pdf_url| may contain a fragment such as "#page=2". That should be passed
|
return VIEWER_URL + '?file=' + encodeURIComponent(pdf_url);
|
||||||
// as a fragment to the viewer, not encoded in pdf_url.
|
|
||||||
var hash = "";
|
|
||||||
var i = pdf_url.indexOf("#");
|
|
||||||
if (i > 0) {
|
|
||||||
hash = pdf_url.slice(i);
|
|
||||||
pdf_url = pdf_url.slice(0, i);
|
|
||||||
}
|
|
||||||
return VIEWER_URL + "?file=" + encodeURIComponent(pdf_url) + hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
||||||
* event. The property "url" is read.
|
* event. The property "url" is read.
|
||||||
* @returns {boolean} True if the PDF file should be downloaded.
|
* @return {boolean} True if the PDF file should be downloaded.
|
||||||
*/
|
*/
|
||||||
function isPdfDownloadable(details) {
|
function isPdfDownloadable(details) {
|
||||||
if (details.url.includes("pdfjs.action=download")) {
|
if (details.url.includes('pdfjs.action=download')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Display the PDF viewer regardless of the Content-Disposition header if the
|
// Display the PDF viewer regardless of the Content-Disposition header if the
|
||||||
@ -47,22 +39,22 @@ function isPdfDownloadable(details) {
|
|||||||
// viewer to open the PDF, but first check whether the Content-Disposition
|
// viewer to open the PDF, but first check whether the Content-Disposition
|
||||||
// header specifies an attachment. This allows sites like Google Drive to
|
// header specifies an attachment. This allows sites like Google Drive to
|
||||||
// operate correctly (#6106).
|
// operate correctly (#6106).
|
||||||
if (details.type === "main_frame" && !details.url.includes("=download")) {
|
if (details.type === 'main_frame' && !details.url.includes('=download')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var cdHeader =
|
var cdHeader = (details.responseHeaders &&
|
||||||
details.responseHeaders &&
|
getHeaderFromHeaders(details.responseHeaders, 'content-disposition'));
|
||||||
getHeaderFromHeaders(details.responseHeaders, "content-disposition");
|
return (cdHeader && /^attachment/i.test(cdHeader.value));
|
||||||
return cdHeader && /^attachment/i.test(cdHeader.value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the header from the list of headers for a given name.
|
* Get the header from the list of headers for a given name.
|
||||||
* @param {Array} headers responseHeaders of webRequest.onHeadersReceived
|
* @param {Array} headers responseHeaders of webRequest.onHeadersReceived
|
||||||
* @returns {undefined|{name: string, value: string}} The header, if found.
|
* @return {undefined|{name: string, value: string}} The header, if found.
|
||||||
*/
|
*/
|
||||||
function getHeaderFromHeaders(headers, headerName) {
|
function getHeaderFromHeaders(headers, headerName) {
|
||||||
for (const header of headers) {
|
for (var i = 0; i < headers.length; ++i) {
|
||||||
|
var header = headers[i];
|
||||||
if (header.name.toLowerCase() === headerName) {
|
if (header.name.toLowerCase() === headerName) {
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
@ -75,23 +67,21 @@ function getHeaderFromHeaders(headers, headerName) {
|
|||||||
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
||||||
* event. The properties "responseHeaders" and "url"
|
* event. The properties "responseHeaders" and "url"
|
||||||
* are read.
|
* are read.
|
||||||
* @returns {boolean} True if the resource is a PDF file.
|
* @return {boolean} True if the resource is a PDF file.
|
||||||
*/
|
*/
|
||||||
function isPdfFile(details) {
|
function isPdfFile(details) {
|
||||||
var header = getHeaderFromHeaders(details.responseHeaders, "content-type");
|
var header = getHeaderFromHeaders(details.responseHeaders, 'content-type');
|
||||||
if (header) {
|
if (header) {
|
||||||
var headerValue = header.value.toLowerCase().split(";", 1)[0].trim();
|
var headerValue = header.value.toLowerCase().split(';', 1)[0].trim();
|
||||||
if (headerValue === "application/pdf") {
|
if (headerValue === 'application/pdf') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (headerValue === "application/octet-stream") {
|
if (headerValue === 'application/octet-stream') {
|
||||||
if (details.url.toLowerCase().indexOf(".pdf") > 0) {
|
if (details.url.toLowerCase().indexOf('.pdf') > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
var cdHeader = getHeaderFromHeaders(
|
var cdHeader =
|
||||||
details.responseHeaders,
|
getHeaderFromHeaders(details.responseHeaders, 'content-disposition');
|
||||||
"content-disposition"
|
|
||||||
);
|
|
||||||
if (cdHeader && /\.pdf(["']|$)/i.test(cdHeader.value)) {
|
if (cdHeader && /\.pdf(["']|$)/i.test(cdHeader.value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -105,27 +95,27 @@ function isPdfFile(details) {
|
|||||||
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
* @param {Object} details First argument of the webRequest.onHeadersReceived
|
||||||
* event. The property "responseHeaders" is read and
|
* event. The property "responseHeaders" is read and
|
||||||
* modified if needed.
|
* modified if needed.
|
||||||
* @returns {Object|undefined} The return value for the onHeadersReceived event.
|
* @return {Object|undefined} The return value for the onHeadersReceived event.
|
||||||
* Object with key "responseHeaders" if the headers
|
* Object with key "responseHeaders" if the headers
|
||||||
* have been modified, undefined otherwise.
|
* have been modified, undefined otherwise.
|
||||||
*/
|
*/
|
||||||
function getHeadersWithContentDispositionAttachment(details) {
|
function getHeadersWithContentDispositionAttachment(details) {
|
||||||
var headers = details.responseHeaders;
|
var headers = details.responseHeaders;
|
||||||
var cdHeader = getHeaderFromHeaders(headers, "content-disposition");
|
var cdHeader = getHeaderFromHeaders(headers, 'content-disposition');
|
||||||
if (!cdHeader) {
|
if (!cdHeader) {
|
||||||
cdHeader = { name: "Content-Disposition" };
|
cdHeader = { name: 'Content-Disposition', };
|
||||||
headers.push(cdHeader);
|
headers.push(cdHeader);
|
||||||
}
|
}
|
||||||
if (!/^attachment/i.test(cdHeader.value)) {
|
if (!/^attachment/i.test(cdHeader.value)) {
|
||||||
cdHeader.value = "attachment" + cdHeader.value.replace(/^[^;]+/i, "");
|
cdHeader.value = 'attachment' + cdHeader.value.replace(/^[^;]+/i, '');
|
||||||
return { responseHeaders: headers };
|
return { responseHeaders: headers, };
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.webRequest.onHeadersReceived.addListener(
|
chrome.webRequest.onHeadersReceived.addListener(
|
||||||
function (details) {
|
function(details) {
|
||||||
if (details.method !== "GET") {
|
if (details.method !== 'GET') {
|
||||||
// Don't intercept POST requests until http://crbug.com/104058 is fixed.
|
// Don't intercept POST requests until http://crbug.com/104058 is fixed.
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
@ -142,33 +132,46 @@ chrome.webRequest.onHeadersReceived.addListener(
|
|||||||
// Implemented in preserve-referer.js
|
// Implemented in preserve-referer.js
|
||||||
saveReferer(details);
|
saveReferer(details);
|
||||||
|
|
||||||
return { redirectUrl: viewerUrl };
|
return { redirectUrl: viewerUrl, };
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
urls: ["<all_urls>"],
|
urls: [
|
||||||
types: ["main_frame", "sub_frame"],
|
'<all_urls>'
|
||||||
|
],
|
||||||
|
types: ['main_frame', 'sub_frame'],
|
||||||
},
|
},
|
||||||
["blocking", "responseHeaders"]
|
['blocking', 'responseHeaders']);
|
||||||
);
|
|
||||||
|
|
||||||
chrome.webRequest.onBeforeRequest.addListener(
|
chrome.webRequest.onBeforeRequest.addListener(
|
||||||
function (details) {
|
function(details) {
|
||||||
if (isPdfDownloadable(details)) {
|
if (isPdfDownloadable(details)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewerUrl = getViewerURL(details.url);
|
var viewerUrl = getViewerURL(details.url);
|
||||||
|
|
||||||
return { redirectUrl: viewerUrl };
|
return { redirectUrl: viewerUrl, };
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
urls: ["file://*/*.pdf", "file://*/*.PDF"],
|
urls: [
|
||||||
types: ["main_frame", "sub_frame"],
|
'file://*/*.pdf',
|
||||||
|
'file://*/*.PDF',
|
||||||
|
...(
|
||||||
|
// Duck-typing: MediaError.prototype.message was added in Chrome 59.
|
||||||
|
MediaError.prototype.hasOwnProperty('message') ? [] :
|
||||||
|
[
|
||||||
|
// Note: Chrome 59 has disabled ftp resource loading by default:
|
||||||
|
// https://www.chromestatus.com/feature/5709390967472128
|
||||||
|
'ftp://*/*.pdf',
|
||||||
|
'ftp://*/*.PDF',
|
||||||
|
]
|
||||||
|
),
|
||||||
|
],
|
||||||
|
types: ['main_frame', 'sub_frame'],
|
||||||
},
|
},
|
||||||
["blocking"]
|
['blocking']);
|
||||||
);
|
|
||||||
|
|
||||||
chrome.extension.isAllowedFileSchemeAccess(function (isAllowedAccess) {
|
chrome.extension.isAllowedFileSchemeAccess(function(isAllowedAccess) {
|
||||||
if (isAllowedAccess) {
|
if (isAllowedAccess) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -177,35 +180,29 @@ chrome.extension.isAllowedFileSchemeAccess(function (isAllowedAccess) {
|
|||||||
// API though, and we can replace the tab with the viewer.
|
// API though, and we can replace the tab with the viewer.
|
||||||
// The viewer will detect that it has no access to file:-URLs, and prompt the
|
// The viewer will detect that it has no access to file:-URLs, and prompt the
|
||||||
// user to activate file permissions.
|
// user to activate file permissions.
|
||||||
chrome.webNavigation.onBeforeNavigate.addListener(
|
chrome.webNavigation.onBeforeNavigate.addListener(function(details) {
|
||||||
function (details) {
|
|
||||||
if (details.frameId === 0 && !isPdfDownloadable(details)) {
|
if (details.frameId === 0 && !isPdfDownloadable(details)) {
|
||||||
chrome.tabs.update(details.tabId, {
|
chrome.tabs.update(details.tabId, {
|
||||||
url: getViewerURL(details.url),
|
url: getViewerURL(details.url),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}, {
|
||||||
{
|
url: [{
|
||||||
url: [
|
urlPrefix: 'file://',
|
||||||
{
|
pathSuffix: '.pdf',
|
||||||
urlPrefix: "file://",
|
}, {
|
||||||
pathSuffix: ".pdf",
|
urlPrefix: 'file://',
|
||||||
},
|
pathSuffix: '.PDF',
|
||||||
{
|
}],
|
||||||
urlPrefix: "file://",
|
});
|
||||||
pathSuffix: ".PDF",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
||||||
if (message && message.action === "getParentOrigin") {
|
if (message && message.action === 'getParentOrigin') {
|
||||||
// getParentOrigin is used to determine whether it is safe to embed a
|
// getParentOrigin is used to determine whether it is safe to embed a
|
||||||
// sensitive (local) file in a frame.
|
// sensitive (local) file in a frame.
|
||||||
if (!sender.tab) {
|
if (!sender.tab) {
|
||||||
sendResponse("");
|
sendResponse('');
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
// TODO: This should be the URL of the parent frame, not the tab. But
|
// TODO: This should be the URL of the parent frame, not the tab. But
|
||||||
@ -214,11 +211,11 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
|||||||
// for making security decisions.
|
// for making security decisions.
|
||||||
var parentUrl = sender.tab.url;
|
var parentUrl = sender.tab.url;
|
||||||
if (!parentUrl) {
|
if (!parentUrl) {
|
||||||
sendResponse("");
|
sendResponse('');
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
if (parentUrl.lastIndexOf("file:", 0) === 0) {
|
if (parentUrl.lastIndexOf('file:', 0) === 0) {
|
||||||
sendResponse("file://");
|
sendResponse('file://');
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
// The regexp should always match for valid URLs, but in case it doesn't,
|
// The regexp should always match for valid URLs, but in case it doesn't,
|
||||||
@ -227,24 +224,31 @@ chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
|
|||||||
sendResponse(origin ? origin[1] : parentUrl);
|
sendResponse(origin ? origin[1] : parentUrl);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (message && message.action === "isAllowedFileSchemeAccess") {
|
if (message && message.action === 'isAllowedFileSchemeAccess') {
|
||||||
chrome.extension.isAllowedFileSchemeAccess(sendResponse);
|
chrome.extension.isAllowedFileSchemeAccess(sendResponse);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (message && message.action === "openExtensionsPageForFileAccess") {
|
if (message && message.action === 'openExtensionsPageForFileAccess') {
|
||||||
var url = "chrome://extensions/?id=" + chrome.runtime.id;
|
var url = 'chrome://extensions/?id=' + chrome.runtime.id;
|
||||||
if (message.data.newTab) {
|
if (message.data.newTab) {
|
||||||
chrome.tabs.create({
|
chrome.tabs.create({
|
||||||
windowId: sender.tab.windowId,
|
windowId: sender.tab.windowId,
|
||||||
index: sender.tab.index + 1,
|
index: sender.tab.index + 1,
|
||||||
url,
|
url: url,
|
||||||
openerTabId: sender.tab.id,
|
openerTabId: sender.tab.id,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
chrome.tabs.update(sender.tab.id, {
|
chrome.tabs.update(sender.tab.id, {
|
||||||
url,
|
url: url,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Remove keys from storage that were once part of the deleted feature-detect.js
|
||||||
|
chrome.storage.local.remove([
|
||||||
|
'featureDetectLastUA',
|
||||||
|
'webRequestRedirectUrl',
|
||||||
|
'extensionSupportsFTP',
|
||||||
|
]);
|
||||||
|
@ -1,13 +1,6 @@
|
|||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"viewerCssTheme": {
|
|
||||||
"title": "Theme",
|
|
||||||
"description": "The theme to use.\n0 = Use system theme.\n1 = Light theme.\n2 = Dark theme.",
|
|
||||||
"type": "integer",
|
|
||||||
"enum": [0, 1, 2],
|
|
||||||
"default": 2
|
|
||||||
},
|
|
||||||
"showPreviousViewOnLoad": {
|
"showPreviousViewOnLoad": {
|
||||||
"description": "DEPRECATED. Set viewOnLoad to 1 to disable showing the last page/position on load.",
|
"description": "DEPRECATED. Set viewOnLoad to 1 to disable showing the last page/position on load.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -17,15 +10,13 @@
|
|||||||
"title": "View position on load",
|
"title": "View position on load",
|
||||||
"description": "The position in the document upon load.\n -1 = Default (uses OpenAction if available, otherwise equal to `viewOnLoad = 0`).\n 0 = The last viewed page/position.\n 1 = The initial page/position.",
|
"description": "The position in the document upon load.\n -1 = Default (uses OpenAction if available, otherwise equal to `viewOnLoad = 0`).\n 0 = The last viewed page/position.\n 1 = The initial page/position.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [-1, 0, 1],
|
"enum": [
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
"default": 0
|
"default": 0
|
||||||
},
|
},
|
||||||
"defaultZoomDelay": {
|
|
||||||
"title": "Default zoom delay",
|
|
||||||
"description": "Delay (in ms) to wait before redrawing the canvas.",
|
|
||||||
"type": "integer",
|
|
||||||
"default": 400
|
|
||||||
},
|
|
||||||
"defaultZoomValue": {
|
"defaultZoomValue": {
|
||||||
"title": "Default zoom level",
|
"title": "Default zoom level",
|
||||||
"description": "Default zoom level of the viewer. Accepted values: 'auto', 'page-actual', 'page-width', 'page-height', 'page-fit', or a zoom level in percents.",
|
"description": "Default zoom level of the viewer. Accepted values: 'auto', 'page-actual', 'page-width', 'page-height', 'page-fit', or a zoom level in percents.",
|
||||||
@ -37,7 +28,13 @@
|
|||||||
"title": "Sidebar state on load",
|
"title": "Sidebar state on load",
|
||||||
"description": "Controls the state of the sidebar upon load.\n -1 = Default (uses PageMode if available, otherwise the last position if available/enabled).\n 0 = Do not show sidebar.\n 1 = Show thumbnails in sidebar.\n 2 = Show document outline in sidebar.\n 3 = Show attachments in sidebar.",
|
"description": "Controls the state of the sidebar upon load.\n -1 = Default (uses PageMode if available, otherwise the last position if available/enabled).\n 0 = Do not show sidebar.\n 1 = Show thumbnails in sidebar.\n 2 = Show document outline in sidebar.\n 3 = Show attachments in sidebar.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [-1, 0, 1, 2, 3],
|
"enum": [
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3
|
||||||
|
],
|
||||||
"default": -1
|
"default": -1
|
||||||
},
|
},
|
||||||
"enableHandToolOnLoad": {
|
"enableHandToolOnLoad": {
|
||||||
@ -45,45 +42,32 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"enableML": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"cursorToolOnLoad": {
|
"cursorToolOnLoad": {
|
||||||
"title": "Cursor tool on load",
|
"title": "Cursor tool on load",
|
||||||
"description": "The cursor tool that is enabled upon load.\n 0 = Text selection tool.\n 1 = Hand tool.",
|
"description": "The cursor tool that is enabled upon load.\n 0 = Text selection tool.\n 1 = Hand tool.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [0, 1],
|
"enum": [
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
"default": 0
|
"default": 0
|
||||||
},
|
},
|
||||||
|
"enableWebGL": {
|
||||||
|
"title": "Enable WebGL",
|
||||||
|
"description": "Whether to enable WebGL.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"eventBusDispatchToDOM": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"pdfBugEnabled": {
|
"pdfBugEnabled": {
|
||||||
"title": "Enable debugging tools",
|
"title": "Enable debugging tools",
|
||||||
"description": "Whether to enable debugging tools.",
|
"description": "Whether to enable debugging tools.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"enableScripting": {
|
|
||||||
"title": "Enable active content (JavaScript) in PDFs",
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether to allow execution of active content (JavaScript) by PDF files.",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"enableHighlightEditor": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"enableHighlightFloatingButton": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"highlightEditorColors": {
|
|
||||||
"type": "string",
|
|
||||||
"default": "yellow=#FFFF98,green=#53FFBC,blue=#80EBFF,pink=#FFCBE6,red=#FF4F5F"
|
|
||||||
},
|
|
||||||
"enableStampEditor": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"disableRange": {
|
"disableRange": {
|
||||||
"title": "Disable range requests",
|
"title": "Disable range requests",
|
||||||
"description": "Whether to disable range requests (not recommended).",
|
"description": "Whether to disable range requests (not recommended).",
|
||||||
@ -111,18 +95,37 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"enhanceTextSelection": {
|
||||||
|
"description": "DEPRECATED. Set textLayerMode to 2 to use the enhanced text selection layer by default.",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"textLayerMode": {
|
"textLayerMode": {
|
||||||
"title": "Text layer mode",
|
"title": "Text layer mode",
|
||||||
"description": "Controls if the text layer is enabled, and the selection mode that is used.\n 0 = Disabled.\n 1 = Enabled.",
|
"description": "Controls if the text layer is enabled, and the selection mode that is used.\n 0 = Disabled.\n 1 = Enabled.\n 2 = (Experimental) Enabled, with enhanced text selection.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [0, 1],
|
"enum": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
"default": 1
|
"default": 1
|
||||||
},
|
},
|
||||||
|
"useOnlyCssZoom": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"externalLinkTarget": {
|
"externalLinkTarget": {
|
||||||
"title": "External links target window",
|
"title": "External links target window",
|
||||||
"description": "Controls how external links will be opened.\n 0 = default.\n 1 = replaces current window.\n 2 = new window/tab.\n 3 = parent.\n 4 = in top window.",
|
"description": "Controls how external links will be opened.\n 0 = default.\n 1 = replaces current window.\n 2 = new window/tab.\n 3 = parent.\n 4 = in top window.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [0, 1, 2, 3, 4],
|
"enum": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4
|
||||||
|
],
|
||||||
"default": 0
|
"default": 0
|
||||||
},
|
},
|
||||||
"disablePageLabels": {
|
"disablePageLabels": {
|
||||||
@ -140,68 +143,51 @@
|
|||||||
"description": "Whether to prevent the extension from reporting the extension and browser version to the extension developers.",
|
"description": "Whether to prevent the extension from reporting the extension and browser version to the extension developers.",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"annotationMode": {
|
"renderer": {
|
||||||
"type": "integer",
|
"type": "string",
|
||||||
"enum": [0, 1, 2, 3],
|
"enum": [
|
||||||
"default": 2
|
"canvas",
|
||||||
|
"svg"
|
||||||
|
],
|
||||||
|
"default": "canvas"
|
||||||
},
|
},
|
||||||
"annotationEditorMode": {
|
"renderInteractiveForms": {
|
||||||
"type": "integer",
|
|
||||||
"enum": [-1, 0, 3, 15],
|
|
||||||
"default": 0
|
|
||||||
},
|
|
||||||
"enablePermissions": {
|
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"enableXfa": {
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"historyUpdateUrl": {
|
"historyUpdateUrl": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"ignoreDestinationZoom": {
|
"enablePrintAutoRotate": {
|
||||||
"title": "Ignore the zoom argument in destinations",
|
"title": "Automatically rotate printed pages",
|
||||||
"description": "When enabled it will maintain the currently active zoom level, rather than letting the PDF document modify it, when navigating to internal destinations.",
|
"description": "When enabled, pages whose orientation differ from the first page are rotated when printed.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"enablePrintAutoRotate": {
|
|
||||||
"title": "Automatically rotate printed pages",
|
|
||||||
"description": "When enabled, landscape pages are rotated when printed.",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"scrollModeOnLoad": {
|
"scrollModeOnLoad": {
|
||||||
"title": "Scroll mode on load",
|
"title": "Scroll mode on load",
|
||||||
"description": "Controls how the viewer scrolls upon load.\n -1 = Default (uses the last position if available/enabled).\n 3 = Page scrolling.\n 0 = Vertical scrolling.\n 1 = Horizontal scrolling.\n 2 = Wrapped scrolling.",
|
"description": "Controls how the viewer scrolls upon load.\n -1 = Default (uses the last position if available/enabled).\n 0 = Vertical scrolling.\n 1 = Horizontal scrolling.\n 2 = Wrapped scrolling.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [-1, 0, 1, 2, 3],
|
"enum": [
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
"default": -1
|
"default": -1
|
||||||
},
|
},
|
||||||
"spreadModeOnLoad": {
|
"spreadModeOnLoad": {
|
||||||
"title": "Spread mode on load",
|
"title": "Spread mode on load",
|
||||||
"description": "Whether the viewer should join pages into spreads upon load.\n -1 = Default (uses the last position if available/enabled).\n 0 = No spreads.\n 1 = Odd spreads.\n 2 = Even spreads.",
|
"description": "Whether the viewer should join pages into spreads upon load.\n -1 = Default (uses the last position if available/enabled).\n 0 = No spreads.\n 1 = Odd spreads.\n 2 = Even spreads.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"enum": [-1, 0, 1, 2],
|
"enum": [
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
"default": -1
|
"default": -1
|
||||||
},
|
|
||||||
"forcePageColors": {
|
|
||||||
"description": "When enabled, the pdf rendering will use the high contrast mode colors",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"pageColorsBackground": {
|
|
||||||
"description": "The color is a string as defined in CSS. Its goal is to help improve readability in high contrast mode",
|
|
||||||
"type": "string",
|
|
||||||
"default": "Canvas"
|
|
||||||
},
|
|
||||||
"pageColorsForeground": {
|
|
||||||
"description": "The color is a string as defined in CSS. Its goal is to help improve readability in high contrast mode",
|
|
||||||
"type": "string",
|
|
||||||
"default": "CanvasText"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,8 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
/* import-globals-from pdfHandler.js */
|
/* import-globals-from pdfHandler.js */
|
||||||
/* exported saveReferer */
|
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
/**
|
/**
|
||||||
* This file is one part of the Referer persistency implementation. The other
|
* This file is one part of the Referer persistency implementation. The other
|
||||||
* part resides in chromecom.js.
|
* part resides in chromecom.js.
|
||||||
@ -42,18 +41,26 @@ var g_requestHeaders = {};
|
|||||||
// g_referrers[tabId][frameId] = referrer of PDF frame.
|
// g_referrers[tabId][frameId] = referrer of PDF frame.
|
||||||
var g_referrers = {};
|
var g_referrers = {};
|
||||||
|
|
||||||
(function () {
|
var extraInfoSpecWithHeaders; // = ['requestHeaders', 'extraHeaders']
|
||||||
|
|
||||||
|
(function() {
|
||||||
var requestFilter = {
|
var requestFilter = {
|
||||||
urls: ["*://*/*"],
|
urls: ['*://*/*'],
|
||||||
types: ["main_frame", "sub_frame"],
|
types: ['main_frame', 'sub_frame'],
|
||||||
};
|
};
|
||||||
chrome.webRequest.onSendHeaders.addListener(
|
function registerListener(extraInfoSpec) {
|
||||||
function (details) {
|
extraInfoSpecWithHeaders = extraInfoSpec;
|
||||||
|
// May throw if the given extraInfoSpec is unsupported.
|
||||||
|
chrome.webRequest.onSendHeaders.addListener(function(details) {
|
||||||
g_requestHeaders[details.requestId] = details.requestHeaders;
|
g_requestHeaders[details.requestId] = details.requestHeaders;
|
||||||
},
|
}, requestFilter, extraInfoSpec);
|
||||||
requestFilter,
|
}
|
||||||
["requestHeaders", "extraHeaders"]
|
try {
|
||||||
);
|
registerListener(['requestHeaders', 'extraHeaders']);
|
||||||
|
} catch (e) {
|
||||||
|
// "extraHeaders" is not supported in Chrome 71 and earlier.
|
||||||
|
registerListener(['requestHeaders']);
|
||||||
|
}
|
||||||
chrome.webRequest.onBeforeRedirect.addListener(forgetHeaders, requestFilter);
|
chrome.webRequest.onBeforeRedirect.addListener(forgetHeaders, requestFilter);
|
||||||
chrome.webRequest.onCompleted.addListener(forgetHeaders, requestFilter);
|
chrome.webRequest.onCompleted.addListener(forgetHeaders, requestFilter);
|
||||||
chrome.webRequest.onErrorOccurred.addListener(forgetHeaders, requestFilter);
|
chrome.webRequest.onErrorOccurred.addListener(forgetHeaders, requestFilter);
|
||||||
@ -66,17 +73,16 @@ var g_referrers = {};
|
|||||||
* @param {object} details - onHeadersReceived event data.
|
* @param {object} details - onHeadersReceived event data.
|
||||||
*/
|
*/
|
||||||
function saveReferer(details) {
|
function saveReferer(details) {
|
||||||
var referer =
|
var referer = g_requestHeaders[details.requestId] &&
|
||||||
g_requestHeaders[details.requestId] &&
|
getHeaderFromHeaders(g_requestHeaders[details.requestId], 'referer');
|
||||||
getHeaderFromHeaders(g_requestHeaders[details.requestId], "referer");
|
referer = referer && referer.value || '';
|
||||||
referer = (referer && referer.value) || "";
|
|
||||||
if (!g_referrers[details.tabId]) {
|
if (!g_referrers[details.tabId]) {
|
||||||
g_referrers[details.tabId] = {};
|
g_referrers[details.tabId] = {};
|
||||||
}
|
}
|
||||||
g_referrers[details.tabId][details.frameId] = referer;
|
g_referrers[details.tabId][details.frameId] = referer;
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.tabs.onRemoved.addListener(function (tabId) {
|
chrome.tabs.onRemoved.addListener(function(tabId) {
|
||||||
delete g_referrers[tabId];
|
delete g_referrers[tabId];
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -84,11 +90,11 @@ chrome.tabs.onRemoved.addListener(function (tabId) {
|
|||||||
// to matching PDF resource requests (only if the Referer is non-empty). The
|
// to matching PDF resource requests (only if the Referer is non-empty). The
|
||||||
// handler is removed as soon as the PDF viewer frame is unloaded.
|
// handler is removed as soon as the PDF viewer frame is unloaded.
|
||||||
chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||||
if (port.name !== "chromecom-referrer") {
|
if (port.name !== 'chromecom-referrer') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Note: sender.frameId is only set in Chrome 41+.
|
// Note: sender.frameId is only set in Chrome 41+.
|
||||||
if (!("frameId" in port.sender)) {
|
if (!('frameId' in port.sender)) {
|
||||||
port.disconnect();
|
port.disconnect();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -96,8 +102,8 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
|||||||
var frameId = port.sender.frameId;
|
var frameId = port.sender.frameId;
|
||||||
|
|
||||||
// If the PDF is viewed for the first time, then the referer will be set here.
|
// If the PDF is viewed for the first time, then the referer will be set here.
|
||||||
var referer = (g_referrers[tabId] && g_referrers[tabId][frameId]) || "";
|
var referer = g_referrers[tabId] && g_referrers[tabId][frameId] || '';
|
||||||
port.onMessage.addListener(function (data) {
|
port.onMessage.addListener(function(data) {
|
||||||
// If the viewer was opened directly (without opening a PDF URL first), then
|
// If the viewer was opened directly (without opening a PDF URL first), then
|
||||||
// the background script does not know about g_referrers, but the viewer may
|
// the background script does not know about g_referrers, but the viewer may
|
||||||
// know about the referer if stored in the history state (see chromecom.js).
|
// know about the referer if stored in the history state (see chromecom.js).
|
||||||
@ -107,22 +113,18 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
|||||||
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||||
if (referer) {
|
if (referer) {
|
||||||
// Only add a blocking request handler if the referer has to be rewritten.
|
// Only add a blocking request handler if the referer has to be rewritten.
|
||||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {
|
||||||
onBeforeSendHeaders,
|
|
||||||
{
|
|
||||||
urls: [data.requestUrl],
|
urls: [data.requestUrl],
|
||||||
types: ["xmlhttprequest"],
|
types: ['xmlhttprequest'],
|
||||||
tabId,
|
tabId: tabId,
|
||||||
},
|
}, ['blocking', ...extraInfoSpecWithHeaders]);
|
||||||
["blocking", "requestHeaders", "extraHeaders"]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// Acknowledge the message, and include the latest referer for this frame.
|
// Acknowledge the message, and include the latest referer for this frame.
|
||||||
port.postMessage(referer);
|
port.postMessage(referer);
|
||||||
});
|
});
|
||||||
|
|
||||||
// The port is only disconnected when the other end reloads.
|
// The port is only disconnected when the other end reloads.
|
||||||
port.onDisconnect.addListener(function () {
|
port.onDisconnect.addListener(function() {
|
||||||
if (g_referrers[tabId]) {
|
if (g_referrers[tabId]) {
|
||||||
delete g_referrers[tabId][frameId];
|
delete g_referrers[tabId][frameId];
|
||||||
}
|
}
|
||||||
@ -132,35 +134,29 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
|||||||
|
|
||||||
// Expose some response headers for fetch API calls from PDF.js;
|
// Expose some response headers for fetch API calls from PDF.js;
|
||||||
// This is a work-around for https://crbug.com/784528
|
// This is a work-around for https://crbug.com/784528
|
||||||
chrome.webRequest.onHeadersReceived.addListener(
|
chrome.webRequest.onHeadersReceived.addListener(exposeOnHeadersReceived, {
|
||||||
exposeOnHeadersReceived,
|
urls: ['https://*/*'],
|
||||||
{
|
types: ['xmlhttprequest'],
|
||||||
urls: ["https://*/*"],
|
tabId: tabId,
|
||||||
types: ["xmlhttprequest"],
|
}, ['blocking', 'responseHeaders']);
|
||||||
tabId,
|
|
||||||
},
|
|
||||||
["blocking", "responseHeaders"]
|
|
||||||
);
|
|
||||||
|
|
||||||
function onBeforeSendHeaders(details) {
|
function onBeforeSendHeaders(details) {
|
||||||
if (details.frameId !== frameId) {
|
if (details.frameId !== frameId) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
var headers = details.requestHeaders;
|
var headers = details.requestHeaders;
|
||||||
var refererHeader = getHeaderFromHeaders(headers, "referer");
|
var refererHeader = getHeaderFromHeaders(headers, 'referer');
|
||||||
if (!refererHeader) {
|
if (!refererHeader) {
|
||||||
refererHeader = { name: "Referer" };
|
refererHeader = { name: 'Referer', };
|
||||||
headers.push(refererHeader);
|
headers.push(refererHeader);
|
||||||
} else if (
|
} else if (refererHeader.value &&
|
||||||
refererHeader.value &&
|
refererHeader.value.lastIndexOf('chrome-extension:', 0) !== 0) {
|
||||||
refererHeader.value.lastIndexOf("chrome-extension:", 0) !== 0
|
|
||||||
) {
|
|
||||||
// Sanity check. If the referer is set, and the value is not the URL of
|
// Sanity check. If the referer is set, and the value is not the URL of
|
||||||
// this extension, then the request was not initiated by this extension.
|
// this extension, then the request was not initiated by this extension.
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
refererHeader.value = referer;
|
refererHeader.value = referer;
|
||||||
return { requestHeaders: headers };
|
return { requestHeaders: headers, };
|
||||||
}
|
}
|
||||||
|
|
||||||
function exposeOnHeadersReceived(details) {
|
function exposeOnHeadersReceived(details) {
|
||||||
@ -168,16 +164,16 @@ chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
var headers = details.responseHeaders;
|
var headers = details.responseHeaders;
|
||||||
var aceh = getHeaderFromHeaders(headers, "access-control-expose-headers");
|
var aceh = getHeaderFromHeaders(headers, 'access-control-expose-headers');
|
||||||
// List of headers that PDF.js uses in src/display/network_utils.js
|
// List of headers that PDF.js uses in src/display/network_utils.js
|
||||||
var acehValue =
|
var acehValue =
|
||||||
"accept-ranges,content-encoding,content-length,content-disposition";
|
'accept-ranges,content-encoding,content-length,content-disposition';
|
||||||
if (aceh) {
|
if (aceh) {
|
||||||
aceh.value += "," + acehValue;
|
aceh.value += ',' + acehValue;
|
||||||
} else {
|
} else {
|
||||||
aceh = { name: "Access-Control-Expose-Headers", value: acehValue };
|
aceh = { name: 'Access-Control-Expose-Headers', value: acehValue, };
|
||||||
headers.push(aceh);
|
headers.push(aceh);
|
||||||
}
|
}
|
||||||
return { responseHeaders: headers };
|
return { responseHeaders: headers, };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -20,12 +20,12 @@ limitations under the License.
|
|||||||
* - extension-router.js retrieves the saved state and opens restoretab.html
|
* - extension-router.js retrieves the saved state and opens restoretab.html
|
||||||
* - restoretab.html (this script) restores the URL and history state.
|
* - restoretab.html (this script) restores the URL and history state.
|
||||||
*/
|
*/
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
var url = decodeURIComponent(location.search.slice(1));
|
var url = decodeURIComponent(location.search.slice(1));
|
||||||
var historyState = decodeURIComponent(location.hash.slice(1));
|
var historyState = decodeURIComponent(location.hash.slice(1));
|
||||||
|
|
||||||
historyState = historyState === "undefined" ? null : JSON.parse(historyState);
|
historyState = historyState === 'undefined' ? null : JSON.parse(historyState);
|
||||||
|
|
||||||
history.replaceState(historyState, null, url);
|
history.replaceState(historyState, null, url);
|
||||||
location.reload();
|
location.reload();
|
||||||
|
@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
// Do not reload the extension when an update becomes available, UNLESS the PDF
|
// Do not reload the extension when an update becomes available, UNLESS the PDF
|
||||||
// viewer is not displaying any PDF files. Otherwise the tabs would close, which
|
// viewer is not displaying any PDF files. Otherwise the tabs would close, which
|
||||||
// is quite disruptive (crbug.com/511670).
|
// is quite disruptive (crbug.com/511670).
|
||||||
chrome.runtime.onUpdateAvailable.addListener(function () {
|
chrome.runtime.onUpdateAvailable.addListener(function() {
|
||||||
if (chrome.extension.getViews({ type: "tab" }).length === 0) {
|
if (chrome.extension.getViews({ type: 'tab', }).length === 0) {
|
||||||
chrome.runtime.reload();
|
chrome.runtime.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -15,20 +15,20 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
/* eslint strict: ["error", "function"] */
|
/* eslint strict: ["error", "function"] */
|
||||||
|
|
||||||
(function () {
|
(function() {
|
||||||
"use strict";
|
'use strict';
|
||||||
// This module sends the browser and extension version to a server, to
|
// This module sends the browser and extension version to a server, to
|
||||||
// determine whether it is safe to drop support for old Chrome versions in
|
// determine whether it is safe to drop support for old Chrome versions in
|
||||||
// future extension updates.
|
// future extension updates.
|
||||||
//
|
//
|
||||||
// The source code for the server is available at:
|
// The source code for the server is available at:
|
||||||
// https://github.com/Rob--W/pdfjs-telemetry
|
// https://github.com/Rob--W/pdfjs-telemetry
|
||||||
var LOG_URL = "https://pdfjs.robwu.nl/logpdfjs";
|
var LOG_URL = 'https://pdfjs.robwu.nl/logpdfjs';
|
||||||
|
|
||||||
// The minimum time to wait before sending a ping, so that we don't send too
|
// The minimum time to wait before sending a ping, so that we don't send too
|
||||||
// many requests even if the user restarts their browser very often.
|
// many requests even if the user restarts their browser very often.
|
||||||
// We want one ping a day, so a minimum delay of 12 hours should be OK.
|
// We want one ping a day, so a minimum delay of 12 hours should be OK.
|
||||||
var MINIMUM_TIME_BETWEEN_PING = 12 * 36e5;
|
var MINIMUM_TIME_BETWEEN_PING = 12 * 36E5;
|
||||||
|
|
||||||
if (chrome.extension.inIncognitoContext) {
|
if (chrome.extension.inIncognitoContext) {
|
||||||
// The extension uses incognito split mode, so there are two background
|
// The extension uses incognito split mode, so there are two background
|
||||||
@ -36,17 +36,17 @@ limitations under the License.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chrome.runtime.id !== "oemmndcbldboiebfnladdacbdfmadadm") {
|
if (chrome.runtime.id !== 'oemmndcbldboiebfnladdacbdfmadadm') {
|
||||||
// Only send telemetry for the official PDF.js extension.
|
// Only send telemetry for the official PDF.js extension.
|
||||||
console.warn("Disabled telemetry because this is not an official build.");
|
console.warn('Disabled telemetry because this is not an official build.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
maybeSendPing();
|
maybeSendPing();
|
||||||
setInterval(maybeSendPing, 36e5);
|
setInterval(maybeSendPing, 36E5);
|
||||||
|
|
||||||
function maybeSendPing() {
|
function maybeSendPing() {
|
||||||
getLoggingPref(function (didOptOut) {
|
getLoggingPref(function(didOptOut) {
|
||||||
if (didOptOut) {
|
if (didOptOut) {
|
||||||
// Respect the user's decision to not send statistics.
|
// Respect the user's decision to not send statistics.
|
||||||
return;
|
return;
|
||||||
@ -70,20 +70,29 @@ limitations under the License.
|
|||||||
|
|
||||||
var deduplication_id = getDeduplicationId(wasUpdated);
|
var deduplication_id = getDeduplicationId(wasUpdated);
|
||||||
var extension_version = chrome.runtime.getManifest().version;
|
var extension_version = chrome.runtime.getManifest().version;
|
||||||
|
if (window.Request && 'mode' in Request.prototype) {
|
||||||
|
// fetch is supported in extensions since Chrome 42 (though the above
|
||||||
|
// feature-detection method detects Chrome 43+).
|
||||||
|
// Unlike XMLHttpRequest, fetch omits credentials such as cookies in the
|
||||||
|
// requests, which guarantees that the server cannot track the client
|
||||||
|
// via HTTP cookies.
|
||||||
fetch(LOG_URL, {
|
fetch(LOG_URL, {
|
||||||
method: "POST",
|
method: 'POST',
|
||||||
headers: new Headers({
|
headers: new Headers({
|
||||||
"Deduplication-Id": deduplication_id,
|
'Deduplication-Id': deduplication_id,
|
||||||
"Extension-Version": extension_version,
|
'Extension-Version': extension_version,
|
||||||
}),
|
}),
|
||||||
// Set mode=cors so that the above custom headers are included in the
|
// Set mode=cors so that the above custom headers are included in the
|
||||||
// request.
|
// request.
|
||||||
mode: "cors",
|
mode: 'cors',
|
||||||
// Omits credentials such as cookies in the requests, which guarantees
|
|
||||||
// that the server cannot track the client via HTTP cookies.
|
|
||||||
credentials: "omit",
|
|
||||||
cache: "no-store",
|
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var x = new XMLHttpRequest();
|
||||||
|
x.open('POST', LOG_URL);
|
||||||
|
x.setRequestHeader('Deduplication-Id', deduplication_id);
|
||||||
|
x.setRequestHeader('Extension-Version', extension_version);
|
||||||
|
x.send();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,11 +107,12 @@ limitations under the License.
|
|||||||
// so it is OK to change the ID if the browser is updated. By changing the
|
// so it is OK to change the ID if the browser is updated. By changing the
|
||||||
// ID, the server cannot track users for a long period even if it wants to.
|
// ID, the server cannot track users for a long period even if it wants to.
|
||||||
if (!id || !/^[0-9a-f]{10}$/.test(id) || wasUpdated) {
|
if (!id || !/^[0-9a-f]{10}$/.test(id) || wasUpdated) {
|
||||||
id = "";
|
id = '';
|
||||||
var buf = new Uint8Array(5);
|
var buf = new Uint8Array(5);
|
||||||
crypto.getRandomValues(buf);
|
crypto.getRandomValues(buf);
|
||||||
for (const c of buf) {
|
for (var i = 0; i < buf.length; ++i) {
|
||||||
id += (c >>> 4).toString(16) + (c & 0xf).toString(16);
|
var c = buf[i];
|
||||||
|
id += (c >>> 4).toString(16) + (c & 0xF).toString(16);
|
||||||
}
|
}
|
||||||
localStorage.telemetryDeduplicationId = id;
|
localStorage.telemetryDeduplicationId = id;
|
||||||
}
|
}
|
||||||
@ -129,12 +139,12 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
function getLoggingPref(callback) {
|
function getLoggingPref(callback) {
|
||||||
// Try to look up the preference in the storage, in the following order:
|
// Try to look up the preference in the storage, in the following order:
|
||||||
var areas = ["sync", "local", "managed"];
|
var areas = ['sync', 'local', 'managed'];
|
||||||
|
|
||||||
next();
|
next();
|
||||||
function next(result) {
|
function next(result) {
|
||||||
var storageAreaName = areas.shift();
|
var storageAreaName = areas.shift();
|
||||||
if (typeof result === "boolean" || !storageAreaName) {
|
if (typeof result === 'boolean' || !storageAreaName) {
|
||||||
callback(result);
|
callback(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -144,7 +154,7 @@ limitations under the License.
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.storage[storageAreaName].get("disableTelemetry", function (items) {
|
chrome.storage[storageAreaName].get('disableTelemetry', function(items) {
|
||||||
next(items && items.disableTelemetry);
|
next(items && items.disableTelemetry);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,17 @@
|
|||||||
"plugin:mozilla/recommended",
|
"plugin:mozilla/recommended",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"parserOptions": {
|
||||||
|
"sourceType": "script",
|
||||||
|
},
|
||||||
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"mozilla"
|
"mozilla"
|
||||||
],
|
],
|
||||||
|
|
||||||
"rules": {
|
"rules": {
|
||||||
|
// Items different from the mozilla/recommended configuration.
|
||||||
|
|
||||||
// Other rules mozilla/recommended hasn't enabled yet.
|
// Other rules mozilla/recommended hasn't enabled yet.
|
||||||
"no-shadow": "error",
|
"no-shadow": "error",
|
||||||
"arrow-body-style": ["error", "as-needed"],
|
"arrow-body-style": ["error", "as-needed"],
|
||||||
|
3
extensions/firefox/.gitignore
vendored
Normal file
3
extensions/firefox/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
metadata.inc
|
||||||
|
chrome.manifest.inc
|
||||||
|
locale/
|
5
extensions/firefox/README.mozilla
Normal file
5
extensions/firefox/README.mozilla
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
This is the PDF.js project output, https://github.com/mozilla/pdf.js
|
||||||
|
|
||||||
|
Current extension version is: PDFJSSCRIPT_VERSION
|
||||||
|
|
||||||
|
Taken from upstream commit: PDFJSSCRIPT_COMMIT
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2021 Mozilla Foundation
|
/* Copyright 2018 Mozilla Foundation
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -13,8 +13,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.xfaLink {
|
"use strict";
|
||||||
opacity: 0.2;
|
|
||||||
background: rgb(255 255 0);
|
var EXPORTED_SYMBOLS = ["PdfJsDefaultPreferences"];
|
||||||
box-shadow: 0 2px 10px rgb(255 255 0);
|
|
||||||
}
|
var PdfJsDefaultPreferences = Object.freeze(
|
||||||
|
PDFJSDev.json("$ROOT/build/default_preferences.json")
|
||||||
|
);
|
131
extensions/firefox/tools/l10n.js
Normal file
131
extensions/firefox/tools/l10n.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Small subset of the webL10n API by Fabien Cazenave for PDF.js extension.
|
||||||
|
(function(window) {
|
||||||
|
var gLanguage = "";
|
||||||
|
var gExternalLocalizerServices = null;
|
||||||
|
var gReadyState = "loading";
|
||||||
|
|
||||||
|
// fetch an l10n objects
|
||||||
|
function getL10nData(key) {
|
||||||
|
var response = gExternalLocalizerServices.getStrings(key);
|
||||||
|
var data = JSON.parse(response);
|
||||||
|
if (!data) {
|
||||||
|
console.warn("[l10n] #" + key + " missing for [" + gLanguage + "]");
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace {{arguments}} with their values
|
||||||
|
function substArguments(text, args) {
|
||||||
|
if (!args) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
return text.replace(/\{\{\s*(\w+)\s*\}\}/g, function(all, name) {
|
||||||
|
return name in args ? args[name] : "{{" + name + "}}";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate a string
|
||||||
|
function translateString(key, args, fallback) {
|
||||||
|
var i = key.lastIndexOf(".");
|
||||||
|
var name, property;
|
||||||
|
if (i >= 0) {
|
||||||
|
name = key.substring(0, i);
|
||||||
|
property = key.substring(i + 1);
|
||||||
|
} else {
|
||||||
|
name = key;
|
||||||
|
property = "textContent";
|
||||||
|
}
|
||||||
|
var data = getL10nData(name);
|
||||||
|
var value = (data && data[property]) || fallback;
|
||||||
|
if (!value) {
|
||||||
|
return "{{" + key + "}}";
|
||||||
|
}
|
||||||
|
return substArguments(value, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate an HTML element
|
||||||
|
function translateElement(element) {
|
||||||
|
if (!element || !element.dataset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the related l10n object
|
||||||
|
var key = element.dataset.l10nId;
|
||||||
|
var data = getL10nData(key);
|
||||||
|
if (!data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get arguments (if any)
|
||||||
|
// TODO: more flexible parser?
|
||||||
|
var args;
|
||||||
|
if (element.dataset.l10nArgs) {
|
||||||
|
try {
|
||||||
|
args = JSON.parse(element.dataset.l10nArgs);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("[l10n] could not parse arguments for #" + key + "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate element
|
||||||
|
// TODO: security check?
|
||||||
|
for (var k in data) {
|
||||||
|
element[k] = substArguments(data[k], args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate an HTML subtree
|
||||||
|
function translateFragment(element) {
|
||||||
|
element = element || document.querySelector("html");
|
||||||
|
|
||||||
|
// check all translatable children (= w/ a `data-l10n-id' attribute)
|
||||||
|
var children = element.querySelectorAll("*[data-l10n-id]");
|
||||||
|
var elementCount = children.length;
|
||||||
|
for (var i = 0; i < elementCount; i++) {
|
||||||
|
translateElement(children[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate element itself if necessary
|
||||||
|
if (element.dataset.l10nId) {
|
||||||
|
translateElement(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public API
|
||||||
|
document.mozL10n = {
|
||||||
|
// get a localized string
|
||||||
|
get: translateString,
|
||||||
|
|
||||||
|
// get the document language
|
||||||
|
getLanguage() {
|
||||||
|
return gLanguage;
|
||||||
|
},
|
||||||
|
|
||||||
|
// get the direction (ltr|rtl) of the current language
|
||||||
|
getDirection() {
|
||||||
|
// http://www.w3.org/International/questions/qa-scripts
|
||||||
|
// Arabic, Hebrew, Farsi, Pashto, Urdu
|
||||||
|
var rtlList = ["ar", "he", "fa", "ps", "ur"];
|
||||||
|
|
||||||
|
// use the short language code for "full" codes like 'ar-sa' (issue 5440)
|
||||||
|
var shortCode = gLanguage.split("-")[0];
|
||||||
|
|
||||||
|
return rtlList.includes(shortCode) ? "rtl" : "ltr";
|
||||||
|
},
|
||||||
|
|
||||||
|
getReadyState() {
|
||||||
|
return gReadyState;
|
||||||
|
},
|
||||||
|
|
||||||
|
setExternalLocalizerServices(externalLocalizerServices) {
|
||||||
|
gExternalLocalizerServices = externalLocalizerServices;
|
||||||
|
gLanguage = gExternalLocalizerServices.getLocale();
|
||||||
|
gReadyState = "complete";
|
||||||
|
},
|
||||||
|
|
||||||
|
// translate an element or document fragment
|
||||||
|
translate: translateFragment
|
||||||
|
};
|
||||||
|
})(this);
|
6
external/.eslintrc
vendored
6
external/.eslintrc
vendored
@ -6,4 +6,10 @@
|
|||||||
"env": {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"rules": {
|
||||||
|
"mozilla/use-includes-instead-of-indexOf": "off",
|
||||||
|
"object-shorthand": "off",
|
||||||
|
"no-restricted-globals": "off",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user