editor.js 6.1 KB

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