feat: editor script setup
This commit is contained in:
parent
cbec1f24aa
commit
db627ed28a
7 changed files with 289 additions and 279 deletions
|
@ -69,6 +69,7 @@
|
||||||
"@faker-js/faker": "7.5.0",
|
"@faker-js/faker": "7.5.0",
|
||||||
"@types/dompurify": "2.3.4",
|
"@types/dompurify": "2.3.4",
|
||||||
"@types/flexsearch": "0.7.3",
|
"@types/flexsearch": "0.7.3",
|
||||||
|
"@types/marked": "4.0.7",
|
||||||
"@types/node": "16.11.64",
|
"@types/node": "16.11.64",
|
||||||
"@typescript-eslint/eslint-plugin": "5.39.0",
|
"@typescript-eslint/eslint-plugin": "5.39.0",
|
||||||
"@typescript-eslint/parser": "5.39.0",
|
"@typescript-eslint/parser": "5.39.0",
|
||||||
|
|
104
pnpm-lock.yaml
104
pnpm-lock.yaml
|
@ -1,4 +1,4 @@
|
||||||
lockfileVersion: 5.3
|
lockfileVersion: 5.4
|
||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
'@4tw/cypress-drag-drop': 2.2.1
|
'@4tw/cypress-drag-drop': 2.2.1
|
||||||
|
@ -17,6 +17,7 @@ specifiers:
|
||||||
'@types/flexsearch': 0.7.3
|
'@types/flexsearch': 0.7.3
|
||||||
'@types/is-touch-device': 1.0.0
|
'@types/is-touch-device': 1.0.0
|
||||||
'@types/lodash.clonedeep': 4.5.7
|
'@types/lodash.clonedeep': 4.5.7
|
||||||
|
'@types/marked': 4.0.7
|
||||||
'@types/node': 16.11.64
|
'@types/node': 16.11.64
|
||||||
'@types/sortablejs': 1.15.0
|
'@types/sortablejs': 1.15.0
|
||||||
'@typescript-eslint/eslint-plugin': 5.39.0
|
'@typescript-eslint/eslint-plugin': 5.39.0
|
||||||
|
@ -86,7 +87,7 @@ dependencies:
|
||||||
'@fortawesome/fontawesome-svg-core': 6.2.0
|
'@fortawesome/fontawesome-svg-core': 6.2.0
|
||||||
'@fortawesome/free-regular-svg-icons': 6.2.0
|
'@fortawesome/free-regular-svg-icons': 6.2.0
|
||||||
'@fortawesome/free-solid-svg-icons': 6.2.0
|
'@fortawesome/free-solid-svg-icons': 6.2.0
|
||||||
'@fortawesome/vue-fontawesome': 3.0.1_21e6b971ab1cbc4f6c07645df616013e
|
'@fortawesome/vue-fontawesome': 3.0.1_ehtls4nlds6e63ahmro7mfqbhy
|
||||||
'@github/hotkey': 2.0.1
|
'@github/hotkey': 2.0.1
|
||||||
'@kyvg/vue3-notification': 2.4.1_vue@3.2.40
|
'@kyvg/vue3-notification': 2.4.1_vue@3.2.40
|
||||||
'@sentry/tracing': 7.14.1
|
'@sentry/tracing': 7.14.1
|
||||||
|
@ -95,7 +96,7 @@ dependencies:
|
||||||
'@types/lodash.clonedeep': 4.5.7
|
'@types/lodash.clonedeep': 4.5.7
|
||||||
'@types/sortablejs': 1.15.0
|
'@types/sortablejs': 1.15.0
|
||||||
'@vueuse/core': 9.3.0_vue@3.2.40
|
'@vueuse/core': 9.3.0_vue@3.2.40
|
||||||
'@vueuse/router': 9.3.0_vue-router@4.1.5+vue@3.2.40
|
'@vueuse/router': 9.3.0_c7eza3xvlyb4mo6qeit5ggeo6u
|
||||||
axios: 0.27.2
|
axios: 0.27.2
|
||||||
blurhash: 2.0.3
|
blurhash: 2.0.3
|
||||||
bulma-css-variables: 0.9.33
|
bulma-css-variables: 0.9.33
|
||||||
|
@ -112,7 +113,7 @@ dependencies:
|
||||||
lodash.debounce: 4.0.8
|
lodash.debounce: 4.0.8
|
||||||
marked: 4.1.1
|
marked: 4.1.1
|
||||||
minimist: 1.2.6
|
minimist: 1.2.6
|
||||||
pinia: 2.0.22_typescript@4.8.4+vue@3.2.40
|
pinia: 2.0.22_bfjwoga25wxjazzogo7o372nwq
|
||||||
register-service-worker: 1.7.2
|
register-service-worker: 1.7.2
|
||||||
snake-case: 3.0.4
|
snake-case: 3.0.4
|
||||||
sortablejs: 1.15.0
|
sortablejs: 1.15.0
|
||||||
|
@ -134,12 +135,13 @@ devDependencies:
|
||||||
'@faker-js/faker': 7.5.0
|
'@faker-js/faker': 7.5.0
|
||||||
'@types/dompurify': 2.3.4
|
'@types/dompurify': 2.3.4
|
||||||
'@types/flexsearch': 0.7.3
|
'@types/flexsearch': 0.7.3
|
||||||
|
'@types/marked': 4.0.7
|
||||||
'@types/node': 16.11.64
|
'@types/node': 16.11.64
|
||||||
'@typescript-eslint/eslint-plugin': 5.39.0_be048b79d04b908735dc19ebba1dbd66
|
'@typescript-eslint/eslint-plugin': 5.39.0_xyciw6oqjoiiono4dhv3uhn5my
|
||||||
'@typescript-eslint/parser': 5.39.0_eslint@8.24.0+typescript@4.8.4
|
'@typescript-eslint/parser': 5.39.0_ypn2ylkkyfa5i233caldtndbqa
|
||||||
'@vitejs/plugin-legacy': 2.2.0_terser@5.10.0+vite@3.1.4
|
'@vitejs/plugin-legacy': 2.2.0_terser@5.10.0+vite@3.1.4
|
||||||
'@vitejs/plugin-vue': 3.1.2_vite@3.1.4+vue@3.2.40
|
'@vitejs/plugin-vue': 3.1.2_vite@3.1.4+vue@3.2.40
|
||||||
'@vue/eslint-config-typescript': 11.0.2_ab5ac96ab635ce1fa6bba69a2b0ff7cb
|
'@vue/eslint-config-typescript': 11.0.2_vnnms2vwgxhb7jv3u2ncwd7xzm
|
||||||
'@vue/test-utils': 2.1.0_vue@3.2.40
|
'@vue/test-utils': 2.1.0_vue@3.2.40
|
||||||
'@vue/tsconfig': 0.1.3_@types+node@16.11.64
|
'@vue/tsconfig': 0.1.3_@types+node@16.11.64
|
||||||
autoprefixer: 10.4.12_postcss@8.4.17
|
autoprefixer: 10.4.12_postcss@8.4.17
|
||||||
|
@ -159,12 +161,12 @@ devDependencies:
|
||||||
sass: 1.55.0
|
sass: 1.55.0
|
||||||
typescript: 4.8.4
|
typescript: 4.8.4
|
||||||
vite: 3.1.4_sass@1.55.0+terser@5.10.0
|
vite: 3.1.4_sass@1.55.0+terser@5.10.0
|
||||||
vite-plugin-pwa: 0.13.1_vite@3.1.4
|
vite-plugin-pwa: 0.13.1_bhe5iaipiq3lmbaxwdxgnnn2gq
|
||||||
vite-svg-loader: 3.6.0
|
vite-svg-loader: 3.6.0
|
||||||
vitest: 0.23.4_ddc85b0b7a78b2cfae025c8e16b7f605
|
vitest: 0.23.4_3xefwc32pczm7lqclshbnn7wau
|
||||||
vue-tsc: 0.40.13_typescript@4.8.4
|
vue-tsc: 0.40.13_typescript@4.8.4
|
||||||
wait-on: 6.0.1
|
wait-on: 6.0.1
|
||||||
workbox-cli: 6.5.4
|
workbox-cli: 6.5.4_acorn@8.8.0
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
@ -1392,7 +1394,7 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
postcss: ^8.2
|
postcss: ^8.2
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/selector-specificity': 2.0.2_cd239324a5aeb6e3cee0fb61f6a33448
|
'@csstools/selector-specificity': 2.0.2_zurzgjffv23ohtxa7nq7nizuja
|
||||||
postcss: 8.4.17
|
postcss: 8.4.17
|
||||||
postcss-selector-parser: 6.0.10
|
postcss-selector-parser: 6.0.10
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -1445,7 +1447,7 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
postcss: ^8.2
|
postcss: ^8.2
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/selector-specificity': 2.0.2_cd239324a5aeb6e3cee0fb61f6a33448
|
'@csstools/selector-specificity': 2.0.2_zurzgjffv23ohtxa7nq7nizuja
|
||||||
postcss: 8.4.17
|
postcss: 8.4.17
|
||||||
postcss-selector-parser: 6.0.10
|
postcss-selector-parser: 6.0.10
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -1530,7 +1532,7 @@ packages:
|
||||||
postcss: 8.4.17
|
postcss: 8.4.17
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@csstools/selector-specificity/2.0.2_cd239324a5aeb6e3cee0fb61f6a33448:
|
/@csstools/selector-specificity/2.0.2_zurzgjffv23ohtxa7nq7nizuja:
|
||||||
resolution: {integrity: sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==}
|
resolution: {integrity: sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==}
|
||||||
engines: {node: ^12 || ^14 || >=16}
|
engines: {node: ^12 || ^14 || >=16}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -1679,7 +1681,7 @@ packages:
|
||||||
'@fortawesome/fontawesome-common-types': 6.2.0
|
'@fortawesome/fontawesome-common-types': 6.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@fortawesome/vue-fontawesome/3.0.1_21e6b971ab1cbc4f6c07645df616013e:
|
/@fortawesome/vue-fontawesome/3.0.1_ehtls4nlds6e63ahmro7mfqbhy:
|
||||||
resolution: {integrity: sha512-CdXZJoCS+aEPec26ZP7hWWU3SaJlQPZSCGdgpQ2qGl2HUmtUUNrI3zC4XWdn1JUmh3t5OuDeRG1qB4eGRNSD4A==}
|
resolution: {integrity: sha512-CdXZJoCS+aEPec26ZP7hWWU3SaJlQPZSCGdgpQ2qGl2HUmtUUNrI3zC4XWdn1JUmh3t5OuDeRG1qB4eGRNSD4A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@fortawesome/fontawesome-svg-core': ~1 || ~6
|
'@fortawesome/fontawesome-svg-core': ~1 || ~6
|
||||||
|
@ -1917,7 +1919,7 @@ packages:
|
||||||
strip-ansi: 7.0.1
|
strip-ansi: 7.0.1
|
||||||
supports-color: 9.2.1
|
supports-color: 9.2.1
|
||||||
tmp-promise: 3.0.3
|
tmp-promise: 3.0.3
|
||||||
ts-node: 10.8.1_56922d2c3e8466316d745c2e9b343672
|
ts-node: 10.8.1_k2jc2lb6qrtdc3lulqxjwnbwoi
|
||||||
typescript: 4.8.4
|
typescript: 4.8.4
|
||||||
update-notifier: 5.1.0
|
update-notifier: 5.1.0
|
||||||
uuid: 8.3.2
|
uuid: 8.3.2
|
||||||
|
@ -2605,7 +2607,7 @@ packages:
|
||||||
resolution: {integrity: sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==}
|
resolution: {integrity: sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@rollup/plugin-babel/5.3.0_@babel+core@7.17.2+rollup@2.79.1:
|
/@rollup/plugin-babel/5.3.0_pf2mys4p2khuj2gysypj3zzjia:
|
||||||
resolution: {integrity: sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==}
|
resolution: {integrity: sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -2989,7 +2991,6 @@ packages:
|
||||||
|
|
||||||
/@types/marked/4.0.7:
|
/@types/marked/4.0.7:
|
||||||
resolution: {integrity: sha512-eEAhnz21CwvKVW+YvRvcTuFKNU9CV1qH+opcgVK3pIMI6YZzDm6gc8o2vHjldFk6MGKt5pueSB7IOpvpx5Qekw==}
|
resolution: {integrity: sha512-eEAhnz21CwvKVW+YvRvcTuFKNU9CV1qH+opcgVK3pIMI6YZzDm6gc8o2vHjldFk6MGKt5pueSB7IOpvpx5Qekw==}
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@types/minimatch/3.0.5:
|
/@types/minimatch/3.0.5:
|
||||||
resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==}
|
resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==}
|
||||||
|
@ -3104,7 +3105,7 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@typescript-eslint/eslint-plugin/5.39.0_be048b79d04b908735dc19ebba1dbd66:
|
/@typescript-eslint/eslint-plugin/5.39.0_xyciw6oqjoiiono4dhv3uhn5my:
|
||||||
resolution: {integrity: sha512-xVfKOkBm5iWMNGKQ2fwX5GVgBuHmZBO1tCRwXmY5oAIsPscfwm2UADDuNB8ZVYCtpQvJK4xpjrK7jEhcJ0zY9A==}
|
resolution: {integrity: sha512-xVfKOkBm5iWMNGKQ2fwX5GVgBuHmZBO1tCRwXmY5oAIsPscfwm2UADDuNB8ZVYCtpQvJK4xpjrK7jEhcJ0zY9A==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3115,10 +3116,10 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/parser': 5.39.0_eslint@8.24.0+typescript@4.8.4
|
'@typescript-eslint/parser': 5.39.0_ypn2ylkkyfa5i233caldtndbqa
|
||||||
'@typescript-eslint/scope-manager': 5.39.0
|
'@typescript-eslint/scope-manager': 5.39.0
|
||||||
'@typescript-eslint/type-utils': 5.39.0_eslint@8.24.0+typescript@4.8.4
|
'@typescript-eslint/type-utils': 5.39.0_ypn2ylkkyfa5i233caldtndbqa
|
||||||
'@typescript-eslint/utils': 5.39.0_eslint@8.24.0+typescript@4.8.4
|
'@typescript-eslint/utils': 5.39.0_ypn2ylkkyfa5i233caldtndbqa
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
eslint: 8.24.0
|
eslint: 8.24.0
|
||||||
ignore: 5.2.0
|
ignore: 5.2.0
|
||||||
|
@ -3130,7 +3131,7 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/parser/5.39.0_eslint@8.24.0+typescript@4.8.4:
|
/@typescript-eslint/parser/5.39.0_ypn2ylkkyfa5i233caldtndbqa:
|
||||||
resolution: {integrity: sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==}
|
resolution: {integrity: sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3158,7 +3159,7 @@ packages:
|
||||||
'@typescript-eslint/visitor-keys': 5.39.0
|
'@typescript-eslint/visitor-keys': 5.39.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/type-utils/5.39.0_eslint@8.24.0+typescript@4.8.4:
|
/@typescript-eslint/type-utils/5.39.0_ypn2ylkkyfa5i233caldtndbqa:
|
||||||
resolution: {integrity: sha512-KJHJkOothljQWzR3t/GunL0TPKY+fGJtnpl+pX+sJ0YiKTz3q2Zr87SGTmFqsCMFrLt5E0+o+S6eQY0FAXj9uA==}
|
resolution: {integrity: sha512-KJHJkOothljQWzR3t/GunL0TPKY+fGJtnpl+pX+sJ0YiKTz3q2Zr87SGTmFqsCMFrLt5E0+o+S6eQY0FAXj9uA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3169,7 +3170,7 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 5.39.0_typescript@4.8.4
|
'@typescript-eslint/typescript-estree': 5.39.0_typescript@4.8.4
|
||||||
'@typescript-eslint/utils': 5.39.0_eslint@8.24.0+typescript@4.8.4
|
'@typescript-eslint/utils': 5.39.0_ypn2ylkkyfa5i233caldtndbqa
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
eslint: 8.24.0
|
eslint: 8.24.0
|
||||||
tsutils: 3.21.0_typescript@4.8.4
|
tsutils: 3.21.0_typescript@4.8.4
|
||||||
|
@ -3183,7 +3184,7 @@ packages:
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/typescript-estree/5.39.0_f1deb5be19df0fe0ff039530117daddf:
|
/@typescript-eslint/typescript-estree/5.39.0_6hpllpqz34h6b7ydsuybc7nn34:
|
||||||
resolution: {integrity: sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==}
|
resolution: {integrity: sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3225,7 +3226,7 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@typescript-eslint/utils/5.39.0_eslint@8.24.0+typescript@4.8.4:
|
/@typescript-eslint/utils/5.39.0_ypn2ylkkyfa5i233caldtndbqa:
|
||||||
resolution: {integrity: sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg==}
|
resolution: {integrity: sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3303,7 +3304,7 @@ packages:
|
||||||
magic-string: 0.26.3
|
magic-string: 0.26.3
|
||||||
regenerator-runtime: 0.13.9
|
regenerator-runtime: 0.13.9
|
||||||
systemjs: 6.12.6
|
systemjs: 6.12.6
|
||||||
terser: 5.10.0
|
terser: 5.10.0_acorn@8.8.0
|
||||||
vite: 3.1.4_sass@1.55.0+terser@5.10.0
|
vite: 3.1.4_sass@1.55.0+terser@5.10.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -3432,7 +3433,7 @@ packages:
|
||||||
resolution: {integrity: sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==}
|
resolution: {integrity: sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vue/eslint-config-typescript/11.0.2_ab5ac96ab635ce1fa6bba69a2b0ff7cb:
|
/@vue/eslint-config-typescript/11.0.2_vnnms2vwgxhb7jv3u2ncwd7xzm:
|
||||||
resolution: {integrity: sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==}
|
resolution: {integrity: sha512-EiKud1NqlWmSapBFkeSrE994qpKx7/27uCGnhdqzllYDpQZroyX/O6bwjEpeuyKamvLbsGdO6PMR2faIf+zFnw==}
|
||||||
engines: {node: ^14.17.0 || >=16.0.0}
|
engines: {node: ^14.17.0 || >=16.0.0}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3443,8 +3444,8 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/eslint-plugin': 5.39.0_be048b79d04b908735dc19ebba1dbd66
|
'@typescript-eslint/eslint-plugin': 5.39.0_xyciw6oqjoiiono4dhv3uhn5my
|
||||||
'@typescript-eslint/parser': 5.39.0_eslint@8.24.0+typescript@4.8.4
|
'@typescript-eslint/parser': 5.39.0_ypn2ylkkyfa5i233caldtndbqa
|
||||||
eslint: 8.24.0
|
eslint: 8.24.0
|
||||||
eslint-plugin-vue: 9.6.0_eslint@8.24.0
|
eslint-plugin-vue: 9.6.0_eslint@8.24.0
|
||||||
typescript: 4.8.4
|
typescript: 4.8.4
|
||||||
|
@ -3551,7 +3552,7 @@ packages:
|
||||||
resolution: {integrity: sha512-GnnfjbzIPJIh9ngL9s9oGU1+Hx/h5/KFqTfJykzh/1xjaHkedV9g0MASpdmPZIP+ynNhKAcEfA6g5i8KXwtoMA==}
|
resolution: {integrity: sha512-GnnfjbzIPJIh9ngL9s9oGU1+Hx/h5/KFqTfJykzh/1xjaHkedV9g0MASpdmPZIP+ynNhKAcEfA6g5i8KXwtoMA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@vueuse/router/9.3.0_vue-router@4.1.5+vue@3.2.40:
|
/@vueuse/router/9.3.0_c7eza3xvlyb4mo6qeit5ggeo6u:
|
||||||
resolution: {integrity: sha512-UFN2MFciprH21oYsAgNHeDJ4Bd86HpRm9gximSN8j6h4fc2aa62fvfhprfHqdTxYAcgcGkMwcc9TO75jOvr8gg==}
|
resolution: {integrity: sha512-UFN2MFciprH21oYsAgNHeDJ4Bd86HpRm9gximSN8j6h4fc2aa62fvfhprfHqdTxYAcgcGkMwcc9TO75jOvr8gg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue-router: '>=4.0.0-rc.1'
|
vue-router: '>=4.0.0-rc.1'
|
||||||
|
@ -5572,7 +5573,7 @@ packages:
|
||||||
resolution: {integrity: sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==}
|
resolution: {integrity: sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==}
|
||||||
engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 5.39.0_f1deb5be19df0fe0ff039530117daddf
|
'@typescript-eslint/typescript-estree': 5.39.0_6hpllpqz34h6b7ydsuybc7nn34
|
||||||
ast-module-types: 3.0.0
|
ast-module-types: 3.0.0
|
||||||
node-source-walk: 5.0.0
|
node-source-walk: 5.0.0
|
||||||
typescript: 4.8.4
|
typescript: 4.8.4
|
||||||
|
@ -10088,7 +10089,7 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/pinia/2.0.22_typescript@4.8.4+vue@3.2.40:
|
/pinia/2.0.22_bfjwoga25wxjazzogo7o372nwq:
|
||||||
resolution: {integrity: sha512-u+b8/BC+tmvo3ACbYO2w5NfxHWFOjvvw9DQnyT0dW8aUMCPRQT5QnfZ5R5W2MzZBMTeZRMQI7V/QFbafmM9QHw==}
|
resolution: {integrity: sha512-u+b8/BC+tmvo3ACbYO2w5NfxHWFOjvvw9DQnyT0dW8aUMCPRQT5QnfZ5R5W2MzZBMTeZRMQI7V/QFbafmM9QHw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@vue/composition-api': ^1.4.0
|
'@vue/composition-api': ^1.4.0
|
||||||
|
@ -10331,7 +10332,7 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
postcss: ^8.2
|
postcss: ^8.2
|
||||||
dependencies:
|
dependencies:
|
||||||
'@csstools/selector-specificity': 2.0.2_cd239324a5aeb6e3cee0fb61f6a33448
|
'@csstools/selector-specificity': 2.0.2_zurzgjffv23ohtxa7nq7nizuja
|
||||||
postcss: 8.4.17
|
postcss: 8.4.17
|
||||||
postcss-selector-parser: 6.0.10
|
postcss-selector-parser: 6.0.10
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -11047,7 +11048,7 @@ packages:
|
||||||
glob: 7.2.0
|
glob: 7.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/rollup-plugin-terser/7.0.2_rollup@2.79.1:
|
/rollup-plugin-terser/7.0.2_acorn@8.8.0+rollup@2.79.1:
|
||||||
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
|
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
rollup: ^2.0.0
|
rollup: ^2.0.0
|
||||||
|
@ -11056,7 +11057,9 @@ packages:
|
||||||
jest-worker: 26.6.2
|
jest-worker: 26.6.2
|
||||||
rollup: 2.79.1
|
rollup: 2.79.1
|
||||||
serialize-javascript: 4.0.0
|
serialize-javascript: 4.0.0
|
||||||
terser: 5.10.0
|
terser: 5.10.0_acorn@8.8.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- acorn
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/rollup-plugin-visualizer/5.8.2_rollup@2.79.1:
|
/rollup-plugin-visualizer/5.8.2_rollup@2.79.1:
|
||||||
|
@ -11938,10 +11941,12 @@ packages:
|
||||||
supports-hyperlinks: 2.2.0
|
supports-hyperlinks: 2.2.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/terser/5.10.0:
|
/terser/5.10.0_acorn@8.8.0:
|
||||||
resolution: {integrity: sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==}
|
resolution: {integrity: sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
acorn: ^8.5.0
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
acorn:
|
acorn:
|
||||||
optional: true
|
optional: true
|
||||||
|
@ -12147,7 +12152,7 @@ packages:
|
||||||
resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==}
|
resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/ts-node/10.8.1_56922d2c3e8466316d745c2e9b343672:
|
/ts-node/10.8.1_k2jc2lb6qrtdc3lulqxjwnbwoi:
|
||||||
resolution: {integrity: sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==}
|
resolution: {integrity: sha512-Wwsnao4DQoJsN034wePSg5nZiw4YKXf56mPIAeD6wVmiv+RytNSWqc2f3fKvcUoV+Yn2+yocD71VOfQHbmVX4g==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -12545,20 +12550,21 @@ packages:
|
||||||
extsprintf: 1.3.0
|
extsprintf: 1.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite-plugin-pwa/0.13.1_vite@3.1.4:
|
/vite-plugin-pwa/0.13.1_bhe5iaipiq3lmbaxwdxgnnn2gq:
|
||||||
resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==}
|
resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^3.1.0
|
vite: ^3.1.0
|
||||||
|
workbox-build: ^6.5.4
|
||||||
|
workbox-window: ^6.5.4
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
fast-glob: 3.2.11
|
fast-glob: 3.2.11
|
||||||
pretty-bytes: 6.0.0
|
pretty-bytes: 6.0.0
|
||||||
rollup: 2.79.1
|
rollup: 2.79.1
|
||||||
vite: 3.1.4_sass@1.55.0+terser@5.10.0
|
vite: 3.1.4_sass@1.55.0+terser@5.10.0
|
||||||
workbox-build: 6.5.4
|
workbox-build: 6.5.4_acorn@8.8.0
|
||||||
workbox-window: 6.5.4
|
workbox-window: 6.5.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/babel__core'
|
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -12593,12 +12599,12 @@ packages:
|
||||||
resolve: 1.22.1
|
resolve: 1.22.1
|
||||||
rollup: 2.78.0
|
rollup: 2.78.0
|
||||||
sass: 1.55.0
|
sass: 1.55.0
|
||||||
terser: 5.10.0
|
terser: 5.10.0_acorn@8.8.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vitest/0.23.4_ddc85b0b7a78b2cfae025c8e16b7f605:
|
/vitest/0.23.4_3xefwc32pczm7lqclshbnn7wau:
|
||||||
resolution: {integrity: sha512-iukBNWqQAv8EKDBUNntspLp9SfpaVFbmzmM0sNcnTxASQZMzRw3PsM6DMlsHiI+I6GeO5/sYDg3ecpC+SNFLrQ==}
|
resolution: {integrity: sha512-iukBNWqQAv8EKDBUNntspLp9SfpaVFbmzmM0sNcnTxASQZMzRw3PsM6DMlsHiI+I6GeO5/sYDg3ecpC+SNFLrQ==}
|
||||||
engines: {node: '>=v14.16.0'}
|
engines: {node: '>=v14.16.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -12912,7 +12918,7 @@ packages:
|
||||||
workbox-core: 6.5.4
|
workbox-core: 6.5.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/workbox-build/6.5.4:
|
/workbox-build/6.5.4_acorn@8.8.0:
|
||||||
resolution: {integrity: sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA==}
|
resolution: {integrity: sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -12920,7 +12926,7 @@ packages:
|
||||||
'@babel/core': 7.17.2
|
'@babel/core': 7.17.2
|
||||||
'@babel/preset-env': 7.16.11_@babel+core@7.17.2
|
'@babel/preset-env': 7.16.11_@babel+core@7.17.2
|
||||||
'@babel/runtime': 7.17.2
|
'@babel/runtime': 7.17.2
|
||||||
'@rollup/plugin-babel': 5.3.0_@babel+core@7.17.2+rollup@2.79.1
|
'@rollup/plugin-babel': 5.3.0_pf2mys4p2khuj2gysypj3zzjia
|
||||||
'@rollup/plugin-node-resolve': 11.2.1_rollup@2.79.1
|
'@rollup/plugin-node-resolve': 11.2.1_rollup@2.79.1
|
||||||
'@rollup/plugin-replace': 2.4.2_rollup@2.79.1
|
'@rollup/plugin-replace': 2.4.2_rollup@2.79.1
|
||||||
'@surma/rollup-plugin-off-main-thread': 2.2.3
|
'@surma/rollup-plugin-off-main-thread': 2.2.3
|
||||||
|
@ -12932,7 +12938,7 @@ packages:
|
||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
pretty-bytes: 5.6.0
|
pretty-bytes: 5.6.0
|
||||||
rollup: 2.79.1
|
rollup: 2.79.1
|
||||||
rollup-plugin-terser: 7.0.2_rollup@2.79.1
|
rollup-plugin-terser: 7.0.2_acorn@8.8.0+rollup@2.79.1
|
||||||
source-map: 0.8.0-beta.0
|
source-map: 0.8.0-beta.0
|
||||||
stringify-object: 3.3.0
|
stringify-object: 3.3.0
|
||||||
strip-comments: 2.0.1
|
strip-comments: 2.0.1
|
||||||
|
@ -12955,6 +12961,7 @@ packages:
|
||||||
workbox-window: 6.5.4
|
workbox-window: 6.5.4
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/babel__core'
|
- '@types/babel__core'
|
||||||
|
- acorn
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -12964,7 +12971,7 @@ packages:
|
||||||
workbox-core: 6.5.4
|
workbox-core: 6.5.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/workbox-cli/6.5.4:
|
/workbox-cli/6.5.4_acorn@8.8.0:
|
||||||
resolution: {integrity: sha512-+Cc0jYh25MofhCROZqfQkpYSAGvykyrUVekuuPaLFbJ8qxX/zzX8hRRpglfwxDwokAjz8S20oEph4s+MyQc+Yw==}
|
resolution: {integrity: sha512-+Cc0jYh25MofhCROZqfQkpYSAGvykyrUVekuuPaLFbJ8qxX/zzX8hRRpglfwxDwokAjz8S20oEph4s+MyQc+Yw==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -12981,9 +12988,10 @@ packages:
|
||||||
stringify-object: 3.3.0
|
stringify-object: 3.3.0
|
||||||
upath: 1.2.0
|
upath: 1.2.0
|
||||||
update-notifier: 4.1.3
|
update-notifier: 4.1.3
|
||||||
workbox-build: 6.5.4
|
workbox-build: 6.5.4_acorn@8.8.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/babel__core'
|
- '@types/babel__core'
|
||||||
|
- acorn
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<vue-easymde
|
<vue-easymde
|
||||||
:configs="config"
|
:configs="config"
|
||||||
@change="bubble"
|
@change="() => bubble()"
|
||||||
@update:modelValue="handleInput"
|
@update:modelValue="handleInput"
|
||||||
class="content"
|
class="content"
|
||||||
v-if="isEditActive"
|
v-if="isEditActive"
|
||||||
|
@ -66,245 +66,245 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import {defineComponent} from 'vue'
|
import {computed, nextTick, onMounted, ref, toRefs, watch} from 'vue'
|
||||||
|
|
||||||
import VueEasymde from './vue-easymde.vue'
|
import VueEasymde from './vue-easymde.vue'
|
||||||
import {marked} from 'marked'
|
import {marked} from 'marked'
|
||||||
import DOMPurify from 'dompurify'
|
import DOMPurify from 'dompurify'
|
||||||
import {setupMarkdownRenderer} from '@/helpers/markdownRenderer'
|
|
||||||
|
|
||||||
import {createEasyMDEConfig} from './editorConfig'
|
import {createEasyMDEConfig} from './editorConfig'
|
||||||
|
|
||||||
import AttachmentModel from '../../models/attachment'
|
import AttachmentModel from '@/models/attachment'
|
||||||
import AttachmentService from '../../services/attachment'
|
import AttachmentService from '@/services/attachment'
|
||||||
import {findCheckboxesInText} from '../../helpers/checklistFromText'
|
|
||||||
|
import {setupMarkdownRenderer} from '@/helpers/markdownRenderer'
|
||||||
|
import {findCheckboxesInText} from '@/helpers/checklistFromText'
|
||||||
import {createRandomID} from '@/helpers/randomId'
|
import {createRandomID} from '@/helpers/randomId'
|
||||||
|
|
||||||
import BaseButton from '@/components/base/BaseButton.vue'
|
import BaseButton from '@/components/base/BaseButton.vue'
|
||||||
import ButtonLink from '@/components/misc/ButtonLink.vue'
|
import ButtonLink from '@/components/misc/ButtonLink.vue'
|
||||||
|
import type { IAttachment } from '@/modelTypes/IAttachment'
|
||||||
|
import type { ITask } from '@/modelTypes/ITask'
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: 'editor',
|
modelValue: {
|
||||||
components: {
|
type: String,
|
||||||
VueEasymde,
|
default: '',
|
||||||
BaseButton,
|
|
||||||
ButtonLink,
|
|
||||||
},
|
},
|
||||||
props: {
|
placeholder: {
|
||||||
modelValue: {
|
type: String,
|
||||||
type: String,
|
default: '',
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
uploadEnabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
uploadCallback: {
|
|
||||||
type: Function,
|
|
||||||
},
|
|
||||||
hasPreview: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
previewIsDefault: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
isEditEnabled: {
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
bottomActions: {
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
emptyText: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
showSave: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
// If a key is passed the editor will go in "edit" mode when the key is pressed.
|
|
||||||
// Disabled if an empty string is passed.
|
|
||||||
editShortcut: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue'],
|
uploadEnabled: {
|
||||||
computed: {
|
type: Boolean,
|
||||||
showPreviewText() {
|
default: false,
|
||||||
return this.isPreviewActive && this.text === '' && this.emptyText !== ''
|
|
||||||
},
|
|
||||||
showEditButton() {
|
|
||||||
return !this.isEditActive && this.text !== ''
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
data() {
|
uploadCallback: {
|
||||||
return {
|
type: Function,
|
||||||
text: '',
|
|
||||||
changeTimeout: null,
|
|
||||||
isEditActive: false,
|
|
||||||
isPreviewActive: true,
|
|
||||||
|
|
||||||
preview: '',
|
|
||||||
attachmentService: null,
|
|
||||||
loadedAttachments: {},
|
|
||||||
config: createEasyMDEConfig({
|
|
||||||
placeholder: this.placeholder,
|
|
||||||
uploadImage: this.uploadEnabled,
|
|
||||||
imageUploadFunction: this.uploadCallback,
|
|
||||||
}),
|
|
||||||
checkboxId: createRandomID(),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
watch: {
|
hasPreview: {
|
||||||
modelValue(modelValue) {
|
type: Boolean,
|
||||||
this.text = modelValue
|
default: true,
|
||||||
this.$nextTick(this.renderPreview)
|
|
||||||
},
|
|
||||||
text(newVal, oldVal) {
|
|
||||||
// Only bubble the new value if it actually changed, but not if the component just got mounted and the text changed from the outside.
|
|
||||||
if (oldVal === '' && this.text === this.modelValue) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.bubble()
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
previewIsDefault: {
|
||||||
if (this.modelValue !== '') {
|
type: Boolean,
|
||||||
this.text = this.modelValue
|
default: true,
|
||||||
}
|
|
||||||
|
|
||||||
if (this.previewIsDefault && this.hasPreview) {
|
|
||||||
this.$nextTick(this.renderPreview)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isPreviewActive = false
|
|
||||||
this.isEditActive = true
|
|
||||||
},
|
},
|
||||||
methods: {
|
isEditEnabled: {
|
||||||
// This gets triggered when only pasting content into the editor.
|
default: true,
|
||||||
// A change event would not get generated by that, an input event does.
|
},
|
||||||
// Therefore, we're using this handler to catch paste events.
|
bottomActions: {
|
||||||
// But because this also gets triggered when typing into the editor, we give
|
default: () => [],
|
||||||
// it a higher timeout to make the timouts cancel each other in that case so
|
},
|
||||||
// that in the end, only one change event is triggered to the outside per change.
|
emptyText: {
|
||||||
handleInput(val) {
|
type: String,
|
||||||
// Don't bubble if the text is up to date
|
default: '',
|
||||||
if (val === this.text) {
|
},
|
||||||
return
|
showSave: {
|
||||||
}
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
this.text = val
|
},
|
||||||
this.bubble(1000)
|
// If a key is passed the editor will go in "edit" mode when the key is pressed.
|
||||||
},
|
// Disabled if an empty string is passed.
|
||||||
bubble(timeout = 500) {
|
editShortcut: {
|
||||||
if (this.changeTimeout !== null) {
|
type: String,
|
||||||
clearTimeout(this.changeTimeout)
|
default: '',
|
||||||
}
|
|
||||||
|
|
||||||
this.changeTimeout = setTimeout(() => {
|
|
||||||
this.$emit('update:modelValue', this.text)
|
|
||||||
}, timeout)
|
|
||||||
},
|
|
||||||
replaceAt(str, index, replacement) {
|
|
||||||
return str.substr(0, index) + replacement + str.substr(index + replacement.length)
|
|
||||||
},
|
|
||||||
findNthIndex(str, n) {
|
|
||||||
const checkboxes = findCheckboxesInText(str)
|
|
||||||
return checkboxes[n]
|
|
||||||
},
|
|
||||||
renderPreview() {
|
|
||||||
setupMarkdownRenderer(this.checkboxId)
|
|
||||||
|
|
||||||
this.preview = DOMPurify.sanitize(marked(this.text), {ADD_ATTR: ['target']})
|
|
||||||
|
|
||||||
// Since the render function is synchronous, we can't do async http requests in it.
|
|
||||||
// Therefore, we can't resolve the blob url at (markdown) compile time.
|
|
||||||
// To work around this, we modify the url after rendering it in the vue component.
|
|
||||||
// We're doing the whole thing in the next tick to ensure the image elements are available in the
|
|
||||||
// dom tree. If we're calling this right after setting this.preview it could be the images were
|
|
||||||
// not already made available.
|
|
||||||
// Some docs at https://stackoverflow.com/q/62865160/10924593
|
|
||||||
this.$nextTick(async () => {
|
|
||||||
const attachmentImage = document.getElementsByClassName('attachment-image')
|
|
||||||
if (attachmentImage) {
|
|
||||||
for (const img of attachmentImage) {
|
|
||||||
// The url is something like /tasks/<id>/attachments/<id>
|
|
||||||
const parts = img.dataset.src.substr(window.API_URL.length + 1).split('/')
|
|
||||||
const taskId = parseInt(parts[1])
|
|
||||||
const attachmentId = parseInt(parts[3])
|
|
||||||
const cacheKey = `${taskId}-${attachmentId}`
|
|
||||||
|
|
||||||
if (typeof this.loadedAttachments[cacheKey] !== 'undefined') {
|
|
||||||
img.src = this.loadedAttachments[cacheKey]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const attachment = new AttachmentModel({taskId: taskId, id: attachmentId})
|
|
||||||
|
|
||||||
if (this.attachmentService === null) {
|
|
||||||
this.attachmentService = new AttachmentService()
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = await this.attachmentService.getBlobUrl(attachment)
|
|
||||||
img.src = url
|
|
||||||
this.loadedAttachments[cacheKey] = url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const textCheckbox = document.getElementsByClassName(`text-checkbox-${this.checkboxId}`)
|
|
||||||
if (textCheckbox) {
|
|
||||||
for (const check of textCheckbox) {
|
|
||||||
check.removeEventListener('change', this.handleCheckboxClick)
|
|
||||||
check.addEventListener('change', this.handleCheckboxClick)
|
|
||||||
check.parentElement.classList.add('has-checkbox')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
handleCheckboxClick(e) {
|
|
||||||
// Find the original markdown checkbox this is targeting
|
|
||||||
const checked = e.target.checked
|
|
||||||
const numMarkdownCheck = parseInt(e.target.dataset.checkboxNum)
|
|
||||||
|
|
||||||
const index = this.findNthIndex(this.text, numMarkdownCheck)
|
|
||||||
if (index < 0 || typeof index === 'undefined') {
|
|
||||||
console.debug('no index found')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
console.debug(index, this.text.substr(index, 9))
|
|
||||||
|
|
||||||
const listPrefix = this.text.substr(index, 1)
|
|
||||||
|
|
||||||
if (checked) {
|
|
||||||
this.text = this.replaceAt(this.text, index, `${listPrefix} [x] `)
|
|
||||||
} else {
|
|
||||||
this.text = this.replaceAt(this.text, index, `${listPrefix} [ ] `)
|
|
||||||
}
|
|
||||||
this.bubble()
|
|
||||||
this.renderPreview()
|
|
||||||
},
|
|
||||||
toggleEdit() {
|
|
||||||
if (this.isEditActive) {
|
|
||||||
this.isPreviewActive = true
|
|
||||||
this.isEditActive = false
|
|
||||||
this.renderPreview()
|
|
||||||
this.bubble(0) // save instantly
|
|
||||||
} else {
|
|
||||||
this.isPreviewActive = false
|
|
||||||
this.isEditActive = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const text = ref('')
|
||||||
|
const changeTimeout = ref<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
const isEditActive = ref(false)
|
||||||
|
const isPreviewActive = ref(true)
|
||||||
|
|
||||||
|
const showPreviewText = computed(() => isPreviewActive.value && text.value === '' && props.emptyText !== '')
|
||||||
|
const showEditButton = computed(() => !isEditActive.value && text.value !== '')
|
||||||
|
|
||||||
|
const preview = ref('')
|
||||||
|
const attachmentService = new AttachmentService()
|
||||||
|
|
||||||
|
type CacheKey = `${ITask['id']}-${IAttachment['id']}`
|
||||||
|
const loadedAttachments = ref<{[key: CacheKey]: string}>({})
|
||||||
|
const config = ref(createEasyMDEConfig({
|
||||||
|
placeholder: props.placeholder,
|
||||||
|
uploadImage: props.uploadEnabled,
|
||||||
|
imageUploadFunction: props.uploadCallback,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const checkboxId = ref(createRandomID())
|
||||||
|
|
||||||
|
const {modelValue} = toRefs(props)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
modelValue,
|
||||||
|
async (value) => {
|
||||||
|
text.value = value
|
||||||
|
await nextTick()
|
||||||
|
renderPreview()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
text,
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
// Only bubble the new value if it actually changed, but not if the component just got mounted and the text changed from the outside.
|
||||||
|
if (oldVal === '' && text.value === modelValue.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bubble()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (modelValue.value !== '') {
|
||||||
|
text.value = modelValue.value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.previewIsDefault && props.hasPreview) {
|
||||||
|
nextTick(() => renderPreview())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isPreviewActive.value = false
|
||||||
|
isEditActive.value = true
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// This gets triggered when only pasting content into the editor.
|
||||||
|
// A change event would not get generated by that, an input event does.
|
||||||
|
// Therefore, we're using this handler to catch paste events.
|
||||||
|
// But because this also gets triggered when typing into the editor, we give
|
||||||
|
// it a higher timeout to make the timouts cancel each other in that case so
|
||||||
|
// that in the end, only one change event is triggered to the outside per change.
|
||||||
|
function handleInput(val: string) {
|
||||||
|
// Don't bubble if the text is up to date
|
||||||
|
if (val === text.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
text.value = val
|
||||||
|
bubble(1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function bubble(timeout = 500) {
|
||||||
|
if (changeTimeout.value !== null) {
|
||||||
|
clearTimeout(changeTimeout.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTimeout.value = setTimeout(() => {
|
||||||
|
emit('update:modelValue', text.value)
|
||||||
|
}, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceAt(str: string, index: number, replacement: string) {
|
||||||
|
return str.slice(0, index) + replacement + str.slice(index + replacement.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
function findNthIndex(str: string, n: number) {
|
||||||
|
const checkboxes = findCheckboxesInText(str)
|
||||||
|
return checkboxes[n]
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPreview() {
|
||||||
|
setupMarkdownRenderer(checkboxId.value)
|
||||||
|
|
||||||
|
preview.value = DOMPurify.sanitize(marked(text.value), {ADD_ATTR: ['target']})
|
||||||
|
|
||||||
|
// Since the render function is synchronous, we can't do async http requests in it.
|
||||||
|
// Therefore, we can't resolve the blob url at (markdown) compile time.
|
||||||
|
// To work around this, we modify the url after rendering it in the vue component.
|
||||||
|
// We're doing the whole thing in the next tick to ensure the image elements are available in the
|
||||||
|
// dom tree. If we're calling this right after setting this.preview it could be the images were
|
||||||
|
// not already made available.
|
||||||
|
// Some docs at https://stackoverflow.com/q/62865160/10924593
|
||||||
|
nextTick().then(async () => {
|
||||||
|
const attachmentImage = document.querySelectorAll<HTMLImageElement>('.attachment-image')
|
||||||
|
if (attachmentImage) {
|
||||||
|
Array.from(attachmentImage).forEach(async (img) => {
|
||||||
|
// The url is something like /tasks/<id>/attachments/<id>
|
||||||
|
const parts = img.dataset.src?.slice(window.API_URL.length + 1).split('/')
|
||||||
|
const taskId = Number(parts[1])
|
||||||
|
const attachmentId = Number(parts[3])
|
||||||
|
const cacheKey: CacheKey = `${taskId}-${attachmentId}`
|
||||||
|
|
||||||
|
if (typeof loadedAttachments.value[cacheKey] !== 'undefined') {
|
||||||
|
img.src = loadedAttachments.value[cacheKey]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const attachment = new AttachmentModel({taskId: taskId, id: attachmentId})
|
||||||
|
|
||||||
|
const url = await attachmentService.getBlobUrl(attachment)
|
||||||
|
img.src = url
|
||||||
|
loadedAttachments.value[cacheKey] = url
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const textCheckbox = document.querySelectorAll<HTMLInputElement>(`.text-checkbox-${checkboxId.value}`)
|
||||||
|
if (textCheckbox) {
|
||||||
|
Array.from(textCheckbox).forEach(check => {
|
||||||
|
check.removeEventListener('change', handleCheckboxClick)
|
||||||
|
check.addEventListener('change', handleCheckboxClick)
|
||||||
|
check.parentElement?.classList.add('has-checkbox')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCheckboxClick(e: Event) {
|
||||||
|
// Find the original markdown checkbox this is targeting
|
||||||
|
const checked = (e.target as HTMLInputElement).checked
|
||||||
|
const numMarkdownCheck = Number((e.target as HTMLInputElement).dataset.checkboxNum)
|
||||||
|
|
||||||
|
const index = findNthIndex(text.value, numMarkdownCheck)
|
||||||
|
if (index < 0 || typeof index === 'undefined') {
|
||||||
|
console.debug('no index found')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.debug(index, text.value.slice(index, 9))
|
||||||
|
|
||||||
|
const listPrefix = text.value.slice(index, 1)
|
||||||
|
|
||||||
|
text.value = replaceAt(text.value, index, `${listPrefix} ${checked ? '[x]' : '[ ]'} `)
|
||||||
|
bubble()
|
||||||
|
renderPreview()
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleEdit() {
|
||||||
|
if (isEditActive.value) {
|
||||||
|
isPreviewActive.value = true
|
||||||
|
isEditActive.value = false
|
||||||
|
renderPreview()
|
||||||
|
bubble(0) // save instantly
|
||||||
|
} else {
|
||||||
|
isPreviewActive.value = false
|
||||||
|
isEditActive.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
@ -8,33 +8,34 @@ export function setupMarkdownRenderer(checkboxId: string) {
|
||||||
let checkboxNum = -1
|
let checkboxNum = -1
|
||||||
marked.use({
|
marked.use({
|
||||||
renderer: {
|
renderer: {
|
||||||
image: (src, title, text) => {
|
image(src: string, title: string, text: string) {
|
||||||
|
|
||||||
title = title ? ` title="${title}` : ''
|
title = title ? ` title="${title}` : ''
|
||||||
|
|
||||||
// If the url starts with the api url, the image is likely an attachment and
|
// If the url starts with the api url, the image is likely an attachment and
|
||||||
// we'll need to download and parse it properly.
|
// we'll need to download and parse it properly.
|
||||||
if (src.substr(0, window.API_URL.length + 7) === `${window.API_URL}/tasks/`) {
|
if (src.slice(0, window.API_URL.length + 7) === `${window.API_URL}/tasks/`) {
|
||||||
return `<img data-src="${src}" alt="${text}" ${title} class="attachment-image"/>`
|
return `<img data-src="${src}" alt="${text}" ${title} class="attachment-image"/>`
|
||||||
}
|
}
|
||||||
|
|
||||||
return `<img src="${src}" alt="${text}" ${title}/>`
|
return `<img src="${src}" alt="${text}" ${title}/>`
|
||||||
},
|
},
|
||||||
checkbox: (checked) => {
|
checkbox(checked: boolean) {
|
||||||
|
let checkedString = ''
|
||||||
if (checked) {
|
if (checked) {
|
||||||
checked = ' checked="checked"'
|
checkedString = 'checked'
|
||||||
}
|
}
|
||||||
|
|
||||||
checkboxNum++
|
checkboxNum++
|
||||||
return `<input type="checkbox" data-checkbox-num="${checkboxNum}" ${checked} class="text-checkbox-${checkboxId}"/>`
|
return `<input type="checkbox" data-checkbox-num="${checkboxNum}" ${checkedString} class="text-checkbox-${checkboxId}"/>`
|
||||||
},
|
},
|
||||||
link: (href, title, text) => {
|
link(href: string, title: string, text: string) {
|
||||||
const isLocal = href.startsWith(`${location.protocol}//${location.hostname}`)
|
const isLocal = href.startsWith(`${location.protocol}//${location.hostname}`)
|
||||||
const html = linkRenderer.call(renderer, href, title, text)
|
const html = linkRenderer.call(renderer, href, title, text)
|
||||||
return isLocal ? html : html.replace(/^<a /, '<a target="_blank" rel="noreferrer noopener nofollow" ')
|
return isLocal ? html : html.replace(/^<a /, '<a target="_blank" rel="noreferrer noopener nofollow" ')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
highlight: function (code, language) {
|
highlight(code, language) {
|
||||||
const validLanguage = hljs.getLanguage(language) ? language : 'plaintext'
|
const validLanguage = hljs.getLanguage(language) ? language : 'plaintext'
|
||||||
return hljs.highlight(code, {language: validLanguage}).value
|
return hljs.highlight(code, {language: validLanguage}).value
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const DEFAULT_ID_LENGTH = 9
|
const DEFAULT_ID_LENGTH = 9
|
||||||
|
|
||||||
export function createRandomID(idLength = DEFAULT_ID_LENGTH) {
|
export function createRandomID(idLength = DEFAULT_ID_LENGTH) {
|
||||||
return Math.random().toString(36).substr(2, idLength)
|
return Math.random().toString(36).slice(2, idLength)
|
||||||
}
|
}
|
|
@ -285,7 +285,7 @@ const getDateFromWeekday = (text: string): dateFoundResult => {
|
||||||
// matched string comes with a space at the end (last part of the regex).
|
// matched string comes with a space at the end (last part of the regex).
|
||||||
let foundText = results[0]
|
let foundText = results[0]
|
||||||
if (foundText.endsWith(' ')) {
|
if (foundText.endsWith(' ')) {
|
||||||
foundText = foundText.substr(0, foundText.length - 1)
|
foundText = foundText.slice(0, foundText.length - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -34,8 +34,8 @@ if (apiUrlFromStorage !== null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the api url does not contain a / at the end
|
// Make sure the api url does not contain a / at the end
|
||||||
if (window.API_URL.substr(window.API_URL.length - 1, window.API_URL.length) === '/') {
|
if (window.API_URL.slice(window.API_URL.length - 1, window.API_URL.length) === '/') {
|
||||||
window.API_URL = window.API_URL.substr(0, window.API_URL.length - 1)
|
window.API_URL = window.API_URL.slice(0, window.API_URL.length - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
Loading…
Reference in a new issue