editor-ckeditor.vue 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <template lang='pug'>
  2. .editor-ckeditor
  3. div(ref='toolbarContainer')
  4. div.contents(ref='editor')
  5. v-system-bar.editor-ckeditor-sysbar(dark, status, color='grey darken-3')
  6. .caption.editor-ckeditor-sysbar-locale {{locale.toUpperCase()}}
  7. .caption.px-3 /{{path}}
  8. template(v-if='$vuetify.breakpoint.mdAndUp')
  9. v-spacer
  10. .caption Visual Editor
  11. v-spacer
  12. .caption {{$t('editor:ckeditor.stats', { chars: stats.characters, words: stats.words })}}
  13. editor-conflict(v-model='isConflict', v-if='isConflict')
  14. page-selector(mode='select', v-model='insertLinkDialog', :open-handler='insertLinkHandler', :path='path', :locale='locale')
  15. </template>
  16. <script>
  17. import _ from 'lodash'
  18. import { get, sync } from 'vuex-pathify'
  19. import DecoupledEditor from '@requarks/ckeditor5'
  20. import EditorConflict from './ckeditor/conflict.vue'
  21. /* global siteLangs */
  22. export default {
  23. components: {
  24. EditorConflict
  25. },
  26. props: {
  27. save: {
  28. type: Function,
  29. default: () => {}
  30. }
  31. },
  32. data() {
  33. return {
  34. editor: null,
  35. stats: {
  36. characters: 0,
  37. words: 0
  38. },
  39. content: '',
  40. isConflict: false,
  41. insertLinkDialog: false
  42. }
  43. },
  44. computed: {
  45. isMobile() {
  46. return this.$vuetify.breakpoint.smAndDown
  47. },
  48. locale: get('page/locale'),
  49. path: get('page/path'),
  50. activeModal: sync('editor/activeModal')
  51. },
  52. methods: {
  53. insertLink () {
  54. this.insertLinkDialog = true
  55. },
  56. insertLinkHandler ({ locale, path }) {
  57. this.editor.execute('link', siteLangs.length > 0 ? `/${locale}/${path})` : `/${path}`)
  58. }
  59. },
  60. async mounted () {
  61. this.$store.set('editor/editorKey', 'ckeditor')
  62. this.editor = await DecoupledEditor.create(this.$refs.editor, {
  63. placeholder: 'Type the page content here',
  64. wordCount: {
  65. onUpdate: stats => {
  66. this.stats = {
  67. characters: stats.characters,
  68. words: stats.words
  69. }
  70. }
  71. }
  72. })
  73. this.$refs.toolbarContainer.appendChild(this.editor.ui.view.toolbar.element)
  74. if (this.mode !== 'create') {
  75. this.editor.setData(this.$store.get('editor/content'))
  76. }
  77. this.editor.model.document.on('change:data', _.debounce(evt => {
  78. this.$store.set('editor/content', this.editor.getData())
  79. }, 300))
  80. this.$root.$on('editorInsert', opts => {
  81. switch (opts.kind) {
  82. case 'IMAGE':
  83. this.editor.execute('imageInsert', {
  84. source: opts.path
  85. })
  86. break
  87. case 'BINARY':
  88. this.editor.execute('link', opts.path, {
  89. linkIsDownloadable: true
  90. })
  91. break
  92. }
  93. })
  94. this.$root.$on('editorLinkToPage', opts => {
  95. this.insertLink()
  96. })
  97. // Handle save conflict
  98. this.$root.$on('saveConflict', () => {
  99. this.isConflict = true
  100. })
  101. this.$root.$on('overwriteEditorContent', () => {
  102. this.editor.setData(this.$store.get('editor/content'))
  103. })
  104. },
  105. beforeDestroy () {
  106. if (this.editor) {
  107. this.editor.destroy()
  108. this.editor = null
  109. }
  110. }
  111. }
  112. </script>
  113. <style lang="scss">
  114. $editor-height: calc(100vh - 64px - 24px);
  115. $editor-height-mobile: calc(100vh - 56px - 16px);
  116. .editor-ckeditor {
  117. background-color: mc('grey', '200');
  118. flex: 1 1 50%;
  119. display: flex;
  120. flex-flow: column nowrap;
  121. height: $editor-height;
  122. max-height: $editor-height;
  123. position: relative;
  124. @at-root .theme--dark & {
  125. background-color: mc('grey', '900');
  126. }
  127. @include until($tablet) {
  128. height: $editor-height-mobile;
  129. max-height: $editor-height-mobile;
  130. }
  131. &-sysbar {
  132. padding-left: 0;
  133. &-locale {
  134. background-color: rgba(255,255,255,.25);
  135. display:inline-flex;
  136. padding: 0 12px;
  137. height: 24px;
  138. width: 63px;
  139. justify-content: center;
  140. align-items: center;
  141. }
  142. }
  143. .ck.ck-toolbar {
  144. border: none;
  145. justify-content: center;
  146. background-color: mc('grey', '300');
  147. color: #FFF;
  148. }
  149. > .ck-editor__editable {
  150. background-color: mc('grey', '100');
  151. overflow-y: auto;
  152. overflow-x: hidden;
  153. padding: 2rem;
  154. box-shadow: 0 0 5px hsla(0, 0, 0, .1);
  155. margin: 1rem auto 0;
  156. width: calc(100vw - 256px - 16vw);
  157. min-height: calc(100vh - 64px - 24px - 1rem - 40px);
  158. border-radius: 5px;
  159. @at-root .theme--dark & {
  160. background-color: #303030;
  161. color: #FFF;
  162. }
  163. @include until($widescreen) {
  164. width: calc(100vw - 2rem);
  165. margin: 1rem 1rem 0 1rem;
  166. min-height: calc(100vh - 64px - 24px - 1rem - 40px);
  167. }
  168. @include until($tablet) {
  169. width: 100%;
  170. margin: 0;
  171. min-height: calc(100vh - 56px - 24px - 76px);
  172. }
  173. &.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-focused {
  174. border-color: #FFF;
  175. box-shadow: 0 0 10px rgba(mc('blue', '700'), .25);
  176. @at-root .theme--dark & {
  177. border-color: #444;
  178. border-bottom: none;
  179. box-shadow: 0 0 10px rgba(#000, .25);
  180. }
  181. }
  182. &.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,
  183. &.ck .ck-editor__nested-editable:focus,
  184. .ck-widget.table td.ck-editor__nested-editable.ck-editor__nested-editable_focused,
  185. .ck-widget.table th.ck-editor__nested-editable.ck-editor__nested-editable_focused {
  186. background-color: mc('grey', '100');
  187. @at-root .theme--dark & {
  188. background-color: mc('grey', '900');
  189. }
  190. }
  191. }
  192. }
  193. </style>