markdown_edit.blade.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. {{-- 调用实例 --}}
  2. {{--
  3. @include('common.markdown_edit')
  4. <textarea
  5. id="markdown-editor"
  6. name="name"
  7. placeholder="请输入至少三个字符的内容。"
  8. rows="6">{{ old('body', $article->body ) }}</textarea>
  9. <script type="text/javascript">
  10. var markdown = new Markdown();
  11. markdown.init({
  12. 'textarea': {
  13. 'id': 'markdown-editor',
  14. }
  15. });
  16. </script>
  17. --}}
  18. {{-- javascript --}}
  19. <link rel="stylesheet" href="{{ assert_cdns('/fonts/font-awesome-4.7.0/css/font-awesome.min.css') }}">
  20. <link rel="stylesheet" href="{{ assert_cdns('/ext/Simplemde_Markdown/dist/simplemde.min.css') }}">
  21. <script src="{{ assert_cdns('/ext/Simplemde_Markdown/dist/simplemde.min.js') }}"></script>
  22. <script src="{{ assert_cdns('/ext/InlineAttachment/dist/codemirror-4.inline-attachment.min.js') }}"></script>
  23. <script src="{{ assert_cdns('/ext/Simplemde_Markdown/HtmlToMarkdown.js') }}"></script>
  24. {{-- 加载 markdown 编辑器 --}}
  25. <script type="text/javascript">
  26. class Markdown{
  27. constructor() {
  28. this.setting = {
  29. 'textarea': {
  30. 'id': 'markdown-editor',
  31. },
  32. 'interval': true,
  33. 'markdown': {
  34. element: document.getElementById('markdown-editor'),
  35. autoDownloadFontAwesome: false,
  36. spellChecker: false,
  37. /*autosave: {
  38. enabled: true,
  39. delay: 5000,
  40. unique_id: "article_content_"
  41. },*/
  42. forceSync: true,
  43. tabSize: 4,
  44. toolbar: [
  45. "bold", "italic", "heading", "|", "quote", "code", "table",
  46. "horizontal-rule", "unordered-list", "ordered-list", "|",
  47. "link", "image", "|", "side-by-side", 'fullscreen', "|",
  48. {
  49. // 自定义[ 发布话题 ]
  50. name: "publish",
  51. action: function customFunction(editor) {
  52. $(editor.element).closest('form').eq(0).submit();
  53. },
  54. className: "fa fa-paper-plane",
  55. title: "{{ isset($_markdown['publish_title']) ? $_markdown['publish_title'] : '发布文章' }}",
  56. },
  57. {
  58. // 自定义[ 清楚缓存 ]
  59. name: "publish",
  60. action: function customFunction(editor) {
  61. localStorage.clear();
  62. localStorage.clear();
  63. localStorage.clear();
  64. localStorage.clear();
  65. localStorage.clear();
  66. localStorage.clear();
  67. alert('清理完成');
  68. },
  69. className: "fa fa-trash",
  70. title: "清除本地缓存",
  71. },
  72. {
  73. // 自定义标签
  74. name: "guide",
  75. action: function customFunction(editor) {
  76. var win = window.open('https://github.com/riku/Markdown-Syntax-CN/blob/master/syntax.md', '_blank');
  77. if (win) {
  78. //Browser has allowed it to be opened
  79. win.focus();
  80. } else {
  81. //Browser has blocked it
  82. alert('Please allow popups for this website');
  83. }
  84. },
  85. className: "fa fa-info-circle f_r",
  86. title: "Markdown 语法!",
  87. }
  88. ],
  89. },
  90. 'uploadFieldName': 'image',
  91. 'jsonFieldName': 'path',
  92. 'uploadUrl': Config.routes.upload_image,
  93. 'events': {
  94. change: function () {},
  95. }
  96. }
  97. /**
  98. * markdown 还原初始化
  99. * window['markdown_markdown-editor'].value('')
  100. */
  101. }
  102. init(opt){
  103. this.create($.extend(true, this.setting, opt));
  104. }
  105. create(setting){
  106. var self = this;
  107. if (document.getElementById(setting.textarea.id)) {
  108. $(document).ready(function () {
  109. self.initSimpleMDE(setting);
  110. });
  111. } else {
  112. console.error('必须先创建好 textarea DOM节点后才可以调用 `init` 方法')
  113. }
  114. }
  115. initSimpleMDE(setting){
  116. var self = this;
  117. var turndownService = new TurndownService();
  118. setting.markdown.element = document.getElementById(setting.textarea.id);
  119. var simplemde = window['markdown_' + setting.textarea.id] = new SimpleMDE(setting.markdown);
  120. if(setting.interval){
  121. var interval = setInterval(function () {
  122. if (simplemde.isFullscreenActive()) {
  123. $('.duke-pulse.editor-fullscreen').hide();
  124. $(window).trigger('resize');
  125. clearInterval(interval);
  126. }
  127. }, 1000);
  128. }
  129. simplemde.codemirror.on("refresh", function () {
  130. $(window).trigger('resize');
  131. });
  132. simplemde.codemirror.on("paste", function () {
  133. $(window).trigger('resize');
  134. });
  135. // 此处转多次是为了防止用户恶意输入
  136. simplemde.codemirror.on("change", function(){
  137. // markdown to html
  138. var html = simplemde.markdown(simplemde.value());
  139. // html to markdown
  140. var markdown = turndownService.turndown(html);
  141. // markdown to html
  142. html = simplemde.markdown(markdown);
  143. setting.events.change(html);
  144. });
  145. // 图片上传
  146. inlineAttachment.editors.codemirror4.attach(simplemde.codemirror, {
  147. uploadUrl: setting.uploadUrl,
  148. uploadFieldName: setting.uploadFieldName ? setting.uploadFieldName : 'file',
  149. jsonFieldName: setting.jsonFieldName ? setting.jsonFieldName : 'filename',
  150. extraParams: {
  151. '_token': Config.token,
  152. 'image_type': 'article',
  153. },
  154. extraHeaders: {
  155. 'X-Requested-With': 'XMLHttpRequest',
  156. 'X-XSRF-TOKEN': Config.token,
  157. 'Authorization': Config.isApi ? document.head.querySelector('meta[name="jwt-token"]').content : ''
  158. },
  159. onFileUploadResponse: function(xhr) {
  160. var result = JSON.parse(xhr.responseText),
  161. filename = result[this.settings.jsonFieldName];
  162. if (result && filename) {
  163. // 拼接 cdns
  164. filename = Config.routes.images_domain + filename;
  165. var newValue;
  166. if (typeof this.settings.urlText === 'function') {
  167. newValue = this.settings.urlText.call(this, filename, result);
  168. } else {
  169. newValue = this.settings.urlText.replace(this.filenameTag, filename);
  170. }
  171. var text = this.editor.getValue().replace(this.lastValue, newValue);
  172. this.editor.setValue(text);
  173. this.settings.onFileUploaded.call(this, filename);
  174. }
  175. return false;
  176. }
  177. });
  178. }
  179. }
  180. </script>