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.

230 lines
6.2 KiB

  1. 'use strict'
  2. import $ from 'jquery'
  3. import Vue from 'vue'
  4. import _ from 'lodash'
  5. import filesize from 'filesize.js'
  6. import SimpleMDE from 'simplemde'
  7. import pageLoader from '../components/page-loader'
  8. // ====================================
  9. // Markdown Editor
  10. // ====================================
  11. module.exports = (alerts, pageEntryPath, socket) => {
  12. if ($('#mk-editor').length === 1) {
  13. Vue.filter('filesize', (v) => {
  14. return _.toUpper(filesize(v))
  15. })
  16. let mdeModalOpenState = false
  17. let vueImage
  18. let vueFile
  19. let vueVideo
  20. let vueCodeBlock
  21. let mde = new SimpleMDE({
  22. autofocus: true,
  23. autoDownloadFontAwesome: false,
  24. element: $('#mk-editor').get(0),
  25. placeholder: 'Enter Markdown formatted content here...',
  26. spellChecker: false,
  27. status: false,
  28. toolbar: [
  29. {
  30. name: 'bold',
  31. action: SimpleMDE.toggleBold,
  32. className: 'icon-bold',
  33. title: 'Bold'
  34. },
  35. {
  36. name: 'italic',
  37. action: SimpleMDE.toggleItalic,
  38. className: 'icon-italic',
  39. title: 'Italic'
  40. },
  41. {
  42. name: 'strikethrough',
  43. action: SimpleMDE.toggleStrikethrough,
  44. className: 'icon-strikethrough',
  45. title: 'Strikethrough'
  46. },
  47. '|',
  48. {
  49. name: 'heading-1',
  50. action: SimpleMDE.toggleHeading1,
  51. className: 'icon-header fa-header-x fa-header-1',
  52. title: 'Big Heading'
  53. },
  54. {
  55. name: 'heading-2',
  56. action: SimpleMDE.toggleHeading2,
  57. className: 'icon-header fa-header-x fa-header-2',
  58. title: 'Medium Heading'
  59. },
  60. {
  61. name: 'heading-3',
  62. action: SimpleMDE.toggleHeading3,
  63. className: 'icon-header fa-header-x fa-header-3',
  64. title: 'Small Heading'
  65. },
  66. {
  67. name: 'quote',
  68. action: SimpleMDE.toggleBlockquote,
  69. className: 'icon-quote-left',
  70. title: 'Quote'
  71. },
  72. '|',
  73. {
  74. name: 'unordered-list',
  75. action: SimpleMDE.toggleUnorderedList,
  76. className: 'icon-th-list',
  77. title: 'Bullet List'
  78. },
  79. {
  80. name: 'ordered-list',
  81. action: SimpleMDE.toggleOrderedList,
  82. className: 'icon-list-ol',
  83. title: 'Numbered List'
  84. },
  85. '|',
  86. {
  87. name: 'link',
  88. action: (editor) => {
  89. /* if(!mdeModalOpenState) {
  90. mdeModalOpenState = true;
  91. $('#modal-editor-link').slideToggle();
  92. } */
  93. window.alert('Coming soon!')
  94. },
  95. className: 'icon-link2',
  96. title: 'Insert Link'
  97. },
  98. {
  99. name: 'image',
  100. action: (editor) => {
  101. if (!mdeModalOpenState) {
  102. vueImage.open()
  103. }
  104. },
  105. className: 'icon-image',
  106. title: 'Insert Image'
  107. },
  108. {
  109. name: 'file',
  110. action: (editor) => {
  111. if (!mdeModalOpenState) {
  112. vueFile.open()
  113. }
  114. },
  115. className: 'icon-paper',
  116. title: 'Insert File'
  117. },
  118. {
  119. name: 'video',
  120. action: (editor) => {
  121. if (!mdeModalOpenState) {
  122. vueVideo.open()
  123. }
  124. },
  125. className: 'icon-video-camera2',
  126. title: 'Insert Video Player'
  127. },
  128. '|',
  129. {
  130. name: 'inline-code',
  131. action: (editor) => {
  132. if (!editor.codemirror.doc.somethingSelected()) {
  133. return alerts.pushError('Invalid selection', 'You must select at least 1 character first.')
  134. }
  135. let curSel = editor.codemirror.doc.getSelections()
  136. curSel = _.map(curSel, (s) => {
  137. return '`' + s + '`'
  138. })
  139. editor.codemirror.doc.replaceSelections(curSel)
  140. },
  141. className: 'icon-terminal',
  142. title: 'Inline Code'
  143. },
  144. {
  145. name: 'code-block',
  146. action: (editor) => {
  147. if (!mdeModalOpenState) {
  148. mdeModalOpenState = true
  149. if (mde.codemirror.doc.somethingSelected()) {
  150. vueCodeBlock.initContent = mde.codemirror.doc.getSelection()
  151. }
  152. vueCodeBlock.open()
  153. }
  154. },
  155. className: 'icon-code',
  156. title: 'Code Block'
  157. },
  158. '|',
  159. {
  160. name: 'table',
  161. action: (editor) => {
  162. window.alert('Coming soon!')
  163. // todo
  164. },
  165. className: 'icon-table',
  166. title: 'Insert Table'
  167. },
  168. {
  169. name: 'horizontal-rule',
  170. action: SimpleMDE.drawHorizontalRule,
  171. className: 'icon-minus2',
  172. title: 'Horizontal Rule'
  173. }
  174. ],
  175. shortcuts: {
  176. 'toggleBlockquote': null,
  177. 'toggleFullScreen': null
  178. }
  179. })
  180. vueImage = require('./editor-image.js')(alerts, mde, mdeModalOpenState, socket)
  181. vueFile = require('./editor-file.js')(alerts, mde, mdeModalOpenState, socket)
  182. vueVideo = require('./editor-video.js')(mde, mdeModalOpenState)
  183. vueCodeBlock = require('./editor-codeblock.js')(mde, mdeModalOpenState)
  184. pageLoader.complete()
  185. // -> Save
  186. let saveCurrentDocument = (ev) => {
  187. $.ajax(window.location.href, {
  188. data: {
  189. markdown: mde.value()
  190. },
  191. dataType: 'json',
  192. method: 'PUT'
  193. }).then((rData, rStatus, rXHR) => {
  194. if (rData.ok) {
  195. window.location.assign('/' + pageEntryPath) // eslint-disable-line no-undef
  196. } else {
  197. alerts.pushError('Something went wrong', rData.error)
  198. }
  199. }, (rXHR, rStatus, err) => {
  200. alerts.pushError('Something went wrong', 'Save operation failed.')
  201. })
  202. }
  203. $('.btn-edit-save, .btn-create-save').on('click', (ev) => {
  204. saveCurrentDocument(ev)
  205. })
  206. $(window).bind('keydown', (ev) => {
  207. if (ev.ctrlKey || ev.metaKey) {
  208. switch (String.fromCharCode(ev.which).toLowerCase()) {
  209. case 's':
  210. ev.preventDefault()
  211. saveCurrentDocument(ev)
  212. break
  213. }
  214. }
  215. })
  216. }
  217. }