index.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /**
  2. * FeHelper HTML转Markdown
  3. */
  4. let editor = null;
  5. let hashtoTimeoutId;
  6. let previewElm;
  7. let previewTextArea;
  8. new Vue({
  9. el: '#pageContainer',
  10. data: {
  11. showPreview: false,
  12. previewText: '效果预览',
  13. codeType: 'Markdown',
  14. nextCodeType: 'HTML',
  15. toolName: {
  16. HTML: 'HTML转Markdown',
  17. Markdown: 'Markdown编辑器'
  18. }
  19. },
  20. mounted: function () {
  21. this.init();
  22. },
  23. methods: {
  24. trans: function () {
  25. editor.setValue('');
  26. this.codeType = {HTML: 'Markdown', Markdown: 'HTML'}[this.codeType];
  27. this.nextCodeType = {HTML: 'Markdown', Markdown: 'HTML'}[this.nextCodeType];
  28. let classList = this.$refs.modMarkdownBox.classList;
  29. if (this.codeType === 'HTML') {
  30. classList.add('mode-h2m');
  31. previewElm.innerHTML = `<textarea disabled></textarea>`;
  32. previewTextArea = previewElm.querySelector('textarea');
  33. } else {
  34. classList.remove('mode-h2m');
  35. previewElm.innerHTML = '';
  36. }
  37. },
  38. /**
  39. * 初始化ctrl+s的保存
  40. */
  41. init() {
  42. previewElm = this.$refs.boxPreview;
  43. // ===========================editor初始化
  44. editor = CodeMirror.fromTextArea(this.$refs.elEditor, {
  45. mode: "gfm",
  46. lineNumbers: true,
  47. matchBrackets: true,
  48. lineWrapping: true,
  49. theme: 'default'
  50. });
  51. editor.on('change', this.updateHashAndPreview);
  52. // ===========================支持save-as
  53. window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
  54. navigator.saveBlob = navigator.saveBlob || navigator.msSaveBlob || navigator.mozSaveBlob || navigator.webkitSaveBlob;
  55. window.saveAs = window.saveAs || window.webkitSaveAs || window.mozSaveAs || window.msSaveAs;
  56. document.addEventListener('keydown', (e) => {
  57. if (e.keyCode === 83 && (e.ctrlKey || e.metaKey)) {
  58. e.preventDefault();
  59. this.saveMarkdown('md');
  60. return false;
  61. }
  62. });
  63. // ===========================支持页面拖拽识别
  64. document.addEventListener('drop', function (e) {
  65. e.preventDefault();
  66. e.stopPropagation();
  67. let theFile = e.dataTransfer.files[0];
  68. let theReader = new FileReader();
  69. theReader.onload = function (e) {
  70. editor.setValue(e.target.result);
  71. };
  72. theReader.readAsText(theFile);
  73. }, false);
  74. this.initWithHash();
  75. },
  76. /**
  77. * 根据Hash进行更新编辑器
  78. */
  79. initWithHash() {
  80. if (this.codeType === 'HTML') return;
  81. if (window.location.hash) {
  82. let h = window.location.hash.replace(/^#/, '');
  83. if (h.slice(0, 5) === 'view:') {
  84. let val = decodeURIComponent(escape(RawDeflate.inflate(atob(h.slice(5)))));
  85. previewElm.innerHTML = marked(val);
  86. previewElm.querySelectorAll('pre code').forEach((block) => {
  87. hljs.highlightBlock(block);
  88. });
  89. document.body.className = 'view';
  90. } else {
  91. editor.setValue(decodeURIComponent(escape(RawDeflate.inflate(atob(h)))));
  92. this.updateHashAndPreview(editor);
  93. editor.focus();
  94. }
  95. } else {
  96. this.updateHashAndPreview(editor);
  97. editor.focus();
  98. }
  99. },
  100. /**
  101. * 更新预览区域
  102. */
  103. updateHashAndPreview() {
  104. try {
  105. if (this.codeType === 'HTML') {
  106. previewTextArea.value = h2m(editor.getValue(), {
  107. converter: 'CommonMark' // CommonMark | MarkdownExtra
  108. });
  109. } else {
  110. previewElm.innerHTML = marked(editor.getValue());
  111. previewElm.querySelectorAll('pre code').forEach((block) => {
  112. hljs.highlightBlock(block);
  113. });
  114. clearTimeout(hashtoTimeoutId);
  115. hashtoTimeoutId = setTimeout(function () {
  116. window.location.hash = btoa(RawDeflate.deflate(unescape(encodeURIComponent(editor.getValue()))))
  117. }, 1000);
  118. }
  119. } catch (e) {
  120. console.log(e);
  121. }
  122. },
  123. saveMarkdown(type) {
  124. let date = new Date();
  125. let name = "FH-" + date.getFullYear() + (date.getMonth() + 1) + date.getDate()
  126. + date.getHours() + date.getMinutes() + date.getSeconds() + `.${type}`;
  127. let code = editor.getValue();
  128. if (this.codeType === 'HTML') {
  129. if (type !== 'html') {
  130. code = previewTextArea.value;
  131. }
  132. } else {
  133. if (type === 'html') {
  134. code = DemoTpl.exportHtml.replace('#title#', name).replace('#style#', DemoTpl.exportCss).replace('#html#', this.getParsedHtml());
  135. }
  136. }
  137. let blob = new Blob([code], {type: type === 'md' ? 'text/plain' : 'text/html'});
  138. if (window.saveAs) {
  139. window.saveAs(blob, name);
  140. } else if (navigator.saveBlob) {
  141. navigator.saveBlob(blob, name);
  142. } else {
  143. let url = URL.createObjectURL(blob);
  144. let link = document.createElement("a");
  145. link.setAttribute("href", url);
  146. link.setAttribute("download", name);
  147. let event = document.createEvent('MouseEvents');
  148. event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
  149. link.dispatchEvent(event);
  150. }
  151. },
  152. /**
  153. * 获取编译后的
  154. * @returns {*}
  155. */
  156. getParsedHtml() {
  157. return previewElm.innerHTML;
  158. },
  159. insert(type) {
  160. let textConfig = {
  161. b: '** text-here **',
  162. i: '* text-here *',
  163. quote: '\n> text-here ',
  164. code: '\n```javascript\n\n\n```\n',
  165. 'unordered-list': '\n\n- text-here\n- text-here\n- text-here\n',
  166. 'ordered-list': '\n\n1. text-here\n2. text-here\n3. text-here\n',
  167. link: '\n[text-here](your-link-url)',
  168. image: '\n![text-here](your-image-src)'
  169. };
  170. editor.replaceSelection(textConfig[type] || '');
  171. editor.focus();
  172. },
  173. getResult: function () {
  174. this.$refs.rstCode.select();
  175. },
  176. setDemo: function () {
  177. editor.setValue(DemoTpl[this.codeType.toLowerCase()]);
  178. },
  179. // 导入内容
  180. importContent: function () {
  181. let that = this;
  182. let fileInput = document.getElementById('fileInput');
  183. if (!fileInput) {
  184. fileInput = document.createElement('input');
  185. fileInput.id = 'fileInput';
  186. fileInput.type = 'file';
  187. fileInput.accept = {HTML: 'text/html', Markdown: 'text/x-markdown'}[that.codeType];
  188. fileInput.style.cssText = 'position:relative;top:-1000px;left:-1000px;';
  189. fileInput.onchange = function (event) {
  190. let reader = new FileReader();
  191. reader.readAsText(fileInput.files[0], 'utf-8');
  192. reader.onload = (evt) => {
  193. editor.setValue(evt.target.result);
  194. document.body.removeChild(fileInput);
  195. };
  196. };
  197. document.body.appendChild(fileInput);
  198. }
  199. fileInput.click();
  200. },
  201. togglePreview() {
  202. let classList = this.$refs.modMarkdownBox.classList;
  203. let closeClass = 'preview-closed';
  204. if (classList.contains(closeClass)) {
  205. classList.remove(closeClass);
  206. } else {
  207. classList.add(closeClass);
  208. }
  209. },
  210. // 通过调用系统打印的形式,打印为pdf
  211. exportContent: function (previewMode) {
  212. let newContent = "<html><head><meta charset='utf-8'/><title></title>" +
  213. "<style>" + DemoTpl.printCss + "</style>" +
  214. "</head><body class='markdown-body'>" + this.getParsedHtml() + "</body></html>";
  215. let newWin = window.open();
  216. newWin.focus();
  217. newWin.document.write(newContent);
  218. if (!previewMode) {
  219. newWin.print();
  220. newWin.document.close();
  221. newWin.close();
  222. }
  223. }
  224. }
  225. });