2
0

editor.js 5.5 KB

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