You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
9.3 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. <template lang="pug">
  2. v-app.editor(:dark='darkMode')
  3. nav-header(dense)
  4. template(slot='actions')
  5. v-btn(
  6. outline
  7. color='green'
  8. @click.native.stop='save'
  9. :class='{ "is-icon": $vuetify.breakpoint.mdAndDown }'
  10. )
  11. v-icon(color='green', :left='$vuetify.breakpoint.lgAndUp') check
  12. span.white--text(v-if='$vuetify.breakpoint.lgAndUp') {{ mode === 'create' ? $t('common:actions.create') : $t('common:actions.save') }}
  13. v-btn(
  14. outline
  15. color='blue'
  16. @click.native.stop='openPropsModal'
  17. :class='{ "is-icon": $vuetify.breakpoint.mdAndDown, "mx-0": !welcomeMode, "ml-0": !welcomeMode }'
  18. )
  19. v-icon(color='blue', :left='$vuetify.breakpoint.lgAndUp') sort_by_alpha
  20. span.white--text(v-if='$vuetify.breakpoint.lgAndUp') {{ $t('editor:page') }}
  21. v-btn(
  22. v-if='!welcomeMode'
  23. outline
  24. color='red'
  25. :class='{ "is-icon": $vuetify.breakpoint.mdAndDown }'
  26. @click.native.stop='exit'
  27. )
  28. v-icon(color='red', :left='$vuetify.breakpoint.lgAndUp') close
  29. span.white--text(v-if='$vuetify.breakpoint.lgAndUp') {{ $t('editor:close') }}
  30. v-content
  31. component(:is='currentEditor')
  32. editor-modal-properties(v-model='dialogProps')
  33. editor-modal-editorselect(v-model='dialogEditorSelector')
  34. editor-modal-unsaved(v-model='dialogUnsaved', @discard='exitGo')
  35. loader(v-model='dialogProgress', :title='$t(`editor:save.processing`)', :subtitle='$t(`editor:save.pleaseWait`)')
  36. v-snackbar(
  37. :color='notification.style'
  38. bottom,
  39. right,
  40. multi-line,
  41. v-model='notificationState'
  42. )
  43. .text-xs-left
  44. v-icon.mr-3(dark) {{ notification.icon }}
  45. span {{ notification.message }}
  46. </template>
  47. <script>
  48. import _ from 'lodash'
  49. import { get, sync } from 'vuex-pathify'
  50. import { AtomSpinner } from 'epic-spinners'
  51. import { Base64 } from 'js-base64'
  52. import createPageMutation from 'gql/editor/create.gql'
  53. import updatePageMutation from 'gql/editor/update.gql'
  54. import editorStore from '@/store/editor'
  55. /* global WIKI */
  56. WIKI.$store.registerModule('editor', editorStore)
  57. export default {
  58. i18nOptions: { namespaces: 'editor' },
  59. components: {
  60. AtomSpinner,
  61. editorCode: () => import(/* webpackChunkName: "editor-code", webpackMode: "lazy" */ './editor/editor-code.vue'),
  62. editorMarkdown: () => import(/* webpackChunkName: "editor-markdown", webpackMode: "lazy" */ './editor/editor-markdown.vue'),
  63. editorWysiwyg: () => import(/* webpackChunkName: "editor-wysiwyg", webpackMode: "lazy" */ './editor/editor-wysiwyg.vue'),
  64. editorModalEditorselect: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-editorselect.vue'),
  65. editorModalProperties: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-properties.vue'),
  66. editorModalUnsaved: () => import(/* webpackChunkName: "editor", webpackMode: "eager" */ './editor/editor-modal-unsaved.vue')
  67. },
  68. props: {
  69. locale: {
  70. type: String,
  71. default: 'en'
  72. },
  73. path: {
  74. type: String,
  75. default: 'home'
  76. },
  77. title: {
  78. type: String,
  79. default: 'Untitled Page'
  80. },
  81. description: {
  82. type: String,
  83. default: ''
  84. },
  85. tags: {
  86. type: Array,
  87. default: () => ([])
  88. },
  89. isPublished: {
  90. type: Boolean,
  91. default: true
  92. },
  93. initEditor: {
  94. type: String,
  95. default: null
  96. },
  97. initMode: {
  98. type: String,
  99. default: 'create'
  100. },
  101. initContent: {
  102. type: String,
  103. default: null
  104. },
  105. pageId: {
  106. type: Number,
  107. default: 0
  108. }
  109. },
  110. data() {
  111. return {
  112. dialogProps: false,
  113. dialogProgress: false,
  114. dialogEditorSelector: false,
  115. dialogUnsaved: false,
  116. initContentParsed: ''
  117. }
  118. },
  119. computed: {
  120. currentEditor: sync('editor/editor'),
  121. darkMode: get('site/dark'),
  122. mode: get('editor/mode'),
  123. notification: get('notification'),
  124. notificationState: sync('notification@isActive'),
  125. welcomeMode() { return this.mode === `create` && this.path === `home` }
  126. },
  127. watch: {
  128. currentEditor(newValue, oldValue) {
  129. if (newValue !== '' && this.mode === 'create') {
  130. _.delay(() => {
  131. this.dialogProps = true
  132. }, 500)
  133. }
  134. }
  135. },
  136. created() {
  137. this.$store.commit('page/SET_ID', this.pageId)
  138. this.$store.commit('page/SET_DESCRIPTION', this.description)
  139. this.$store.commit('page/SET_IS_PUBLISHED', this.isPublished)
  140. this.$store.commit('page/SET_LOCALE', this.locale)
  141. this.$store.commit('page/SET_PATH', this.path)
  142. this.$store.commit('page/SET_TAGS', this.tags)
  143. this.$store.commit('page/SET_TITLE', this.title)
  144. this.$store.commit('page/SET_MODE', 'edit')
  145. },
  146. mounted() {
  147. this.$store.set('editor/mode', this.initMode || 'create')
  148. this.initContentParsed = this.initContent ? Base64.decode(this.initContent) : '# Header\n\nYour content here'
  149. this.$store.set('editor/content', this.initContentParsed)
  150. if (this.mode === 'create') {
  151. _.delay(() => {
  152. this.dialogEditorSelector = true
  153. }, 500)
  154. } else {
  155. this.currentEditor = `editor${_.startCase(this.initEditor || 'markdown')}`
  156. }
  157. },
  158. methods: {
  159. openPropsModal(name) {
  160. this.dialogProps = true
  161. },
  162. showProgressDialog(textKey) {
  163. this.dialogProgress = true
  164. },
  165. hideProgressDialog() {
  166. this.dialogProgress = false
  167. },
  168. async save() {
  169. this.showProgressDialog('saving')
  170. try {
  171. if (this.$store.get('editor/mode') === 'create') {
  172. // --------------------------------------------
  173. // -> CREATE PAGE
  174. // --------------------------------------------
  175. let resp = await this.$apollo.mutate({
  176. mutation: createPageMutation,
  177. variables: {
  178. content: this.$store.get('editor/content'),
  179. description: this.$store.get('page/description'),
  180. editor: 'markdown',
  181. locale: this.$store.get('page/locale'),
  182. isPrivate: false,
  183. isPublished: this.$store.get('page/isPublished'),
  184. path: this.$store.get('page/path'),
  185. publishEndDate: this.$store.get('page/publishEndDate') || '',
  186. publishStartDate: this.$store.get('page/publishStartDate') || '',
  187. tags: this.$store.get('page/tags'),
  188. title: this.$store.get('page/title')
  189. }
  190. })
  191. resp = _.get(resp, 'data.pages.create', {})
  192. if (_.get(resp, 'responseResult.succeeded')) {
  193. this.$store.commit('showNotification', {
  194. message: this.$t('editor:save.success'),
  195. style: 'success',
  196. icon: 'check'
  197. })
  198. this.$store.set('editor/id', _.get(resp, 'page.id'))
  199. this.$store.set('editor/mode', 'update')
  200. window.location.assign(`/${this.$store.get('page/path')}`)
  201. } else {
  202. throw new Error(_.get(resp, 'responseResult.message'))
  203. }
  204. } else {
  205. // --------------------------------------------
  206. // -> UPDATE EXISTING PAGE
  207. // --------------------------------------------
  208. let resp = await this.$apollo.mutate({
  209. mutation: updatePageMutation,
  210. variables: {
  211. id: this.$store.get('page/id'),
  212. content: this.$store.get('editor/content'),
  213. description: this.$store.get('page/description'),
  214. editor: 'markdown',
  215. locale: this.$store.get('page/locale'),
  216. isPrivate: false,
  217. isPublished: this.$store.get('page/isPublished'),
  218. path: this.$store.get('page/path'),
  219. publishEndDate: this.$store.get('page/publishEndDate') || '',
  220. publishStartDate: this.$store.get('page/publishStartDate') || '',
  221. tags: this.$store.get('page/tags'),
  222. title: this.$store.get('page/title')
  223. }
  224. })
  225. resp = _.get(resp, 'data.pages.update', {})
  226. if (_.get(resp, 'responseResult.succeeded')) {
  227. this.$store.commit('showNotification', {
  228. message: this.$t('editor:save.success'),
  229. style: 'success',
  230. icon: 'check'
  231. })
  232. } else {
  233. throw new Error(_.get(resp, 'responseResult.message'))
  234. }
  235. }
  236. this.initContentParsed = this.$store.get('editor/content')
  237. } catch (err) {
  238. this.$store.commit('showNotification', {
  239. message: err.message,
  240. style: 'error',
  241. icon: 'warning'
  242. })
  243. }
  244. this.hideProgressDialog()
  245. },
  246. async exit() {
  247. if (this.initContentParsed !== this.$store.get('editor/content')) {
  248. this.dialogUnsaved = true
  249. } else {
  250. this.exitGo()
  251. }
  252. },
  253. exitGo() {
  254. this.$store.commit(`loadingStart`, 'editor-close')
  255. this.currentEditor = ''
  256. _.delay(() => {
  257. if (this.$store.get('editor/mode') === 'create') {
  258. window.location.assign(`/`)
  259. } else {
  260. window.location.assign(`/${this.$store.get('page/path')}`)
  261. }
  262. }, 500)
  263. }
  264. }
  265. }
  266. </script>
  267. <style lang='scss'>
  268. .editor {
  269. background-color: mc('grey', '900') !important;
  270. min-height: 100vh;
  271. }
  272. .atom-spinner.is-inline {
  273. display: inline-block;
  274. }
  275. </style>