diff --git a/coeditor_frontend/package-lock.json b/coeditor_frontend/package-lock.json index ca058a2..350798f 100644 --- a/coeditor_frontend/package-lock.json +++ b/coeditor_frontend/package-lock.json @@ -31,7 +31,9 @@ "@vue/cli-plugin-vuex": "~5.0.0", "@vue/cli-service": "~5.0.0", "eslint": "^7.32.0", - "eslint-plugin-vue": "^8.0.3" + "eslint-plugin-vue": "^8.0.3", + "unplugin-auto-import": "^0.16.1", + "unplugin-vue-components": "^0.25.0" } }, "node_modules/@achrinza/node-ipc": { @@ -61,6 +63,15 @@ "node": ">=6.0.0" } }, + "node_modules/@antfu/utils": { + "version": "0.7.10", + "resolved": "https://registry.npmmirror.com/@antfu/utils/-/utils-0.7.10.tgz", + "integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@babel/code-frame": { "version": "7.26.0", "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.0.tgz", @@ -2676,6 +2687,40 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.3", + "resolved": "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz", @@ -3847,9 +3892,9 @@ } }, "node_modules/acorn": { - "version": "8.13.0", - "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.13.0.tgz", - "integrity": "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w==", + "version": "8.14.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -4928,6 +4973,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", @@ -8028,6 +8079,22 @@ "json5": "lib/cli.js" } }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz", @@ -8567,6 +8634,18 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mlly": { + "version": "1.7.3", + "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.7.3.tgz", + "integrity": "sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^1.1.2", + "pkg-types": "^1.2.1", + "ufo": "^1.5.4" + } + }, "node_modules/module-alias": { "version": "2.2.3", "resolved": "https://registry.npmmirror.com/module-alias/-/module-alias-2.2.3.tgz", @@ -9153,6 +9232,12 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", @@ -9182,6 +9267,17 @@ "node": ">=8" } }, + "node_modules/pkg-types": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.2.1.tgz", + "integrity": "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==", + "dev": true, + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.2", + "pathe": "^1.1.2" + } + }, "node_modules/portfinder": { "version": "1.0.32", "resolved": "https://registry.npmmirror.com/portfinder/-/portfinder-1.0.32.tgz", @@ -10335,6 +10431,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz", @@ -10861,6 +10963,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/strip-literal/-/strip-literal-2.1.0.tgz", + "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", + "dev": true, + "dependencies": { + "js-tokens": "^9.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", + "dev": true + }, "node_modules/stylehacks": { "version": "5.1.1", "resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz", @@ -11237,6 +11357,12 @@ "node": ">= 0.6" } }, + "node_modules/ufo": { + "version": "1.5.4", + "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.19.8.tgz", @@ -11283,6 +11409,48 @@ "node": ">=4" } }, + "node_modules/unimport": { + "version": "3.13.2", + "resolved": "https://registry.npmmirror.com/unimport/-/unimport-3.13.2.tgz", + "integrity": "sha512-VKAepeIb6BWLtBl4tmyHY1/7rJgz3ynmZrWf8cU1a+v5Uv/k1gyyAEeGBnYcrwy8bxG5sflxEx4a9VQUqOVHUA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.3", + "acorn": "^8.14.0", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.12", + "mlly": "^1.7.3", + "pathe": "^1.1.2", + "pkg-types": "^1.2.1", + "scule": "^1.3.0", + "strip-literal": "^2.1.0", + "unplugin": "^1.15.0" + } + }, + "node_modules/unimport/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unimport/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", @@ -11301,6 +11469,167 @@ "node": ">= 0.8" } }, + "node_modules/unplugin": { + "version": "1.16.0", + "resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-1.16.0.tgz", + "integrity": "sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/unplugin-auto-import": { + "version": "0.16.1", + "resolved": "https://registry.npmmirror.com/unplugin-auto-import/-/unplugin-auto-import-0.16.1.tgz", + "integrity": "sha512-H3Ky56cGEEHTssxUIFuGXTowGVlT/Bp3MBx1yyCzUHzAtdrO+2r9zpid32f2AkTpQxo2lch6yaTK61Im+rEyPQ==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.2", + "@rollup/pluginutils": "^5.0.2", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", + "minimatch": "^9.0.1", + "unimport": "^3.0.7", + "unplugin": "^1.3.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-auto-import/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/unplugin-auto-import/node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unplugin-auto-import/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/unplugin-vue-components": { + "version": "0.25.0", + "resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-0.25.0.tgz", + "integrity": "sha512-HxrQ4GMSS1RwVww2av3a42cABo/v5AmTRN9iARv6e/xwkrfTyHhLh84kFwXxKkXK61vxDHxaryn694mQmkiVBg==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.3", + "@rollup/pluginutils": "^5.0.2", + "chokidar": "^3.5.3", + "debug": "^4.3.4", + "fast-glob": "^3.2.12", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", + "minimatch": "^9.0.1", + "resolve": "^1.22.2", + "unplugin": "^1.3.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/unplugin-vue-components/node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unplugin-vue-components/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/unplugin/node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", diff --git a/coeditor_frontend/package.json b/coeditor_frontend/package.json index b9c1f7c..567cf17 100644 --- a/coeditor_frontend/package.json +++ b/coeditor_frontend/package.json @@ -31,7 +31,9 @@ "@vue/cli-plugin-vuex": "~5.0.0", "@vue/cli-service": "~5.0.0", "eslint": "^7.32.0", - "eslint-plugin-vue": "^8.0.3" + "eslint-plugin-vue": "^8.0.3", + "unplugin-auto-import": "^0.16.1", + "unplugin-vue-components": "^0.25.0" }, "eslintConfig": { "root": true, diff --git a/coeditor_frontend/src/components/plugins.js b/coeditor_frontend/src/components/plugins.js index 5980994..e77f49d 100644 --- a/coeditor_frontend/src/components/plugins.js +++ b/coeditor_frontend/src/components/plugins.js @@ -1,18 +1,101 @@ import { - Plugin, - ButtonView, + AccessibilityHelp, + Alignment, + Autoformat, + AutoImage, + AutoLink, + Autosave, + BalloonToolbar, + Base64UploadAdapter, + BlockQuote, + Bold, + Code, + CodeBlock, + Essentials, + FindAndReplace, + FontBackgroundColor, + FontColor, + FontFamily, + FontSize, + GeneralHtmlSupport, + Heading, + Highlight, + HorizontalLine, + ImageBlock, + ImageCaption, + ImageInline, + ImageInsert, + ImageInsertViaUrl, + ImageResize, + ImageStyle, + ImageTextAlternative, + ImageToolbar, + ImageUpload, + Indent, + IndentBlock, + Italic, + Link, + LinkImage, + List, + ListProperties, + Markdown, + MediaEmbed, + Mention, + PageBreak, + Paragraph, + PasteFromMarkdownExperimental, + PasteFromOffice, + RemoveFormat, + SelectAll, + SpecialCharacters, + SpecialCharactersArrows, + SpecialCharactersCurrency, + SpecialCharactersEssentials, + SpecialCharactersLatin, + SpecialCharactersMathematical, + SpecialCharactersText, + Strikethrough, + Style, + Subscript, + Superscript, + Table, + TableCaption, + TableCellProperties, + TableColumnResize, + TableProperties, + TableToolbar, + TextTransformation, + TodoList, + Underline, + Undo, + + Plugin, + ButtonView, createDropdown, Collection, addListToDropdown, } from 'ckeditor5'; +import translations from 'ckeditor5/translations/zh-cn.js'; import { asBlob } from 'html-docx-js-typescript' import { saveAs } from 'file-saver'; import { - getStyle, - getPageContent + getStyle, + getPageContent, + getUserConfigFromBackend, + saveData } from './utils'; // 导出为docx插件 +function exportWord(){ + const pageContent = getPageContent(); + const style = getStyle(); + const page = '' + style + '' + pageContent + '' + + // console.log(page); + asBlob(page).then(data => { + saveAs(data, 'file.docx') // save as docx file + }); // asBlob() return Promise +} class Export2Word extends Plugin { init() { const editor = this.editor; @@ -27,22 +110,20 @@ class Export2Word extends Plugin { tooltip: true, // 图标 直接插入svg文件 - icon: '' - + icon: '', + keystroke: 'Ctrl+W' }); // Execute a callback function when the button is clicked button.on('execute', () => { - const pageContent = getPageContent(); - const style = getStyle(); - const page = '' + style + '' + pageContent + '' - - // console.log(page); - asBlob(page).then(data => { - saveAs(data, 'file.docx') // save as docx file - }); // asBlob() return Promise + exportWord(); + }); + + // 添加快捷键 Ctrl+W 导出为docx + editor.keystrokes.set('Ctrl+W', (event, cancel) => { + exportWord(); + cancel(); }); - return button; }); @@ -66,7 +147,22 @@ class Export2Word extends Plugin { } } + // 导出为PDF插件 +function printPDF() { + const pageContent = getPageContent(); + console.log(pageContent); + const style = getStyle(); + // 去掉element中的 ck-focused ck-weight_selected消除页面和图片的蓝边 + const page = '' + style + '' + pageContent.replaceAll('ck-focused', 'ck-blurred').replaceAll('ck-weight_selected', '') + '' + const newWindow = window.open('', 'PrintDocument', 'height=600,width=700,top=50,left=50'); + newWindow.document.write(page); + newWindow.document.close(); + newWindow.print(); + newWindow.onafterprint = function () { + newWindow.close(); + } +} class Export2PDF extends Plugin { init() { const editor = this.editor; @@ -81,30 +177,26 @@ class Export2PDF extends Plugin { tooltip: true, // 图标 直接插入svg文件 - icon: '' - + icon: '', + keystroke: 'Ctrl+P' }); // Execute a callback function when the button is clicked button.on('execute', () => { - const pageContent = getPageContent(); - console.log(pageContent); - const style = getStyle(); - // 去掉element中的 ck-focused ck-weight_selected消除页面和图片的蓝边 - const page = '' + style + '' + pageContent.replaceAll('ck-focused', 'ck-blurred').replaceAll('ck-weight_selected', '') + '' - const newWindow = window.open('', 'PrintDocument', 'height=600,width=700,top=50,left=50'); - newWindow.document.write(page); - newWindow.document.close(); - newWindow.print(); - newWindow.onafterprint = function () { - newWindow.close(); - } + printPDF(); + }); + + // 添加快捷键 Ctrl+P 导出为PDF + editor.keystrokes.set('Ctrl+P', (event, cancel) => { + printPDF(); + cancel(); }); return button; }); } } + // 智能润色插件 class Translation extends Plugin { init() { @@ -174,8 +266,9 @@ class Translation extends Plugin { }); } } -// 侧边栏 -class ToggleSideBar extends Plugin{ + +// 侧边栏按钮 +class ToggleSideBar extends Plugin { // constructor(toggleSidebar) { // super(); // this.toggleSidebar = toggleSidebar; @@ -200,7 +293,6 @@ class ToggleSideBar extends Plugin{ button.on('execute', () => { // 打开sidebar const bt = document.getElementById("toggleSidebarButton"); - console.log(bt); bt.click(); }); @@ -209,4 +301,288 @@ class ToggleSideBar extends Plugin{ } } -export { Export2Word, Export2PDF, Translation, ToggleSideBar }; \ No newline at end of file +// 保存按钮 +class SaveButton extends Plugin { + // constructor(toggleSidebar) { + // super(); + // this.toggleSidebar = toggleSidebar; + // } + init() { + const editor = this.editor; + + editor.ui.componentFactory.add('SaveButton', () => { + // The button will be an instance of ButtonView. + const button = new ButtonView(); + + button.set({ + label: '保存', + // withText: true + tooltip: true, + // 图标 直接插入svg文件 + icon: '', + keystroke: 'Ctrl+S' + + }); + + // Execute a callback function when the button is clicked + button.on('execute', () => { + saveData(getPageContent()) + }); + + return button; + }); + + // 添加快捷键 Ctrl+S 保存 + editor.keystrokes.set('Ctrl+S', (event, cancel) => { + saveData(getPageContent()); + cancel(); + }); + } +} + +// 配置CKEditor5 +function setConfig() { + // 获取用户的样式配置 + const userConfig = getUserConfigFromBackend(); + return { + toolbar: { + items: [ + 'undo', + 'redo', + '|', + 'heading', + 'style', + '|', + 'fontSize', + 'fontFamily', + 'fontColor', + 'fontBackgroundColor', + '|', + 'bold', + 'italic', + 'underline', + '|', + 'link', + 'insertImage', + 'insertTable', + 'highlight', + 'codeBlock', + 'blockquote', + '|', + 'alignment', + 'bulletedList', + 'numberedList', + 'outdent', + 'indent', + '|', 'ExportToWord', 'ExportToPDF', 'translate', 'SideBar', 'SaveButton' + ], + shouldNotGroupWhenFull: true + }, + plugins: [ + AccessibilityHelp, + Alignment, + Autoformat, + AutoImage, + AutoLink, + Autosave, + BalloonToolbar, + Base64UploadAdapter, + BlockQuote, + Bold, + Code, + CodeBlock, + Essentials, + FindAndReplace, + FontBackgroundColor, + FontColor, + FontFamily, + FontSize, + GeneralHtmlSupport, + Heading, + Highlight, + HorizontalLine, + ImageBlock, + ImageCaption, + ImageInline, + ImageInsert, + ImageInsertViaUrl, + ImageResize, + ImageStyle, + ImageTextAlternative, + ImageToolbar, + ImageUpload, + Indent, + IndentBlock, + Italic, + Link, + LinkImage, + List, + ListProperties, + Markdown, + MediaEmbed, + Mention, + PageBreak, + Paragraph, + PasteFromMarkdownExperimental, + PasteFromOffice, + RemoveFormat, + SelectAll, + SpecialCharacters, + SpecialCharactersArrows, + SpecialCharactersCurrency, + SpecialCharactersEssentials, + SpecialCharactersLatin, + SpecialCharactersMathematical, + SpecialCharactersText, + Strikethrough, + Style, + Subscript, + Superscript, + Table, + TableCaption, + TableCellProperties, + TableColumnResize, + TableProperties, + TableToolbar, + TextTransformation, + TodoList, + Underline, + Undo, + Export2Word, Translation, Export2PDF, ToggleSideBar, SaveButton + ], + balloonToolbar: ['bold', 'italic', '|', 'link', 'insertImage', '|', 'bulletedList', 'numberedList'], + //自定义设置字体 + fontFamily: { + // 自定义字体 + options: userConfig.fontFamily.options, + // 启用对所有字体名称的支持 + supportAllValues: true, + }, + fontSize: { + // 五号,小四,四号,小三,三号,小二,二号 + options: userConfig.fontSize.options, + supportAllValues: true + }, + heading: { + options: [ + { + model: 'paragraph', + title: 'Paragraph', + class: 'ck-heading_paragraph' + }, + { + model: 'heading1', + view: 'h1', + title: 'Heading 1', + class: 'ck-heading_heading1' + }, + { + model: 'heading2', + view: 'h2', + title: 'Heading 2', + class: 'ck-heading_heading2' + }, + { + model: 'heading3', + view: 'h3', + title: 'Heading 3', + class: 'ck-heading_heading3' + }, + { + model: 'heading4', + view: 'h4', + title: 'Heading 4', + class: 'ck-heading_heading4' + }, + { + model: 'heading5', + view: 'h5', + title: 'Heading 5', + class: 'ck-heading_heading5' + }, + { + model: 'heading6', + view: 'h6', + title: 'Heading 6', + class: 'ck-heading_heading6' + } + ] + }, + htmlSupport: { + allow: [ + { + name: /^.*$/, + styles: true, + attributes: true, + classes: true + } + ] + }, + image: { + toolbar: [ + 'toggleImageCaption', + 'imageTextAlternative', + '|', + 'imageStyle:inline', + 'imageStyle:wrapText', + 'imageStyle:breakText', + '|', + 'resizeImage' + ] + }, + initialData: + '', + language: 'zh-cn', + link: { + addTargetToExternalLinks: true, + defaultProtocol: 'https://', + decorators: { + toggleDownloadable: { + mode: 'manual', + label: 'Downloadable', + attributes: { + download: 'file' + } + } + } + }, + list: { + properties: { + styles: true, + startIndex: true, + reversed: true + } + }, + mention: { + feeds: [ + { + marker: '@', + feed: [ + /* See: https://ckeditor.com/docs/ckeditor5/latest/features/mentions.html */ + ] + } + ] + }, + menuBar: { + isVisible: true, + removeItems: ['help'], + }, + placeholder: 'Type or paste your content here!', + // 用户可以自定义和管理样式 + style: { + definitions: userConfig.style.definitions + }, + table: { + contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties'] + }, + autosave: { + waitingTime: 180000, // (in ms) 3minutes + save() { + // TODO save + return saveData(getPageContent()); + } + }, + translations: [translations] + } +} +export { Export2Word, Export2PDF, Translation, ToggleSideBar, setConfig }; \ No newline at end of file diff --git a/coeditor_frontend/src/components/utils.js b/coeditor_frontend/src/components/utils.js index 1b1bacb..a489cb5 100644 --- a/coeditor_frontend/src/components/utils.js +++ b/coeditor_frontend/src/components/utils.js @@ -75,11 +75,6 @@ export function getUserConfigFromBackend() { name: 'Code (bright)', element: 'pre', classes: ['fancy-code', 'fancy-code-bright'] - }, - { - name: 'GradientBorder', - element: 'p', - classes: ['gradientborder'] } ] } = options; @@ -126,9 +121,9 @@ export function getStyle() { // 获取用户编辑的内容 export function getPageContent() { - // const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div.ck.ck-reset.ck-editor.ck-rounded-corners > div.ck.ck-editor__main > div"); - const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div"); - return pageContent.innerHTML; + const pageContent =document.querySelector("#app > div > div > div.editor-container.editor-container_document-editor.editor-container_include-style > div.editor-container__editor-wrapper > div > div"); + // const pageContent = document.querySelector("#app > div > div > div > div.editor-container__editor-wrapper > div > div > div"); + return pageContent.outerHTML; } // 获取并应用用户定义的样式 @@ -140,4 +135,4 @@ export function getAndApplyUserStyles() { styleElement.innerHTML = styles; document.head.appendChild(styleElement); return styles; -} \ No newline at end of file +} diff --git a/coeditor_frontend/src/public/sidebar.css b/coeditor_frontend/src/public/sidebar.css new file mode 100644 index 0000000..5e083fe --- /dev/null +++ b/coeditor_frontend/src/public/sidebar.css @@ -0,0 +1,127 @@ +/*侧边栏样式*/ +.sidebar { + position: fixed; + top: 0; + left: 0; + width: 350px; + height: 100%; + overflow-y: hidden; + transition: transform 0.3s ease; + transform: translateX(-100%); + background-color: #f9f9f9; + padding-left: 8px; + /* 调整内边距,使文字右移 */ + padding-right: 8px; + /* 调整内边距,使文字右移 */ + z-index: 9; + border-right: 5px solid #aec7e5; + resize: horizontal; + overflow: auto; +} + +.sidebar.active { + transform: translateX(0); +} + +.sidebar-menu { + flex-direction: row; + justify-content: space-between; + /* background-color: rgb(182, 229, 244); */ + border-radius: 19px; + /* 添加圆角 */ + display: flex; +} + +.sidebar-menu .el-sub-menu { + display: flex; + flex-direction: column; +} + +.sidebar-menu .el-menu-item { + flex: 1; + text-align: left; + background-color: #9cd6ce; + border-radius: 8px; + /* 添加圆角 */ + margin: 2px 0; + /* 添加间距 */ +} + +.sidebar-menu .el-menu-item span { + display: block; + padding: 10px; + background-color: #ffffff; + border-radius: 4px; +} + +.sidebar-menu .el-menu-item span:hover { + background-color: #e0e0e0; +} + +.preview { + margin-top: 20px; + /* 调整预览区与表单之间的距离 */ + border: 1px solid #ccc; + /* 添加边框 */ + padding: 10px; + /* 添加内边距 */ + border-radius: 4px; + /* 添加圆角 */ +} + +.form-item { + margin-bottom: 1px; + /* 减小表单项之间的距离 */ +} + +.chat-container { + display: flex; + flex-direction: column; + height: 90vh; + justify-content: space-between; +} + +.messages { + flex: 1; + overflow-y: auto; + margin-bottom: 10px; +} + +.message pre { + white-space: pre-wrap; + /* 保留空白符,但允许自动换行 */ + word-wrap: break-word; + /* 允许长单词换行 */ +} + +.input-area { + display: flex; +} + +.input-area input { + flex: 1; + padding: 10px; + border: 1px solid #ccc; + border-radius: 4px; +} + +.input-area button { + padding: 10px 15px; + background-color: #2980b9; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + margin-left: 5px; +} + +.input-area button:hover { + background-color: #3498db; +} + +.message { + margin: 5px 0; + padding: 10px; + border-radius: 4px; + background-color: #ecf0f1; +} \ No newline at end of file diff --git a/coeditor_frontend/src/views/CkeditorView.vue b/coeditor_frontend/src/views/CkeditorView.vue index 39b4e9d..9fe7dae 100644 --- a/coeditor_frontend/src/views/CkeditorView.vue +++ b/coeditor_frontend/src/views/CkeditorView.vue @@ -18,8 +18,8 @@ id="toggleSidebarButton">打开/关闭侧边栏