diff --git a/.eslintrc.json b/.eslintrc.json index e541fba09acf3aa85ed8184a0177355b75c45ff1..c30e2875013ae6e238fd07f0480d80977f133a11 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -14,11 +14,11 @@ "sourceType": "module" }, "rules": { - "no-unused-vars": ["error", { "args": "none" }], + "no-unused-vars": ["error", {"args": "none"}], "semi": [2, "always"], "jsdoc/require-jsdoc": 0, "jsdoc/require-param-description": 0, "jsdoc/require-returns": 0, "jsdoc/require-param-type": 0 } -} \ No newline at end of file +} diff --git a/.renovaterc.json b/.renovaterc.json index 2fb8654e16cebfc829d59526237d65eb19738950..2425a872d0e00d9114668e2e2cd328dd0fa5e2ec 100644 --- a/.renovaterc.json +++ b/.renovaterc.json @@ -1,13 +1,9 @@ { - "extends": [ - "config:base", - "group:allNonMajor", - "schedule:weekly" - ], - "ignorePresets": [":prHourlyLimit2"], - "rangeStrategy": "update-lockfile", - "composer": { - "enabled": false - }, - "cloneSubmodules": true -} \ No newline at end of file + "extends": ["config:base", "group:allNonMajor", "schedule:weekly"], + "ignorePresets": [":prHourlyLimit2"], + "rangeStrategy": "update-lockfile", + "composer": { + "enabled": false + }, + "cloneSubmodules": true +} diff --git a/app-template/app.manifest.json b/app-template/app.manifest.json index e9e4eb8d65bb52dd8a3a400eee4432ae5c34e7ea..b8aaf361e7a8d41ba10efd1a5b90459a83d768ea 100644 --- a/app-template/app.manifest.json +++ b/app-template/app.manifest.json @@ -1,56 +1,55 @@ { - "short_name": "esign", - "name": "Electronic Signature Service", - "start_url": "./", - "icons": [ - { - "src": "images/icon-72x72.png", - "sizes": "72x72", - "type": "image/png" - }, - { - "src": "images/icon-96x96.png", - "sizes": "96x96", - "type": "image/png" - }, - { - "src": "images/icon-128x128.png", - "sizes": "128x128", - "type": "image/png" - }, - { - "src": "images/icon-144x144.png", - "sizes": "144x144", - "type": "image/png" - }, - { - "src": "images/icon-152x152.png", - "sizes": "152x152", - "type": "image/png" - }, - { - "src": "images/icon-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "images/icon-384x384.png", - "sizes": "384x384", - "type": "image/png" - }, - { - "src": "images/icon-256x256.png", - "sizes": "256x256", - "type": "image/png" - }, - { - "src": "images/icon-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "background_color": "#FEFEFE", - "display": "standalone", - "theme_color": "#FFFFFF" + "short_name": "esign", + "name": "Electronic Signature Service", + "start_url": "./", + "icons": [ + { + "src": "images/icon-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "images/icon-96x96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "images/icon-128x128.png", + "sizes": "128x128", + "type": "image/png" + }, + { + "src": "images/icon-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "images/icon-152x152.png", + "sizes": "152x152", + "type": "image/png" + }, + { + "src": "images/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "images/icon-384x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "images/icon-256x256.png", + "sizes": "256x256", + "type": "image/png" + }, + { + "src": "images/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "background_color": "#FEFEFE", + "display": "standalone", + "theme_color": "#FFFFFF" } - diff --git a/app-template/topic.metadata.json b/app-template/topic.metadata.json index 45aee4f788dea5490b71f22ca87105701e093dcf..013b68e9070730d91c9df388c752406a157d575e 100644 --- a/app-template/topic.metadata.json +++ b/app-template/topic.metadata.json @@ -1,21 +1,21 @@ { - "name": { - "de": "Elektronisches Signaturservice", - "en": "Electronic Signatures" - }, - "short_name": { - "de": "Elektronisches Signaturservice", - "en": "Electronic Signatures" - }, - "description": { - "de": "Mit dieser Applikation können Sie PDF-Dokumente signieren", - "en": "With this application you can sign PDF documents" - }, - "routing_name": "signature", - "activities": [ - {"path": "/app/dbp-qualified-signature-pdf-upload.metadata.json"}, - {"path": "/app/dbp-signature-verification.metadata.json"}, - {"path": "/app/dbp-official-signature-pdf-upload.metadata.json"} - ], - "attributes": [] -} \ No newline at end of file + "name": { + "de": "Elektronisches Signaturservice", + "en": "Electronic Signatures" + }, + "short_name": { + "de": "Elektronisches Signaturservice", + "en": "Electronic Signatures" + }, + "description": { + "de": "Mit dieser Applikation können Sie PDF-Dokumente signieren", + "en": "With this application you can sign PDF documents" + }, + "routing_name": "signature", + "activities": [ + {"path": "/app/dbp-qualified-signature-pdf-upload.metadata.json"}, + {"path": "/app/dbp-signature-verification.metadata.json"}, + {"path": "/app/dbp-official-signature-pdf-upload.metadata.json"} + ], + "attributes": [] +} diff --git a/app.config.js b/app.config.js index 843b6b730a7e27a33f26ec2ef639f1b9b5a14b1f..309a55dce7385a147bc2f098b80649eb5e9f3340 100644 --- a/app.config.js +++ b/app.config.js @@ -11,7 +11,7 @@ export default { nextcloudName: 'TU Graz cloud', pdfAsQualifiedlySigningServer: 'https://sig-dev.tugraz.at', hiddenActivities: ['dbp-signature-verification-full'], - enableAnnotations: true + enableAnnotations: true, }, bs: { basePath: '/dist/', @@ -25,7 +25,7 @@ export default { nextcloudName: 'TU Graz cloud', pdfAsQualifiedlySigningServer: 'https://sig-dev.tugraz.at', hiddenActivities: [], - enableAnnotations: true + enableAnnotations: true, }, development: { basePath: '/apps/signature/', @@ -39,7 +39,7 @@ export default { nextcloudName: 'TU Graz cloud', pdfAsQualifiedlySigningServer: 'https://sig-dev.tugraz.at', hiddenActivities: ['dbp-signature-verification-full'], - enableAnnotations: true + enableAnnotations: true, }, demo: { basePath: '/apps/signature/', @@ -53,7 +53,7 @@ export default { nextcloudName: 'TU Graz cloud', pdfAsQualifiedlySigningServer: 'https://sig-demo.tugraz.at', hiddenActivities: ['dbp-signature-verification-full'], - enableAnnotations: true + enableAnnotations: true, }, production: { basePath: '/', @@ -67,6 +67,6 @@ export default { nextcloudName: 'TU Graz cloud', pdfAsQualifiedlySigningServer: 'https://sig.tugraz.at', hiddenActivities: ['dbp-signature-verification-full'], - enableAnnotations: false + enableAnnotations: false, }, -}; \ No newline at end of file +}; diff --git a/assets/manifest.json b/assets/manifest.json index 28b62f1f8085d7a28e65ed17905295acd9df3519..67847a7b12c8838e1c999b31edbec2a7046b3c13 100644 --- a/assets/manifest.json +++ b/assets/manifest.json @@ -1,56 +1,55 @@ { - "short_name": "TU Graz esign", - "name": "TU Graz Electronic Signature Service", - "start_url": "./", - "icons": [ - { - "src": "local/@dbp-topics/signature/icon-72x72.png", - "sizes": "72x72", - "type": "image/png" - }, - { - "src": "local/@dbp-topics/signature/icon-96x96.png", - "sizes": "96x96", - "type": "image/png" - }, - { - "src": "local/@dbp-topics/signature/icon-128x128.png", - "sizes": "128x128", - "type": "image/png" - }, - { - "src": "local/@dbp-topics/signature/icon-144x144.png", - "sizes": "144x144", - "type": "image/png" - }, - { - "src": "local/@dbp-topics/signature/icon-152x152.png", - "sizes": "152x152", - "type": "image/png" - }, - { - "src": "local/@dbp-topics/signature/icon-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "local/@dbp-topics/signature/icon-384x384.png", - "sizes": "384x384", - "type": "image/png" - }, - { - "src": "local/@dbp-topics/signature/icon-256x256.png", - "sizes": "256x256", - "type": "image/png" - }, - { - "src": "local/@dbp-topics/signature/icon-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "background_color": "#FEFEFE", - "display": "standalone", - "theme_color": "#FFFFFF" + "short_name": "TU Graz esign", + "name": "TU Graz Electronic Signature Service", + "start_url": "./", + "icons": [ + { + "src": "local/@dbp-topics/signature/icon-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "local/@dbp-topics/signature/icon-96x96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "local/@dbp-topics/signature/icon-128x128.png", + "sizes": "128x128", + "type": "image/png" + }, + { + "src": "local/@dbp-topics/signature/icon-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "local/@dbp-topics/signature/icon-152x152.png", + "sizes": "152x152", + "type": "image/png" + }, + { + "src": "local/@dbp-topics/signature/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "local/@dbp-topics/signature/icon-384x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "local/@dbp-topics/signature/icon-256x256.png", + "sizes": "256x256", + "type": "image/png" + }, + { + "src": "local/@dbp-topics/signature/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "background_color": "#FEFEFE", + "display": "standalone", + "theme_color": "#FFFFFF" } - diff --git a/i18next-scanner.config.js b/i18next-scanner.config.js index d2338d3ed316fa8d93ed8f6cb1c2acfdb9040ad6..895a82ac5dfbe4154cee47479c145548e8faf2e5 100644 --- a/i18next-scanner.config.js +++ b/i18next-scanner.config.js @@ -1,18 +1,16 @@ module.exports = { - input: [ - 'src/**/*.js', - ], + input: ['src/**/*.js'], output: './', options: { debug: false, removeUnusedKeys: true, - lngs: ['en','de'], + lngs: ['en', 'de'], func: { - list: ['i18n.t', '_i18n.t'] + list: ['i18n.t', '_i18n.t'], }, resource: { loadPath: 'src/i18n/{{lng}}/{{ns}}.json', - savePath: 'src/i18n/{{lng}}/{{ns}}.json' + savePath: 'src/i18n/{{lng}}/{{ns}}.json', }, }, -} +}; diff --git a/karma.conf.js b/karma.conf.js index 69fe68571aa9078e6b177e0ca1cc747ba3aa0a27..4d47ec4572a4101dae0311a9da43a9c75a330169 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,25 +1,25 @@ -module.exports = function(config) { - config.set({ - basePath: 'dist', - frameworks: ['mocha'], - client: { - mocha: { - ui: 'tdd', - }, - }, - files: [ - {pattern: './*.js', included: true, watched: true, served: true, type: 'module'}, - {pattern: './**/*', included: false, watched: true, served: true}, - ], - autoWatch: true, - browsers: ['ChromiumHeadlessNoSandbox', 'FirefoxHeadless'], - customLaunchers: { - ChromiumHeadlessNoSandbox: { - base: 'ChromiumHeadless', - flags: ['--no-sandbox'] - } - }, - singleRun: false, - logLevel: config.LOG_ERROR - }); -} +module.exports = function (config) { + config.set({ + basePath: 'dist', + frameworks: ['mocha'], + client: { + mocha: { + ui: 'tdd', + }, + }, + files: [ + {pattern: './*.js', included: true, watched: true, served: true, type: 'module'}, + {pattern: './**/*', included: false, watched: true, served: true}, + ], + autoWatch: true, + browsers: ['ChromiumHeadlessNoSandbox', 'FirefoxHeadless'], + customLaunchers: { + ChromiumHeadlessNoSandbox: { + base: 'ChromiumHeadless', + flags: ['--no-sandbox'], + }, + }, + singleRun: false, + logLevel: config.LOG_ERROR, + }); +}; diff --git a/package.json b/package.json index aa8954d271a11b647dd5f43f4209e61517ba4b4b..b85d528c79cce0e6ca6f7e806d3348c52114991b 100644 --- a/package.json +++ b/package.json @@ -1,79 +1,79 @@ { - "name": "@dbp-topics/signature", - "internalName": "dbp-signature", - "version": "1.0.26", - "main": "src/dbp-signature.js", - "license": "LGPL-2.1-or-later", - "repository": { - "type": "git", - "url": "https://gitlab.tugraz.at/dbp/esign/signature.git" - }, - "private": true, - "workspaces": [ - "vendor/toolkit/packages/*" - ], - "devDependencies": { - "@babel/core": "^7.10.3", - "@babel/preset-env": "^7.10.3", - "@rollup/plugin-babel": "^5.0.4", - "@rollup/plugin-commonjs": "^21.0.0", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.0", - "@rollup/plugin-url": "^6.0.0", - "can-npm-publish": "^1.3.3", - "chai": "^4.2.0", - "eslint": "^8.0.1", - "eslint-plugin-jsdoc": "^37.0.0", - "glob": "^7.1.6", - "i18next-scanner": "^3.0.0", - "karma": "^6.0.0", - "karma-chrome-launcher": "^3.1.0", - "karma-firefox-launcher": "^2.1.0", - "karma-mocha": "^2.0.1", - "mocha": "^9.0.0", - "prettier": "^2.5.1", - "rollup": "^2.18.1", - "rollup-plugin-copy": "^3.3.0", - "rollup-plugin-delete": "^2.0.0", - "rollup-plugin-emit-ejs": "^3.1.0", - "rollup-plugin-license": "^2.1.0", - "rollup-plugin-serve": "^1.0.1", - "rollup-plugin-terser": "^7.0.2", - "selfsigned": "^2.0.0" - }, - "dependencies": { - "@dbp-toolkit/app-shell": "^0.2.0", - "@dbp-toolkit/auth": "^0.2.0", - "@dbp-toolkit/common": "^0.2.0", - "@dbp-toolkit/file-handling": "^0.2.0", - "@dbp-toolkit/font-source-sans-pro": "^0.2.0", - "@dbp-toolkit/language-select": "^0.2.0", - "@dbp-toolkit/notification": "^0.2.0", - "@dbp-toolkit/organization-select": "^0.2.0", - "@dbp-toolkit/person-profile": "^0.2.0", - "@digital-blueprint/annotpdf": "^1.0.13-a", - "@open-wc/scoped-elements": "^2.0.0", - "fabric": "^4.2.0", - "file-saver": "^2.0.2", - "i18next": "^21.4.2", - "jszip": "^3.5.0", - "lit": "^2.0.0", - "pdfjs-dist": "^2.12.313", - "universal-router": "^9.0.1" - }, - "scripts": { - "format": "yarn run format:eslint && yarn run format:prettier", - "format:eslint": "eslint \"**/*.{js,ts}\" --fix", - "format:prettier": "prettier \"**/*.{js,json,ts}\" --write", - "build": "rollup -c", - "i18next": "i18next-scanner", - "watch": "rollup -c --watch", - "watch-local": "yarn run watch", - "watch-full": "rollup -c --watch --environment FORCE_FULL", - "watch-bs": "rollup -c --watch --environment APP_ENV:bs", - "test": "rollup -c --environment APP_ENV:test && karma start --singleRun", - "test-full": "rollup -c --environment FORCE_FULL,APP_ENV:test && karma start --singleRun", - "lint": "eslint .", - "publish": "sed -i 's/\"private\": true/\"private\": false/' package.json && can-npm-publish --verbose 2>&1 && npm publish --access public 2>&1; sed -i 's/\"private\": false/\"private\": true/' package.json" - } + "name": "@dbp-topics/signature", + "internalName": "dbp-signature", + "version": "1.0.26", + "main": "src/dbp-signature.js", + "license": "LGPL-2.1-or-later", + "repository": { + "type": "git", + "url": "https://gitlab.tugraz.at/dbp/esign/signature.git" + }, + "private": true, + "workspaces": [ + "vendor/toolkit/packages/*" + ], + "devDependencies": { + "@babel/core": "^7.10.3", + "@babel/preset-env": "^7.10.3", + "@rollup/plugin-babel": "^5.0.4", + "@rollup/plugin-commonjs": "^21.0.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.0.0", + "@rollup/plugin-url": "^6.0.0", + "can-npm-publish": "^1.3.3", + "chai": "^4.2.0", + "eslint": "^8.0.1", + "eslint-plugin-jsdoc": "^37.0.0", + "glob": "^7.1.6", + "i18next-scanner": "^3.0.0", + "karma": "^6.0.0", + "karma-chrome-launcher": "^3.1.0", + "karma-firefox-launcher": "^2.1.0", + "karma-mocha": "^2.0.1", + "mocha": "^9.0.0", + "prettier": "^2.5.1", + "rollup": "^2.18.1", + "rollup-plugin-copy": "^3.3.0", + "rollup-plugin-delete": "^2.0.0", + "rollup-plugin-emit-ejs": "^3.1.0", + "rollup-plugin-license": "^2.1.0", + "rollup-plugin-serve": "^1.0.1", + "rollup-plugin-terser": "^7.0.2", + "selfsigned": "^2.0.0" + }, + "dependencies": { + "@dbp-toolkit/app-shell": "^0.2.0", + "@dbp-toolkit/auth": "^0.2.0", + "@dbp-toolkit/common": "^0.2.0", + "@dbp-toolkit/file-handling": "^0.2.0", + "@dbp-toolkit/font-source-sans-pro": "^0.2.0", + "@dbp-toolkit/language-select": "^0.2.0", + "@dbp-toolkit/notification": "^0.2.0", + "@dbp-toolkit/organization-select": "^0.2.0", + "@dbp-toolkit/person-profile": "^0.2.0", + "@digital-blueprint/annotpdf": "^1.0.13-a", + "@open-wc/scoped-elements": "^2.0.0", + "fabric": "^4.2.0", + "file-saver": "^2.0.2", + "i18next": "^21.4.2", + "jszip": "^3.5.0", + "lit": "^2.0.0", + "pdfjs-dist": "^2.12.313", + "universal-router": "^9.0.1" + }, + "scripts": { + "format": "yarn run format:eslint && yarn run format:prettier", + "format:eslint": "eslint \"**/*.{js,ts}\" --fix", + "format:prettier": "prettier \"**/*.{js,json,ts}\" --write", + "build": "rollup -c", + "i18next": "i18next-scanner", + "watch": "rollup -c --watch", + "watch-local": "yarn run watch", + "watch-full": "rollup -c --watch --environment FORCE_FULL", + "watch-bs": "rollup -c --watch --environment APP_ENV:bs", + "test": "rollup -c --environment APP_ENV:test && karma start --singleRun", + "test-full": "rollup -c --environment FORCE_FULL,APP_ENV:test && karma start --singleRun", + "lint": "eslint .", + "publish": "sed -i 's/\"private\": true/\"private\": false/' package.json && can-npm-publish --verbose 2>&1 && npm publish --access public 2>&1; sed -i 's/\"private\": false/\"private\": true/' package.json" + } } diff --git a/rollup.config.js b/rollup.config.js index ceb158f2df239df9886095ae5ac2bcf6e5e814d8..aea6a6265b703245aab2ab2fa42cef5a8dd231bf 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -4,27 +4,32 @@ import glob from 'glob'; import resolve from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; import copy from 'rollup-plugin-copy'; -import {terser} from "rollup-plugin-terser"; +import {terser} from 'rollup-plugin-terser'; import json from '@rollup/plugin-json'; import serve from 'rollup-plugin-serve'; -import urlPlugin from "@rollup/plugin-url"; +import urlPlugin from '@rollup/plugin-url'; import license from 'rollup-plugin-license'; import del from 'rollup-plugin-delete'; -import emitEJS from 'rollup-plugin-emit-ejs' +import emitEJS from 'rollup-plugin-emit-ejs'; import {getBabelOutputPlugin} from '@rollup/plugin-babel'; import appConfig from './app.config.js'; -import {getPackagePath, getBuildInfo, generateTLSConfig, getDistPath} from './vendor/toolkit/rollup.utils.js'; +import { + getPackagePath, + getBuildInfo, + generateTLSConfig, + getDistPath, +} from './vendor/toolkit/rollup.utils.js'; const pkg = require('./package.json'); -const appEnv = (typeof process.env.APP_ENV !== 'undefined') ? process.env.APP_ENV : 'local'; +const appEnv = typeof process.env.APP_ENV !== 'undefined' ? process.env.APP_ENV : 'local'; const watch = process.env.ROLLUP_WATCH === 'true'; -const buildFull = (!watch && appEnv !== 'test') || (process.env.FORCE_FULL !== undefined); +const buildFull = (!watch && appEnv !== 'test') || process.env.FORCE_FULL !== undefined; let useTerser = buildFull; let useBabel = buildFull; let checkLicenses = buildFull; let useHTTPS = false; -console.log("APP_ENV: " + appEnv); +console.log('APP_ENV: ' + appEnv); let config; if (appEnv in appConfig) { @@ -64,167 +69,205 @@ if (watch) { } function getOrigin(url) { - if (url) - return new URL(url).origin; + if (url) return new URL(url).origin; return ''; } config.CSP = `default-src 'self' 'unsafe-eval' 'unsafe-inline' \ -${getOrigin(config.matomoUrl)} ${getOrigin(config.keyCloakBaseURL)} ${getOrigin(config.entryPointURL)} \ +${getOrigin(config.matomoUrl)} ${getOrigin(config.keyCloakBaseURL)} ${getOrigin( + config.entryPointURL +)} \ httpbin.org ${getOrigin(config.nextcloudBaseURL)} www.handy-signatur.at \ ${getOrigin(config.pdfAsQualifiedlySigningServer)}; \ img-src * blob: data:; font-src 'self' data:`; export default (async () => { - let privatePath = await getDistPath(pkg.name) + let privatePath = await getDistPath(pkg.name); return { - input: (appEnv != 'test') ? [ - 'src/' + pkg.internalName + '.js', - 'src/dbp-official-signature-pdf-upload.js', - 'src/dbp-qualified-signature-pdf-upload.js', - 'src/dbp-signature-verification.js', - 'src/dbp-signature-verification-full.js', - ] : glob.sync('test/**/*.js'), - output: { - dir: 'dist', - entryFileNames: '[name].js', - chunkFileNames: 'shared/[name].[hash].[format].js', - format: 'esm', - sourcemap: true - }, - preserveEntrySignatures: false, - // external: ['zlib', 'http', 'fs', 'https', 'url'], - onwarn: function (warning, warn) { - // ignore chai warnings - if (warning.code === 'CIRCULAR_DEPENDENCY' && warning.message.includes('/chai/')) { - return; - } - // keycloak bundled code uses eval - if (warning.code === 'EVAL') { - return; - } - warn(warning); - }, - plugins: [ - del({ - targets: 'dist/*' - }), - emitEJS({ - src: 'assets', - include: ['**/*.ejs', '**/.*.ejs'], - data: { - getUrl: (p) => { - return url.resolve(config.basePath, p); - }, - getPrivateUrl: (p) => { - return url.resolve(`${config.basePath}${privatePath}/`, p); - }, - isVisible: (name) => { - return !config.hiddenActivities.includes(name); - }, - name: pkg.internalName, - entryPointURL: config.entryPointURL, - nextcloudWebAppPasswordURL: config.nextcloudWebAppPasswordURL, - nextcloudWebDavURL: config.nextcloudWebDavURL, - nextcloudBaseURL: config.nextcloudBaseURL, - nextcloudFileURL: config.nextcloudFileURL, - nextcloudName: config.nextcloudName, - keyCloakBaseURL: config.keyCloakBaseURL, - keyCloakClientId: config.keyCloakClientId, - keyCloakRealm: config.keyCloakRealm, - CSP: config.CSP, - matomoUrl: config.matomoUrl, - matomoSiteId: config.matomoSiteId, - buildInfo: getBuildInfo(appEnv), - enableAnnotations: config.enableAnnotations, - } - }), - resolve({ - // ignore node_modules from vendored packages - moduleDirectories: [path.join(process.cwd(), 'node_modules')], - browser: true, - preferBuiltins: true - }), - checkLicenses && license({ - banner: { - commentStyle: 'ignored', - content: ` + input: + appEnv != 'test' + ? [ + 'src/' + pkg.internalName + '.js', + 'src/dbp-official-signature-pdf-upload.js', + 'src/dbp-qualified-signature-pdf-upload.js', + 'src/dbp-signature-verification.js', + 'src/dbp-signature-verification-full.js', + ] + : glob.sync('test/**/*.js'), + output: { + dir: 'dist', + entryFileNames: '[name].js', + chunkFileNames: 'shared/[name].[hash].[format].js', + format: 'esm', + sourcemap: true, + }, + preserveEntrySignatures: false, + // external: ['zlib', 'http', 'fs', 'https', 'url'], + onwarn: function (warning, warn) { + // ignore chai warnings + if (warning.code === 'CIRCULAR_DEPENDENCY' && warning.message.includes('/chai/')) { + return; + } + // keycloak bundled code uses eval + if (warning.code === 'EVAL') { + return; + } + warn(warning); + }, + plugins: [ + del({ + targets: 'dist/*', + }), + emitEJS({ + src: 'assets', + include: ['**/*.ejs', '**/.*.ejs'], + data: { + getUrl: (p) => { + return url.resolve(config.basePath, p); + }, + getPrivateUrl: (p) => { + return url.resolve(`${config.basePath}${privatePath}/`, p); + }, + isVisible: (name) => { + return !config.hiddenActivities.includes(name); + }, + name: pkg.internalName, + entryPointURL: config.entryPointURL, + nextcloudWebAppPasswordURL: config.nextcloudWebAppPasswordURL, + nextcloudWebDavURL: config.nextcloudWebDavURL, + nextcloudBaseURL: config.nextcloudBaseURL, + nextcloudFileURL: config.nextcloudFileURL, + nextcloudName: config.nextcloudName, + keyCloakBaseURL: config.keyCloakBaseURL, + keyCloakClientId: config.keyCloakClientId, + keyCloakRealm: config.keyCloakRealm, + CSP: config.CSP, + matomoUrl: config.matomoUrl, + matomoSiteId: config.matomoSiteId, + buildInfo: getBuildInfo(appEnv), + enableAnnotations: config.enableAnnotations, + }, + }), + resolve({ + // ignore node_modules from vendored packages + moduleDirectories: [path.join(process.cwd(), 'node_modules')], + browser: true, + preferBuiltins: true, + }), + checkLicenses && + license({ + banner: { + commentStyle: 'ignored', + content: ` License: <%= pkg.license %> Dependencies: <% _.forEach(dependencies, function (dependency) { if (dependency.name) { %> <%= dependency.name %>: <%= dependency.license %><% }}) %> -`}, - thirdParty: { - allow: { - test: '(MIT OR BSD-3-Clause OR Apache-2.0 OR LGPL-2.1-or-later)', - failOnUnlicensed: true, - failOnViolation: true, - }, - }, - }), - commonjs({ - include: 'node_modules/**', - }), - json(), - urlPlugin({ - limit: 0, - include: [ - await getPackagePath('select2', '**/*.css'), - ], - emitFiles: true, - fileName: 'shared/[name].[hash][extname]' - }), - copy({ - targets: [ - {src: 'assets/*-placeholder.png', dest: 'dist/' + await getDistPath(pkg.name)}, - {src: 'assets/*.css', dest: 'dist/' + await getDistPath(pkg.name)}, - {src: 'assets/*.ico', dest: 'dist/' + await getDistPath(pkg.name)}, - {src: 'src/*.metadata.json', dest: 'dist'}, - {src: 'assets/*.svg', dest: 'dist/' + await getDistPath(pkg.name)}, - {src: 'assets/htaccess-shared', dest: 'dist/shared/', rename: '.htaccess'}, - {src: 'assets/icon-*.png', dest: 'dist/' + await getDistPath(pkg.name)}, - {src: 'assets/apple-*.png', dest: 'dist/' + await getDistPath(pkg.name)}, - {src: 'assets/safari-*.svg', dest: 'dist/' + await getDistPath(pkg.name)}, - {src: 'assets/images/*', dest: 'dist/images'}, - {src: 'assets/manifest.json', dest: 'dist', rename: pkg.internalName + '.manifest.json'}, - {src: 'assets/silent-check-sso.html', dest:'dist'}, - {src: 'assets/dbp-signature-maintenance.html', dest:'dist'}, - { - src: await getPackagePath('pdfjs-dist', 'legacy/build/pdf.worker.js'), - dest: 'dist/' + await getDistPath(pkg.name, 'pdfjs') - }, - {src: await getPackagePath('pdfjs-dist', 'cmaps/*'), dest: 'dist/' + await getDistPath(pkg.name, 'pdfjs')}, // do we want all map files? - {src: await getPackagePath('@dbp-toolkit/font-source-sans-pro', 'files/*'), dest: 'dist/' + await getDistPath(pkg.name, 'fonts/source-sans-pro')}, - {src: await getPackagePath('@dbp-toolkit/common', 'src/spinner.js'), dest: 'dist/' + await getDistPath(pkg.name)}, - {src: await getPackagePath('@dbp-toolkit/common', 'misc/browser-check.js'), dest: 'dist/' + await getDistPath(pkg.name)}, - {src: await getPackagePath('@dbp-toolkit/common', 'assets/icons/*.svg'), dest: 'dist/' + await getDistPath('@dbp-toolkit/common', 'icons')}, - {src: await getPackagePath('tabulator-tables', 'dist/css'), dest: 'dist/' + await getDistPath('@dbp-toolkit/file-handling', 'tabulator-tables')}, - ], - }), - useBabel && getBabelOutputPlugin({ - compact: false, - presets: [[ - '@babel/preset-env', { - loose: true, - shippedProposals: true, - bugfixes: true, - modules: false, - targets: { - esmodules: true - } - } - ]], - }), - useTerser ? terser() : false, - watch ? serve({ - contentBase: '.', - host: '127.0.0.1', - port: 8001, - historyApiFallback: config.basePath + pkg.internalName + '.html', - https: useHTTPS ? await generateTLSConfig() : false, - headers: { - 'Content-Security-Policy': config.CSP - }, - }) : false - ] -};})(); \ No newline at end of file +`, + }, + thirdParty: { + allow: { + test: '(MIT OR BSD-3-Clause OR Apache-2.0 OR LGPL-2.1-or-later)', + failOnUnlicensed: true, + failOnViolation: true, + }, + }, + }), + commonjs({ + include: 'node_modules/**', + }), + json(), + urlPlugin({ + limit: 0, + include: [await getPackagePath('select2', '**/*.css')], + emitFiles: true, + fileName: 'shared/[name].[hash][extname]', + }), + copy({ + targets: [ + { + src: 'assets/*-placeholder.png', + dest: 'dist/' + (await getDistPath(pkg.name)), + }, + {src: 'assets/*.css', dest: 'dist/' + (await getDistPath(pkg.name))}, + {src: 'assets/*.ico', dest: 'dist/' + (await getDistPath(pkg.name))}, + {src: 'src/*.metadata.json', dest: 'dist'}, + {src: 'assets/*.svg', dest: 'dist/' + (await getDistPath(pkg.name))}, + {src: 'assets/htaccess-shared', dest: 'dist/shared/', rename: '.htaccess'}, + {src: 'assets/icon-*.png', dest: 'dist/' + (await getDistPath(pkg.name))}, + {src: 'assets/apple-*.png', dest: 'dist/' + (await getDistPath(pkg.name))}, + {src: 'assets/safari-*.svg', dest: 'dist/' + (await getDistPath(pkg.name))}, + {src: 'assets/images/*', dest: 'dist/images'}, + { + src: 'assets/manifest.json', + dest: 'dist', + rename: pkg.internalName + '.manifest.json', + }, + {src: 'assets/silent-check-sso.html', dest: 'dist'}, + {src: 'assets/dbp-signature-maintenance.html', dest: 'dist'}, + { + src: await getPackagePath('pdfjs-dist', 'legacy/build/pdf.worker.js'), + dest: 'dist/' + (await getDistPath(pkg.name, 'pdfjs')), + }, + { + src: await getPackagePath('pdfjs-dist', 'cmaps/*'), + dest: 'dist/' + (await getDistPath(pkg.name, 'pdfjs')), + }, // do we want all map files? + { + src: await getPackagePath('@dbp-toolkit/font-source-sans-pro', 'files/*'), + dest: 'dist/' + (await getDistPath(pkg.name, 'fonts/source-sans-pro')), + }, + { + src: await getPackagePath('@dbp-toolkit/common', 'src/spinner.js'), + dest: 'dist/' + (await getDistPath(pkg.name)), + }, + { + src: await getPackagePath('@dbp-toolkit/common', 'misc/browser-check.js'), + dest: 'dist/' + (await getDistPath(pkg.name)), + }, + { + src: await getPackagePath('@dbp-toolkit/common', 'assets/icons/*.svg'), + dest: 'dist/' + (await getDistPath('@dbp-toolkit/common', 'icons')), + }, + { + src: await getPackagePath('tabulator-tables', 'dist/css'), + dest: + 'dist/' + + (await getDistPath('@dbp-toolkit/file-handling', 'tabulator-tables')), + }, + ], + }), + useBabel && + getBabelOutputPlugin({ + compact: false, + presets: [ + [ + '@babel/preset-env', + { + loose: true, + shippedProposals: true, + bugfixes: true, + modules: false, + targets: { + esmodules: true, + }, + }, + ], + ], + }), + useTerser ? terser() : false, + watch + ? serve({ + contentBase: '.', + host: '127.0.0.1', + port: 8001, + historyApiFallback: config.basePath + pkg.internalName + '.html', + https: useHTTPS ? await generateTLSConfig() : false, + headers: { + 'Content-Security-Policy': config.CSP, + }, + }) + : false, + ], + }; +})(); diff --git a/src/activity.js b/src/activity.js index b661ce5db375e09a2c3591e1d650e7de6eb7339c..9b3900cee1bf515ad94042aa153416e90a457b5a 100644 --- a/src/activity.js +++ b/src/activity.js @@ -12,4 +12,4 @@ export class Activity { let desc = this._data['description']; return desc[lang] ?? desc['en']; } -} \ No newline at end of file +} diff --git a/src/base-element.js b/src/base-element.js index 487063c67afaba4b36c20e651dcaf280aca2871a..e30d1728eb72e12ec892b9e33437d7a32c4373ab 100644 --- a/src/base-element.js +++ b/src/base-element.js @@ -9,16 +9,22 @@ export class BaseLitElement extends DBPLitElement { static get properties() { return { ...super.properties, - auth: { type: Object }, + auth: {type: Object}, }; } _(selector) { - return this.shadowRoot === null ? this.querySelector(selector) : this.shadowRoot.querySelector(selector); + return this.shadowRoot === null + ? this.querySelector(selector) + : this.shadowRoot.querySelector(selector); } _hasSignaturePermissions(roleName) { - return (this.auth.person && Array.isArray(this.auth.person.roles) && this.auth.person.roles.indexOf(roleName) !== -1); + return ( + this.auth.person && + Array.isArray(this.auth.person.roles) && + this.auth.person.roles.indexOf(roleName) !== -1 + ); } _updateAuth() { @@ -34,7 +40,7 @@ export class BaseLitElement extends DBPLitElement { update(changedProperties) { changedProperties.forEach((oldValue, propName) => { switch (propName) { - case "auth": + case 'auth': this._updateAuth(); break; } @@ -51,12 +57,11 @@ export class BaseLitElement extends DBPLitElement { } isLoggedIn() { - return (this.auth.person !== undefined && this.auth.person !== null); + return this.auth.person !== undefined && this.auth.person !== null; } isLoading() { - if (this._loginStatus === "logged-out") - return false; - return (!this.isLoggedIn() && this.auth.token !== undefined); + if (this._loginStatus === 'logged-out') return false; + return !this.isLoggedIn() && this.auth.token !== undefined; } } diff --git a/src/dbp-official-signature-pdf-upload.js b/src/dbp-official-signature-pdf-upload.js index e534994abaad44f3fb4d08e15303e6c9e48cdd17..f55b018f34080aea6413bb58f060fd42660fa8d2 100644 --- a/src/dbp-official-signature-pdf-upload.js +++ b/src/dbp-official-signature-pdf-upload.js @@ -2,23 +2,23 @@ import {createInstance} from './i18n.js'; import {humanFileSize} from '@dbp-toolkit/common/i18next.js'; import {css, html} from 'lit'; import {ScopedElementsMixin} from '@open-wc/scoped-elements'; -import DBPSignatureLitElement from "./dbp-signature-lit-element"; -import {PdfPreview} from "./dbp-pdf-preview"; +import DBPSignatureLitElement from './dbp-signature-lit-element'; +import {PdfPreview} from './dbp-pdf-preview'; import * as commonUtils from '@dbp-toolkit/common/utils'; import * as utils from './utils'; import {Button, Icon, MiniSpinner} from '@dbp-toolkit/common'; import * as commonStyles from '@dbp-toolkit/common/styles'; import {classMap} from 'lit/directives/class-map.js'; import {FileSource} from '@dbp-toolkit/file-handling'; -import JSONLD from "@dbp-toolkit/common/jsonld"; +import JSONLD from '@dbp-toolkit/common/jsonld'; import {TextSwitch} from './textswitch.js'; -import {FileSink} from "@dbp-toolkit/file-handling"; +import {FileSink} from '@dbp-toolkit/file-handling'; import {name as pkgName} from './../package.json'; import {send as notify} from '@dbp-toolkit/common/notification'; -import {OrganizationSelect} from "@dbp-toolkit/organization-select"; +import {OrganizationSelect} from '@dbp-toolkit/organization-select'; import metadata from './dbp-official-signature-pdf-upload.metadata.json'; import {Activity} from './activity.js'; -import {PdfAnnotationView} from "./dbp-pdf-annotation-view"; +import {PdfAnnotationView} from './dbp-pdf-annotation-view'; import * as SignatureStyles from './styles'; class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElement) { @@ -27,21 +27,21 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem this._i18n = createInstance(); this.lang = this._i18n.language; this.entryPointUrl = ''; - this.nextcloudWebAppPasswordURL = ""; - this.nextcloudWebDavURL = ""; - this.nextcloudName = ""; - this.nextcloudFileURL = ""; - this.nextcloudAuthInfo = ""; + this.nextcloudWebAppPasswordURL = ''; + this.nextcloudWebDavURL = ''; + this.nextcloudName = ''; + this.nextcloudFileURL = ''; + this.nextcloudAuthInfo = ''; this.signedFiles = []; this.signedFilesCount = 0; this.signedFilesToDownload = 0; this.errorFiles = []; this.errorFilesCount = 0; - this.uploadStatusFileName = ""; - this.uploadStatusText = ""; + this.uploadStatusFileName = ''; + this.uploadStatusText = ''; this.currentFile = {}; - this.currentFileName = ""; - this.currentFilePlacementMode = ""; + this.currentFileName = ''; + this.currentFilePlacementMode = ''; this.currentFileSignaturePlacement = {}; this.signingProcessEnabled = false; this.signingProcessActive = false; @@ -60,65 +60,67 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem this.isAnnotationViewVisible = false; this.addAnnotationInProgress = false; this.activity = new Activity(metadata); - this.fileHandlingEnabledTargets = "local"; + this.fileHandlingEnabledTargets = 'local'; } static get scopedElements() { return { - 'dbp-icon': Icon, - 'dbp-file-source': FileSource, - 'dbp-file-sink': FileSink, - 'dbp-pdf-preview': PdfPreview, - 'dbp-mini-spinner': MiniSpinner, - 'dbp-button': Button, - 'dbp-textswitch': TextSwitch, - 'dbp-organization-select': OrganizationSelect, - 'dbp-pdf-annotation-view': PdfAnnotationView, + 'dbp-icon': Icon, + 'dbp-file-source': FileSource, + 'dbp-file-sink': FileSink, + 'dbp-pdf-preview': PdfPreview, + 'dbp-mini-spinner': MiniSpinner, + 'dbp-button': Button, + 'dbp-textswitch': TextSwitch, + 'dbp-organization-select': OrganizationSelect, + 'dbp-pdf-annotation-view': PdfAnnotationView, }; } static get properties() { return { ...super.properties, - lang: { type: String }, - entryPointUrl: { type: String, attribute: 'entry-point-url' }, - nextcloudWebAppPasswordURL: { type: String, attribute: 'nextcloud-web-app-password-url' }, - nextcloudWebDavURL: { type: String, attribute: 'nextcloud-webdav-url' }, - nextcloudName: { type: String, attribute: 'nextcloud-name' }, - nextcloudFileURL: { type: String, attribute: 'nextcloud-file-url' }, + lang: {type: String}, + entryPointUrl: {type: String, attribute: 'entry-point-url'}, + nextcloudWebAppPasswordURL: {type: String, attribute: 'nextcloud-web-app-password-url'}, + nextcloudWebDavURL: {type: String, attribute: 'nextcloud-webdav-url'}, + nextcloudName: {type: String, attribute: 'nextcloud-name'}, + nextcloudFileURL: {type: String, attribute: 'nextcloud-file-url'}, nextcloudAuthInfo: {type: String, attribute: 'nextcloud-auth-info'}, - signedFiles: { type: Array, attribute: false }, - signedFilesCount: { type: Number, attribute: false }, - signedFilesToDownload: { type: Number, attribute: false }, - queuedFilesCount: { type: Number, attribute: false }, - errorFiles: { type: Array, attribute: false }, - errorFilesCount: { type: Number, attribute: false }, - uploadInProgress: { type: Boolean, attribute: false }, - uploadStatusFileName: { type: String, attribute: false }, - uploadStatusText: { type: String, attribute: false }, - signingProcessEnabled: { type: Boolean, attribute: false }, - signingProcessActive: { type: Boolean, attribute: false }, - queueBlockEnabled: { type: Boolean, attribute: false }, - currentFile: { type: Object, attribute: false }, - currentFileName: { type: String, attribute: false }, - signaturePlacementInProgress: { type: Boolean, attribute: false }, - withSigBlock: { type: Boolean, attribute: false }, - isSignaturePlacement: { type: Boolean, attribute: false }, - allowAnnotating: { type: Boolean, attribute: 'allow-annotating' }, - isAnnotationViewVisible: { type: Boolean, attribute: false }, - queuedFilesAnnotations: { type: Array, attribute: false }, - queuedFilesAnnotationsCount: { type: Number, attribute: false }, - addAnnotationInProgress: { type: Boolean, attribute: false }, - queuedFilesAnnotationModes: { type: Array, attribute: false }, - queuedFilesAnnotationSaved: { type: Array, attribute: false }, - fileHandlingEnabledTargets: { type: String, attribute: 'file-handling-enabled-targets' }, + signedFiles: {type: Array, attribute: false}, + signedFilesCount: {type: Number, attribute: false}, + signedFilesToDownload: {type: Number, attribute: false}, + queuedFilesCount: {type: Number, attribute: false}, + errorFiles: {type: Array, attribute: false}, + errorFilesCount: {type: Number, attribute: false}, + uploadInProgress: {type: Boolean, attribute: false}, + uploadStatusFileName: {type: String, attribute: false}, + uploadStatusText: {type: String, attribute: false}, + signingProcessEnabled: {type: Boolean, attribute: false}, + signingProcessActive: {type: Boolean, attribute: false}, + queueBlockEnabled: {type: Boolean, attribute: false}, + currentFile: {type: Object, attribute: false}, + currentFileName: {type: String, attribute: false}, + signaturePlacementInProgress: {type: Boolean, attribute: false}, + withSigBlock: {type: Boolean, attribute: false}, + isSignaturePlacement: {type: Boolean, attribute: false}, + allowAnnotating: {type: Boolean, attribute: 'allow-annotating'}, + isAnnotationViewVisible: {type: Boolean, attribute: false}, + queuedFilesAnnotations: {type: Array, attribute: false}, + queuedFilesAnnotationsCount: {type: Number, attribute: false}, + addAnnotationInProgress: {type: Boolean, attribute: false}, + queuedFilesAnnotationModes: {type: Array, attribute: false}, + queuedFilesAnnotationSaved: {type: Array, attribute: false}, + fileHandlingEnabledTargets: {type: String, attribute: 'file-handling-enabled-targets'}, }; } connectedCallback() { super.connectedCallback(); // needs to be called in a function to get the variable scope of "this" - setInterval(() => { this.handleQueuedFiles(); }, 1000); + setInterval(() => { + this.handleQueuedFiles(); + }, 1000); } async queueFile(file) { @@ -151,9 +153,9 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem if (this.queuedFilesNeedsPlacement.get(key) && !isManual) { // Some have a signature but are not "manual", stop everything notify({ - "body": i18n.t('error-manual-positioning-missing'), - "type": "danger", - "timeout": 5, + body: i18n.t('error-manual-positioning-missing'), + type: 'danger', + timeout: 5, }); this.signingProcessEnabled = false; this.signingProcessActive = false; @@ -174,7 +176,7 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem let params = {}; // prepare parameters to tell PDF-AS where and how the signature should be placed - if (this.queuedFilesPlacementModes[key] === "manual") { + if (this.queuedFilesPlacementModes[key] === 'manual') { const data = this.queuedFilesSignaturePlacements[key]; if (data !== undefined) { params = utils.fabricjs2pdfasPosition(data); @@ -194,9 +196,6 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem this.uploadInProgress = false; } - - - /** * Decides if the "beforeunload" event needs to be canceled * @@ -228,7 +227,6 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem event.returnValue = ''; } - addToErrorFiles(file) { this.endSigningProcessIfQueueEmpty(); @@ -238,7 +236,10 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem this.errorFilesCount++; this.sendSetPropertyEvent('analytics-event', { - 'category': 'officiallySigning', 'action': 'SigningFailed', 'name': file.json["hydra:description"]}); + category: 'officiallySigning', + action: 'SigningFailed', + name: file.json['hydra:description'], + }); } /** @@ -247,7 +248,7 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem onFileUploadFinished(data) { if (data.status !== 201) { this.addToErrorFiles(data); - } else if (data.json["@type"] === "http://schema.org/MediaObject" ) { + } else if (data.json['@type'] === 'http://schema.org/MediaObject') { // this doesn't seem to trigger an update() execution this.signedFiles.push(data.json); // this triggers the correct update() execution @@ -256,23 +257,28 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem this.currentFileName = entryPoint.name; this.endSigningProcessIfQueueEmpty(); this.sendSetPropertyEvent('analytics-event', { - 'category': 'OfficialSigning', 'action': 'DocumentSigned', 'name': data.json.contentSize}); + category: 'OfficialSigning', + action: 'DocumentSigned', + name: data.json.contentSize, + }); } } update(changedProperties) { changedProperties.forEach((oldValue, propName) => { switch (propName) { - case "lang": + case 'lang': this._i18n.changeLanguage(this.lang); break; - case "entryPointUrl": + case 'entryPointUrl': JSONLD.getInstance(this.entryPointUrl).then((jsonld) => { let apiUrlBase; try { - apiUrlBase = jsonld.getApiUrlForEntityName("EsignAdvancedlySignedDocument"); + apiUrlBase = jsonld.getApiUrlForEntityName( + 'EsignAdvancedlySignedDocument' + ); } catch (error) { - apiUrlBase = jsonld.getApiUrlForEntityName("AdvancedlySignedDocument"); + apiUrlBase = jsonld.getApiUrlForEntityName('AdvancedlySignedDocument'); } this.fileSourceUrl = apiUrlBase; }); @@ -290,7 +296,7 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem } async stopSigningProcess() { - console.log("stop"); + console.log('stop'); this.signingProcessEnabled = false; this.signingProcessActive = false; @@ -303,8 +309,6 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem } } - - static get styles() { // language=css return css` @@ -334,44 +338,67 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem results.push(html` <div class="file-block"> <div class="header"> - <span class="filename"><strong>${file.name}</strong> (${humanFileSize(file.size)})</span> - <button class="button close" + <span class="filename"> + <strong>${file.name}</strong> + (${humanFileSize(file.size)}) + </span> + <button + class="button close" ?disabled="${this.signingProcessEnabled}" title="${i18n.t('official-pdf-upload.remove-queued-file-button-title')}" - @click="${() => { this.takeFileFromQueue(id); }}"> - <dbp-icon name="trash"></dbp-icon></button> + @click="${() => { + this.takeFileFromQueue(id); + }}"> + <dbp-icon name="trash"></dbp-icon> + </button> </div> <div class="bottom-line"> <div></div> - <button class="button" + <button + class="button" ?disabled="${this.signingProcessEnabled}" - @click="${() => { this.showPreview(id); }}">${i18n.t('official-pdf-upload.show-preview')}</button> + @click="${() => { + this.showPreview(id); + }}"> + ${i18n.t('official-pdf-upload.show-preview')} + </button> <span class="headline">${i18n.t('official-pdf-upload.positioning')}:</span> - <dbp-textswitch name1="auto" + <dbp-textswitch + name1="auto" name2="manual" - name="${this.queuedFilesPlacementModes[id] || "auto"}" - class="${classMap({'placement-missing': placementMissing, 'switch': true})}" + name="${this.queuedFilesPlacementModes[id] || 'auto'}" + class="${classMap({ + 'placement-missing': placementMissing, + switch: true, + })}" value1="${i18n.t('official-pdf-upload.positioning-automatic')}" value2="${i18n.t('official-pdf-upload.positioning-manual')}" ?disabled="${this.signingProcessEnabled}" - @change=${ (e) => this.queuePlacementSwitch(id, e.target.name) }></dbp-textswitch> - <span class="headline ${classMap({hidden: !this.allowAnnotating})}">${i18n.t('official-pdf-upload.annotation')}:</span> + @change=${(e) => + this.queuePlacementSwitch(id, e.target.name)}></dbp-textswitch> + <span class="headline ${classMap({hidden: !this.allowAnnotating})}"> + ${i18n.t('official-pdf-upload.annotation')}: + </span> <div class="${classMap({hidden: !this.allowAnnotating})}"> - <dbp-textswitch id="annotation-switch" + <dbp-textswitch + id="annotation-switch" name1="no-text" name2="text-selected" - name="${this.queuedFilesAnnotationModes[id] || "no-text"}" - class="${classMap({'switch': true})}" + name="${this.queuedFilesAnnotationModes[id] || 'no-text'}" + class="${classMap({switch: true})}" value1="${i18n.t('official-pdf-upload.annotation-no')}" value2="${i18n.t('official-pdf-upload.annotation-yes')}" ?disabled="${this.signingProcessEnabled}" - @change=${ (e) => this.showAnnotationView(id, e.target.name) }></dbp-textswitch> + @change=${(e) => + this.showAnnotationView(id, e.target.name)}></dbp-textswitch> </div> </div> <div class="error-line"> - ${ placementMissing ? html` - ${i18n.t('label-manual-positioning-missing')} - ` : '' } + ${placementMissing + ? html` + ${i18n.t('label-manual-positioning-missing')} + ` + : ''} </div> </div> `); @@ -396,11 +423,18 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem results.push(html` <div class="file-block" id="file-block-${id}"> <div class="header"> - <span class="filename"><span class="bold-filename">${file.name}</span> (${humanFileSize(file.contentSize)})</span> - <button class="button close" + <span class="filename"> + <span class="bold-filename">${file.name}</span> + (${humanFileSize(file.contentSize)}) + </span> + <button + class="button close" title="${i18n.t('official-pdf-upload.download-file-button-title')}" - @click="${() => { this.downloadFileClickHandler(file, 'file-block-' + id); }}"> - <dbp-icon name="download"></dbp-icon></button> + @click="${() => { + this.downloadFileClickHandler(file, 'file-block-' + id); + }}"> + <dbp-icon name="download"></dbp-icon> + </button> </div> </div> `); @@ -429,19 +463,33 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem results.push(html` <div class="file-block error"> <div class="header"> - <span class="filename"><strong>${data.file.name}</strong> (${humanFileSize(data.file.size)})</span> + <span class="filename"> + <strong>${data.file.name}</strong> + (${humanFileSize(data.file.size)}) + </span> <div class="buttons"> - <button class="button" - title="${i18n.t('official-pdf-upload.re-upload-file-button-title')}" - @click="${() => {this.fileQueueingClickHandler(data.file, id);}}"><dbp-icon name="reload"></dbp-icon></button> - <button class="button" - title="${i18n.t('official-pdf-upload.remove-failed-file-button-title')}" - @click="${() => { this.takeFailedFileFromQueue(id); }}"> - <dbp-icon name="trash"></dbp-icon></button> + <button + class="button" + title="${i18n.t('official-pdf-upload.re-upload-file-button-title')}" + @click="${() => { + this.fileQueueingClickHandler(data.file, id); + }}"> + <dbp-icon name="reload"></dbp-icon> + </button> + <button + class="button" + title="${i18n.t( + 'official-pdf-upload.remove-failed-file-button-title' + )}" + @click="${() => { + this.takeFailedFileFromQueue(id); + }}"> + <dbp-icon name="trash"></dbp-icon> + </button> </div> </div> <div class="bottom-line"> - <strong class="error">${data.json["hydra:description"]}</strong> + <strong class="error">${data.json['hydra:description']}</strong> </div> </div> `); @@ -455,24 +503,29 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem } render() { - const placeholderUrl = commonUtils.getAssetURL(pkgName, 'official-signature-placeholder.png'); + const placeholderUrl = commonUtils.getAssetURL( + pkgName, + 'official-signature-placeholder.png' + ); const i18n = this._i18n; return html` - <div class="${classMap({hidden: !this.isLoggedIn() || !this.hasSignaturePermissions() || this.isLoading()})}"> + <div + class="${classMap({ + hidden: + !this.isLoggedIn() || !this.hasSignaturePermissions() || this.isLoading(), + })}"> <div class="field"> <h2>${this.activity.getName(this.lang)}</h2> - <p class="subheadline"> - ${this.activity.getDescription(this.lang)} - </p> + <p class="subheadline">${this.activity.getDescription(this.lang)}</p> <div class="control"> - - <p> - ${i18n.t('official-pdf-upload.upload-text')} - </p> - <button @click="${() => { this._("#file-source").setAttribute("dialog-open", ""); }}" - ?disabled="${this.signingProcessActive}" - class="button is-primary"> + <p>${i18n.t('official-pdf-upload.upload-text')}</p> + <button + @click="${() => { + this._('#file-source').setAttribute('dialog-open', ''); + }}" + ?disabled="${this.signingProcessActive}" + class="button is-primary"> ${i18n.t('official-pdf-upload.upload-button-label')} </button> <dbp-file-source @@ -492,132 +545,200 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem text="${i18n.t('official-pdf-upload.upload-area-text')}" button-label="${i18n.t('official-pdf-upload.upload-button-label')}" @dbp-file-source-file-selected="${this.onFileSelected}" - @dbp-file-source-switched="${this.onFileSourceSwitch}" - ></dbp-file-source> + @dbp-file-source-switched="${this + .onFileSourceSwitch}"></dbp-file-source> </div> </div> <div id="grid-container"> <div class="left-container"> - <div class="files-block field ${classMap({hidden: !this.queueBlockEnabled})}"> + <div + class="files-block field ${classMap({ + hidden: !this.queueBlockEnabled, + })}"> <!-- Queued files headline and queueing spinner --> - <h3 class="${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <h3 + class="${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${i18n.t('official-pdf-upload.queued-files-label')} </h3> <!-- Buttons to start/stop signing process and clear queue --> <div class="control field"> - <button @click="${this.clearQueuedFiles}" - ?disabled="${this.queuedFilesCount === 0 || this.signingProcessActive || this.isUserInterfaceDisabled()}" - class="button ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <button + @click="${this.clearQueuedFiles}" + ?disabled="${this.queuedFilesCount === 0 || + this.signingProcessActive || + this.isUserInterfaceDisabled()}" + class="button ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${i18n.t('official-pdf-upload.clear-all')} </button> - <button @click="${() => { this.signingProcessEnabled = true; this.signingProcessActive = true; }}" - ?disabled="${this.queuedFilesCount === 0}" - class="button is-right is-primary ${classMap( - { - "is-disabled": this.isUserInterfaceDisabled(), - hidden: this.signingProcessActive - })}"> + <button + @click="${() => { + this.signingProcessEnabled = true; + this.signingProcessActive = true; + }}" + ?disabled="${this.queuedFilesCount === 0}" + class="button is-right is-primary ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + hidden: this.signingProcessActive, + })}"> ${i18n.t('official-pdf-upload.start-signing-process-button')} </button> <!-- --> - <button @click="${this.stopSigningProcess}" - id="cancel-signing-process" - class="button is-right ${classMap({hidden: !this.signingProcessActive})}"> + <button + @click="${this.stopSigningProcess}" + id="cancel-signing-process" + class="button is-right ${classMap({ + hidden: !this.signingProcessActive, + })}"> ${i18n.t('official-pdf-upload.stop-signing-process-button')} </button> <!-- --> </div> <!-- List of queued files --> - <div class="control file-list ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="control file-list ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${this.getQueuedFilesHtml()} </div> <!-- Text "queue empty" --> - <div class="empty-queue control ${classMap({hidden: this.queuedFilesCount !== 0, "is-disabled": this.isUserInterfaceDisabled()})}"> - ${i18n.t('official-pdf-upload.queued-files-empty1')}<br /> + <div + class="empty-queue control ${classMap({ + hidden: this.queuedFilesCount !== 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> + ${i18n.t('official-pdf-upload.queued-files-empty1')} + <br /> ${i18n.t('official-pdf-upload.queued-files-empty2')} </div> </div> <!-- List of signed PDFs --> - <div class="files-block field ${classMap({hidden: this.signedFilesCount === 0, "is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="files-block field ${classMap({ + hidden: this.signedFilesCount === 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> <h3>${i18n.t('official-pdf-upload.signed-files-label')}</h3> <!-- Button to download all signed PDFs --> <div class="field ${classMap({hidden: this.signedFilesCount === 0})}"> <div class="control"> - <button @click="${this.clearSignedFiles}" - class="button"> + <button @click="${this.clearSignedFiles}" class="button"> ${i18n.t('official-pdf-upload.clear-all')} </button> - <dbp-button id="zip-download-button" - value="${i18n.t('official-pdf-upload.download-zip-button')}" - title="${i18n.t('official-pdf-upload.download-zip-button-tooltip')}" - class="is-right" - @click="${this.zipDownloadClickHandler}" - type="is-primary"></dbp-button> + <dbp-button + id="zip-download-button" + value="${i18n.t('official-pdf-upload.download-zip-button')}" + title="${i18n.t( + 'official-pdf-upload.download-zip-button-tooltip' + )}" + class="is-right" + @click="${this.zipDownloadClickHandler}" + type="is-primary"></dbp-button> </div> </div> - <div class="control"> - ${this.getSignedFilesHtml()} - </div> + <div class="control">${this.getSignedFilesHtml()}</div> </div> <!-- List of errored files --> - <div class="files-block error-files field ${classMap({hidden: this.errorFilesCount === 0, "is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="files-block error-files field ${classMap({ + hidden: this.errorFilesCount === 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> <h3>${i18n.t('official-pdf-upload.error-files-label')}</h3> <!-- Button to upload errored files again --> <div class="field ${classMap({hidden: this.errorFilesCount === 0})}"> <div class="control"> - <button @click="${this.clearErrorFiles}" - class="button"> + <button @click="${this.clearErrorFiles}" class="button"> ${i18n.t('official-pdf-upload.clear-all')} </button> - <dbp-button id="re-upload-all-button" - ?disabled="${this.uploadInProgress}" - value="${i18n.t('official-pdf-upload.re-upload-all-button')}" - title="${i18n.t('official-pdf-upload.re-upload-all-button-title')}" - class="is-right" - @click="${this.reUploadAllClickHandler}" - type="is-primary"></dbp-button> + <dbp-button + id="re-upload-all-button" + ?disabled="${this.uploadInProgress}" + value="${i18n.t( + 'official-pdf-upload.re-upload-all-button' + )}" + title="${i18n.t( + 'official-pdf-upload.re-upload-all-button-title' + )}" + class="is-right" + @click="${this.reUploadAllClickHandler}" + type="is-primary"></dbp-button> </div> </div> - <div class="control"> - ${this.getErrorFilesHtml()} - </div> + <div class="control">${this.getErrorFilesHtml()}</div> </div> </div> <div class="right-container"> <!-- PDF preview --> - <div id="pdf-preview" class="field ${classMap({hidden: !this.signaturePlacementInProgress})}"> - <h3>${this.withSigBlock ? i18n.t('official-pdf-upload.signature-placement-label') : i18n.t('official-pdf-upload.preview-label')}</h3> + <div + id="pdf-preview" + class="field ${classMap({hidden: !this.signaturePlacementInProgress})}"> + <h3> + ${this.withSigBlock + ? i18n.t('official-pdf-upload.signature-placement-label') + : i18n.t('official-pdf-upload.preview-label')} + </h3> <div class="box-header"> <div class="filename"> - <strong>${this.currentFile.name}</strong> (${humanFileSize(this.currentFile !== undefined ? this.currentFile.size : 0)}) + <strong>${this.currentFile.name}</strong> + (${humanFileSize( + this.currentFile !== undefined ? this.currentFile.size : 0 + )}) </div> - <button class="button is-cancel" - @click="${this.hidePDF}"><dbp-icon name="close"></dbp-icon></button> + <button class="button is-cancel" @click="${this.hidePDF}"> + <dbp-icon name="close"></dbp-icon> + </button> </div> - <dbp-pdf-preview lang="${this.lang}" - allow-signature-rotation - signature-placeholder-image-src="${placeholderUrl}" - signature-width="162" - signature-height="28" - @dbp-pdf-preview-accept="${this.storePDFData}" - @dbp-pdf-preview-cancel="${this.hidePDF}"></dbp-pdf-preview> + <dbp-pdf-preview + lang="${this.lang}" + allow-signature-rotation + signature-placeholder-image-src="${placeholderUrl}" + signature-width="162" + signature-height="28" + @dbp-pdf-preview-accept="${this.storePDFData}" + @dbp-pdf-preview-cancel="${this.hidePDF}"></dbp-pdf-preview> </div> <!-- Annotation view --> - <div id="annotation-view" class="field ${classMap({hidden: !this.isAnnotationViewVisible || !this.allowAnnotating})}"> + <div + id="annotation-view" + class="field ${classMap({ + hidden: !this.isAnnotationViewVisible || !this.allowAnnotating, + })}"> <h2>${i18n.t('official-pdf-upload.annotation-view-label')}</h2> <div class="box-header"> <div class="filename"> - <strong>${this.currentFile.file !== undefined ? this.currentFile.file.name : ''}</strong> (${humanFileSize(this.currentFile.file !== undefined ? this.currentFile.file.size : 0)}) + <strong> + ${this.currentFile.file !== undefined + ? this.currentFile.file.name + : ''} + </strong> + (${humanFileSize( + this.currentFile.file !== undefined + ? this.currentFile.file.size + : 0 + )}) </div> - <button class="button is-cancel annotation" - @click="${this.hideAnnotationView}"><dbp-icon name="close" id="close-icon"></dbp-icon></button> + <button + class="button is-cancel annotation" + @click="${this.hideAnnotationView}"> + <dbp-icon name="close" id="close-icon"></dbp-icon> + </button> </div> - <dbp-pdf-annotation-view lang="${this.lang}" - @dbp-pdf-annotations-save="${this.processAnnotationEvent}" - @dbp-pdf-annotations-cancel="${this.processAnnotationCancelEvent}"></dbp-pdf-annotation-view> + <dbp-pdf-annotation-view + lang="${this.lang}" + @dbp-pdf-annotations-save="${this.processAnnotationEvent}" + @dbp-pdf-annotations-cancel="${this + .processAnnotationCancelEvent}"></dbp-pdf-annotation-view> </div> <!-- File upload progress --> - <div id="upload-progress" class="field notification is-info ${classMap({hidden: !this.uploadInProgress})}"> + <div + id="upload-progress" + class="field notification is-info ${classMap({ + hidden: !this.uploadInProgress, + })}"> <dbp-mini-spinner></dbp-mini-spinner> <strong>${this.uploadStatusFileName}</strong> ${this.uploadStatusText} @@ -625,17 +746,27 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem </div> </div> </div> - <div class="notification is-warning ${classMap({hidden: this.isLoggedIn() || this.isLoading()})}"> + <div + class="notification is-warning ${classMap({ + hidden: this.isLoggedIn() || this.isLoading(), + })}"> ${i18n.t('error-login-message')} </div> - <div class="notification is-danger ${classMap({hidden: this.hasSignaturePermissions() || !this.isLoggedIn() || this.isLoading()})}"> + <div + class="notification is-danger ${classMap({ + hidden: + this.hasSignaturePermissions() || !this.isLoggedIn() || this.isLoading(), + })}"> ${i18n.t('error-permission-message')} </div> <div class="${classMap({hidden: !this.isLoading()})}"> <dbp-mini-spinner></dbp-mini-spinner> </div> - <dbp-file-sink id="file-sink" - context="${i18n.t('qualified-pdf-upload.save-field-label', {count: this.signedFilesToDownload})}" + <dbp-file-sink + id="file-sink" + context="${i18n.t('qualified-pdf-upload.save-field-label', { + count: this.signedFilesToDownload, + })}" filename="signed-documents.zip" subscribe="initial-file-handling-state:initial-file-handling-state,clipboard-files:clipboard-files" enabled-targets="${this.fileHandlingEnabledTargets}" @@ -643,8 +774,7 @@ class OfficialSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElem nextcloud-web-dav-url="${this.nextcloudWebDavURL}" nextcloud-name="${this.nextcloudName}" nextcloud-file-url="${this.nextcloudFileURL}" - lang="${this.lang}" - ></dbp-file-sink> + lang="${this.lang}"></dbp-file-sink> `; } } diff --git a/src/dbp-official-signature-pdf-upload.metadata.json b/src/dbp-official-signature-pdf-upload.metadata.json index 70d177e459fd81f45a989c74b5d81ebb74de6cd4..af84d67286310f73a52536efc81677f6371f25b2 100644 --- a/src/dbp-official-signature-pdf-upload.metadata.json +++ b/src/dbp-official-signature-pdf-upload.metadata.json @@ -1,19 +1,19 @@ { - "element": "dbp-official-signature-pdf-upload", - "module_src": "dbp-official-signature-pdf-upload.js", - "routing_name": "official-pdf-upload", - "name": { - "de": "Dokumente amtssignieren", - "en": "Officially sign documents" - }, - "short_name": { - "de": "Dokumente amtssignieren", - "en": "Officially sign documents" - }, - "description": { - "de": "Erlaubt das Hochladen von PDF-Dokumenten, um sie mit einer Amtssignatur zu versehen", - "en": "Allows upload of PDF-documents to officially sign them" - }, - "subscribe": "lang,entry-point-url,nextcloud-web-app-password-url,nextcloud-webdav-url,nextcloud-name,nextcloud-auth-info,nextcloud-file-url,auth,allow-annotating,file-handling-enabled-targets", - "required_roles": ["ROLE_SCOPE_OFFICIAL-SIGNATURE"] + "element": "dbp-official-signature-pdf-upload", + "module_src": "dbp-official-signature-pdf-upload.js", + "routing_name": "official-pdf-upload", + "name": { + "de": "Dokumente amtssignieren", + "en": "Officially sign documents" + }, + "short_name": { + "de": "Dokumente amtssignieren", + "en": "Officially sign documents" + }, + "description": { + "de": "Erlaubt das Hochladen von PDF-Dokumenten, um sie mit einer Amtssignatur zu versehen", + "en": "Allows upload of PDF-documents to officially sign them" + }, + "subscribe": "lang,entry-point-url,nextcloud-web-app-password-url,nextcloud-webdav-url,nextcloud-name,nextcloud-auth-info,nextcloud-file-url,auth,allow-annotating,file-handling-enabled-targets", + "required_roles": ["ROLE_SCOPE_OFFICIAL-SIGNATURE"] } diff --git a/src/dbp-pdf-annotation-view.js b/src/dbp-pdf-annotation-view.js index 93e55bb5529420f74cd1464efdad6e7f37d008bb..edc199af2de49958fe195d6d756927844c6da9d9 100644 --- a/src/dbp-pdf-annotation-view.js +++ b/src/dbp-pdf-annotation-view.js @@ -4,8 +4,8 @@ import {classMap} from 'lit/directives/class-map.js'; import {ScopedElementsMixin} from '@open-wc/scoped-elements'; import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element'; import {MiniSpinner, Icon} from '@dbp-toolkit/common'; -import {OrganizationSelect} from "@dbp-toolkit/organization-select"; -import { send } from '@dbp-toolkit/common/notification'; +import {OrganizationSelect} from '@dbp-toolkit/organization-select'; +import {send} from '@dbp-toolkit/common/notification'; import * as commonStyles from '@dbp-toolkit/common/styles'; import * as utils from './utils'; @@ -38,24 +38,24 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { static get properties() { return { ...super.properties, - lang: { type: String }, - key: { type: Number }, - isTextHidden: { type: Boolean, attribute: false }, - isSelected: { type: Boolean, attribute: false }, - annotationRows: { type: Array, attribute: false }, - queuedFilesAnnotationsCount: { type: Number, attribute: false }, + lang: {type: String}, + key: {type: Number}, + isTextHidden: {type: Boolean, attribute: false}, + isSelected: {type: Boolean, attribute: false}, + annotationRows: {type: Array, attribute: false}, + queuedFilesAnnotationsCount: {type: Number, attribute: false}, }; } update(changedProperties) { changedProperties.forEach((oldValue, propName) => { switch (propName) { - case "lang": + case 'lang': this._i18n.changeLanguage(this.lang); break; } }); - + super.update(changedProperties); } @@ -67,7 +67,7 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { } /** - * Deletes all fields and restore introduction text + * Deletes all fields and restore introduction text */ deleteAll() { this.annotationRows = []; @@ -77,8 +77,11 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { sendCancelEvent() { console.log('cancel event called'); - const event = new CustomEvent("dbp-pdf-annotations-cancel", - { "detail": {}, bubbles: true, composed: true }); + const event = new CustomEvent('dbp-pdf-annotations-cancel', { + detail: {}, + bubbles: true, + composed: true, + }); this.dispatchEvent(event); } @@ -90,12 +93,16 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { if (annotationTypeData['hasOrganization']) { let organization = annotation.organizationValue; - if (typeof organization === 'undefined' || organization === null || organization === '') { + if ( + typeof organization === 'undefined' || + organization === null || + organization === '' + ) { send({ - "summary": i18n.t('annotation-view.empty-organization-title'), - "body": i18n.t('annotation-view.empty-organization-message'), - "type": "danger", - "timeout": 5, + summary: i18n.t('annotation-view.empty-organization-title'), + body: i18n.t('annotation-view.empty-organization-message'), + type: 'danger', + timeout: 5, }); return false; } @@ -103,10 +110,12 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { if (annotation['value'] === null || annotation['value'] === '') { send({ - "summary": i18n.t('annotation-view.empty-annotation-title', {annotationType: annotationTypeData.name[this.lang]}), - "body": i18n.t('annotation-view.empty-annotation-message'), - "type": "danger", - "timeout": 5, + summary: i18n.t('annotation-view.empty-annotation-title', { + annotationType: annotationTypeData.name[this.lang], + }), + body: i18n.t('annotation-view.empty-annotation-message'), + type: 'danger', + timeout: 5, }); return false; } @@ -114,12 +123,15 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { const pattern = new RegExp('[A-Za-z0-9ÄäÖöÜüß*\\/?! &@()=+_-]*'); let matchResult = annotation['value'].match(pattern); - if (matchResult[0] === undefined || annotation['value'].length !== matchResult[0].length) { + if ( + matchResult[0] === undefined || + annotation['value'].length !== matchResult[0].length + ) { send({ - "summary": i18n.t('annotation-view.invalid-annotation-text-title'), - "body": i18n.t('annotation-view.invalid-annotation-text-message'), - "type": "danger", - "timeout": 5, + summary: i18n.t('annotation-view.invalid-annotation-text-title'), + body: i18n.t('annotation-view.invalid-annotation-text-message'), + type: 'danger', + timeout: 5, }); return false; } @@ -134,13 +146,16 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { if (!this.validateValues()) { return; } - + const data = { - "key": this.key, - "annotationRows": this.annotationRows, + key: this.key, + annotationRows: this.annotationRows, }; - const event = new CustomEvent("dbp-pdf-annotations-save", - { "detail": data, bubbles: true, composed: true }); + const event = new CustomEvent('dbp-pdf-annotations-save', { + detail: data, + bubbles: true, + composed: true, + }); this.dispatchEvent(event); if (this.annotationRows.length === 0) { @@ -160,7 +175,7 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { let e = this._('#additional-select'); let type = e?.options[e?.selectedIndex]?.value; - this.annotationRows.push({'annotationType': type, 'value': ''}); + this.annotationRows.push({annotationType: type, value: ''}); // we just need this so the UI will update this.queuedFilesAnnotationsCount++; @@ -193,7 +208,7 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { // delete this.annotationRows[id]; //length of array doesn't change this.annotationRows.splice(id, 1); - if(this.annotationRows.length === 0) { + if (this.annotationRows.length === 0) { this.isTextHidden = false; this.sendCancelEvent(); } @@ -218,10 +233,10 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { div.annotation-block { display: grid; - row-gap: .3em; + row-gap: 0.3em; align-items: center; - + margin-left: 2px; margin-right: 2px; } @@ -233,7 +248,7 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { .border { border-top: var(--dbp-border-dark); - padding-bottom: .5em; + padding-bottom: 0.5em; } .border-wrapper { border: var(--dbp-border-dark); @@ -260,7 +275,7 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { } .delete-elements .button { - margin-left: .5em; + margin-left: 0.5em; } select:not(.select) { @@ -314,9 +329,7 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { } /* Handling for small displays (like mobile devices) */ - @media only screen - and (orientation: portrait) - and (max-width: 768px) { + @media only screen and (orientation: portrait) and (max-width: 768px) { .nav-buttons { flex-direction: column; } @@ -326,7 +339,6 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { grid-template-columns: auto 42px; column-gap: 3px; } - } `; } @@ -337,43 +349,64 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { * @returns {*[]} Array of html templates */ getAnnotationsHtml() { - const i18n = this._i18n; - const annotations = this.annotationRows || []; - const ids = Object.keys(annotations); - let results = []; + const i18n = this._i18n; + const annotations = this.annotationRows || []; + const ids = Object.keys(annotations); + let results = []; - ids.forEach((id) => { + ids.forEach((id) => { const data = this.annotationRows[id] || []; const annotationTypeData = utils.getAnnotationTypes(data.annotationType); const name = annotationTypeData.name[this.lang]; results.push(html` - <div class="${classMap({'with-organization': annotationTypeData.hasOrganization, 'annotation-block': true})}"> + <div + class="${classMap({ + 'with-organization': annotationTypeData.hasOrganization, + 'annotation-block': true, + })}"> <div class="inner-grid"> <label><strong>${name}</strong></label> - <button class="button close" - title="${i18n.t('annotation-view.remove-field')}" - @click="${() => { this.removeAnnotation(id); } }"> - <dbp-icon name="trash"></dbp-icon></button> + <button + class="button close" + title="${i18n.t('annotation-view.remove-field')}" + @click="${() => { + this.removeAnnotation(id); + }}"> + <dbp-icon name="trash"></dbp-icon> + </button> </div> - <dbp-organization-select subscribe="lang:lang,entry-point-url:entry-point-url,auth:auth" - class="${classMap({hidden: !annotationTypeData.hasOrganization})}" - value="${data.organizationValue}" - @change=${e => { - this.updateAnnotation(id, 'organizationValue', e.target.value); - this.updateAnnotation(id, 'organizationNumber', JSON.parse(e.target.getAttribute("data-object")).alternateName); - }}></dbp-organization-select> - - <input type="text" .value="${data.value}" class="input" pattern="[A-Za-z0-9ÄäÖöÜüß\*\\/! &@()=+_-]*" - placeholder="${annotationTypeData.hasOrganization ? i18n.t('annotation-view.businessnumber-placeholder') : i18n.t('annotation-view.intended-use-placeholder')}" - @change=${e => { this.updateAnnotation(id, 'value', e.target.value); }}> + <dbp-organization-select + subscribe="lang:lang,entry-point-url:entry-point-url,auth:auth" + class="${classMap({hidden: !annotationTypeData.hasOrganization})}" + value="${data.organizationValue}" + @change=${(e) => { + this.updateAnnotation(id, 'organizationValue', e.target.value); + this.updateAnnotation( + id, + 'organizationNumber', + JSON.parse(e.target.getAttribute('data-object')).alternateName + ); + }}></dbp-organization-select> + + <input + type="text" + .value="${data.value}" + class="input" + pattern="[A-Za-z0-9ÄäÖöÜüß*\\/! &@()=+_-]*" + placeholder="${annotationTypeData.hasOrganization + ? i18n.t('annotation-view.businessnumber-placeholder') + : i18n.t('annotation-view.intended-use-placeholder')}" + @change=${(e) => { + this.updateAnnotation(id, 'value', e.target.value); + }} /> </div> `); - }); + }); - return results; - } + return results; + } render() { const i18n = this._i18n; @@ -383,22 +416,30 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { <div class="nav-buttons"> <div class="add-elements"> - <select id="additional-select" @change="${() => { this.isSelected = true; } }"> + <select id="additional-select" @change="${() => { + this.isSelected = true; + }}"> ${utils.getAnnotationTypeSelectOptionsHtml('', this.lang)} - <option value="" disabled selected>${i18n.t('annotation-view.insert-field')}</option> + <option value="" disabled selected>${i18n.t( + 'annotation-view.insert-field' + )}</option> </select> <button class="button" title="${i18n.t('annotation-view.insert-field')}" - @click="${() => { this.addAnnotation(); } }" - ?disabled="${ !this.isSelected }"> + @click="${() => { + this.addAnnotation(); + }}" + ?disabled="${!this.isSelected}"> <dbp-icon name="checkmark-circle"></dbp-icon></button> </button> </div> <button class="button is-primary" title="${i18n.t('annotation-view.save-all-button-title')}" - @click="${() => { this.saveAll(); } }" - ?disabled="${ this.annotationRows.length === 0 }"> + @click="${() => { + this.saveAll(); + }}" + ?disabled="${this.annotationRows.length === 0}"> ${i18n.t('annotation-view.save-all-button-text')} </button> </div> @@ -408,16 +449,22 @@ export class PdfAnnotationView extends ScopedElementsMixin(DBPLitElement) { </div> <div id="fields-wrapper"> <div id="inside-fields"> - <div class="text ${classMap({hidden: this.isTextHidden || this.annotationRows.length > 0})}"> + <div class="text ${classMap({ + hidden: this.isTextHidden || this.annotationRows.length > 0, + })}"> <p>${i18n.t('annotation-view.introduction')}</p> </div> ${this.getAnnotationsHtml()} </div> <div class="delete-elements"> - <button class="button ${classMap({hidden: !this.isTextHidden && this.annotationRows.length === 0})}" + <button class="button ${classMap({ + hidden: !this.isTextHidden && this.annotationRows.length === 0, + })}" title="${i18n.t('annotation-view.delete-all-button-title')}" - @click="${() => { this.deleteAll(); } }" - ?disabled="${ this.annotationRows.length === 0 }"> + @click="${() => { + this.deleteAll(); + }}" + ?disabled="${this.annotationRows.length === 0}"> ${i18n.t('annotation-view.delete-all-button-text')} </button> </div> diff --git a/src/dbp-pdf-preview.js b/src/dbp-pdf-preview.js index 3efaf7010c1fdbeb537a4d5a96639520ed8d522d..cc6e8b649cb3095c617432c1cb27ce9d541bc0e7 100644 --- a/src/dbp-pdf-preview.js +++ b/src/dbp-pdf-preview.js @@ -5,7 +5,7 @@ import {live} from 'lit/directives/live.js'; import {ScopedElementsMixin} from '@open-wc/scoped-elements'; import DBPLitElement from '@dbp-toolkit/common/dbp-lit-element'; import {MiniSpinner, Icon} from '@dbp-toolkit/common'; -import * as commonUtils from "@dbp-toolkit/common/utils"; +import * as commonUtils from '@dbp-toolkit/common/utils'; import * as commonStyles from '@dbp-toolkit/common/styles'; import pdfjs from 'pdfjs-dist/legacy/build/pdf.js'; import {name as pkgName} from './../package.json'; @@ -54,25 +54,25 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { static get properties() { return { ...super.properties, - lang: { type: String }, - currentPage: { type: Number, attribute: false }, - totalPages: { type: Number, attribute: false }, - isShowPage: { type: Boolean, attribute: false }, - isPageRenderingInProgress: { type: Boolean, attribute: false }, - isPageLoaded: { type: Boolean, attribute: false }, - showErrorMessage: { type: Boolean, attribute: false }, - isShowPlacement: { type: Boolean, attribute: false }, - placeholder: { type: String, attribute: 'signature-placeholder-image-src' }, - signature_width: { type: Number, attribute: 'signature-width' }, - signature_height: { type: Number, attribute: 'signature-height' }, - allowSignatureRotation: { type: Boolean, attribute: 'allow-signature-rotation' }, + lang: {type: String}, + currentPage: {type: Number, attribute: false}, + totalPages: {type: Number, attribute: false}, + isShowPage: {type: Boolean, attribute: false}, + isPageRenderingInProgress: {type: Boolean, attribute: false}, + isPageLoaded: {type: Boolean, attribute: false}, + showErrorMessage: {type: Boolean, attribute: false}, + isShowPlacement: {type: Boolean, attribute: false}, + placeholder: {type: String, attribute: 'signature-placeholder-image-src'}, + signature_width: {type: Number, attribute: 'signature-width'}, + signature_height: {type: Number, attribute: 'signature-height'}, + allowSignatureRotation: {type: Boolean, attribute: 'allow-signature-rotation'}, }; } update(changedProperties) { changedProperties.forEach((oldValue, propName) => { switch (propName) { - case "lang": + case 'lang': this._i18n.changeLanguage(this.lang); break; } @@ -92,12 +92,15 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { } window.removeEventListener('resize', this._onWindowResize); super.disconnectedCallback(); - } + } connectedCallback() { super.connectedCallback(); const that = this; - pdfjs.GlobalWorkerOptions.workerSrc = commonUtils.getAssetURL(pkgName, 'pdfjs/pdf.worker.js'); + pdfjs.GlobalWorkerOptions.workerSrc = commonUtils.getAssetURL( + pkgName, + 'pdfjs/pdf.worker.js' + ); window.addEventListener('resize', this._onWindowResize); @@ -119,9 +122,14 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { }); // add signature image - fabric.Image.fromURL(this.placeholder, function(image) { + fabric.Image.fromURL(this.placeholder, function (image) { // add a red border around the signature placeholder - image.set({stroke: "#e4154b", strokeWidth: that.border_width, strokeUniform: true, centeredRotation: true}); + image.set({ + stroke: '#e4154b', + strokeWidth: that.border_width, + strokeUniform: true, + centeredRotation: true, + }); // disable controls, we currently don't want resizing and do rotation with a button image.hasControls = false; @@ -131,12 +139,12 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { }); this.fabricCanvas.on({ - 'object:moving': function(e) { - e.target.opacity = 0.5; + 'object:moving': function (e) { + e.target.opacity = 0.5; + }, + 'object:modified': function (e) { + e.target.opacity = 1; }, - 'object:modified': function(e) { - e.target.opacity = 1; - } }); // this.fabricCanvas.on("object:moved", function(opt){ console.log(opt); }); @@ -169,10 +177,24 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { } // bottom-right corner - if (obj.getBoundingRect().top + obj.getBoundingRect().height > obj.canvas.height || - obj.getBoundingRect().left + obj.getBoundingRect().width > obj.canvas.width) { - obj.top = Math.min(obj.top, obj.canvas.height - obj.getBoundingRect().height + obj.top - obj.getBoundingRect().top); - obj.left = Math.min(obj.left, obj.canvas.width - obj.getBoundingRect().width + obj.left - obj.getBoundingRect().left); + if ( + obj.getBoundingRect().top + obj.getBoundingRect().height > obj.canvas.height || + obj.getBoundingRect().left + obj.getBoundingRect().width > obj.canvas.width + ) { + obj.top = Math.min( + obj.top, + obj.canvas.height - + obj.getBoundingRect().height + + obj.top - + obj.getBoundingRect().top + ); + obj.left = Math.min( + obj.left, + obj.canvas.width - + obj.getBoundingRect().width + + obj.left - + obj.getBoundingRect().left + ); } } @@ -200,20 +222,20 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { // move signature if placementData was set if (item !== undefined) { - if (placementData["scaleX"] !== undefined) { - item.set("scaleX", placementData["scaleX"] * this.canvasToPdfScale); + if (placementData['scaleX'] !== undefined) { + item.set('scaleX', placementData['scaleX'] * this.canvasToPdfScale); } - if (placementData["scaleY"] !== undefined) { - item.set("scaleY", placementData["scaleY"] * this.canvasToPdfScale); + if (placementData['scaleY'] !== undefined) { + item.set('scaleY', placementData['scaleY'] * this.canvasToPdfScale); } - if (placementData["left"] !== undefined) { - item.set("left", placementData["left"] * this.canvasToPdfScale); + if (placementData['left'] !== undefined) { + item.set('left', placementData['left'] * this.canvasToPdfScale); } - if (placementData["top"] !== undefined) { - item.set("top", placementData["top"] * this.canvasToPdfScale); + if (placementData['top'] !== undefined) { + item.set('top', placementData['top'] * this.canvasToPdfScale); } - if (placementData["angle"] !== undefined) { - item.set("angle", placementData["angle"]); + if (placementData['angle'] !== undefined) { + item.set('angle', placementData['angle']); } } @@ -237,7 +259,7 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { // show the first page // if the placementData has no values we want to initialize the signature position - await this.showPage(page, placementData["scaleX"] === undefined); + await this.showPage(page, placementData['scaleX'] === undefined); this.isPageLoaded = true; @@ -269,7 +291,7 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { // get handle of page await this.pdfDoc.getPage(pageNumber).then(async (page) => { // original width of the pdf page at scale 1 - const originalViewport = page.getViewport({ scale: 1 }); + const originalViewport = page.getViewport({scale: 1}); this.currentPageOriginalHeight = originalViewport.height; // set the canvas width to the width of the container (minus the borders) @@ -280,23 +302,23 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { const oldScale = this.canvasToPdfScale; this.canvasToPdfScale = this.canvas.width / originalViewport.width; - console.log("this.canvasToPdfScale: " + this.canvasToPdfScale); + console.log('this.canvasToPdfScale: ' + this.canvasToPdfScale); // get viewport to render the page at required scale - const viewport = page.getViewport({ scale: this.canvasToPdfScale }); + const viewport = page.getViewport({scale: this.canvasToPdfScale}); // set canvas height same as viewport height this.fabricCanvas.setHeight(viewport.height); this.canvas.height = viewport.height; // setting page loader height for smooth experience - this._("#page-loader").style.height = this.canvas.height + 'px'; - this._("#page-loader").style.lineHeight = this.canvas.height + 'px'; + this._('#page-loader').style.height = this.canvas.height + 'px'; + this._('#page-loader').style.lineHeight = this.canvas.height + 'px'; // page is rendered on <canvas> element const render_context = { canvasContext: this.canvas.getContext('2d'), - viewport: viewport + viewport: viewport, }; let signature = this.getSignatureRect(); @@ -315,8 +337,12 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { }; const sigSize = signature.getOriginalSize(); - const scaleX = (this.canvas.width / sigSize.width) * (sigSizeMM.width / documentSizeMM.width); - const scaleY = (this.canvas.height / sigSize.height) * (sigSizeMM.height / documentSizeMM.height); + const scaleX = + (this.canvas.width / sigSize.width) * + (sigSizeMM.width / documentSizeMM.width); + const scaleY = + (this.canvas.height / sigSize.height) * + (sigSizeMM.height / documentSizeMM.height); const offsetTop = sigPosMM.top * pointsPerMM; const offsetLeft = sigPosMM.left * pointsPerMM; @@ -326,17 +352,17 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { angle: 0, top: offsetTop, left: offsetLeft, - lockUniScaling: true // lock aspect ratio when resizing + lockUniScaling: true, // lock aspect ratio when resizing }); } else { // adapt signature scale to new scale const scaleAdapt = this.canvasToPdfScale / oldScale; signature.set({ - scaleX: signature.get("scaleX") * scaleAdapt, - scaleY: signature.get("scaleY") * scaleAdapt, - left: signature.get("left") * scaleAdapt, - top: signature.get("top") * scaleAdapt + scaleX: signature.get('scaleX') * scaleAdapt, + scaleY: signature.get('scaleY') * scaleAdapt, + left: signature.get('left') * scaleAdapt, + top: signature.get('top') * scaleAdapt, }); signature.setCoords(); @@ -344,66 +370,77 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { // render the page contents in the canvas try { - await page.render(render_context).promise.then(() => { - console.log('Page rendered'); - that.isPageRenderingInProgress = false; - - return page.getAnnotations(); - }).then(function(annotationData) { - // remove all child nodes - that.annotationLayer.innerHTML = ''; - // update size - that.annotationLayer.style.height = that.canvas.height + 'px'; - that.annotationLayer.style.width = that.canvas.width + 'px'; - - // create all supported annotations - annotationData.forEach((annotation) => { - const subtype = annotation.subtype; - let text = ''; - switch (subtype) { - case 'Text': - case 'FreeText': - // Annotations by Adobe Acrobat already have an appearance that can be viewed by pdf.js - if (annotation.hasAppearance) { - return; - } - - text = annotation.contents; - break; - case 'Widget': - // Annotations by Adobe Acrobat already have an appearance that can be viewed by pdf.js - if (annotation.hasAppearance) { + await page + .render(render_context) + .promise.then(() => { + console.log('Page rendered'); + that.isPageRenderingInProgress = false; + + return page.getAnnotations(); + }) + .then(function (annotationData) { + // remove all child nodes + that.annotationLayer.innerHTML = ''; + // update size + that.annotationLayer.style.height = that.canvas.height + 'px'; + that.annotationLayer.style.width = that.canvas.width + 'px'; + + // create all supported annotations + annotationData.forEach((annotation) => { + const subtype = annotation.subtype; + let text = ''; + switch (subtype) { + case 'Text': + case 'FreeText': + // Annotations by Adobe Acrobat already have an appearance that can be viewed by pdf.js + if (annotation.hasAppearance) { + return; + } + + text = annotation.contents; + break; + case 'Widget': + // Annotations by Adobe Acrobat already have an appearance that can be viewed by pdf.js + if (annotation.hasAppearance) { + return; + } + + text = annotation.alternativeText; + break; + default: + // we don't support other types return; - } - - text = annotation.alternativeText; - break; - default: - // we don't support other types - return; - } - - const annotationDiv = document.createElement("div"); - const annotationDivInner = document.createElement("div"); - annotationDiv.className = 'annotation annotation-' + subtype; - annotationDiv.style.left = (annotation.rect[0] * that.canvasToPdfScale) + 'px'; - annotationDiv.style.bottom = (annotation.rect[1] * that.canvasToPdfScale) + 'px'; - annotationDiv.style.width = ((annotation.rect[2] - annotation.rect[0]) * that.canvasToPdfScale) + 'px'; - annotationDiv.style.height = ((annotation.rect[3] - annotation.rect[1]) * that.canvasToPdfScale) + 'px'; - annotationDivInner.innerText = text === '' ? subtype : text; - - annotationDiv.appendChild(annotationDivInner); - that.annotationLayer.appendChild(annotationDiv); + } + + const annotationDiv = document.createElement('div'); + const annotationDivInner = document.createElement('div'); + annotationDiv.className = 'annotation annotation-' + subtype; + annotationDiv.style.left = + annotation.rect[0] * that.canvasToPdfScale + 'px'; + annotationDiv.style.bottom = + annotation.rect[1] * that.canvasToPdfScale + 'px'; + annotationDiv.style.width = + (annotation.rect[2] - annotation.rect[0]) * + that.canvasToPdfScale + + 'px'; + annotationDiv.style.height = + (annotation.rect[3] - annotation.rect[1]) * + that.canvasToPdfScale + + 'px'; + annotationDivInner.innerText = text === '' ? subtype : text; + + annotationDiv.appendChild(annotationDivInner); + that.annotationLayer.appendChild(annotationDiv); + }); + + // console.log("annotationData render", annotationData); }); - - // console.log("annotationData render", annotationData); - }); - } catch(error) { + } catch (error) { console.error(error.message); that.isPageRenderingInProgress = false; } }); - } catch(error) { + } catch (error) { console.error(error.message); that.isPageRenderingInProgress = false; } @@ -411,13 +448,13 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { sendAcceptEvent() { const item = this.getSignatureRect(); - let left = item.get("left"); - let top = item.get("top"); - const angle = item.get("angle"); + let left = item.get('left'); + let top = item.get('top'); + const angle = item.get('angle'); // fabricjs includes the stroke in the image position // and we have to remove it - const border_offset = (this.border_width / 2); + const border_offset = this.border_width / 2; if (angle === 0) { left += border_offset; top += border_offset; @@ -433,24 +470,30 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { } const data = { - "currentPage": this.currentPage, - "scaleX": item.get("scaleX") / this.canvasToPdfScale, - "scaleY": item.get("scaleY") / this.canvasToPdfScale, - "width": item.get("width") * item.get("scaleX") / this.canvasToPdfScale, - "height": item.get("height") * item.get("scaleY") / this.canvasToPdfScale, - "left": left / this.canvasToPdfScale, - "top": top / this.canvasToPdfScale, - "bottom": this.currentPageOriginalHeight - (top / this.canvasToPdfScale), - "angle": item.get("angle") + currentPage: this.currentPage, + scaleX: item.get('scaleX') / this.canvasToPdfScale, + scaleY: item.get('scaleY') / this.canvasToPdfScale, + width: (item.get('width') * item.get('scaleX')) / this.canvasToPdfScale, + height: (item.get('height') * item.get('scaleY')) / this.canvasToPdfScale, + left: left / this.canvasToPdfScale, + top: top / this.canvasToPdfScale, + bottom: this.currentPageOriginalHeight - top / this.canvasToPdfScale, + angle: item.get('angle'), }; - const event = new CustomEvent("dbp-pdf-preview-accept", - { "detail": data, bubbles: true, composed: true }); + const event = new CustomEvent('dbp-pdf-preview-accept', { + detail: data, + bubbles: true, + composed: true, + }); this.dispatchEvent(event); } sendCancelEvent() { - const event = new CustomEvent("dbp-pdf-preview-cancel", - { "detail": {}, bubbles: true, composed: true }); + const event = new CustomEvent('dbp-pdf-preview-cancel', { + detail: {}, + bubbles: true, + composed: true, + }); this.dispatchEvent(event); } @@ -459,7 +502,7 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { */ async rotateSignature() { let signature = this.getSignatureRect(); - let angle = (signature.get("angle") + 90) % 360; + let angle = (signature.get('angle') + 90) % 360; signature.rotate(angle); signature.setCoords(); this.enforceCanvasBoundaries(signature); @@ -474,12 +517,12 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { ${commonStyles.getGeneralCSS()} ${commonStyles.getButtonCSS()} - #pdf-meta input[type=number]{ + #pdf-meta input[type=number] { max-width: 50px; } #page-loader { - display:flex; + display: flex; align-items: center; justify-content: center; } @@ -546,7 +589,7 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { margin: 2px; } - input[type=number] { + input[type='number'] { border: var(--dbp-border-dark); padding: 0 0.3em; } @@ -561,15 +604,16 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { .button.is-cancel { color: var(--dbp-danger-dark); } - - .error-message{ + + .error-message { text-align: center; border: 1px solid black; border-top: 0px; padding: 15px; } - - #canvas-wrapper canvas#fabric-canvas, #canvas-wrapper canvas.upper-canvas{ + + #canvas-wrapper canvas#fabric-canvas, + #canvas-wrapper canvas.upper-canvas { border: unset; } `; @@ -580,66 +624,114 @@ export class PdfPreview extends ScopedElementsMixin(DBPLitElement) { const i18n = this._i18n; return html` - -<!-- + <!-- <form> <input type="file" name="pdf" id="upload-pdf-input"> </form> --> <div id="pdf-main-container" class="${classMap({hidden: !this.isShowPage})}"> - <dbp-mini-spinner class="${classMap({hidden: this.isPageLoaded || this.showErrorMessage})}"></dbp-mini-spinner> - <div class="error-message ${classMap({hidden: !this.showErrorMessage || this.isPageLoaded})}"> + <dbp-mini-spinner + class="${classMap({ + hidden: this.isPageLoaded || this.showErrorMessage, + })}"></dbp-mini-spinner> + <div + class="error-message ${classMap({ + hidden: !this.showErrorMessage || this.isPageLoaded, + })}"> ${i18n.t('pdf-preview.error-message')} </div> <div class="${classMap({hidden: !this.isPageLoaded})}"> <div id="pdf-meta"> <div class="buttons ${classMap({hidden: !this.isPageLoaded})}"> - <button class="button ${classMap({hidden: !this.isShowPlacement || isRotationHidden})}" - title="${i18n.t('pdf-preview.rotate-signature')}" - @click="${() => { this.rotateSignature(); } }" - ?disabled="${this.isPageRenderingInProgress}">⟳ ${i18n.t('pdf-preview.rotate')}</button> + <button + class="button ${classMap({ + hidden: !this.isShowPlacement || isRotationHidden, + })}" + title="${i18n.t('pdf-preview.rotate-signature')}" + @click="${() => { + this.rotateSignature(); + }}" + ?disabled="${this.isPageRenderingInProgress}"> + ⟳ ${i18n.t('pdf-preview.rotate')} + </button> <div class="nav-buttons"> - <button class="button" - title="${i18n.t('pdf-preview.first-page')}" - @click="${async () => { await this.showPage(1); } }" - ?disabled="${this.isPageRenderingInProgress || this.currentPage === 1}"> + <button + class="button" + title="${i18n.t('pdf-preview.first-page')}" + @click="${async () => { + await this.showPage(1); + }}" + ?disabled="${this.isPageRenderingInProgress || + this.currentPage === 1}"> <dbp-icon name="angle-double-left"></dbp-icon> </button> - <button class="button" - title="${i18n.t('pdf-preview.previous-page')}" - @click="${async () => { if (this.currentPage > 1) await this.showPage(--this.currentPage); } }" - ?disabled="${this.isPageRenderingInProgress || this.currentPage === 1}"> + <button + class="button" + title="${i18n.t('pdf-preview.previous-page')}" + @click="${async () => { + if (this.currentPage > 1) + await this.showPage(--this.currentPage); + }}" + ?disabled="${this.isPageRenderingInProgress || + this.currentPage === 1}"> <dbp-icon name="chevron-left"></dbp-icon> </button> - <input type="number" + <input + type="number" min="1" max="${this.totalPages}" @input="${this.onPageNumberChanged}" - .value="${live(this.currentPage)}"> - <div class="page-info">${i18n.t('pdf-preview.page-count', {totalPages: this.totalPages, })}</div> - <button class="button" - title="${i18n.t('pdf-preview.next-page')}" - @click="${async () => { if (this.currentPage < this.totalPages) await this.showPage(++this.currentPage); } }" - ?disabled="${this.isPageRenderingInProgress || this.currentPage === this.totalPages}"> + .value="${live(this.currentPage)}" /> + <div class="page-info"> + ${i18n.t('pdf-preview.page-count', { + totalPages: this.totalPages, + })} + </div> + <button + class="button" + title="${i18n.t('pdf-preview.next-page')}" + @click="${async () => { + if (this.currentPage < this.totalPages) + await this.showPage(++this.currentPage); + }}" + ?disabled="${this.isPageRenderingInProgress || + this.currentPage === this.totalPages}"> <dbp-icon name="chevron-right"></dbp-icon> </button> - <button class="button" - title="${i18n.t('pdf-preview.last-page')}" - @click="${async () => { await this.showPage(this.totalPages); } }" - ?disabled="${this.isPageRenderingInProgress || this.currentPage === this.totalPages}"> + <button + class="button" + title="${i18n.t('pdf-preview.last-page')}" + @click="${async () => { + await this.showPage(this.totalPages); + }}" + ?disabled="${this.isPageRenderingInProgress || + this.currentPage === this.totalPages}"> <dbp-icon name="angle-double-right"></dbp-icon> </button> </div> - <button class="button is-primary ${classMap({hidden: !this.isShowPlacement})}" - @click="${() => { this.sendAcceptEvent(); } }">${i18n.t('pdf-preview.continue')}</button> + <button + class="button is-primary ${classMap({ + hidden: !this.isShowPlacement, + })}" + @click="${() => { + this.sendAcceptEvent(); + }}"> + ${i18n.t('pdf-preview.continue')} + </button> </div> </div> - <div id="canvas-wrapper" class="${classMap({hidden: this.isPageRenderingInProgress})}"> + <div + id="canvas-wrapper" + class="${classMap({hidden: this.isPageRenderingInProgress})}"> <canvas id="pdf-canvas"></canvas> <div id="annotation-layer"></div> - <canvas id="fabric-canvas" class="${classMap({hidden: !this.isShowPlacement})}"></canvas> + <canvas + id="fabric-canvas" + class="${classMap({hidden: !this.isShowPlacement})}"></canvas> + </div> + <div class="${classMap({hidden: !this.isPageRenderingInProgress})}"> + <dbp-mini-spinner id="page-loader"></dbp-mini-spinner> </div> - <div class="${classMap({hidden: !this.isPageRenderingInProgress})}"><dbp-mini-spinner id="page-loader"></dbp-mini-spinner></div> </div> </div> `; diff --git a/src/dbp-qualified-signature-pdf-upload.js b/src/dbp-qualified-signature-pdf-upload.js index 4272d632fe612344671866d2745c9682254baeba..025c6490cbcf497b146b473180c3279bce6ac0ff 100644 --- a/src/dbp-qualified-signature-pdf-upload.js +++ b/src/dbp-qualified-signature-pdf-upload.js @@ -2,23 +2,23 @@ import {createInstance} from './i18n.js'; import {humanFileSize} from '@dbp-toolkit/common/i18next.js'; import {css, html} from 'lit'; import {ScopedElementsMixin} from '@open-wc/scoped-elements'; -import DBPSignatureLitElement from "./dbp-signature-lit-element"; -import {PdfPreview} from "./dbp-pdf-preview"; +import DBPSignatureLitElement from './dbp-signature-lit-element'; +import {PdfPreview} from './dbp-pdf-preview'; import * as commonUtils from '@dbp-toolkit/common/utils'; import * as utils from './utils'; import {Button, Icon, MiniSpinner} from '@dbp-toolkit/common'; import * as commonStyles from '@dbp-toolkit/common/styles'; import {classMap} from 'lit/directives/class-map.js'; import {FileSource} from '@dbp-toolkit/file-handling'; -import JSONLD from "@dbp-toolkit/common/jsonld"; +import JSONLD from '@dbp-toolkit/common/jsonld'; import {TextSwitch} from './textswitch.js'; -import {FileSink} from "@dbp-toolkit/file-handling"; +import {FileSink} from '@dbp-toolkit/file-handling'; import {name as pkgName} from './../package.json'; import {send as notify} from '@dbp-toolkit/common/notification'; import metadata from './dbp-qualified-signature-pdf-upload.metadata.json'; import {Activity} from './activity.js'; -import {PdfAnnotationView} from "./dbp-pdf-annotation-view"; -import { ExternalSignIFrame } from './ext-sign-iframe.js'; +import {PdfAnnotationView} from './dbp-pdf-annotation-view'; +import {ExternalSignIFrame} from './ext-sign-iframe.js'; import * as SignatureStyles from './styles'; class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitElement) { @@ -27,22 +27,22 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle this._i18n = createInstance(); this.lang = this._i18n.language; this.entryPointUrl = ''; - this.nextcloudWebAppPasswordURL = ""; - this.nextcloudWebDavURL = ""; - this.nextcloudName = ""; - this.nextcloudFileURL = ""; - this.nextcloudAuthInfo = ""; + this.nextcloudWebAppPasswordURL = ''; + this.nextcloudWebDavURL = ''; + this.nextcloudName = ''; + this.nextcloudFileURL = ''; + this.nextcloudAuthInfo = ''; this.externalAuthInProgress = false; this.signedFiles = []; this.signedFilesCount = 0; this.signedFilesToDownload = 0; this.errorFiles = []; this.errorFilesCount = 0; - this.uploadStatusFileName = ""; - this.uploadStatusText = ""; + this.uploadStatusFileName = ''; + this.uploadStatusText = ''; this.currentFile = {}; - this.currentFileName = ""; - this.currentFilePlacementMode = ""; + this.currentFileName = ''; + this.currentFilePlacementMode = ''; this.currentFileSignaturePlacement = {}; this.signingProcessEnabled = false; this.signingProcessActive = false; @@ -61,67 +61,69 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle this.isAnnotationViewVisible = false; this.addAnnotationInProgress = false; this.activity = new Activity(metadata); - this.fileHandlingEnabledTargets = "local"; + this.fileHandlingEnabledTargets = 'local'; this._onReceiveBeforeUnload = this.onReceiveBeforeUnload.bind(this); } static get scopedElements() { return { - 'dbp-icon': Icon, - 'dbp-file-source': FileSource, - 'dbp-file-sink': FileSink, - 'dbp-pdf-preview': PdfPreview, - 'dbp-mini-spinner': MiniSpinner, - 'dbp-button': Button, - 'dbp-textswitch': TextSwitch, - 'dbp-pdf-annotation-view': PdfAnnotationView, - 'external-sign-iframe': ExternalSignIFrame, + 'dbp-icon': Icon, + 'dbp-file-source': FileSource, + 'dbp-file-sink': FileSink, + 'dbp-pdf-preview': PdfPreview, + 'dbp-mini-spinner': MiniSpinner, + 'dbp-button': Button, + 'dbp-textswitch': TextSwitch, + 'dbp-pdf-annotation-view': PdfAnnotationView, + 'external-sign-iframe': ExternalSignIFrame, }; } static get properties() { return { ...super.properties, - lang: { type: String }, - entryPointUrl: { type: String, attribute: 'entry-point-url' }, - nextcloudWebAppPasswordURL: { type: String, attribute: 'nextcloud-web-app-password-url' }, - nextcloudWebDavURL: { type: String, attribute: 'nextcloud-webdav-url' }, - nextcloudName: { type: String, attribute: 'nextcloud-name' }, - nextcloudFileURL: { type: String, attribute: 'nextcloud-file-url' }, + lang: {type: String}, + entryPointUrl: {type: String, attribute: 'entry-point-url'}, + nextcloudWebAppPasswordURL: {type: String, attribute: 'nextcloud-web-app-password-url'}, + nextcloudWebDavURL: {type: String, attribute: 'nextcloud-webdav-url'}, + nextcloudName: {type: String, attribute: 'nextcloud-name'}, + nextcloudFileURL: {type: String, attribute: 'nextcloud-file-url'}, nextcloudAuthInfo: {type: String, attribute: 'nextcloud-auth-info'}, - signedFiles: { type: Array, attribute: false }, - signedFilesCount: { type: Number, attribute: false }, - signedFilesToDownload: { type: Number, attribute: false }, - queuedFilesCount: { type: Number, attribute: false }, - errorFiles: { type: Array, attribute: false }, - errorFilesCount: { type: Number, attribute: false }, - uploadInProgress: { type: Boolean, attribute: false }, - uploadStatusFileName: { type: String, attribute: false }, - uploadStatusText: { type: String, attribute: false }, - externalAuthInProgress: { type: Boolean, attribute: false }, - signingProcessEnabled: { type: Boolean, attribute: false }, - signingProcessActive: { type: Boolean, attribute: false }, - queueBlockEnabled: { type: Boolean, attribute: false }, - currentFile: { type: Object, attribute: false }, - currentFileName: { type: String, attribute: false }, - signaturePlacementInProgress: { type: Boolean, attribute: false }, - withSigBlock: { type: Boolean, attribute: false }, - isSignaturePlacement: { type: Boolean, attribute: false }, - allowAnnotating: { type: Boolean, attribute: 'allow-annotating' }, - isAnnotationViewVisible: { type: Boolean, attribute: false }, - queuedFilesAnnotations: { type: Array, attribute: false }, - queuedFilesAnnotationsCount: { type: Number, attribute: false }, - addAnnotationInProgress: { type: Boolean, attribute: false }, - queuedFilesAnnotationModes: { type: Array, attribute: false }, - queuedFilesAnnotationSaved: { type: Array, attribute: false }, - fileHandlingEnabledTargets: {type: String, attribute: 'file-handling-enabled-targets'} + signedFiles: {type: Array, attribute: false}, + signedFilesCount: {type: Number, attribute: false}, + signedFilesToDownload: {type: Number, attribute: false}, + queuedFilesCount: {type: Number, attribute: false}, + errorFiles: {type: Array, attribute: false}, + errorFilesCount: {type: Number, attribute: false}, + uploadInProgress: {type: Boolean, attribute: false}, + uploadStatusFileName: {type: String, attribute: false}, + uploadStatusText: {type: String, attribute: false}, + externalAuthInProgress: {type: Boolean, attribute: false}, + signingProcessEnabled: {type: Boolean, attribute: false}, + signingProcessActive: {type: Boolean, attribute: false}, + queueBlockEnabled: {type: Boolean, attribute: false}, + currentFile: {type: Object, attribute: false}, + currentFileName: {type: String, attribute: false}, + signaturePlacementInProgress: {type: Boolean, attribute: false}, + withSigBlock: {type: Boolean, attribute: false}, + isSignaturePlacement: {type: Boolean, attribute: false}, + allowAnnotating: {type: Boolean, attribute: 'allow-annotating'}, + isAnnotationViewVisible: {type: Boolean, attribute: false}, + queuedFilesAnnotations: {type: Array, attribute: false}, + queuedFilesAnnotationsCount: {type: Number, attribute: false}, + addAnnotationInProgress: {type: Boolean, attribute: false}, + queuedFilesAnnotationModes: {type: Array, attribute: false}, + queuedFilesAnnotationSaved: {type: Array, attribute: false}, + fileHandlingEnabledTargets: {type: String, attribute: 'file-handling-enabled-targets'}, }; } connectedCallback() { super.connectedCallback(); // needs to be called in a function to get the variable scope of "this" - setInterval(() => { this.handleQueuedFiles(); }, 1000); + setInterval(() => { + this.handleQueuedFiles(); + }, 1000); // we want to be able to cancel the leaving of the page window.addEventListener('beforeunload', this._onReceiveBeforeUnload); @@ -154,7 +156,12 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle return; } - if (!this.signingProcessEnabled || this.externalAuthInProgress || this.uploadInProgress || this.addAnnotationInProgress) { + if ( + !this.signingProcessEnabled || + this.externalAuthInProgress || + this.uploadInProgress || + this.addAnnotationInProgress + ) { return; } this.signaturePlacementInProgress = false; @@ -165,9 +172,9 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle if (this.queuedFilesNeedsPlacement.get(key) && !isManual) { // Some have a signature but are not "manual", stop everything notify({ - "body": i18n.t('error-manual-positioning-missing'), - "type": "danger", - "timeout": 5, + body: i18n.t('error-manual-positioning-missing'), + type: 'danger', + timeout: 5, }); this.signingProcessEnabled = false; this.signingProcessActive = false; @@ -188,7 +195,7 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle let params = {}; // prepare parameters to tell PDF-AS where and how the signature should be placed - if (this.queuedFilesPlacementModes[key] === "manual") { + if (this.queuedFilesPlacementModes[key] === 'manual') { const data = this.queuedFilesSignaturePlacements[key]; if (data !== undefined) { params = utils.fabricjs2pdfasPosition(data); @@ -208,11 +215,6 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle this.uploadInProgress = false; } - - - - - /** * Decides if the "beforeunload" event needs to be canceled * @@ -254,18 +256,15 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle let errorParsed = error; // Common Error Messages fpr pdf-as: https://www.buergerkarte.at/konzept/securitylayer/spezifikation/20140114/errorcodes/errorcodes.html // SecurityLayer Error: [6000] Unklassifizierter Abbruch durch den Bürger. - if (error.includes('SecurityLayer Error: [6001]')) - { + if (error.includes('SecurityLayer Error: [6001]')) { errorParsed = i18n.t('error-cancel-message'); } // SecurityLayer Error: [6001] Abbruch durch den Bürger über die Benutzerschnittstelle. - else if (error.includes('SecurityLayer Error: [6000]')) - { + else if (error.includes('SecurityLayer Error: [6000]')) { errorParsed = i18n.t('error-cancel-message'); } // SecurityLayer Error: [6002] Abbruch auf Grund mangelnder Rechte zur Befehlsausführung. - else if (error.includes('SecurityLayer Error: [6002]')) - { + else if (error.includes('SecurityLayer Error: [6002]')) { errorParsed = i18n.t('error-rights-message'); } return errorParsed; @@ -275,74 +274,84 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle const sessionId = event.detail.id; // check if sessionId is valid - if ((typeof sessionId !== 'string') || (sessionId.length < 15)) { + if (typeof sessionId !== 'string' || sessionId.length < 15) { return; } - console.log("Got iframe message for sessionId " + sessionId); + console.log('Got iframe message for sessionId ' + sessionId); const that = this; // get correct file name - const fileName = this.currentFileName === "" ? "mydoc.pdf" : this.currentFileName; + const fileName = this.currentFileName === '' ? 'mydoc.pdf' : this.currentFileName; // fetch pdf from api gateway with sessionId - JSONLD.getInstance(this.entryPointUrl).then((jsonld) => { - let apiUrlBase; - try { - apiUrlBase = jsonld.getApiUrlForEntityName("EsignQualifiedlySignedDocument"); - } catch (error) { - apiUrlBase = jsonld.getApiUrlForEntityName("QualifiedlySignedDocument"); - } - - const apiUrl = apiUrlBase + '/' + encodeURIComponent(sessionId) + '?fileName=' + - encodeURIComponent(fileName); - - fetch(apiUrl, { - headers: { - 'Content-Type': 'application/ld+json', - 'Authorization': 'Bearer ' + that.auth.token, - }, - }) - .then(result => { - // hide iframe - that.externalAuthInProgress = false; - this._("#iframe").reset(); - this.endSigningProcessIfQueueEmpty(); - - if (!result.ok) throw result; - - return result.json(); + JSONLD.getInstance(this.entryPointUrl).then( + (jsonld) => { + let apiUrlBase; + try { + apiUrlBase = jsonld.getApiUrlForEntityName('EsignQualifiedlySignedDocument'); + } catch (error) { + apiUrlBase = jsonld.getApiUrlForEntityName('QualifiedlySignedDocument'); + } + + const apiUrl = + apiUrlBase + + '/' + + encodeURIComponent(sessionId) + + '?fileName=' + + encodeURIComponent(fileName); + + fetch(apiUrl, { + headers: { + 'Content-Type': 'application/ld+json', + Authorization: 'Bearer ' + that.auth.token, + }, }) - .then((document) => { - // this doesn't seem to trigger an update() execution - that.signedFiles.push(document); - // this triggers the correct update() execution - that.signedFilesCount++; - - this.sendSetPropertyEvent('analytics-event', { - 'category': 'QualifiedlySigning', 'action': 'DocumentSigned', 'name': document.contentSize}); - }).catch(error => { - let file = this.currentFile; - // let's override the json to inject an error message - file.json = {"hydra:description" : "Download failed!"}; - - this.addToErrorFiles(file); - }); - }, {}, that.lang); + .then((result) => { + // hide iframe + that.externalAuthInProgress = false; + this._('#iframe').reset(); + this.endSigningProcessIfQueueEmpty(); + + if (!result.ok) throw result; + + return result.json(); + }) + .then((document) => { + // this doesn't seem to trigger an update() execution + that.signedFiles.push(document); + // this triggers the correct update() execution + that.signedFilesCount++; + + this.sendSetPropertyEvent('analytics-event', { + category: 'QualifiedlySigning', + action: 'DocumentSigned', + name: document.contentSize, + }); + }) + .catch((error) => { + let file = this.currentFile; + // let's override the json to inject an error message + file.json = {'hydra:description': 'Download failed!'}; + + this.addToErrorFiles(file); + }); + }, + {}, + that.lang + ); } - _onIFrameError(event) { let error = event.detail.message; let file = this.currentFile; - file.json = {"hydra:description" : this.parseError(error)}; + file.json = {'hydra:description': this.parseError(error)}; this.addToErrorFiles(file); - this._("#iframe").reset(); + this._('#iframe').reset(); this.externalAuthInProgress = false; this.endSigningProcessIfQueueEmpty(); } - addToErrorFiles(file) { this.endSigningProcessIfQueueEmpty(); @@ -352,7 +361,10 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle this.errorFilesCount++; this.sendSetPropertyEvent('analytics-event', { - 'category': 'QualifiedlySigning', 'action': 'SigningFailed', 'name': file.json["hydra:description"]}); + category: 'QualifiedlySigning', + action: 'SigningFailed', + name: file.json['hydra:description'], + }); } /** @@ -361,7 +373,7 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle onFileUploadFinished(data) { if (data.status !== 201) { this.addToErrorFiles(data); - } else if (data.json["@type"] === "http://schema.org/EntryPoint" ) { + } else if (data.json['@type'] === 'http://schema.org/EntryPoint') { // after the "real" upload we immediately start with the 2FA process // show the iframe and lock processing @@ -374,7 +386,7 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle this.currentFile = data; // we want to load the redirect url in the iframe - let iframe = this._("#iframe"); + let iframe = this._('#iframe'); iframe.setUrl(entryPoint.url); } } @@ -382,18 +394,20 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle update(changedProperties) { changedProperties.forEach((oldValue, propName) => { switch (propName) { - case "lang": + case 'lang': this._i18n.changeLanguage(this.lang); break; - case "entryPointUrl": + case 'entryPointUrl': JSONLD.getInstance(this.entryPointUrl).then((jsonld) => { let apiUrlBase; try { - apiUrlBase = jsonld.getApiUrlForEntityName("EsignQualifiedSigningRequest"); + apiUrlBase = jsonld.getApiUrlForEntityName( + 'EsignQualifiedSigningRequest' + ); } catch (error) { - apiUrlBase = jsonld.getApiUrlForEntityName("QualifiedSigningRequest"); + apiUrlBase = jsonld.getApiUrlForEntityName('QualifiedSigningRequest'); } - this.fileSourceUrl = apiUrlBase ; + this.fileSourceUrl = apiUrlBase; }); break; } @@ -408,7 +422,6 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle super.clearQueuedFiles(); } - static get styles() { // language=css return css` @@ -454,44 +467,69 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle results.push(html` <div class="file-block"> <div class="header"> - <span class="filename"><strong>${file.name}</strong> (${humanFileSize(file.size)})</span> - <button class="button close" + <span class="filename"> + <strong>${file.name}</strong> + (${humanFileSize(file.size)}) + </span> + <button + class="button close" ?disabled="${this.signingProcessEnabled}" - title="${i18n.t('qualified-pdf-upload.remove-queued-file-button-title')}" - @click="${() => { this.takeFileFromQueue(id); }}"> - <dbp-icon name="trash"></dbp-icon></button> + title="${i18n.t( + 'qualified-pdf-upload.remove-queued-file-button-title' + )}" + @click="${() => { + this.takeFileFromQueue(id); + }}"> + <dbp-icon name="trash"></dbp-icon> + </button> </div> <div class="bottom-line"> <div></div> - <button class="button" + <button + class="button" ?disabled="${this.signingProcessEnabled}" - @click="${() => { this.showPreview(id); }}">${i18n.t('qualified-pdf-upload.show-preview')}</button> + @click="${() => { + this.showPreview(id); + }}"> + ${i18n.t('qualified-pdf-upload.show-preview')} + </button> <span class="headline">${i18n.t('qualified-pdf-upload.positioning')}:</span> - <dbp-textswitch name1="auto" + <dbp-textswitch + name1="auto" name2="manual" - name="${this.queuedFilesPlacementModes[id] || "auto"}" - class="${classMap({'placement-missing': placementMissing, 'switch': true})}" + name="${this.queuedFilesPlacementModes[id] || 'auto'}" + class="${classMap({ + 'placement-missing': placementMissing, + switch: true, + })}" value1="${i18n.t('qualified-pdf-upload.positioning-automatic')}" value2="${i18n.t('qualified-pdf-upload.positioning-manual')}" ?disabled="${this.signingProcessEnabled}" - @change=${ (e) => this.queuePlacementSwitch(id, e.target.name) }></dbp-textswitch> - <span class="headline ${classMap({hidden: !this.allowAnnotating})}">${i18n.t('qualified-pdf-upload.annotation')}:</span> + @change=${(e) => + this.queuePlacementSwitch(id, e.target.name)}></dbp-textswitch> + <span class="headline ${classMap({hidden: !this.allowAnnotating})}"> + ${i18n.t('qualified-pdf-upload.annotation')}: + </span> <div class="${classMap({hidden: !this.allowAnnotating})}"> - <dbp-textswitch id="annotation-switch" + <dbp-textswitch + id="annotation-switch" name1="no-text" name2="text-selected" - name="${this.queuedFilesAnnotationModes[id] || "no-text"}" - class="${classMap({'switch': true})}" + name="${this.queuedFilesAnnotationModes[id] || 'no-text'}" + class="${classMap({switch: true})}" value1="${i18n.t('qualified-pdf-upload.annotation-no')}" value2="${i18n.t('qualified-pdf-upload.annotation-yes')}" ?disabled="${this.signingProcessEnabled}" - @change=${ (e) => this.showAnnotationView(id, e.target.name) }></dbp-textswitch> + @change=${(e) => + this.showAnnotationView(id, e.target.name)}></dbp-textswitch> </div> </div> <div class="error-line"> - ${ placementMissing ? html` - ${i18n.t('label-manual-positioning-missing')} - ` : '' } + ${placementMissing + ? html` + ${i18n.t('label-manual-positioning-missing')} + ` + : ''} </div> </div> `); @@ -516,11 +554,18 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle results.push(html` <div class="file-block" id="file-block-${id}"> <div class="header"> - <span class="filename"><span class="bold-filename">${file.name}</span> (${humanFileSize(file.contentSize)})</span> - <button class="button close" + <span class="filename"> + <span class="bold-filename">${file.name}</span> + (${humanFileSize(file.contentSize)}) + </span> + <button + class="button close" title="${i18n.t('qualified-pdf-upload.download-file-button-title')}" - @click="${() => { this.downloadFileClickHandler(file, 'file-block-' + id); }}"> - <dbp-icon name="download"></dbp-icon></button> + @click="${() => { + this.downloadFileClickHandler(file, 'file-block-' + id); + }}"> + <dbp-icon name="download"></dbp-icon> + </button> </div> </div> `); @@ -549,19 +594,35 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle results.push(html` <div class="file-block error"> <div class="header"> - <span class="filename"><strong>${data.file.name}</strong> (${humanFileSize(data.file.size)})</span> + <span class="filename"> + <strong>${data.file.name}</strong> + (${humanFileSize(data.file.size)}) + </span> <div class="buttons"> - <button class="button" - title="${i18n.t('qualified-pdf-upload.re-upload-file-button-title')}" - @click="${() => {this.fileQueueingClickHandler(data.file, id);}}"><dbp-icon name="reload"></dbp-icon></button> - <button class="button" - title="${i18n.t('qualified-pdf-upload.remove-failed-file-button-title')}" - @click="${() => { this.takeFailedFileFromQueue(id); }}"> - <dbp-icon name="trash"></dbp-icon></button> + <button + class="button" + title="${i18n.t( + 'qualified-pdf-upload.re-upload-file-button-title' + )}" + @click="${() => { + this.fileQueueingClickHandler(data.file, id); + }}"> + <dbp-icon name="reload"></dbp-icon> + </button> + <button + class="button" + title="${i18n.t( + 'qualified-pdf-upload.remove-failed-file-button-title' + )}" + @click="${() => { + this.takeFailedFileFromQueue(id); + }}"> + <dbp-icon name="trash"></dbp-icon> + </button> </div> </div> <div class="bottom-line"> - <strong class="error">${data.json["hydra:description"]}</strong> + <strong class="error">${data.json['hydra:description']}</strong> </div> </div> `); @@ -579,7 +640,7 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle return; } - this._("#iframe").reset(); + this._('#iframe').reset(); this.signingProcessEnabled = false; this.externalAuthInProgress = false; this.signingProcessActive = false; @@ -594,24 +655,29 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle } render() { - const placeholderUrl = commonUtils.getAssetURL(pkgName, 'qualified-signature-placeholder.png'); + const placeholderUrl = commonUtils.getAssetURL( + pkgName, + 'qualified-signature-placeholder.png' + ); const i18n = this._i18n; return html` - <div class="${classMap({hidden: !this.isLoggedIn() || !this.hasSignaturePermissions() || this.isLoading()})}"> - <div class="field ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="${classMap({ + hidden: + !this.isLoggedIn() || !this.hasSignaturePermissions() || this.isLoading(), + })}"> + <div class="field ${classMap({'is-disabled': this.isUserInterfaceDisabled()})}"> <h2>${this.activity.getName(this.lang)}</h2> - <p class="subheadline"> - ${this.activity.getDescription(this.lang)} - </p> + <p class="subheadline">${this.activity.getDescription(this.lang)}</p> <div class="control"> - - <p> - ${i18n.t('qualified-pdf-upload.upload-text')} - </p> - <button @click="${() => { this._("#file-source").setAttribute("dialog-open", ""); }}" - ?disabled="${this.signingProcessActive}" - class="button is-primary"> + <p>${i18n.t('qualified-pdf-upload.upload-text')}</p> + <button + @click="${() => { + this._('#file-source').setAttribute('dialog-open', ''); + }}" + ?disabled="${this.signingProcessActive}" + class="button is-primary"> ${i18n.t('qualified-pdf-upload.upload-button-label')} </button> <dbp-file-source @@ -631,165 +697,261 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle text="${i18n.t('qualified-pdf-upload.upload-area-text')}" button-label="${i18n.t('qualified-pdf-upload.upload-button-label')}" @dbp-file-source-file-selected="${this.onFileSelected}" - @dbp-file-source-switched="${this.onFileSourceSwitch}" - ></dbp-file-source> + @dbp-file-source-switched="${this + .onFileSourceSwitch}"></dbp-file-source> </div> </div> <div id="grid-container"> <div class="left-container"> - <div class="files-block field ${classMap({hidden: !this.queueBlockEnabled})}"> + <div + class="files-block field ${classMap({ + hidden: !this.queueBlockEnabled, + })}"> <!-- Queued files headline and queueing spinner --> - <h3 class="${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <h3 + class="${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${i18n.t('qualified-pdf-upload.queued-files-label')} </h3> <!-- Buttons to start/stop signing process and clear queue --> <div class="control field"> - <button @click="${this.clearQueuedFiles}" - ?disabled="${this.queuedFilesCount === 0 || this.signingProcessActive || this.isUserInterfaceDisabled()}" - class="button ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <button + @click="${this.clearQueuedFiles}" + ?disabled="${this.queuedFilesCount === 0 || + this.signingProcessActive || + this.isUserInterfaceDisabled()}" + class="button ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${i18n.t('qualified-pdf-upload.clear-all')} </button> - <button @click="${() => { this.signingProcessEnabled = true; this.signingProcessActive = true; }}" - ?disabled="${this.queuedFilesCount === 0}" - class="button is-right is-primary ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <button + @click="${() => { + this.signingProcessEnabled = true; + this.signingProcessActive = true; + }}" + ?disabled="${this.queuedFilesCount === 0}" + class="button is-right is-primary ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${i18n.t('qualified-pdf-upload.start-signing-process-button')} </button> <!-- <button @click="${this.stopSigningProcess}" ?disabled="${this.uploadInProgress}" id="cancel-signing-process" - class="button is-right ${classMap({hidden: !this.signingProcessActive})}"> + class="button is-right ${classMap({ + hidden: !this.signingProcessActive, + })}"> ${i18n.t('qualified-pdf-upload.stop-signing-process-button')} </button> --> </div> <!-- List of queued files --> - <div class="control file-list ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="control file-list ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${this.getQueuedFilesHtml()} </div> <!-- Text "queue empty" --> - <div class="empty-queue control ${classMap({hidden: this.queuedFilesCount !== 0, "is-disabled": this.isUserInterfaceDisabled()})}"> - ${i18n.t('qualified-pdf-upload.queued-files-empty1')}<br /> + <div + class="empty-queue control ${classMap({ + hidden: this.queuedFilesCount !== 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> + ${i18n.t('qualified-pdf-upload.queued-files-empty1')} + <br /> ${i18n.t('qualified-pdf-upload.queued-files-empty2')} </div> </div> <!-- List of signed PDFs --> - <div class="files-block field ${classMap({hidden: this.signedFilesCount === 0, "is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="files-block field ${classMap({ + hidden: this.signedFilesCount === 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> <h3>${i18n.t('qualified-pdf-upload.signed-files-label')}</h3> <!-- Button to download all signed PDFs --> <div class="field ${classMap({hidden: this.signedFilesCount === 0})}"> <div class="control"> - <button @click="${this.clearSignedFiles}" - class="button"> + <button @click="${this.clearSignedFiles}" class="button"> ${i18n.t('qualified-pdf-upload.clear-all')} </button> - <dbp-button id="zip-download-button" - value="${i18n.t('qualified-pdf-upload.download-zip-button')}" - title="${i18n.t('qualified-pdf-upload.download-zip-button-tooltip')}" - class="is-right" - @click="${this.zipDownloadClickHandler}" - type="is-primary"></dbp-button> + <dbp-button + id="zip-download-button" + value="${i18n.t( + 'qualified-pdf-upload.download-zip-button' + )}" + title="${i18n.t( + 'qualified-pdf-upload.download-zip-button-tooltip' + )}" + class="is-right" + @click="${this.zipDownloadClickHandler}" + type="is-primary"></dbp-button> </div> </div> - <div class="control"> - ${this.getSignedFilesHtml()} - </div> + <div class="control">${this.getSignedFilesHtml()}</div> </div> <!-- List of errored files --> - <div class="files-block error-files field ${classMap({hidden: this.errorFilesCount === 0, "is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="files-block error-files field ${classMap({ + hidden: this.errorFilesCount === 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> <h3>${i18n.t('qualified-pdf-upload.error-files-label')}</h3> <!-- Button to upload errored files again --> <div class="field ${classMap({hidden: this.errorFilesCount === 0})}"> <div class="control"> - <button @click="${this.clearErrorFiles}" - class="button"> + <button @click="${this.clearErrorFiles}" class="button"> ${i18n.t('qualified-pdf-upload.clear-all')} </button> - <dbp-button id="re-upload-all-button" - ?disabled="${this.uploadInProgress}" - value="${i18n.t('qualified-pdf-upload.re-upload-all-button')}" - title="${i18n.t('qualified-pdf-upload.re-upload-all-button-title')}" - class="is-right" - @click="${this.reUploadAllClickHandler}" - type="is-primary"></dbp-button> + <dbp-button + id="re-upload-all-button" + ?disabled="${this.uploadInProgress}" + value="${i18n.t( + 'qualified-pdf-upload.re-upload-all-button' + )}" + title="${i18n.t( + 'qualified-pdf-upload.re-upload-all-button-title' + )}" + class="is-right" + @click="${this.reUploadAllClickHandler}" + type="is-primary"></dbp-button> </div> </div> - <div class="control"> - ${this.getErrorFilesHtml()} - </div> + <div class="control">${this.getErrorFilesHtml()}</div> </div> </div> <div class="right-container"> <!-- PDF preview --> - <div id="pdf-preview" class="field ${classMap({hidden: !this.signaturePlacementInProgress})}"> - <h3>${this.withSigBlock ? i18n.t('qualified-pdf-upload.signature-placement-label') : i18n.t('qualified-pdf-upload.preview-label')}</h3> + <div + id="pdf-preview" + class="field ${classMap({hidden: !this.signaturePlacementInProgress})}"> + <h3> + ${this.withSigBlock + ? i18n.t('qualified-pdf-upload.signature-placement-label') + : i18n.t('qualified-pdf-upload.preview-label')} + </h3> <div class="box-header"> <div class="filename"> - <strong>${this.currentFile.name}</strong> (${humanFileSize(this.currentFile !== undefined ? this.currentFile.size : 0)}) + <strong>${this.currentFile.name}</strong> + (${humanFileSize( + this.currentFile !== undefined ? this.currentFile.size : 0 + )}) </div> - <button class="button is-cancel" - @click="${this.hidePDF}"><dbp-icon name="close"></dbp-icon></button> + <button class="button is-cancel" @click="${this.hidePDF}"> + <dbp-icon name="close"></dbp-icon> + </button> </div> - <dbp-pdf-preview lang="${this.lang}" - allow-signature-rotation - signature-placeholder-image-src="${placeholderUrl}" - signature-width="80" - signature-height="29" - @dbp-pdf-preview-accept="${this.storePDFData}" - @dbp-pdf-preview-cancel="${this.hidePDF}"></dbp-pdf-preview> + <dbp-pdf-preview + lang="${this.lang}" + allow-signature-rotation + signature-placeholder-image-src="${placeholderUrl}" + signature-width="80" + signature-height="29" + @dbp-pdf-preview-accept="${this.storePDFData}" + @dbp-pdf-preview-cancel="${this.hidePDF}"></dbp-pdf-preview> </div> <!-- Annotation view --> - <div id="annotation-view" class="field ${classMap({hidden: !this.isAnnotationViewVisible || !this.allowAnnotating})}"> + <div + id="annotation-view" + class="field ${classMap({ + hidden: !this.isAnnotationViewVisible || !this.allowAnnotating, + })}"> <h2>${i18n.t('qualified-pdf-upload.annotation-view-label')}</h2> <div class="box-header"> <div class="filename"> - <strong>${this.currentFile.file !== undefined ? this.currentFile.file.name : ''}</strong> (${humanFileSize(this.currentFile.file !== undefined ? this.currentFile.file.size : 0)}) + <strong> + ${this.currentFile.file !== undefined + ? this.currentFile.file.name + : ''} + </strong> + (${humanFileSize( + this.currentFile.file !== undefined + ? this.currentFile.file.size + : 0 + )}) </div> - <button class="button is-cancel annotation" - @click="${this.hideAnnotationView}"><dbp-icon name="close" id="close-icon"></dbp-icon></button> + <button + class="button is-cancel annotation" + @click="${this.hideAnnotationView}"> + <dbp-icon name="close" id="close-icon"></dbp-icon> + </button> </div> - <dbp-pdf-annotation-view lang="${this.lang}" - @dbp-pdf-annotations-save="${this.processAnnotationEvent}" - @dbp-pdf-annotations-cancel="${this.processAnnotationCancelEvent}"></dbp-pdf-annotation-view> + <dbp-pdf-annotation-view + lang="${this.lang}" + @dbp-pdf-annotations-save="${this.processAnnotationEvent}" + @dbp-pdf-annotations-cancel="${this + .processAnnotationCancelEvent}"></dbp-pdf-annotation-view> </div> <!-- File upload progress --> - <div id="upload-progress" class="field notification is-info ${classMap({hidden: !this.uploadInProgress})}"> + <div + id="upload-progress" + class="field notification is-info ${classMap({ + hidden: !this.uploadInProgress, + })}"> <dbp-mini-spinner></dbp-mini-spinner> <strong>${this.uploadStatusFileName}</strong> ${this.uploadStatusText} </div> <!-- External auth --> - <div id="external-auth" class="files-block field ${classMap({hidden: !this.externalAuthInProgress})}"> + <div + id="external-auth" + class="files-block field ${classMap({ + hidden: !this.externalAuthInProgress, + })}"> <h3>${i18n.t('qualified-pdf-upload.current-signing-process-label')}</h3> <div class="box"> <div class="box-header"> <div class="filename"> - <strong>${this.currentFileName}</strong> (${humanFileSize(this.currentFile.file !== undefined ? this.currentFile.file.size : 0)}) + <strong>${this.currentFileName}</strong> + (${humanFileSize( + this.currentFile.file !== undefined + ? this.currentFile.file.size + : 0 + )}) </div> - <button class="button is-cancel" - title="${i18n.t('qualified-pdf-upload.stop-signing-process-button')}" - @click="${this.stopSigningProcess}"><dbp-icon name="close"></dbp-icon></button> + <button + class="button is-cancel" + title="${i18n.t( + 'qualified-pdf-upload.stop-signing-process-button' + )}" + @click="${this.stopSigningProcess}"> + <dbp-icon name="close"></dbp-icon> + </button> </div> - <external-sign-iframe id="iframe" + <external-sign-iframe + id="iframe" @signature-error="${this._onIFrameError}" - @signature-done="${this._onIFrameDone}" - ></external-sign-iframe> + @signature-done="${this._onIFrameDone}"></external-sign-iframe> </div> </div> </div> </div> </div> - <div class="notification is-warning ${classMap({hidden: this.isLoggedIn() || this.isLoading()})}"> + <div + class="notification is-warning ${classMap({ + hidden: this.isLoggedIn() || this.isLoading(), + })}"> ${i18n.t('error-login-message')} </div> - <div class="notification is-danger ${classMap({hidden: this.hasSignaturePermissions() || !this.isLoggedIn() || this.isLoading()})}"> + <div + class="notification is-danger ${classMap({ + hidden: + this.hasSignaturePermissions() || !this.isLoggedIn() || this.isLoading(), + })}"> ${i18n.t('error-permission-message')} </div> <div class="${classMap({hidden: !this.isLoading()})}"> <dbp-mini-spinner></dbp-mini-spinner> </div> - <dbp-file-sink id="file-sink" - context="${i18n.t('qualified-pdf-upload.save-field-label', {count: this.signedFilesToDownload})}" + <dbp-file-sink + id="file-sink" + context="${i18n.t('qualified-pdf-upload.save-field-label', { + count: this.signedFilesToDownload, + })}" filename="signed-documents.zip" subscribe="initial-file-handling-state:initial-file-handling-state" enabled-targets="${this.fileHandlingEnabledTargets}" @@ -797,8 +959,7 @@ class QualifiedSignaturePdfUpload extends ScopedElementsMixin(DBPSignatureLitEle nextcloud-web-dav-url="${this.nextcloudWebDavURL}" nextcloud-name="${this.nextcloudName}" nextcloud-file-url="${this.nextcloudFileURL}" - lang="${this.lang}" - ></dbp-file-sink> + lang="${this.lang}"></dbp-file-sink> `; } } diff --git a/src/dbp-qualified-signature-pdf-upload.metadata.json b/src/dbp-qualified-signature-pdf-upload.metadata.json index 8ce6b818135419613ee116ac6a39afd16d11ca85..72b2eefecaba6341168351967837dac15188db09 100644 --- a/src/dbp-qualified-signature-pdf-upload.metadata.json +++ b/src/dbp-qualified-signature-pdf-upload.metadata.json @@ -1,18 +1,18 @@ { - "element": "dbp-qualified-signature-pdf-upload", - "module_src": "dbp-qualified-signature-pdf-upload.js", - "routing_name": "qualified-pdf-upload", - "name": { - "de": "Dokument persönlich signieren", - "en": "Personally sign document" - }, - "short_name": { - "de": "Dokument persönlich signieren", - "en": "Personally sign document" - }, - "description": { - "de": "Erlaubt das Hochladen von PDF-Dokumenten, um sie mit einer persönlichen elektronischen Signatur zu versehen", - "en": "Allows upload of PDF-documents to personally sign them" - }, - "subscribe": "lang,entry-point-url,nextcloud-web-app-password-url,nextcloud-webdav-url,nextcloud-name,nextcloud-auth-info,nextcloud-file-url,file-handling-enabled-targets,auth,allow-annotating" + "element": "dbp-qualified-signature-pdf-upload", + "module_src": "dbp-qualified-signature-pdf-upload.js", + "routing_name": "qualified-pdf-upload", + "name": { + "de": "Dokument persönlich signieren", + "en": "Personally sign document" + }, + "short_name": { + "de": "Dokument persönlich signieren", + "en": "Personally sign document" + }, + "description": { + "de": "Erlaubt das Hochladen von PDF-Dokumenten, um sie mit einer persönlichen elektronischen Signatur zu versehen", + "en": "Allows upload of PDF-documents to personally sign them" + }, + "subscribe": "lang,entry-point-url,nextcloud-web-app-password-url,nextcloud-webdav-url,nextcloud-name,nextcloud-auth-info,nextcloud-file-url,file-handling-enabled-targets,auth,allow-annotating" } diff --git a/src/dbp-signature-lit-element.js b/src/dbp-signature-lit-element.js index 8c17d12d3dec158a18855de4502d95de7076f91c..cd0bf33cd368e21eddfdd8ed3a0148bb50885c37 100644 --- a/src/dbp-signature-lit-element.js +++ b/src/dbp-signature-lit-element.js @@ -1,8 +1,8 @@ -import * as utils from "./utils"; -import * as commonUtils from "@dbp-toolkit/common/utils"; +import * as utils from './utils'; +import * as commonUtils from '@dbp-toolkit/common/utils'; import {BaseLitElement} from './base-element.js'; import {SignatureEntry} from './signature-entry.js'; -import {getPDFSignatureCount} from "./utils"; +import {getPDFSignatureCount} from './utils'; export default class DBPSignatureLitElement extends BaseLitElement { constructor() { @@ -14,7 +14,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { this._queueKey = 0; // will be set in function update - this.fileSourceUrl = ""; + this.fileSourceUrl = ''; this.fileSource = ''; this.nextcloudDefaultDir = ''; @@ -53,11 +53,10 @@ export default class DBPSignatureLitElement extends BaseLitElement { } /** - * @param {*} key - * @param {*} name + * @param {*} key + * @param {*} name */ async showAnnotationView(key, name) { - this.queuedFilesAnnotationModes[key] = name; console.log(name); @@ -90,8 +89,8 @@ export default class DBPSignatureLitElement extends BaseLitElement { } /** - * - * @param {*} event + * + * @param {*} event */ processAnnotationEvent(event) { let annotationDetails = event.detail; @@ -102,13 +101,13 @@ export default class DBPSignatureLitElement extends BaseLitElement { this.isAnnotationViewVisible = false; this.addAnnotationInProgress = false; - this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = "text-selected"; + this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = 'text-selected'; this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey] = true; } /** - * - * @param {*} event + * + * @param {*} event */ processAnnotationCancelEvent(event) { let key = this.currentPreviewQueueKey; @@ -117,7 +116,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { this.queuedFilesAnnotations[key] = undefined; this.disableAnnotationsForKey(key); - this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = "no-text"; + this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = 'no-text'; this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey] = false; } @@ -127,10 +126,13 @@ export default class DBPSignatureLitElement extends BaseLitElement { hideAnnotationView() { console.log('hide view - x click'); - if (this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey] !== undefined && this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey]) { - this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = "text-selected"; + if ( + this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey] !== undefined && + this.queuedFilesAnnotationSaved[this.currentPreviewQueueKey] + ) { + this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = 'text-selected'; } else { - this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = "no-text"; + this.queuedFilesAnnotationModes[this.currentPreviewQueueKey] = 'no-text'; } this.isAnnotationViewVisible = false; this.addAnnotationInProgress = false; @@ -151,7 +153,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { const activityNameEN = this.activity.getName('en'); await commonUtils.asyncObjectForEach(annotations, async (annotation) => { - console.log("annotation", annotation); + console.log('annotation', annotation); const annotationType = (annotation.annotationType || '').trim(); const organizationNumber = (annotation.organizationNumber || '').trim(); @@ -164,8 +166,16 @@ export default class DBPSignatureLitElement extends BaseLitElement { const annotationTypeData = utils.getAnnotationTypes(annotationType); pdfFactory = await utils.addKeyValuePdfAnnotationsToAnnotationFactory( - pdfFactory, activityNameDE, activityNameEN, this.auth['user-full-name'], annotationType, - annotationTypeData.name.de, annotationTypeData.name.en, organizationNumber, value); + pdfFactory, + activityNameDE, + activityNameEN, + this.auth['user-full-name'], + annotationType, + annotationTypeData.name.de, + annotationTypeData.name.en, + organizationNumber, + value + ); }); // output the AnnotationFactory as File again @@ -287,17 +297,21 @@ export default class DBPSignatureLitElement extends BaseLitElement { // add annotations if (annotations.length > 0) { file = await this.addAnnotationsToFile(file, annotations); - console.log("uploadFile file", file); + console.log('uploadFile file', file); // Also send annotations to the server so they get included in the signature block let userText = []; for (let annotation of annotations) { const annotationTypeData = utils.getAnnotationTypes(annotation['annotationType']); - const organizationNumberText = annotation['organizationNumber'] ? ` (${annotation['organizationNumber']})` : ''; + const organizationNumberText = annotation['organizationNumber'] + ? ` (${annotation['organizationNumber']})` + : ''; userText.push({ - 'description': `${annotationTypeData.name.de || ''} / ${annotationTypeData.name.en || ''}`, - 'value': annotation['value'] + organizationNumberText + description: `${annotationTypeData.name.de || ''} / ${ + annotationTypeData.name.en || '' + }`, + value: annotation['value'] + organizationNumberText, }); } formData.append('user_text', JSON.stringify(userText)); @@ -309,14 +323,13 @@ export default class DBPSignatureLitElement extends BaseLitElement { formData.append(key, params[key]); } - // I got a 60s timeout in Google Chrome and found no way to increase that await fetch(url, { method: 'POST', headers: { - 'Authorization': 'Bearer ' + this.auth.token, + Authorization: 'Bearer ' + this.auth.token, }, - body: formData + body: formData, }) .then((response) => { /* Done. Inform the user */ @@ -337,10 +350,10 @@ export default class DBPSignatureLitElement extends BaseLitElement { return; } - let data = { + let data = { fileName: file.name, status: response.status, - json: {"hydra:description": ""} + json: {'hydra:description': ''}, }; try { @@ -356,8 +369,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { this.onFileUploadFinished(data); } - onFileSourceSwitch(event) - { + onFileSourceSwitch(event) { if (event.detail.source) { this.fileSource = event.detail.source; } @@ -376,15 +388,19 @@ export default class DBPSignatureLitElement extends BaseLitElement { // add all signed pdf-files this.signedFiles.forEach((file) => { const arr = utils.convertDataURIToBinary(file.contentUrl); - const binaryFile = new File([arr], file.name, { type: utils.getDataURIContentType(file.contentUrl) }); + const binaryFile = new File([arr], file.name, { + type: utils.getDataURIContentType(file.contentUrl), + }); files.push(binaryFile); }); this.signedFilesToDownload = files.length; - this._("#file-sink").files = files; - this._("#zip-download-button").stop(); + this._('#file-sink').files = files; + this._('#zip-download-button').stop(); // mark downloaded files buttons - const spans = this.shadowRoot.querySelectorAll('.file-block > div.header > span.filename > span.bold-filename'); - spans.forEach(span => { + const spans = this.shadowRoot.querySelectorAll( + '.file-block > div.header > span.filename > span.bold-filename' + ); + spans.forEach((span) => { span.classList.remove('bold-filename'); }); } @@ -393,7 +409,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { * @param data */ onFileUploadFinished(data) { - console.log("Override me"); + console.log('Override me'); } /** @@ -405,12 +421,16 @@ export default class DBPSignatureLitElement extends BaseLitElement { async downloadFileClickHandler(file, id) { let files = []; const arr = utils.convertDataURIToBinary(file.contentUrl); - const binaryFile = new File([arr], file.name, { type: utils.getDataURIContentType(file.contentUrl) }); + const binaryFile = new File([arr], file.name, { + type: utils.getDataURIContentType(file.contentUrl), + }); files.push(binaryFile); this.signedFilesToDownload = files.length; - this._("#file-sink").files = files; + this._('#file-sink').files = files; // mark downloaded files button - const span = this.shadowRoot.querySelector('#' + id + ' > div.header > span.filename > span.bold-filename'); + const span = this.shadowRoot.querySelector( + '#' + id + ' > div.header > span.filename > span.bold-filename' + ); if (span) { span.classList.remove('bold-filename'); } @@ -420,8 +440,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { let entry = this.queuedFiles[id]; let sigCount = await getPDFSignatureCount(entry.file); this.queuedFilesNeedsPlacement.delete(id); - if (sigCount > 0) - this.queuedFilesNeedsPlacement.set(id, true); + if (sigCount > 0) this.queuedFilesNeedsPlacement.set(id, true); } storePDFData(event) { @@ -442,7 +461,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { hidePDF(event) { // reset placement mode to "auto" if no placement was confirmed previously if (this.queuedFilesSignaturePlacements[this.currentPreviewQueueKey] === undefined) { - this.queuedFilesPlacementModes[this.currentPreviewQueueKey] = "auto"; + this.queuedFilesPlacementModes[this.currentPreviewQueueKey] = 'auto'; } this.signaturePlacementInProgress = false; } @@ -451,7 +470,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { this.queuedFilesPlacementModes[key] = name; console.log(name); - if (name === "manual") { + if (name === 'manual') { this.showPreview(key, true); } else if (this.currentPreviewQueueKey === key) { this.signaturePlacementInProgress = false; @@ -472,8 +491,6 @@ export default class DBPSignatureLitElement extends BaseLitElement { this.queueFile(ev.detail.file); } - - /** * Re-Upload all failed files */ @@ -489,7 +506,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { await this.fileQueueingClickHandler(file.file, id); }); - that._("#re-upload-all-button").stop(); + that._('#re-upload-all-button').stop(); } /** @@ -509,7 +526,7 @@ export default class DBPSignatureLitElement extends BaseLitElement { * @param key * @param withSigBlock */ - async showPreview(key, withSigBlock=false) { + async showPreview(key, withSigBlock = false) { if (this.signingProcessEnabled) { return; } @@ -521,18 +538,18 @@ export default class DBPSignatureLitElement extends BaseLitElement { // start signature placement process this.signaturePlacementInProgress = true; this.withSigBlock = withSigBlock; - const previewTag = this.getScopedTagName("dbp-pdf-preview"); + const previewTag = this.getScopedTagName('dbp-pdf-preview'); await this._(previewTag).showPDF( entry.file, withSigBlock, //this.queuedFilesPlacementModes[key] === "manual", - this.queuedFilesSignaturePlacements[key]); + this.queuedFilesSignaturePlacements[key] + ); } onLanguageChanged(e) { this.lang = e.detail.lang; } - /** * Takes a failed file off of the queue * @@ -544,7 +561,6 @@ export default class DBPSignatureLitElement extends BaseLitElement { return file; } - clearSignedFiles() { this.signedFiles = []; this.signedFilesCount = 0; @@ -556,8 +572,11 @@ export default class DBPSignatureLitElement extends BaseLitElement { } isUserInterfaceDisabled() { - return this.signaturePlacementInProgress || this.externalAuthInProgress || this.uploadInProgress || this.addAnnotationInProgress; + return ( + this.signaturePlacementInProgress || + this.externalAuthInProgress || + this.uploadInProgress || + this.addAnnotationInProgress + ); } - - } diff --git a/src/dbp-signature-verification-full.js b/src/dbp-signature-verification-full.js index 2c6dfc46b89922ae7758a5ee4839227871b7e68f..562199547c984fc74432de5676b233da24f02cd7 100644 --- a/src/dbp-signature-verification-full.js +++ b/src/dbp-signature-verification-full.js @@ -2,14 +2,14 @@ import {createInstance} from './i18n.js'; import {humanFileSize} from '@dbp-toolkit/common/i18next.js'; import {css, html} from 'lit'; import {ScopedElementsMixin} from '@open-wc/scoped-elements'; -import DBPSignatureLitElement from "./dbp-signature-lit-element"; -import {PdfPreview} from "./dbp-pdf-preview"; +import DBPSignatureLitElement from './dbp-signature-lit-element'; +import {PdfPreview} from './dbp-pdf-preview'; import * as commonUtils from '@dbp-toolkit/common/utils'; import {Icon, MiniSpinner, Button} from '@dbp-toolkit/common'; import * as commonStyles from '@dbp-toolkit/common/styles'; import {classMap} from 'lit/directives/class-map.js'; import {FileSource} from '@dbp-toolkit/file-handling'; -import JSONLD from "@dbp-toolkit/common/jsonld"; +import JSONLD from '@dbp-toolkit/common/jsonld'; import {name as pkgName} from './../package.json'; import metadata from './dbp-signature-verification-full.metadata.json'; import {Activity} from './activity.js'; @@ -21,29 +21,29 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme this._i18n = createInstance(); this.lang = this._i18n.language; this.entryPointUrl = ''; - this.nextcloudWebAppPasswordURL = ""; - this.nextcloudWebDavURL = ""; - this.nextcloudName = ""; - this.nextcloudFileURL = ""; + this.nextcloudWebAppPasswordURL = ''; + this.nextcloudWebDavURL = ''; + this.nextcloudName = ''; + this.nextcloudFileURL = ''; this.verifiedFiles = []; this.verifiedFilesCount = 0; this.errorFiles = []; this.errorFilesCount = 0; - this.uploadStatusFileName = ""; - this.uploadStatusText = ""; + this.uploadStatusFileName = ''; + this.uploadStatusText = ''; this.currentFile = {}; - this.currentFileName = ""; - this.currentFilePlacementMode = ""; + this.currentFileName = ''; + this.currentFilePlacementMode = ''; this.currentFileSignaturePlacement = {}; this.verificationProcessEnabled = false; this.verificationProcessActive = false; this.previewInProgress = false; this.currentPreviewQueueKey = ''; - this.fileHandlingEnabledTargets="local"; + this.fileHandlingEnabledTargets = 'local'; // will be set in function update - this.verificationUrl = ""; + this.verificationUrl = ''; } static get scopedElements() { @@ -59,35 +59,37 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme static get properties() { return { ...super.properties, - lang: { type: String }, - entryPointUrl: { type: String, attribute: 'entry-point-url' }, - nextcloudWebAppPasswordURL: { type: String, attribute: 'nextcloud-web-app-password-url' }, - nextcloudWebDavURL: { type: String, attribute: 'nextcloud-webdav-url' }, - nextcloudName: { type: String, attribute: 'nextcloud-name' }, - nextcloudFileURL: { type: String, attribute: 'nextcloud-file-url' }, - verifiedFiles: { type: Array, attribute: false }, - verifiedFilesCount: { type: Number, attribute: false }, - queuedFilesCount: { type: Number, attribute: false }, - errorFiles: { type: Array, attribute: false }, - errorFilesCount: { type: Number, attribute: false }, - uploadInProgress: { type: Boolean, attribute: false }, - uploadStatusFileName: { type: String, attribute: false }, - uploadStatusText: { type: String, attribute: false }, - verificationProcessEnabled: { type: Boolean, attribute: false }, - verificationProcessActive: { type: Boolean, attribute: false }, - queueBlockEnabled: { type: Boolean, attribute: false }, - currentFile: { type: Object, attribute: false }, - currentFileName: { type: String, attribute: false }, - previewInProgress: { type: Boolean, attribute: false }, - isSignaturePlacement: { type: Boolean, attribute: false }, - fileHandlingEnabledTargets: { type: String, attribute: 'file-handling-enabled-targets'} + lang: {type: String}, + entryPointUrl: {type: String, attribute: 'entry-point-url'}, + nextcloudWebAppPasswordURL: {type: String, attribute: 'nextcloud-web-app-password-url'}, + nextcloudWebDavURL: {type: String, attribute: 'nextcloud-webdav-url'}, + nextcloudName: {type: String, attribute: 'nextcloud-name'}, + nextcloudFileURL: {type: String, attribute: 'nextcloud-file-url'}, + verifiedFiles: {type: Array, attribute: false}, + verifiedFilesCount: {type: Number, attribute: false}, + queuedFilesCount: {type: Number, attribute: false}, + errorFiles: {type: Array, attribute: false}, + errorFilesCount: {type: Number, attribute: false}, + uploadInProgress: {type: Boolean, attribute: false}, + uploadStatusFileName: {type: String, attribute: false}, + uploadStatusText: {type: String, attribute: false}, + verificationProcessEnabled: {type: Boolean, attribute: false}, + verificationProcessActive: {type: Boolean, attribute: false}, + queueBlockEnabled: {type: Boolean, attribute: false}, + currentFile: {type: Object, attribute: false}, + currentFileName: {type: String, attribute: false}, + previewInProgress: {type: Boolean, attribute: false}, + isSignaturePlacement: {type: Boolean, attribute: false}, + fileHandlingEnabledTargets: {type: String, attribute: 'file-handling-enabled-targets'}, }; } connectedCallback() { super.connectedCallback(); // needs to be called in a function to get the variable scope of "this" - setInterval(() => { this.handleQueuedFiles(); }, 1000); + setInterval(() => { + this.handleQueuedFiles(); + }, 1000); } /** @@ -174,7 +176,7 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme * @param ev */ onFileSelected(ev) { - console.log("File was selected: ev", ev); + console.log('File was selected: ev', ev); this.queueFile(ev.detail.file); } @@ -187,7 +189,10 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme this.errorFilesCount++; this.sendSetPropertyEvent('analytics-event', { - 'category': 'officiallyVerification', 'action': 'VerificationFailed', 'name': file.json["hydra:description"]}); + category: 'officiallyVerification', + action: 'VerificationFailed', + name: file.json['hydra:description'], + }); } /** @@ -196,7 +201,9 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme onFileUploadFinished(data) { if (data.status !== 201) { this.addToErrorFiles(data); - } else if (data.json["@type"] === "https://schema.tugraz.at/ElectronicSignatureVerificationReport" ) { + } else if ( + data.json['@type'] === 'https://schema.tugraz.at/ElectronicSignatureVerificationReport' + ) { // this doesn't seem to trigger an update() execution this.verifiedFiles.push(data.json); // this triggers the correct update() execution @@ -210,16 +217,20 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme update(changedProperties) { changedProperties.forEach((oldValue, propName) => { switch (propName) { - case "lang": + case 'lang': this._i18n.changeLanguage(this.lang); break; - case "entryPointUrl": + case 'entryPointUrl': JSONLD.getInstance(this.entryPointUrl).then((jsonld) => { let apiUrlBase; try { - apiUrlBase = jsonld.getApiUrlForEntityName("EsignElectronicSignatureVerificationReport"); + apiUrlBase = jsonld.getApiUrlForEntityName( + 'EsignElectronicSignatureVerificationReport' + ); } catch (error) { - apiUrlBase = jsonld.getApiUrlForEntityName("ElectronicSignatureVerificationReport"); + apiUrlBase = jsonld.getApiUrlForEntityName( + 'ElectronicSignatureVerificationReport' + ); } this.fileSourceUrl = apiUrlBase; }); @@ -251,7 +262,7 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme await this.fileQueueingClickHandler(file.file, id); }); - that._("#re-upload-all-button").stop(); + that._('#re-upload-all-button').stop(); } /** @@ -281,7 +292,7 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme console.log(file); // start signature placement process this.previewInProgress = true; - const previewTag = this.getScopedTagName("dbp-pdf-preview"); + const previewTag = this.getScopedTagName('dbp-pdf-preview'); await this._(previewTag).showPDF(file); } @@ -336,7 +347,6 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme grid-gap: 10px; margin-top: 10px; } - `; } @@ -356,18 +366,32 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme results.push(html` <div class="file-block"> <div class="header"> - <span class="filename"><strong>${file.name}</strong> (${humanFileSize(file.size)})</span> - <button class="button close" + <span class="filename"> + <strong>${file.name}</strong> + (${humanFileSize(file.size)}) + </span> + <button + class="button close" ?disabled="${this.verificationProcessEnabled}" - title="${i18n.t('signature-verification.remove-queued-file-button-title')}" - @click="${() => { this.takeFileFromQueue(id); }}"> - <dbp-icon name="trash"></dbp-icon></button> + title="${i18n.t( + 'signature-verification.remove-queued-file-button-title' + )}" + @click="${() => { + this.takeFileFromQueue(id); + }}"> + <dbp-icon name="trash"></dbp-icon> + </button> </div> <div class="bottom-line"> <div></div> - <button class="button" + <button + class="button" ?disabled="${this.verificationProcessEnabled}" - @click="${() => { this.showPreview(id); }}">${i18n.t('signature-verification.show-preview')}</button> + @click="${() => { + this.showPreview(id); + }}"> + ${i18n.t('signature-verification.show-preview')} + </button> </div> </div> `); @@ -388,11 +412,11 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme ids.forEach((id) => { const report = this.verifiedFiles[id]; - console.log("report", report); + console.log('report', report); let signatures = []; report.signatures.forEach((signature) => { - console.log("signature", signature); + console.log('signature', signature); signatures.push(html` <tr> @@ -400,7 +424,12 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme <td>${signature.familyName}</td> <td>${signature.nationality}</td> <td>${signature.serialNumber}</td> - <td class="${classMap({"verification-ok": signature.valueMessage === "OK"})}">${signature.valueMessage}</td> + <td + class="${classMap({ + 'verification-ok': signature.valueMessage === 'OK', + })}"> + ${signature.valueMessage} + </td> </tr> `); }); @@ -418,9 +447,7 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme <th>${i18n.t('signature-verification.serial-number')}</th> <th>${i18n.t('signature-verification.value-message')}</th> </thead> - <tbody> - ${signatures} - </tbody> + <tbody>${signatures}</tbody> </table> <div class="${classMap({hidden: signatures.length !== 0})}"> ${i18n.t('signature-verification.no-signatures-found')} @@ -452,19 +479,35 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme results.push(html` <div class="file-block error"> <div class="header"> - <span class="filename"><strong>${data.file.name}</strong> (${humanFileSize(data.file.size)})</span> + <span class="filename"> + <strong>${data.file.name}</strong> + (${humanFileSize(data.file.size)}) + </span> <div class="buttons"> - <button class="button" - title="${i18n.t('signature-verification.re-upload-file-button-title')}" - @click="${() => {this.fileQueueingClickHandler(data.file, id);}}"><dbp-icon name="reload"></dbp-icon></button> - <button class="button" - title="${i18n.t('signature-verification.remove-failed-file-button-title')}" - @click="${() => { this.takeFailedFileFromQueue(id); }}"> - <dbp-icon name="trash"></dbp-icon></button> + <button + class="button" + title="${i18n.t( + 'signature-verification.re-upload-file-button-title' + )}" + @click="${() => { + this.fileQueueingClickHandler(data.file, id); + }}"> + <dbp-icon name="reload"></dbp-icon> + </button> + <button + class="button" + title="${i18n.t( + 'signature-verification.remove-failed-file-button-title' + )}" + @click="${() => { + this.takeFailedFileFromQueue(id); + }}"> + <dbp-icon name="trash"></dbp-icon> + </button> </div> </div> <div class="bottom-line"> - <strong class="error">${data.json["hydra:description"]}</strong> + <strong class="error">${data.json['hydra:description']}</strong> </div> </div> `); @@ -479,24 +522,29 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme render() { const i18n = this._i18n; - const placeholderUrl = commonUtils.getAssetURL(pkgName, 'official-signature-placeholder.png'); + const placeholderUrl = commonUtils.getAssetURL( + pkgName, + 'official-signature-placeholder.png' + ); const activity = new Activity(metadata); return html` - <div class="${classMap({hidden: !this.isLoggedIn() || !this.hasSignaturePermissions() || this.isLoading()})}"> + <div + class="${classMap({ + hidden: + !this.isLoggedIn() || !this.hasSignaturePermissions() || this.isLoading(), + })}"> <div class="field"> <h2>${activity.getName(this.lang)}</h2> - <p class="subheadline"> - ${activity.getDescription(this.lang)} - </p> + <p class="subheadline">${activity.getDescription(this.lang)}</p> <div class="control"> - - <p> - ${i18n.t('signature-verification.upload-text')} - </p> - <button @click="${() => { this._("#file-source").setAttribute("dialog-open", ""); }}" - ?disabled="${this.signingProcessActive}" - class="button is-primary"> + <p>${i18n.t('signature-verification.upload-text')}</p> + <button + @click="${() => { + this._('#file-source').setAttribute('dialog-open', ''); + }}" + ?disabled="${this.signingProcessActive}" + class="button is-primary"> ${i18n.t('signature-verification.upload-button-label')} </button> <dbp-file-source @@ -514,96 +562,142 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme text="${i18n.t('signature-verification.upload-area-text')}" button-label="${i18n.t('signature-verification.upload-button-label')}" @dbp-file-source-file-selected="${this.onFileSelected}" - @dbp-file-source-switched="${this.onFileSourceSwitch}" - ></dbp-file-source> + @dbp-file-source-switched="${this + .onFileSourceSwitch}"></dbp-file-source> </div> </div> <div id="grid-container"> <div class="left-container"> - <div class="files-block field ${classMap({hidden: !this.queueBlockEnabled})}"> + <div + class="files-block field ${classMap({ + hidden: !this.queueBlockEnabled, + })}"> <!-- Queued files headline and queueing spinner --> - <h3 class="${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <h3 + class="${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${i18n.t('signature-verification.queued-files-label')} </h3> <!-- Buttons to start/stop verification process and clear queue --> <div class="control field"> - <button @click="${this.clearQueuedFiles}" - ?disabled="${this.queuedFilesCount === 0 || this.verificationProcessActive || this.isUserInterfaceDisabled()}" - class="button ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <button + @click="${this.clearQueuedFiles}" + ?disabled="${this.queuedFilesCount === 0 || + this.verificationProcessActive || + this.isUserInterfaceDisabled()}" + class="button ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${i18n.t('signature-verification.clear-all')} </button> - <button @click="${() => { this.verificationProcessEnabled = true; this.verificationProcessActive = true; }}" - ?disabled="${this.queuedFilesCount === 0}" - class="button is-right is-primary ${classMap( - { - "is-disabled": this.isUserInterfaceDisabled(), - hidden: this.verificationProcessActive - })}"> - ${i18n.t('signature-verification.start-verification-process-button')} + <button + @click="${() => { + this.verificationProcessEnabled = true; + this.verificationProcessActive = true; + }}" + ?disabled="${this.queuedFilesCount === 0}" + class="button is-right is-primary ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + hidden: this.verificationProcessActive, + })}"> + ${i18n.t( + 'signature-verification.start-verification-process-button' + )} </button> <!-- --> - <button @click="${this.stopVerificationProcess}" - ?disabled="${this.uploadInProgress}" - id="cancel-verification-process" - class="button is-right ${classMap({hidden: !this.verificationProcessActive})}"> - ${i18n.t('signature-verification.stop-verification-process-button')} + <button + @click="${this.stopVerificationProcess}" + ?disabled="${this.uploadInProgress}" + id="cancel-verification-process" + class="button is-right ${classMap({ + hidden: !this.verificationProcessActive, + })}"> + ${i18n.t( + 'signature-verification.stop-verification-process-button' + )} </button> <!-- --> </div> <!-- List of queued files --> - <div class="control file-list ${classMap({"is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="control file-list ${classMap({ + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> ${this.getQueuedFilesHtml()} </div> <!-- Text "queue empty" --> - <div class="empty-queue control ${classMap({hidden: this.queuedFilesCount !== 0, "is-disabled": this.isUserInterfaceDisabled()})}"> - ${i18n.t('signature-verification.queued-files-empty1')}<br /> + <div + class="empty-queue control ${classMap({ + hidden: this.queuedFilesCount !== 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> + ${i18n.t('signature-verification.queued-files-empty1')} + <br /> ${i18n.t('signature-verification.queued-files-empty2')} </div> </div> <!-- List of errored files --> - <div class="files-block error-files field ${classMap({hidden: this.errorFilesCount === 0, "is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="files-block error-files field ${classMap({ + hidden: this.errorFilesCount === 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> <h3>${i18n.t('signature-verification.error-files-label')}</h3> <!-- Button to upload errored files again --> <div class="field ${classMap({hidden: this.errorFilesCount === 0})}"> <div class="control"> - <button @click="${this.clearErrorFiles}" - class="button"> + <button @click="${this.clearErrorFiles}" class="button"> ${i18n.t('signature-verification.clear-all')} </button> - <dbp-button id="re-upload-all-button" - ?disabled="${this.uploadInProgress}" - value="${i18n.t('signature-verification.re-upload-all-button')}" - title="${i18n.t('signature-verification.re-upload-all-button-title')}" - class="is-right" - @click="${this.reUploadAllClickHandler}" - type="is-primary"></dbp-button> + <dbp-button + id="re-upload-all-button" + ?disabled="${this.uploadInProgress}" + value="${i18n.t( + 'signature-verification.re-upload-all-button' + )}" + title="${i18n.t( + 'signature-verification.re-upload-all-button-title' + )}" + class="is-right" + @click="${this.reUploadAllClickHandler}" + type="is-primary"></dbp-button> </div> </div> - <div class="control"> - ${this.getErrorFilesHtml()} - </div> + <div class="control">${this.getErrorFilesHtml()}</div> </div> </div> <div class="right-container"> <!-- PDF preview --> - <div id="pdf-preview" class="field ${classMap({hidden: !this.previewInProgress})}"> + <div + id="pdf-preview" + class="field ${classMap({hidden: !this.previewInProgress})}"> <h2>${i18n.t('signature-verification.preview-label')}</h2> <div class="box-header"> <div class="filename"> - <strong>${this.currentFile.name}</strong> (${humanFileSize(this.currentFile !== undefined ? this.currentFile.size : 0)}) + <strong>${this.currentFile.name}</strong> + (${humanFileSize( + this.currentFile !== undefined ? this.currentFile.size : 0 + )}) </div> - <button class="button is-cancel" - @click="${this.hidePDF}"><dbp-icon name="close"></dbp-icon></button> + <button class="button is-cancel" @click="${this.hidePDF}"> + <dbp-icon name="close"></dbp-icon> + </button> </div> - <dbp-pdf-preview lang="${this.lang}" - allow-signature-rotation - signature-placeholder-image-src="${placeholderUrl}" - signature-width="146" - signature-height="42" - @dbp-pdf-preview-cancel="${this.hidePDF}"></dbp-pdf-preview> + <dbp-pdf-preview + lang="${this.lang}" + allow-signature-rotation + signature-placeholder-image-src="${placeholderUrl}" + signature-width="146" + signature-height="42" + @dbp-pdf-preview-cancel="${this.hidePDF}"></dbp-pdf-preview> </div> <!-- File upload progress --> - <div id="upload-progress" class="field notification is-info ${classMap({hidden: !this.uploadInProgress})}"> + <div + id="upload-progress" + class="field notification is-info ${classMap({ + hidden: !this.uploadInProgress, + })}"> <dbp-mini-spinner></dbp-mini-spinner> <strong>${this.uploadStatusFileName}</strong> ${this.uploadStatusText} @@ -611,26 +705,34 @@ class SignatureVerificationFull extends ScopedElementsMixin(DBPSignatureLitEleme </div> </div> <!-- List of verified PDFs --> - <div class="verified-files files-block field ${classMap({hidden: this.verifiedFilesCount === 0, "is-disabled": this.isUserInterfaceDisabled()})}"> + <div + class="verified-files files-block field ${classMap({ + hidden: this.verifiedFilesCount === 0, + 'is-disabled': this.isUserInterfaceDisabled(), + })}"> <h3>${i18n.t('signature-verification.verified-files-label')}</h3> <!-- Button to clear verified PDFs --> <div class="field ${classMap({hidden: this.verifiedFilesCount === 0})}"> <div class="control"> - <button @click="${this.clearVerifiedFiles}" - class="button"> + <button @click="${this.clearVerifiedFiles}" class="button"> ${i18n.t('signature-verification.clear-all')} </button> </div> </div> - <div class="control"> - ${this.getVerifiedFilesHtml()} - </div> + <div class="control">${this.getVerifiedFilesHtml()}</div> </div> </div> - <div class="notification is-warning ${classMap({hidden: this.isLoggedIn() || this.isLoading()})}"> + <div + class="notification is-warning ${classMap({ + hidden: this.isLoggedIn() || this.isLoading(), + })}"> ${i18n.t('error-login-message')} </div> - <div class="notification is-danger ${classMap({hidden: this.hasSignaturePermissions() || !this.isLoggedIn() || this.isLoading()})}"> + <div + class="notification is-danger ${classMap({ + hidden: + this.hasSignaturePermissions() || !this.isLoggedIn() || this.isLoading(), + })}"> ${i18n.t('error-permission-message')} </div> <div class="${classMap({hidden: !this.isLoading()})}"> diff --git a/src/dbp-signature-verification-full.metadata.json b/src/dbp-signature-verification-full.metadata.json index 3e5a5f0d4307b38a7c87ff72816152cb8042a9b2..62c1cff485b506834669e1f4b4fbbd74ff055eef 100644 --- a/src/dbp-signature-verification-full.metadata.json +++ b/src/dbp-signature-verification-full.metadata.json @@ -1,18 +1,18 @@ { - "element": "dbp-signature-verification-full", - "module_src": "dbp-signature-verification-full.js", - "routing_name": "signature-verification-full", - "name": { - "de": "Signierte Dokumente verifizieren", - "en": "Verify signed documents" - }, - "short_name": { - "de": "Signierte Dokumente verifizieren", - "en": "Verify signed documents" - }, - "description": { - "de": "Erlaubt das Verifizieren von signierten PDF-Dokumenten", - "en": "Allows verification of signed PDF-documents" - }, - "subscribe": "lang,entry-point-url,nextcloud-web-app-password-url,nextcloud-webdav-url,nextcloud-name,nextcloud-file-url,file-handling-enabled-targets,auth" + "element": "dbp-signature-verification-full", + "module_src": "dbp-signature-verification-full.js", + "routing_name": "signature-verification-full", + "name": { + "de": "Signierte Dokumente verifizieren", + "en": "Verify signed documents" + }, + "short_name": { + "de": "Signierte Dokumente verifizieren", + "en": "Verify signed documents" + }, + "description": { + "de": "Erlaubt das Verifizieren von signierten PDF-Dokumenten", + "en": "Allows verification of signed PDF-documents" + }, + "subscribe": "lang,entry-point-url,nextcloud-web-app-password-url,nextcloud-webdav-url,nextcloud-name,nextcloud-file-url,file-handling-enabled-targets,auth" } diff --git a/src/dbp-signature-verification.js b/src/dbp-signature-verification.js index 0c2bcb993d15b5c76c01b9ec4cb34a4511ce7fd2..d69b5b8e9ba1af6e944d175f152667ce5f196116 100644 --- a/src/dbp-signature-verification.js +++ b/src/dbp-signature-verification.js @@ -1,13 +1,12 @@ import {createInstance} from './i18n.js'; import {css, html} from 'lit'; import {ScopedElementsMixin} from '@open-wc/scoped-elements'; -import DBPSignatureLitElement from "./dbp-signature-lit-element"; +import DBPSignatureLitElement from './dbp-signature-lit-element'; import * as commonUtils from '@dbp-toolkit/common/utils'; import * as commonStyles from '@dbp-toolkit/common/styles'; import metadata from './dbp-signature-verification.metadata.json'; import {Activity} from './activity.js'; - class SignatureVerification extends ScopedElementsMixin(DBPSignatureLitElement) { constructor() { super(); @@ -16,20 +15,20 @@ class SignatureVerification extends ScopedElementsMixin(DBPSignatureLitElement) } static get scopedElements() { - return { }; + return {}; } static get properties() { return { ...super.properties, - lang: { type: String }, + lang: {type: String}, }; } update(changedProperties) { changedProperties.forEach((oldValue, propName) => { switch (propName) { - case "lang": + case 'lang': this._i18n.changeLanguage(this.lang); break; } @@ -59,18 +58,18 @@ class SignatureVerification extends ScopedElementsMixin(DBPSignatureLitElement) margin-bottom: 0px; } - .int-link-internal{ + .int-link-internal { transition: background-color 0.15s, color 0.15s; border-bottom: var(--dbp-border-dark); } - - .int-link-internal:hover{ + + .int-link-internal:hover { background-color: var(--dbp-hover-base); color: var(--dbp-hover-text); } - - .int-link-internal:after{ - content: "\\00a0\\00a0\\00a0"; + + .int-link-internal:after { + content: '\\00a0\\00a0\\00a0'; background-image: url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3Ardf%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20height%3D%228.6836mm%22%20width%3D%225.2043mm%22%20version%3D%221.1%22%20xmlns%3Acc%3D%22http%3A%2F%2Fcreativecommons.org%2Fns%23%22%20xmlns%3Adc%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%22%20viewBox%3D%220%200%2018.440707%2030.768605%22%3E%3Cg%20transform%3D%22translate(-382.21%20-336.98)%22%3E%3Cpath%20style%3D%22stroke-linejoin%3Around%3Bstroke%3A%23000%3Bstroke-linecap%3Around%3Bstroke-miterlimit%3A10%3Bstroke-width%3A2%3Bfill%3Anone%22%20d%3D%22m383.22%20366.74%2016.43-14.38-16.43-14.37%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E'); background-size: 73%; background-repeat: no-repeat; @@ -80,9 +79,9 @@ class SignatureVerification extends ScopedElementsMixin(DBPSignatureLitElement) animation: 0.15s linkIconOut; font-size: 103%; } - - .int-link-internal:hover::after{ - content: "\\00a0\\00a0\\00a0"; + + .int-link-internal:hover::after { + content: '\\00a0\\00a0\\00a0'; background-image: url('data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3Ardf%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20height%3D%228.6836mm%22%20width%3D%225.2043mm%22%20version%3D%221.1%22%20xmlns%3Acc%3D%22http%3A%2F%2Fcreativecommons.org%2Fns%23%22%20xmlns%3Adc%3D%22http%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%22%20viewBox%3D%220%200%2018.440707%2030.768605%22%3E%3Cg%20transform%3D%22translate(-382.21%20-336.98)%22%3E%3Cpath%20style%3D%22stroke-linejoin%3Around%3Bstroke%3A%23FFF%3Bstroke-linecap%3Around%3Bstroke-miterlimit%3A10%3Bstroke-width%3A2%3Bfill%3Anone%22%20d%3D%22m383.22%20366.74%2016.43-14.38-16.43-14.37%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E'); background-size: 73%; background-repeat: no-repeat; @@ -93,7 +92,7 @@ class SignatureVerification extends ScopedElementsMixin(DBPSignatureLitElement) font-size: 103%; } - .subheadline{ + .subheadline { font-style: italic; padding-left: 2em; margin-top: -1px; @@ -108,16 +107,16 @@ class SignatureVerification extends ScopedElementsMixin(DBPSignatureLitElement) const activity = new Activity(metadata); return html` <h2>${activity.getName(this.lang)}</h2> - <p class="subheadline"> - ${activity.getDescription(this.lang)} - </p> - <p> - ${i18n.t('signature-verification-extern.description-text')} - </p> - <a target="_blank" rel="noopener" class="int-link-internal" href="https://www.signaturpruefung.gv.at">${i18n.t('signature-verification-extern.link-label')}</a> - <p> - ${i18n.t('signature-verification-extern.adobe-reader-text')} - </p> + <p class="subheadline">${activity.getDescription(this.lang)}</p> + <p>${i18n.t('signature-verification-extern.description-text')}</p> + <a + target="_blank" + rel="noopener" + class="int-link-internal" + href="https://www.signaturpruefung.gv.at"> + ${i18n.t('signature-verification-extern.link-label')} + </a> + <p>${i18n.t('signature-verification-extern.adobe-reader-text')}</p> <slot name="additional-information"></slot> `; } diff --git a/src/dbp-signature-verification.metadata.json b/src/dbp-signature-verification.metadata.json index 8a688b40d9c4a14668abefb3b545f4303938b856..d8110dcb7cf8bc42784c2602cf9b492e516a7900 100644 --- a/src/dbp-signature-verification.metadata.json +++ b/src/dbp-signature-verification.metadata.json @@ -1,18 +1,18 @@ { - "element": "dbp-signature-verification", - "module_src": "dbp-signature-verification.js", - "routing_name": "signature-verification", - "name": { - "de": "Signierte Dokumente verifizieren", - "en": "Verify signed documents" - }, - "short_name": { - "de": "Signierte Dokumente verifizieren", - "en": "Verify signed documents" - }, - "description": { - "de": "Erlaubt das Verifizieren von signierten PDF-Dokumenten", - "en": "Allows verification of signed PDF-documents" - }, - "subscribe": "lang,entry-point-url,auth,html-overrides" + "element": "dbp-signature-verification", + "module_src": "dbp-signature-verification.js", + "routing_name": "signature-verification", + "name": { + "de": "Signierte Dokumente verifizieren", + "en": "Verify signed documents" + }, + "short_name": { + "de": "Signierte Dokumente verifizieren", + "en": "Verify signed documents" + }, + "description": { + "de": "Erlaubt das Verifizieren von signierten PDF-Dokumenten", + "en": "Allows verification of signed PDF-documents" + }, + "subscribe": "lang,entry-point-url,auth,html-overrides" } diff --git a/src/dbp-signature.js b/src/dbp-signature.js index d8e83b1d03dc28f37ba1a0eb64297fd8204517c7..81661050707422ca382e267700306bffab452425 100644 --- a/src/dbp-signature.js +++ b/src/dbp-signature.js @@ -1,7 +1,7 @@ import {AppShell} from '@dbp-toolkit/app-shell'; import * as commonUtils from '@dbp-toolkit/common/utils'; -import {Translated} from "@dbp-toolkit/common/src/translated"; -import {TUGrazLogo} from "@dbp-toolkit/app-shell/src/tugraz-logo"; +import {Translated} from '@dbp-toolkit/common/src/translated'; +import {TUGrazLogo} from '@dbp-toolkit/app-shell/src/tugraz-logo'; commonUtils.defineCustomElement('dbp-signature', AppShell); commonUtils.defineCustomElement('dbp-translated', Translated); diff --git a/src/ext-sign-iframe.js b/src/ext-sign-iframe.js index b760134fc72a1ac649fc518936d918e2fbce9ea6..a8bb341e3bd40a427f387ee0db098d7a94d05e15 100644 --- a/src/ext-sign-iframe.js +++ b/src/ext-sign-iframe.js @@ -5,13 +5,12 @@ import {ScopedElementsMixin} from '@open-wc/scoped-elements'; /** * Set the URL via setUrl(), reset via reset(). - * + * * Emits two custom events: * signature-error with a "message" * signature-done with an "id" */ export class ExternalSignIFrame extends ScopedElementsMixin(LitElement) { - constructor() { super(); this._loading = false; @@ -20,13 +19,13 @@ export class ExternalSignIFrame extends ScopedElementsMixin(LitElement) { static get scopedElements() { return { - 'dbp-mini-spinner': MiniSpinner, + 'dbp-mini-spinner': MiniSpinner, }; } static get properties() { return { - _loading: { type: Boolean, attribute: false }, + _loading: {type: Boolean, attribute: false}, }; } @@ -47,28 +46,32 @@ export class ExternalSignIFrame extends ScopedElementsMixin(LitElement) { if (data.cause) { error = `${error}: ${data.cause}`; } - this.dispatchEvent(new CustomEvent('signature-error', { - detail: { - message: error, - } - })); + this.dispatchEvent( + new CustomEvent('signature-error', { + detail: { + message: error, + }, + }) + ); } else if (data.type === 'pdf-as-callback') { - this.dispatchEvent(new CustomEvent('signature-done', { - detail: { - id: data.sessionId, - } - })); + this.dispatchEvent( + new CustomEvent('signature-done', { + detail: { + id: data.sessionId, + }, + }) + ); } } setUrl(url) { - let iframe = this.renderRoot.querySelector("#iframe"); + let iframe = this.renderRoot.querySelector('#iframe'); this._loading = true; iframe.src = url; } reset() { - this.setUrl("about:blank"); + this.setUrl('about:blank'); } static get styles() { @@ -93,18 +96,23 @@ export class ExternalSignIFrame extends ScopedElementsMixin(LitElement) { } render() { - let onDone = (event) => { this._loading = false; }; return html` - ${ this._loading ? html`<dbp-mini-spinner></dbp-mini-spinner>` : html`` } + ${this._loading + ? html` + <dbp-mini-spinner></dbp-mini-spinner> + ` + : html``} <!-- "scrolling" is deprecated, but still seem to help --> - <iframe id="iframe" class=${classMap({hidden: this._loading})} + <iframe + id="iframe" + class=${classMap({hidden: this._loading})} @load="${onDone}" @error="${onDone}" scrolling="no"></iframe> `; } -} \ No newline at end of file +} diff --git a/src/i18n.js b/src/i18n.js index 975c1993e2a567940c74f8d957a6b2a018125548..0c6fedc883e4f02965df30acfb47fa37e11a268c 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -5,4 +5,4 @@ import en from './i18n/en/translation.json'; export function createInstance() { return _createInstance({en: en, de: de}, 'de', 'en'); -} \ No newline at end of file +} diff --git a/src/i18n/de/translation.json b/src/i18n/de/translation.json index 74465c51c80f85330bc0cf1b60417f2d5f29a721..0f4772ccc3b41b2efa87be3da38559121bdf19a4 100644 --- a/src/i18n/de/translation.json +++ b/src/i18n/de/translation.json @@ -1,141 +1,141 @@ { - "official-pdf-upload": { - "upload-text": "Die Amtssignatur des \"Elektronische Signaturservice\" ist eine Applikation, mit der Sie PDF-Dateien mit einer elektronischen Amtssignatur versehen können.", - "upload-area-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument per Drag & Drop oder per Direktauswahl hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.", - "queued-files-label": "Dokumente in der Warteschlange", - "queued-files-empty1": "Kein Dokument in der Warteschlange", - "queued-files-empty2": "Sie können jetzt ein neues Dokument hochladen", - "remove-failed-file-button-title": "Fehlgeschlagenes Dokument entfernen", - "remove-queued-file-button-title": "Dokument aus der Warteschlange entfernen", - "clear-all": "Alle entfernen", - "start-signing-process-button": "Signatur starten", - "stop-signing-process-button": "Unterbrechen", - "show-preview": "Dokument anzeigen", - "positioning-automatic": "Auto", - "positioning-manual": "Manuell", - "preview-label": "Dokumentenansicht", - "signed-files-label": "Signierte Dokumente", - "download-zip-button": "Alle speichern unter", - "download-zip-button-tooltip": "Alle signierten Dokumente speichern", - "upload-button-label": "PDF-Dokumente auswählen", - "download-file-button-title": "Signiertes PDF Dokument speichern", - "error-files-label": "Fehlgeschlagene Dokumente", - "re-upload-file-button-title": "Erneut in die Warteschlange stellen", - "upload-status-file-text": "({{fileSize}}) wird hochgeladen und verarbeitet...", - "re-upload-all-button": "Alle wiederholen", - "re-upload-all-button-title": "Alle fehlgeschlagen Signaturvorgänge erneut in die Warteschlange stellen", - "signature-placement-label": "Signatur platzieren", - "positioning": "Positionierung", - "confirm-page-leave": "Sind Sie sicher, dass Sie die Seite verlassen wollen? Es stehen signierte Dokumente zum Download bereit.", - "file-picker-context": "PDF-Dokumente zum Signieren auswählen (max. 32 MB pro Datei)", - "annotation": "Anmerkungen", - "annotation-no": "Nein", - "annotation-yes": "Ja", - "annotation-view-label": "Anmerkungen zu Dokument hinzufügen" - }, - "qualified-pdf-upload": { - "save-field-label": "{{count}} Datei speichern", - "save-field-label_plural": "{{count}} Dateien speichern", - "upload-text": "Das \"Elektronische Signaturservice\" ist eine Applikation, mit der Sie PDF-Dateien mit einer persönlichen, elektronischen (qualifizierten) Signatur versehen können. Eine qualifizierte Signatur ist Ihre persönliche Unterschrift im Internet und der eigenhändigen Unterschrift rechtlich gleichgestellt.", - "upload-area-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument per Drag & Drop oder per Direktauswahl hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.", - "current-signing-process-label": "Aktueller Signaturprozess", - "queued-files-label": "Dokumente in der Warteschlange", - "queued-files-empty1": "Kein Dokument in der Warteschlange", - "queued-files-empty2": "Sie können jetzt ein neues Dokument hochladen", - "remove-failed-file-button-title": "Fehlgeschlagenes Dokument entfernen", - "remove-queued-file-button-title": "Dokument aus der Warteschlange entfernen", - "clear-all": "Alle entfernen", - "start-signing-process-button": "Signatur starten", - "stop-signing-process-button": "Unterbrechen", - "show-preview": "Dokument anzeigen", - "positioning-automatic": "Auto", - "positioning-manual": "Manuell", - "preview-label": "Dokumentenansicht", - "signed-files-label": "Signierte Dokumente", - "download-zip-button": "Alle speichern unter", - "download-zip-button-tooltip": "Alle signierten Dokumente speichern", - "upload-button-label": "PDF-Dokumente auswählen", - "download-file-button-title": "Signiertes PDF Dokument speichern", - "error-files-label": "Fehlgeschlagene Dokumente", - "re-upload-file-button-title": "Erneut in die Warteschlange stellen", - "upload-status-file-text": "({{fileSize}}) wird hochgeladen und verarbeitet...", - "re-upload-all-button": "Alle wiederholen", - "re-upload-all-button-title": "Alle fehlgeschlagen Signaturvorgänge erneut in die Warteschlange stellen", - "signature-placement-label": "Signatur platzieren", - "positioning": "Positionierung", - "confirm-page-leave": "Sind Sie sicher, dass Sie die Seite verlassen wollen? Es stehen signierte Dokumente zum Download bereit.", - "file-picker-context": "PDF-Dokumente zum Signieren auswählen (max. 32 MB pro Datei)", - "annotation": "Anmerkungen", - "annotation-no": "Nein", - "annotation-yes": "Ja", - "annotation-view-label": "Anmerkungen zu Dokument hinzufügen" - }, - "signature-verification": { - "upload-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.", - "upload-area-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument per Drag & Drop oder per Direktauswahl hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.", - "queued-files-label": "Dokumente in der Warteschlange", - "queued-files-empty1": "Kein Dokument in der Warteschlange", - "queued-files-empty2": "Sie können jetzt ein neues Dokument hochladen", - "remove-failed-file-button-title": "Fehlgeschlagenes Dokument entfernen", - "remove-queued-file-button-title": "Dokument aus der Warteschlange entfernen", - "clear-all": "Alle entfernen", - "start-verification-process-button": "Verifikation starten", - "stop-verification-process-button": "Verifikation unterbrechen", - "show-preview": "Dokument anzeigen", - "preview-label": "Dokumentenansicht", - "verified-files-label": "Verifizierte Dokumente", - "upload-button-label": "PDF-Dokumente auswählen", - "error-files-label": "Fehlgeschlagene Dokumente", - "re-upload-file-button-title": "Erneut in die Warteschlange stellen", - "upload-status-file-text": "({{fileSize}}) wird hochgeladen und verifiziert...", - "re-upload-all-button": "Alle wiederholen", - "re-upload-all-button-title": "Alle fehlgeschlagenen Verifikationsprozesse erneut in die Warteschlange stellen", - "given-name": "Vorname", - "last-name": "Nachname", - "nationality": "Nationalität", - "serial-number": "Seriennummer", - "value-message": "Überprüfung", - "no-signatures-found": "Es wurden keine Signaturen gefunden.", - "confirm-page-leave": "Sind Sie sicher, dass Sie die Seite verlassen wollen? Es stehen signierte Dokumente zum Download bereit.", - "file-picker-context": "PDF-Dokumente zum Verifizieren auswählen (max. 32 MB pro Datei)" - }, - "signature-verification-extern": { - "description-text": "Um eine PDF-Signatur auf ihre Gültigkeit zu überprüfen, benutzen Sie bitte das Verifikationsservice der Rundfunk und Telekom Regulierungs-GmbH. Mit diesem Verifikationsservice können Sie überprüfen, ob das Dokument eine valide Signatur enthält.", - "link-label": "Zum RTR Verifikationsservice wechseln", - "adobe-reader-text": "Des Weiteren besteht auch die Möglichkeit, das Dokument lokal mit dem Adobe Reader zu überprüfen." - }, - "pdf-preview": { - "first-page": "Erste Seite", - "previous-page": "Vorherige Seite", - "next-page": "Nächste Seite", - "last-page": "Letzte Seite", - "page-count": "von {{totalPages}}", - "rotate-signature": "Signatur im Uhrzeigersinn rotieren", - "rotate": "Signatur rotieren", - "continue": "Platzierung bestätigen", - "error-message": "Fehler: Dieses Dokument ist beschädigt." - }, - "annotation-view": { - "delete-all-button-text": "Alle entfernen", - "delete-all-button-title": "Alle entfernen", - "save-all-button-text": "Für Dokument übernehmen", - "save-all-button-title": "Für Dokument übernehmen", - "insert-field": "Neues Feld einfügen", - "remove-field": "Feld löschen", - "businessnumber-placeholder": "Fügen Sie hier die Geschäftszahl ein (z.B. 247/1/2020-S)", - "intended-use-placeholder": "Fügen Sie hier den gewünschten Text ein", - "introduction": "In diesem Bereich können Sie zusätzlichen Text definieren, der in der Signatur enthalten sein soll. Klicken Sie dafür auf \"Neues Feld einfügen\" und wählen Sie das gewünschte Feld aus. Klicken Sie dann auf das \"+\" um das Feld einzufügen und den gewünschten Text einzugeben.", - "empty-annotation-title": "{{annotationType}} ist leer!", - "empty-annotation-message": "Bitte tragen Sie einen Wert für die gewählte Anmerkung ein.", - "empty-organization-title": "Organisation wurde nicht ausgewählt!", - "empty-organization-message": "Bitte wählen Sie Ihre Organisation aus, bevor Sie die gewählte Anmerkung übernehmen.", - "invalid-annotation-text-title": "Ungültiger Eingabewert!", - "invalid-annotation-text-message": "Sie haben ein oder mehrere ungültige Zeichen eingegeben. Zulässige Sonderzeichen sind: \\/ !=+-_*&()" - }, - "error-permission-message": "Sie müssen das Recht auf Amtssignaturen besitzen um diese Funktion nutzen zu können!", - "error-login-message": "Sie müssen angemeldet sein um diese Funktion nutzen zu können!", - "error-cancel-message": "Der Signaturprozess wurde manuell abgebrochen.", - "error-rights-message": "Abbruch auf Grund mangelnder Rechte Ihres Accounts.", - "label-manual-positioning-missing": "Bestehende Signatur vorhanden, bitte wählen Sie ihre Positionierung manuell.", - "error-manual-positioning-missing": "Ein oder mehrere Signaturen in der Warteschlange müssen manuell positioniert werden." + "official-pdf-upload": { + "upload-text": "Die Amtssignatur des \"Elektronische Signaturservice\" ist eine Applikation, mit der Sie PDF-Dateien mit einer elektronischen Amtssignatur versehen können.", + "upload-area-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument per Drag & Drop oder per Direktauswahl hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.", + "queued-files-label": "Dokumente in der Warteschlange", + "queued-files-empty1": "Kein Dokument in der Warteschlange", + "queued-files-empty2": "Sie können jetzt ein neues Dokument hochladen", + "remove-failed-file-button-title": "Fehlgeschlagenes Dokument entfernen", + "remove-queued-file-button-title": "Dokument aus der Warteschlange entfernen", + "clear-all": "Alle entfernen", + "start-signing-process-button": "Signatur starten", + "stop-signing-process-button": "Unterbrechen", + "show-preview": "Dokument anzeigen", + "positioning-automatic": "Auto", + "positioning-manual": "Manuell", + "preview-label": "Dokumentenansicht", + "signed-files-label": "Signierte Dokumente", + "download-zip-button": "Alle speichern unter", + "download-zip-button-tooltip": "Alle signierten Dokumente speichern", + "upload-button-label": "PDF-Dokumente auswählen", + "download-file-button-title": "Signiertes PDF Dokument speichern", + "error-files-label": "Fehlgeschlagene Dokumente", + "re-upload-file-button-title": "Erneut in die Warteschlange stellen", + "upload-status-file-text": "({{fileSize}}) wird hochgeladen und verarbeitet...", + "re-upload-all-button": "Alle wiederholen", + "re-upload-all-button-title": "Alle fehlgeschlagen Signaturvorgänge erneut in die Warteschlange stellen", + "signature-placement-label": "Signatur platzieren", + "positioning": "Positionierung", + "confirm-page-leave": "Sind Sie sicher, dass Sie die Seite verlassen wollen? Es stehen signierte Dokumente zum Download bereit.", + "file-picker-context": "PDF-Dokumente zum Signieren auswählen (max. 32 MB pro Datei)", + "annotation": "Anmerkungen", + "annotation-no": "Nein", + "annotation-yes": "Ja", + "annotation-view-label": "Anmerkungen zu Dokument hinzufügen" + }, + "qualified-pdf-upload": { + "save-field-label": "{{count}} Datei speichern", + "save-field-label_plural": "{{count}} Dateien speichern", + "upload-text": "Das \"Elektronische Signaturservice\" ist eine Applikation, mit der Sie PDF-Dateien mit einer persönlichen, elektronischen (qualifizierten) Signatur versehen können. Eine qualifizierte Signatur ist Ihre persönliche Unterschrift im Internet und der eigenhändigen Unterschrift rechtlich gleichgestellt.", + "upload-area-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument per Drag & Drop oder per Direktauswahl hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.", + "current-signing-process-label": "Aktueller Signaturprozess", + "queued-files-label": "Dokumente in der Warteschlange", + "queued-files-empty1": "Kein Dokument in der Warteschlange", + "queued-files-empty2": "Sie können jetzt ein neues Dokument hochladen", + "remove-failed-file-button-title": "Fehlgeschlagenes Dokument entfernen", + "remove-queued-file-button-title": "Dokument aus der Warteschlange entfernen", + "clear-all": "Alle entfernen", + "start-signing-process-button": "Signatur starten", + "stop-signing-process-button": "Unterbrechen", + "show-preview": "Dokument anzeigen", + "positioning-automatic": "Auto", + "positioning-manual": "Manuell", + "preview-label": "Dokumentenansicht", + "signed-files-label": "Signierte Dokumente", + "download-zip-button": "Alle speichern unter", + "download-zip-button-tooltip": "Alle signierten Dokumente speichern", + "upload-button-label": "PDF-Dokumente auswählen", + "download-file-button-title": "Signiertes PDF Dokument speichern", + "error-files-label": "Fehlgeschlagene Dokumente", + "re-upload-file-button-title": "Erneut in die Warteschlange stellen", + "upload-status-file-text": "({{fileSize}}) wird hochgeladen und verarbeitet...", + "re-upload-all-button": "Alle wiederholen", + "re-upload-all-button-title": "Alle fehlgeschlagen Signaturvorgänge erneut in die Warteschlange stellen", + "signature-placement-label": "Signatur platzieren", + "positioning": "Positionierung", + "confirm-page-leave": "Sind Sie sicher, dass Sie die Seite verlassen wollen? Es stehen signierte Dokumente zum Download bereit.", + "file-picker-context": "PDF-Dokumente zum Signieren auswählen (max. 32 MB pro Datei)", + "annotation": "Anmerkungen", + "annotation-no": "Nein", + "annotation-yes": "Ja", + "annotation-view-label": "Anmerkungen zu Dokument hinzufügen" + }, + "signature-verification": { + "upload-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.", + "upload-area-text": "Sie können in diesem Bereich PDF-Dokumente mit einer Maximalgröße von bis zu 32MB pro Dokument per Drag & Drop oder per Direktauswahl hochladen. Die PDF-Dokumente dürfen sich auch in ZIP-Dateien befinden.", + "queued-files-label": "Dokumente in der Warteschlange", + "queued-files-empty1": "Kein Dokument in der Warteschlange", + "queued-files-empty2": "Sie können jetzt ein neues Dokument hochladen", + "remove-failed-file-button-title": "Fehlgeschlagenes Dokument entfernen", + "remove-queued-file-button-title": "Dokument aus der Warteschlange entfernen", + "clear-all": "Alle entfernen", + "start-verification-process-button": "Verifikation starten", + "stop-verification-process-button": "Verifikation unterbrechen", + "show-preview": "Dokument anzeigen", + "preview-label": "Dokumentenansicht", + "verified-files-label": "Verifizierte Dokumente", + "upload-button-label": "PDF-Dokumente auswählen", + "error-files-label": "Fehlgeschlagene Dokumente", + "re-upload-file-button-title": "Erneut in die Warteschlange stellen", + "upload-status-file-text": "({{fileSize}}) wird hochgeladen und verifiziert...", + "re-upload-all-button": "Alle wiederholen", + "re-upload-all-button-title": "Alle fehlgeschlagenen Verifikationsprozesse erneut in die Warteschlange stellen", + "given-name": "Vorname", + "last-name": "Nachname", + "nationality": "Nationalität", + "serial-number": "Seriennummer", + "value-message": "Überprüfung", + "no-signatures-found": "Es wurden keine Signaturen gefunden.", + "confirm-page-leave": "Sind Sie sicher, dass Sie die Seite verlassen wollen? Es stehen signierte Dokumente zum Download bereit.", + "file-picker-context": "PDF-Dokumente zum Verifizieren auswählen (max. 32 MB pro Datei)" + }, + "signature-verification-extern": { + "description-text": "Um eine PDF-Signatur auf ihre Gültigkeit zu überprüfen, benutzen Sie bitte das Verifikationsservice der Rundfunk und Telekom Regulierungs-GmbH. Mit diesem Verifikationsservice können Sie überprüfen, ob das Dokument eine valide Signatur enthält.", + "link-label": "Zum RTR Verifikationsservice wechseln", + "adobe-reader-text": "Des Weiteren besteht auch die Möglichkeit, das Dokument lokal mit dem Adobe Reader zu überprüfen." + }, + "pdf-preview": { + "first-page": "Erste Seite", + "previous-page": "Vorherige Seite", + "next-page": "Nächste Seite", + "last-page": "Letzte Seite", + "page-count": "von {{totalPages}}", + "rotate-signature": "Signatur im Uhrzeigersinn rotieren", + "rotate": "Signatur rotieren", + "continue": "Platzierung bestätigen", + "error-message": "Fehler: Dieses Dokument ist beschädigt." + }, + "annotation-view": { + "delete-all-button-text": "Alle entfernen", + "delete-all-button-title": "Alle entfernen", + "save-all-button-text": "Für Dokument übernehmen", + "save-all-button-title": "Für Dokument übernehmen", + "insert-field": "Neues Feld einfügen", + "remove-field": "Feld löschen", + "businessnumber-placeholder": "Fügen Sie hier die Geschäftszahl ein (z.B. 247/1/2020-S)", + "intended-use-placeholder": "Fügen Sie hier den gewünschten Text ein", + "introduction": "In diesem Bereich können Sie zusätzlichen Text definieren, der in der Signatur enthalten sein soll. Klicken Sie dafür auf \"Neues Feld einfügen\" und wählen Sie das gewünschte Feld aus. Klicken Sie dann auf das \"+\" um das Feld einzufügen und den gewünschten Text einzugeben.", + "empty-annotation-title": "{{annotationType}} ist leer!", + "empty-annotation-message": "Bitte tragen Sie einen Wert für die gewählte Anmerkung ein.", + "empty-organization-title": "Organisation wurde nicht ausgewählt!", + "empty-organization-message": "Bitte wählen Sie Ihre Organisation aus, bevor Sie die gewählte Anmerkung übernehmen.", + "invalid-annotation-text-title": "Ungültiger Eingabewert!", + "invalid-annotation-text-message": "Sie haben ein oder mehrere ungültige Zeichen eingegeben. Zulässige Sonderzeichen sind: \\/ !=+-_*&()" + }, + "error-permission-message": "Sie müssen das Recht auf Amtssignaturen besitzen um diese Funktion nutzen zu können!", + "error-login-message": "Sie müssen angemeldet sein um diese Funktion nutzen zu können!", + "error-cancel-message": "Der Signaturprozess wurde manuell abgebrochen.", + "error-rights-message": "Abbruch auf Grund mangelnder Rechte Ihres Accounts.", + "label-manual-positioning-missing": "Bestehende Signatur vorhanden, bitte wählen Sie ihre Positionierung manuell.", + "error-manual-positioning-missing": "Ein oder mehrere Signaturen in der Warteschlange müssen manuell positioniert werden." } diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json index 4cdd8b6195639c9e87462b4588964dd3233772d5..50fdfb968d49305c9a37a30d9f5dc77f552c48ab 100644 --- a/src/i18n/en/translation.json +++ b/src/i18n/en/translation.json @@ -1,141 +1,141 @@ { - "official-pdf-upload": { - "upload-text": "The official signature of the \"Electronic Signature Service\" is an application with which you can provide PDF files with an electronic (qualified) official signature. A qualified signature is legally equivalent to your personal signature on the Internet and a handwritten signature.", - "upload-area-text": "In this area you can upload PDF-documents up to a size of 32MB via Drag & Drop or by selecting them directly. The PDF-documents can also be located in a ZIP-file.", - "queued-files-label": "Queued documents", - "queued-files-empty1": "No queued documents", - "queued-files-empty2": "You can now upload more documents", - "remove-failed-file-button-title": "Remove failed document", - "remove-queued-file-button-title": "Remove document from queue", - "clear-all": "Clear all", - "start-signing-process-button": "Start signing", - "stop-signing-process-button": "Stop signing", - "show-preview": "Show document", - "positioning-automatic": "Auto", - "positioning-manual": "Manual", - "preview-label": "Document view", - "signed-files-label": "Signed documents", - "download-zip-button": "Save all", - "download-zip-button-tooltip": "Save all signed documents", - "upload-button-label": "Select PDF-documents", - "download-file-button-title": "Save signed PDF", - "error-files-label": "Failed documents", - "re-upload-file-button-title": "Queue again", - "upload-status-file-text": "({{fileSize}}) is currently uploading and being processed...", - "re-upload-all-button": "Queue all", - "re-upload-all-button-title": "Queue all failed documents again", - "signature-placement-label": "Place signature", - "positioning": "Positioning", - "confirm-page-leave": "Are you sure you want to leave this page? There are still signed documents ready to be downloaded.", - "file-picker-context": "Upload PDF-documents to sign (max. 32 MB per file)", - "annotation": "Annotations", - "annotation-no": "No", - "annotation-yes": "Yes", - "annotation-view-label": "Add annotations to document" - }, - "qualified-pdf-upload": { - "save-field-label": "Save {{count}} file", - "save-field-label_plural": "Save {{count}} files", - "upload-text": "The \"Electronic Signature Service\" is an application with which you can provide PDF files with a personal, electronic (qualified) signature. A qualified signature is legally equivalent to your personal signature on the Internet and a handwritten signature.", - "upload-area-text": "In this area you can upload PDF-documents up to a size of 32MB via Drag & Drop or by selecting them directly. The PDF-documents can also be located in a ZIP-file.", - "current-signing-process-label": "Current signing process", - "queued-files-label": "Queued documents", - "queued-files-empty1": "No queued documents", - "queued-files-empty2": "You can now upload more documents", - "remove-failed-file-button-title": "Remove failed document", - "remove-queued-file-button-title": "Remove document from queue", - "clear-all": "Clear all", - "start-signing-process-button": "Start signing", - "stop-signing-process-button": "Stop signing", - "show-preview": "Show document", - "positioning-automatic": "Auto", - "positioning-manual": "Manual", - "preview-label": "Document view", - "signed-files-label": "Signed documents", - "download-zip-button": "Save all", - "download-zip-button-tooltip": "Save all signed documents", - "upload-button-label": "Select PDF-documents", - "download-file-button-title": "Save signed PDF", - "error-files-label": "Failed documents", - "re-upload-file-button-title": "Queue again", - "upload-status-file-text": "({{fileSize}}) is currently uploading and being processed...", - "re-upload-all-button": "Queue all", - "re-upload-all-button-title": "Queue all failed documents again", - "signature-placement-label": "Place signature", - "positioning": "Positioning", - "confirm-page-leave": "Are you sure you want to leave this page? There are still signed documents ready to be downloaded.", - "file-picker-context": "Upload PDF-documents to sign (max. 32 MB per file)", - "annotation": "Annotations", - "annotation-no": "No", - "annotation-yes": "Yes", - "annotation-view-label": "Add annotations to document" - }, - "signature-verification": { - "upload-text": "In this area you can upload PDF-documents up to a size of 32MB. The PDF-documents can also be located in a ZIP-file.", - "upload-area-text": "In this area you can upload PDF-documents up to a size of 32MB via Drag & Drop or by selecting them directly. The PDF-documents can also be located in a ZIP-file.", - "queued-files-label": "Queued documents", - "queued-files-empty1": "No queued documents", - "queued-files-empty2": "You can now upload more documents", - "remove-failed-file-button-title": "Remove failed document", - "remove-queued-file-button-title": "Remove document from queue", - "clear-all": "Clear all", - "start-verification-process-button": "Start verification", - "stop-verification-process-button": "Stop verification", - "show-preview": "Show document", - "preview-label": "Document view", - "verified-files-label": "Verified documents", - "upload-button-label": "Select PDF-documents", - "error-files-label": "Failed verification processes", - "re-upload-file-button-title": "Queue again", - "upload-status-file-text": "({{fileSize}}) is currently uploading and being processed...", - "re-upload-all-button": "Queue all", - "re-upload-all-button-title": "Queue all failed documents again", - "given-name": "Given name", - "last-name": "Last name", - "nationality": "Nationality", - "serial-number": "Serial number", - "value-message": "Verification", - "no-signatures-found": "No signatures were found.", - "confirm-page-leave": "Are you sure you want to leave this page? There are still signed documents ready to be downloaded.", - "file-picker-context": "Upload PDF-documents to verify (max. 32 MB per file)" - }, - "signature-verification-extern": { - "description-text": "To check a PDF signature for validity, please use the verification service of the Rundfunk und Telekom Regulierungs-GmbH. This verification service allows you to check whether the document contains a valid signature.", - "link-label": "Switch to the RTR verification service", - "adobe-reader-text": "Furthermore, it is also possible to verify the signature locally with the Adobe Reader." - }, - "pdf-preview": { - "first-page": "First page", - "previous-page": "Previous page", - "next-page": "Next page", - "last-page": "Last page", - "page-count": "of {{totalPages}}", - "rotate-signature": "Rotate signature clockwise", - "rotate": "Rotate signature", - "continue": "Confirm placement", - "error-message": "Error: This document is incorrect." - }, - "annotation-view": { - "delete-all-button-text": "Clear all", - "delete-all-button-title": "Clear all", - "save-all-button-text": "Add to document", - "save-all-button-title": "Add to document", - "insert-field": "Insert new field", - "remove-field": "Delete field", - "businessnumber-placeholder": "Insert business number here (e.g. 247/1/2020-S)", - "intended-use-placeholder": "Insert text here", - "introduction": "In this area you can define additional text to be included in the signature. To do this, click on \"Insert new field\" and select the desired field. Then click on the \"+\" to insert the field and enter the desired text.", - "empty-annotation-title": "{{annotationType}} is empty!", - "empty-annotation-message": "Please enter a value for the selected annotation.", - "empty-organization-title": "Organization was not selected!", - "empty-organization-message": "Please select your organization before applying the selected annotation.", - "invalid-annotation-text-title": "Invalid Input Value!", - "invalid-annotation-text-message": "You have entered one or more invalid characters. Valid special characters are: \\/ !?=+-_*&()" - }, - "error-permission-message": "You need have permissions to use the official signature to use this function!", - "error-login-message": "You need to be logged in to use this function!", - "error-cancel-message": "The signature process was manually aborted.", - "error-rights-message": "Abort due to insufficient rights of your account.", - "label-manual-positioning-missing": "Existing signature present, please select its positioning manually.", - "error-manual-positioning-missing": "One or more signatures in the queue must be positioned manually." + "official-pdf-upload": { + "upload-text": "The official signature of the \"Electronic Signature Service\" is an application with which you can provide PDF files with an electronic (qualified) official signature. A qualified signature is legally equivalent to your personal signature on the Internet and a handwritten signature.", + "upload-area-text": "In this area you can upload PDF-documents up to a size of 32MB via Drag & Drop or by selecting them directly. The PDF-documents can also be located in a ZIP-file.", + "queued-files-label": "Queued documents", + "queued-files-empty1": "No queued documents", + "queued-files-empty2": "You can now upload more documents", + "remove-failed-file-button-title": "Remove failed document", + "remove-queued-file-button-title": "Remove document from queue", + "clear-all": "Clear all", + "start-signing-process-button": "Start signing", + "stop-signing-process-button": "Stop signing", + "show-preview": "Show document", + "positioning-automatic": "Auto", + "positioning-manual": "Manual", + "preview-label": "Document view", + "signed-files-label": "Signed documents", + "download-zip-button": "Save all", + "download-zip-button-tooltip": "Save all signed documents", + "upload-button-label": "Select PDF-documents", + "download-file-button-title": "Save signed PDF", + "error-files-label": "Failed documents", + "re-upload-file-button-title": "Queue again", + "upload-status-file-text": "({{fileSize}}) is currently uploading and being processed...", + "re-upload-all-button": "Queue all", + "re-upload-all-button-title": "Queue all failed documents again", + "signature-placement-label": "Place signature", + "positioning": "Positioning", + "confirm-page-leave": "Are you sure you want to leave this page? There are still signed documents ready to be downloaded.", + "file-picker-context": "Upload PDF-documents to sign (max. 32 MB per file)", + "annotation": "Annotations", + "annotation-no": "No", + "annotation-yes": "Yes", + "annotation-view-label": "Add annotations to document" + }, + "qualified-pdf-upload": { + "save-field-label": "Save {{count}} file", + "save-field-label_plural": "Save {{count}} files", + "upload-text": "The \"Electronic Signature Service\" is an application with which you can provide PDF files with a personal, electronic (qualified) signature. A qualified signature is legally equivalent to your personal signature on the Internet and a handwritten signature.", + "upload-area-text": "In this area you can upload PDF-documents up to a size of 32MB via Drag & Drop or by selecting them directly. The PDF-documents can also be located in a ZIP-file.", + "current-signing-process-label": "Current signing process", + "queued-files-label": "Queued documents", + "queued-files-empty1": "No queued documents", + "queued-files-empty2": "You can now upload more documents", + "remove-failed-file-button-title": "Remove failed document", + "remove-queued-file-button-title": "Remove document from queue", + "clear-all": "Clear all", + "start-signing-process-button": "Start signing", + "stop-signing-process-button": "Stop signing", + "show-preview": "Show document", + "positioning-automatic": "Auto", + "positioning-manual": "Manual", + "preview-label": "Document view", + "signed-files-label": "Signed documents", + "download-zip-button": "Save all", + "download-zip-button-tooltip": "Save all signed documents", + "upload-button-label": "Select PDF-documents", + "download-file-button-title": "Save signed PDF", + "error-files-label": "Failed documents", + "re-upload-file-button-title": "Queue again", + "upload-status-file-text": "({{fileSize}}) is currently uploading and being processed...", + "re-upload-all-button": "Queue all", + "re-upload-all-button-title": "Queue all failed documents again", + "signature-placement-label": "Place signature", + "positioning": "Positioning", + "confirm-page-leave": "Are you sure you want to leave this page? There are still signed documents ready to be downloaded.", + "file-picker-context": "Upload PDF-documents to sign (max. 32 MB per file)", + "annotation": "Annotations", + "annotation-no": "No", + "annotation-yes": "Yes", + "annotation-view-label": "Add annotations to document" + }, + "signature-verification": { + "upload-text": "In this area you can upload PDF-documents up to a size of 32MB. The PDF-documents can also be located in a ZIP-file.", + "upload-area-text": "In this area you can upload PDF-documents up to a size of 32MB via Drag & Drop or by selecting them directly. The PDF-documents can also be located in a ZIP-file.", + "queued-files-label": "Queued documents", + "queued-files-empty1": "No queued documents", + "queued-files-empty2": "You can now upload more documents", + "remove-failed-file-button-title": "Remove failed document", + "remove-queued-file-button-title": "Remove document from queue", + "clear-all": "Clear all", + "start-verification-process-button": "Start verification", + "stop-verification-process-button": "Stop verification", + "show-preview": "Show document", + "preview-label": "Document view", + "verified-files-label": "Verified documents", + "upload-button-label": "Select PDF-documents", + "error-files-label": "Failed verification processes", + "re-upload-file-button-title": "Queue again", + "upload-status-file-text": "({{fileSize}}) is currently uploading and being processed...", + "re-upload-all-button": "Queue all", + "re-upload-all-button-title": "Queue all failed documents again", + "given-name": "Given name", + "last-name": "Last name", + "nationality": "Nationality", + "serial-number": "Serial number", + "value-message": "Verification", + "no-signatures-found": "No signatures were found.", + "confirm-page-leave": "Are you sure you want to leave this page? There are still signed documents ready to be downloaded.", + "file-picker-context": "Upload PDF-documents to verify (max. 32 MB per file)" + }, + "signature-verification-extern": { + "description-text": "To check a PDF signature for validity, please use the verification service of the Rundfunk und Telekom Regulierungs-GmbH. This verification service allows you to check whether the document contains a valid signature.", + "link-label": "Switch to the RTR verification service", + "adobe-reader-text": "Furthermore, it is also possible to verify the signature locally with the Adobe Reader." + }, + "pdf-preview": { + "first-page": "First page", + "previous-page": "Previous page", + "next-page": "Next page", + "last-page": "Last page", + "page-count": "of {{totalPages}}", + "rotate-signature": "Rotate signature clockwise", + "rotate": "Rotate signature", + "continue": "Confirm placement", + "error-message": "Error: This document is incorrect." + }, + "annotation-view": { + "delete-all-button-text": "Clear all", + "delete-all-button-title": "Clear all", + "save-all-button-text": "Add to document", + "save-all-button-title": "Add to document", + "insert-field": "Insert new field", + "remove-field": "Delete field", + "businessnumber-placeholder": "Insert business number here (e.g. 247/1/2020-S)", + "intended-use-placeholder": "Insert text here", + "introduction": "In this area you can define additional text to be included in the signature. To do this, click on \"Insert new field\" and select the desired field. Then click on the \"+\" to insert the field and enter the desired text.", + "empty-annotation-title": "{{annotationType}} is empty!", + "empty-annotation-message": "Please enter a value for the selected annotation.", + "empty-organization-title": "Organization was not selected!", + "empty-organization-message": "Please select your organization before applying the selected annotation.", + "invalid-annotation-text-title": "Invalid Input Value!", + "invalid-annotation-text-message": "You have entered one or more invalid characters. Valid special characters are: \\/ !?=+-_*&()" + }, + "error-permission-message": "You need have permissions to use the official signature to use this function!", + "error-login-message": "You need to be logged in to use this function!", + "error-cancel-message": "The signature process was manually aborted.", + "error-rights-message": "Abort due to insufficient rights of your account.", + "label-manual-positioning-missing": "Existing signature present, please select its positioning manually.", + "error-manual-positioning-missing": "One or more signatures in the queue must be positioned manually." } diff --git a/src/signature-entry.js b/src/signature-entry.js index 0f6b0302453c86149437e251124ac66b94a27a1d..8a85781f337e673973267003202d842d2409f3e2 100644 --- a/src/signature-entry.js +++ b/src/signature-entry.js @@ -1,7 +1,6 @@ export class SignatureEntry { - constructor(key, file) { this.key = key; this.file = file; } -} \ No newline at end of file +} diff --git a/src/styles.js b/src/styles.js index 355e2652a0831c4066722a71f2807c6d03c8982b..da8fa237762b5532a42e89eb9e418d11642efb6c 100644 --- a/src/styles.js +++ b/src/styles.js @@ -3,7 +3,6 @@ import {css} from 'lit'; export function getSignatureCss() { // language=css return css` - #annotation-view .button.is-cancel { background: transparent; border: none; @@ -14,19 +13,22 @@ export function getSignatureCss() { padding-right: 2px; } - #annotation-view .box-header, #external-auth .box-header { + #annotation-view .box-header, + #external-auth .box-header { display: flex; justify-content: space-between; align-items: start; } - #annotation-view .box-header .filename, #external-auth .box-header .filename { + #annotation-view .box-header .filename, + #external-auth .box-header .filename { overflow: hidden; text-overflow: ellipsis; margin-right: 0.5em; } - #pdf-preview, #annotation-view { + #pdf-preview, + #annotation-view { min-width: 320px; box-sizing: border-box; } @@ -40,7 +42,8 @@ export function getSignatureCss() { font-weight: 600; } - #pdf-preview .box-header, #annotation-view .box-header { + #pdf-preview .box-header, + #annotation-view .box-header { border: var(--dbp-border-dark); border-bottom-width: 0; padding: 0.5em 0.5em 0 0.5em; @@ -73,7 +76,6 @@ export function getSignatureCss() { vertical-align: middle; } - .file .info strong { font-weight: 600; } @@ -84,7 +86,8 @@ export function getSignatureCss() { margin-right: 5px; } - .error, #cancel-signing-process { + .error, + #cancel-signing-process { color: var(--dbp-danger-dark); } @@ -94,11 +97,12 @@ export function getSignatureCss() { } /* using dbp-icon doesn't work */ - button > [name=close], a > [name=close] { + button > [name='close'], + a > [name='close'] { font-size: 0.8em; } - a > [name=close] { + a > [name='close'] { color: var(--dbp-accent-dark); } @@ -119,17 +123,18 @@ export function getSignatureCss() { margin-right: 0; flex: 1 0; } - - .file-block, .box { + + .file-block, + .box { border: var(--dbp-border-dark); padding: 10px; } - .file-block, .box .file { + .file-block, + .box .file { margin-top: 0; } - .file-block { max-width: 320px; margin-bottom: 10px; @@ -171,7 +176,8 @@ export function getSignatureCss() { text-align: right; } - .file-block .filename, .file-block div.bottom-line .headline { + .file-block .filename, + .file-block div.bottom-line .headline { text-overflow: ellipsis; overflow: hidden; } @@ -183,7 +189,7 @@ export function getSignatureCss() { .bold-filename { font-weight: bold; } - + #pdf-preview .button.is-cancel { color: var(--dbp-accent-dark); } @@ -202,12 +208,14 @@ export function getSignatureCss() { color: inherit; } - .is-disabled, .is-disabled.button[disabled] { + .is-disabled, + .is-disabled.button[disabled] { opacity: 0.2; pointer-events: none; } - #pdf-preview, #annotation-view { + #pdf-preview, + #annotation-view { position: sticky; top: 0px; height: 100vh; @@ -227,12 +235,12 @@ export function getSignatureCss() { margin-right: 0.5em; } - #grid-container{ + #grid-container { margin-top: 2rem; /*padding-top: 2rem;*/ } - .border{ + .border { border-top: var(--dbp-border-dark); margin-top: 2rem; padding-top: 2rem; @@ -243,7 +251,7 @@ export function getSignatureCss() { border-radius: var(--dbp-border-radius); } - .subheadline{ + .subheadline { font-style: italic; padding-left: 2em; margin-top: -1px; @@ -251,11 +259,9 @@ export function getSignatureCss() { margin-bottom: 1.2em; } - @media only screen - and (orientation: portrait) - and (max-width: 768px) { + @media only screen and (orientation: portrait) and (max-width: 768px) { /* Modal preview, upload and external auth */ - div.right-container > * { + div.right-container > * { position: fixed; z-index: 1000; padding: 10px; @@ -284,14 +290,11 @@ export function getSignatureCss() { .file-block { max-width: inherit; } - - #pdf-preview, #annotation-view { + + #pdf-preview, + #annotation-view { position: fixed; } } - - `; - - -} \ No newline at end of file +} diff --git a/src/textswitch.js b/src/textswitch.js index 608d9c0868f7c6b182e2daead7690754b2cfdab0..989992a94680ef10f6dcadc66ce49bd62429d410 100644 --- a/src/textswitch.js +++ b/src/textswitch.js @@ -1,8 +1,8 @@ import {html, LitElement, css} from 'lit'; import * as commonStyles from '@dbp-toolkit/common/styles'; -const BUTTON1 = "button1"; -const BUTTON2 = "button2"; +const BUTTON1 = 'button1'; +const BUTTON2 = 'button2'; /** * Attributes: @@ -10,34 +10,34 @@ const BUTTON2 = "button2"; * name1/name2: The names of the buttons * name: The active name * disabled: Disable the switch - * + * * Events: * change: when button is clicked - * + * * Example: * <my-tag name="one" name1="one" name2="two" value1="One", value2="Two"></my-tag> */ export class TextSwitch extends LitElement { constructor() { super(); - this.value1 = ""; - this.value2 = ""; - this.name1 = ""; - this.name2 = ""; - this.name = ""; + this.value1 = ''; + this.value2 = ''; + this.name1 = ''; + this.name2 = ''; + this.name = ''; this.disabled = false; this._active = BUTTON1; } static get properties() { return { - value1: { type: String }, - value2: { type: String }, - name1: { type: String }, - name2: { type: String }, - name: { type: String, reflect: true }, - disabled: { type: Boolean }, - _active: { type: Boolean }, + value1: {type: String}, + value2: {type: String}, + name1: {type: String}, + name2: {type: String}, + name: {type: String, reflect: true}, + disabled: {type: Boolean}, + _active: {type: Boolean}, }; } @@ -55,12 +55,12 @@ export class TextSwitch extends LitElement { #button1 { border-right-width: 0; } - - .button:first-child{ + + .button:first-child { border-radius: var(--dbp-border-radius) 0 0 var(--dbp-border-radius); } - .button:last-child{ + .button:last-child { border-radius: 0 var(--dbp-border-radius) var(--dbp-border-radius) 0; } @@ -82,7 +82,7 @@ export class TextSwitch extends LitElement { update(changedProperties) { changedProperties.forEach((oldValue, propName) => { - if (propName === "name") { + if (propName === 'name') { if (this[propName] === this.name1) { this._active = BUTTON1; } else if (this[propName] === this.name2) { @@ -100,7 +100,7 @@ export class TextSwitch extends LitElement { this.name = this._active === BUTTON1 ? this.name1 : this.name2; // send event only when buttons are clicked - const event = new CustomEvent("change", { + const event = new CustomEvent('change', { bubbles: true, cancelable: false, }); @@ -110,9 +110,18 @@ export class TextSwitch extends LitElement { return html` <div> - <button @click="${onClick}" class="button ${this._active === BUTTON1 ? `active` : ``}" id="${BUTTON1}" ?disabled="${this.disabled}"> + <button + @click="${onClick}" + class="button ${this._active === BUTTON1 ? `active` : ``}" + id="${BUTTON1}" + ?disabled="${this.disabled}"> ${this.value1} - </button><button @click="${onClick}" class="button ${this._active === BUTTON2 ? `active` : ``}" id="${BUTTON2}" ?disabled="${this.disabled}"> + </button> + <button + @click="${onClick}" + class="button ${this._active === BUTTON2 ? `active` : ``}" + id="${BUTTON2}" + ?disabled="${this.disabled}"> ${this.value2} </button> </div> diff --git a/src/utils.js b/src/utils.js index 0da722ee50b3336a9bcff4762d5d635f5e8e31f9..d4c585c1bdd9f3c6765f5d70a77f5c990110ec83 100644 --- a/src/utils.js +++ b/src/utils.js @@ -9,8 +9,8 @@ import {html} from 'lit'; * @param results * @param identifierAttribute */ -export const findObjectInApiResults = (identifier, results, identifierAttribute = "@id") => { - const members = results["hydra:member"]; +export const findObjectInApiResults = (identifier, results, identifierAttribute = '@id') => { + const members = results['hydra:member']; if (members === undefined) { return; @@ -24,7 +24,7 @@ export const findObjectInApiResults = (identifier, results, identifierAttribute }; export const getPDFFileBase64Content = (file) => { - return file.contentUrl.replace(/data:\s*application\/pdf;\s*base64,/, ""); + return file.contentUrl.replace(/data:\s*application\/pdf;\s*base64,/, ''); }; export const convertDataURIToBinary = (dataURI) => { @@ -35,7 +35,7 @@ export const convertDataURIToBinary = (dataURI) => { const rawLength = raw.length; let array = new Uint8Array(rawLength); - for(let i = 0; i < rawLength; i++) { + for (let i = 0; i < rawLength; i++) { array[i] = raw.charCodeAt(i); } @@ -49,18 +49,16 @@ export const getDataURIContentType = (dataURI) => { return dataURI.substring(5, base64Index); }; -export const baseName = (str) => -{ +export const baseName = (str) => { let base = String(str).substring(str.lastIndexOf('/') + 1); - if (base.lastIndexOf(".") !== -1) { - base = base.substring(0, base.lastIndexOf(".")); + if (base.lastIndexOf('.') !== -1) { + base = base.substring(0, base.lastIndexOf('.')); } return base; }; - export const fabricjs2pdfasPosition = (data) => { let angle = -(data.angle - 360) % 360; let bottom = data.bottom; @@ -81,7 +79,7 @@ export const fabricjs2pdfasPosition = (data) => { x: Math.round(left), r: angle, w: Math.round(data.width), // only width, no "height" allowed in PDF-AS - p: data.currentPage + p: data.currentPage, }; }; @@ -134,8 +132,9 @@ export const readArrayBufferFileContent = async (file) => { */ export const getPDFSignatureCount = async (file) => { const sigRegex = new RegExp( - "/Type\\s*/Sig(.|\\s)*?/SubFilter\\s*(/ETSI\\.CAdES\\.detached|/adbe\\.pkcs7\\.detached)", - "g"); + '/Type\\s*/Sig(.|\\s)*?/SubFilter\\s*(/ETSI\\.CAdES\\.detached|/adbe\\.pkcs7\\.detached)', + 'g' + ); const content = await readBinaryFileContent(file); let matches = 0; while (sigRegex.exec(content) !== null) { @@ -154,7 +153,7 @@ export const getPDFSignatureCount = async (file) => { export const writeAnnotationFactoryToFile = (annotationFactory, file) => { const blob = annotationFactory.write(); - return new File([blob], file.name, { type: file.type }); + return new File([blob], file.name, {type: file.type}); }; /** @@ -183,8 +182,17 @@ export const getAnnotationFactoryFromFile = async (file) => { * @param value * @returns {AnnotationFactory} prepared to annotate */ -export const addKeyValuePdfAnnotationsToAnnotationFactory = (annotationFactory, activityNameDE, activityNameEN, personName, - annotationType, annotationTypeNameDE, annotationTypeNameEN, organizationNumber, value) => { +export const addKeyValuePdfAnnotationsToAnnotationFactory = ( + annotationFactory, + activityNameDE, + activityNameEN, + personName, + annotationType, + annotationTypeNameDE, + annotationTypeNameEN, + organizationNumber, + value +) => { annotationType = annotationType.trim(); annotationTypeNameDE = annotationTypeNameDE.trim(); annotationTypeNameEN = annotationTypeNameEN.trim(); @@ -198,12 +206,13 @@ export const addKeyValuePdfAnnotationsToAnnotationFactory = (annotationFactory, // add human readable annotation let author = personName + ' via "' + activityNameDE + ' / ' + activityNameEN + '"'; - let content = annotationTypeNameDE + ': ' + value +"\n" + annotationTypeNameEN + ': ' + value; + let content = annotationTypeNameDE + ': ' + value + '\n' + annotationTypeNameEN + ': ' + value; annotationFactory = addPdfAnnotationToAnnotationFactory(annotationFactory, author, content); // add machine readable annotation const organizationNumberContent = organizationNumber !== '' ? '_' + organizationNumber : ''; - author = 'Maschinell aufgebracht, bitte nicht entfernen / Applied automatically, please do not remove'; + author = + 'Maschinell aufgebracht, bitte nicht entfernen / Applied automatically, please do not remove'; content = 'dbp_annotation_' + annotationType + organizationNumberContent + '=' + value; annotationFactory = addPdfAnnotationToAnnotationFactory(annotationFactory, author, content); @@ -225,13 +234,16 @@ export const addPdfAnnotationToAnnotationFactory = (annotationFactory, author, c // annotationFactory.checkRect(4, rect); // Create single free text annotation with print flag and 0 font size - let annotation = Object.assign(annotationFactory.createBaseAnnotation(page, rect, content, author), { - annotation_flag: 4, // enable print to be PDF/A conform - color: {r: 1, g: 1, b: 1}, // white to (maybe) hide it better - opacity: 0.001, // we can't set to 0 because of "if (opacity) {" - defaultAppearance: "/Invalid_font 0 Tf" // font size 0 to (maybe) hide it better - }); - annotation.type = "/FreeText"; + let annotation = Object.assign( + annotationFactory.createBaseAnnotation(page, rect, content, author), + { + annotation_flag: 4, // enable print to be PDF/A conform + color: {r: 1, g: 1, b: 1}, // white to (maybe) hide it better + opacity: 0.001, // we can't set to 0 because of "if (opacity) {" + defaultAppearance: '/Invalid_font 0 Tf', // font size 0 to (maybe) hide it better + } + ); + annotation.type = '/FreeText'; annotationFactory.annotations.push(annotation); return annotationFactory; @@ -245,20 +257,20 @@ export const addPdfAnnotationToAnnotationFactory = (annotationFactory, author, c */ export const getAnnotationTypes = (key = null) => { const types = { - 'bbe3a371': { - 'name': { - 'de': 'Geschäftszahl', - 'en': 'Businessnumber', + bbe3a371: { + name: { + de: 'Geschäftszahl', + en: 'Businessnumber', }, - 'hasOrganization': true, + hasOrganization: true, }, '85a4eb4c': { - 'name': { - 'de': 'Verwendungszweck', - 'en': 'Intended use', + name: { + de: 'Verwendungszweck', + en: 'Intended use', }, - 'hasOrganization': false, - } + hasOrganization: false, + }, }; return key === null ? types : types[key] || {}; diff --git a/test/unit.js b/test/unit.js index 89598602d2a48500b26a4f8eb7984b4024ae8e01..16959e8d801962c303741d59609cb513e41e5b16 100644 --- a/test/unit.js +++ b/test/unit.js @@ -5,63 +5,65 @@ import '../src/dbp-signature.js'; import {getPDFSignatureCount} from '../src/utils.js'; suite('dbp-official-signature-pdf-upload basics', () => { - let node; + let node; - suiteSetup(async () => { - node = document.createElement('dbp-official-signature-pdf-upload'); - document.body.appendChild(node); - await node.updateComplete; - }); + suiteSetup(async () => { + node = document.createElement('dbp-official-signature-pdf-upload'); + document.body.appendChild(node); + await node.updateComplete; + }); - suiteTeardown(() => { - node.remove(); - }); + suiteTeardown(() => { + node.remove(); + }); - test('should render', () => { - assert(node.shadowRoot !== undefined); - }); + test('should render', () => { + assert(node.shadowRoot !== undefined); + }); }); suite('dbp-signature-app basics', () => { - let node; + let node; - suiteSetup(async () => { - node = document.createElement('dbp-app'); - document.body.appendChild(node); - await node.updateComplete; - }); + suiteSetup(async () => { + node = document.createElement('dbp-app'); + document.body.appendChild(node); + await node.updateComplete; + }); - suiteTeardown(() => { - node.remove(); - }); + suiteTeardown(() => { + node.remove(); + }); - test('should render', () => { - assert(node.shadowRoot !== undefined); - }); + test('should render', () => { + assert(node.shadowRoot !== undefined); + }); }); suite('pdf signature detection', () => { - function getPDFFile(data) { return new File([new Blob([data])], 'test.pdf', {type: 'application/pdf'}); } test('getPDFSignatureCount', async () => { // Produced via pdf-as-web - let sig1 = "/Type\n/Sig\n/Filter\n/Adobe.PPKLite\n/SubFilter\n/ETSI.CAdES.detached"; - let sig2 = "/Type\n/Sig\n/Filter\n/Adobe.PPKLite\n/SubFilter\n/adbe.pkcs7.detached"; + let sig1 = '/Type\n/Sig\n/Filter\n/Adobe.PPKLite\n/SubFilter\n/ETSI.CAdES.detached'; + let sig2 = '/Type\n/Sig\n/Filter\n/Adobe.PPKLite\n/SubFilter\n/adbe.pkcs7.detached'; // Produced via https://www.handy-signatur.at - let sig3 = "/Type /Sig\n/Name (Max Meier)\n/Location ()\n/Reason ()\n/M (D:20210201154123+01'00')\n/Filter /asign.ECDSA\n/SubFilter /ETSI.CAdES.detached"; + let sig3 = + "/Type /Sig\n/Name (Max Meier)\n/Location ()\n/Reason ()\n/M (D:20210201154123+01'00')\n/Filter /asign.ECDSA\n/SubFilter /ETSI.CAdES.detached"; - assert(await getPDFSignatureCount(getPDFFile(sig1)) === 1); - assert(await getPDFSignatureCount(getPDFFile(sig2)) === 1); - assert(await getPDFSignatureCount(getPDFFile(sig3)) === 1); - assert(await getPDFSignatureCount(getPDFFile(sig1 + sig2)) === 2); - assert(await getPDFSignatureCount(getPDFFile("foo" + sig1 + "bar" + sig2 + "quux")) === 2); - assert(await getPDFSignatureCount(getPDFFile("\nfoo" + sig1 + "bar\n")) === 1); - assert(await getPDFSignatureCount(getPDFFile("\nfoo" + sig2 + "bar\n")) === 1); + assert((await getPDFSignatureCount(getPDFFile(sig1))) === 1); + assert((await getPDFSignatureCount(getPDFFile(sig2))) === 1); + assert((await getPDFSignatureCount(getPDFFile(sig3))) === 1); + assert((await getPDFSignatureCount(getPDFFile(sig1 + sig2))) === 2); + assert( + (await getPDFSignatureCount(getPDFFile('foo' + sig1 + 'bar' + sig2 + 'quux'))) === 2 + ); + assert((await getPDFSignatureCount(getPDFFile('\nfoo' + sig1 + 'bar\n'))) === 1); + assert((await getPDFSignatureCount(getPDFFile('\nfoo' + sig2 + 'bar\n'))) === 1); - assert(await getPDFSignatureCount(getPDFFile("foobar")) === 0); - assert(await getPDFSignatureCount(getPDFFile("")) === 0); + assert((await getPDFSignatureCount(getPDFFile('foobar'))) === 0); + assert((await getPDFSignatureCount(getPDFFile(''))) === 0); }); });