From dc4020679f21b0c8dde39529b200861a59e8e115 Mon Sep 17 00:00:00 2001 From: Kailash Nadh Date: Mon, 6 Jul 2020 00:46:08 +0530 Subject: [PATCH] Add syntax highlighted HTML code editor --- frontend/package.json | 1 + frontend/src/assets/style.scss | 10 ++++++ frontend/src/components/Editor.vue | 53 +++++++++++++++++++++++++++--- frontend/yarn.lock | 51 ++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 4 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 6022e94..3cc421e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,7 @@ "axios": "^0.19.2", "buefy": "^0.8.20", "c3": "^0.7.18", + "codeflask": "^1.4.1", "core-js": "^3.6.5", "dayjs": "^1.8.28", "humps": "^2.0.1", diff --git a/frontend/src/assets/style.scss b/frontend/src/assets/style.scss index aaecd00..6a733d7 100644 --- a/frontend/src/assets/style.scss +++ b/frontend/src/assets/style.scss @@ -126,6 +126,16 @@ section { } } +/* HTML code editor */ +.html-editor { + position: relative; + width: 100%; + min-height: 250px; + height: 65vh; + border: 1px solid $grey-lighter; + border-radius: 2px; +} + /* Table colors and padding */ .main table { thead th { diff --git a/frontend/src/components/Editor.vue b/frontend/src/components/Editor.vue index 144b33e..0eac32e 100644 --- a/frontend/src/components/Editor.vue +++ b/frontend/src/components/Editor.vue @@ -33,10 +33,8 @@ /> - - +
import 'quill/dist/quill.snow.css'; import 'quill/dist/quill.core.css'; + import { quillEditor } from 'vue-quill-editor'; +import CodeFlask from 'codeflask'; + import CampaignPreview from './CampaignPreview.vue'; import Media from '../views/Media.vue'; @@ -155,6 +156,31 @@ export default { this.$emit('input', { contentType: this.form.format, body: this.form.body }); }, + initHTMLEditor() { + // CodeFlask editor is rendered in a shadow DOM tree to keep its styles + // sandboxed away from the global styles. + const el = document.createElement('code-flask'); + el.attachShadow({ mode: 'open' }); + el.shadowRoot.innerHTML = ` + +
+ `; + this.$refs.htmlEditor.appendChild(el); + + const flask = new CodeFlask(el.shadowRoot.getElementById('area'), { + language: 'html', + lineNumbers: true, + styleParent: el.shadowRoot, + readonly: this.disabled, + }); + + flask.updateCode(this.form.body); + flask.onUpdate((b) => { + this.form.body = b; + this.$emit('input', { contentType: this.form.format, body: this.form.body }); + }); + }, + togglePreview() { this.isPreviewing = !this.isPreviewing; }, @@ -168,6 +194,12 @@ export default { }, }, + computed: { + htmlFormat() { + return this.form.format; + }, + }, + watch: { // Capture contentType and body passed from the parent as props. contentType(f) { @@ -182,6 +214,19 @@ export default { body(b) { this.form.body = b; }, + + htmlFormat(f) { + if (f !== 'html') { + return; + } + + this.$nextTick(() => { + this.initHTMLEditor(); + }); + }, + }, + + mounted() { }, }; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 246eee0..f2f54cf 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -923,6 +923,11 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== +"@types/prismjs@^1.9.1": + version "1.16.1" + resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.16.1.tgz#50b82947207847db6abcbcd14caa89e3b897c259" + integrity sha512-RNgcK3FEc1GpeOkamGDq42EYkb6yZW5OWQwTS56NJIB8WL0QGISQglA7En7NUx9RGP8AC52DOe+squqbAckXlA== + "@types/q@^1.5.1": version "1.5.4" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" @@ -2306,6 +2311,15 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== +clipboard@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376" + integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg== + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + clipboardy@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290" @@ -2366,6 +2380,14 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= +codeflask@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/codeflask/-/codeflask-1.4.1.tgz#c5229854e3f648377922a75f1145f7316030d3db" + integrity sha512-4vb2IbE/iwvP0Uubhd2ixVeysm3KNC2pl7SoDaisxq1juhZzvap3qbaX7B2CtpQVvv5V9sjcQK8hO0eTcY0V9Q== + dependencies: + "@types/prismjs" "^1.9.1" + prismjs "^1.14.0" + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -3264,6 +3286,11 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +delegate@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" + integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -4444,6 +4471,13 @@ globule@^1.0.0: lodash "~4.17.12" minimatch "~3.0.2" +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= + dependencies: + delegate "^3.1.2" + graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.2: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" @@ -7095,6 +7129,13 @@ pretty-error@^2.0.2: renderkid "^2.0.1" utila "~0.4" +prismjs@^1.14.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.20.0.tgz#9b685fc480a3514ee7198eac6a3bf5024319ff03" + integrity sha512-AEDjSrVNkynnw6A+B1DsFkd6AVdTnp+/WoUixFRULlCLZVRZlVQMVWio/16jv7G1FscUxQxOQhWwApgbnxr6kQ== + optionalDependencies: + clipboard "^2.0.0" + private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -7743,6 +7784,11 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= +select@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= + selfsigned@^1.10.7: version "1.10.7" resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b" @@ -8531,6 +8577,11 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-emitter@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" + integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"