editor-js.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. <?php if(!defined('__TYPECHO_ADMIN__')) exit; ?>
  2. <?php $content = !empty($post) ? $post : $page; if ($options->markdown): ?>
  3. <script src="<?php $options->adminStaticUrl('js', 'hyperdown.js'); ?>"></script>
  4. <script src="<?php $options->adminStaticUrl('js', 'pagedown.js'); ?>"></script>
  5. <script src="<?php $options->adminStaticUrl('js', 'paste.js'); ?>"></script>
  6. <script src="<?php $options->adminStaticUrl('js', 'purify.js'); ?>"></script>
  7. <script>
  8. $(document).ready(function () {
  9. var textarea = $('#text'),
  10. isFullScreen = false,
  11. toolbar = $('<div class="editor" id="wmd-button-bar" />').insertBefore(textarea.parent()),
  12. preview = $('<div id="wmd-preview" class="wmd-hidetab" />').insertAfter('.editor');
  13. var options = {}, isMarkdown = <?php echo intval($content->isMarkdown || !$content->have()); ?>;
  14. options.strings = {
  15. bold: '<?php _e('加粗'); ?> <strong> Ctrl+B',
  16. boldexample: '<?php _e('加粗文字'); ?>',
  17. italic: '<?php _e('斜体'); ?> <em> Ctrl+I',
  18. italicexample: '<?php _e('斜体文字'); ?>',
  19. link: '<?php _e('链接'); ?> <a> Ctrl+L',
  20. linkdescription: '<?php _e('请输入链接描述'); ?>',
  21. quote: '<?php _e('引用'); ?> <blockquote> Ctrl+Q',
  22. quoteexample: '<?php _e('引用文字'); ?>',
  23. code: '<?php _e('代码'); ?> <pre><code> Ctrl+K',
  24. codeexample: '<?php _e('请输入代码'); ?>',
  25. image: '<?php _e('图片'); ?> <img> Ctrl+G',
  26. imagedescription: '<?php _e('请输入图片描述'); ?>',
  27. olist: '<?php _e('数字列表'); ?> <ol> Ctrl+O',
  28. ulist: '<?php _e('普通列表'); ?> <ul> Ctrl+U',
  29. litem: '<?php _e('列表项目'); ?>',
  30. heading: '<?php _e('标题'); ?> <h1>/<h2> Ctrl+H',
  31. headingexample: '<?php _e('标题文字'); ?>',
  32. hr: '<?php _e('分割线'); ?> <hr> Ctrl+R',
  33. more: '<?php _e('摘要分割线'); ?> <!--more--> Ctrl+M',
  34. undo: '<?php _e('撤销'); ?> - Ctrl+Z',
  35. redo: '<?php _e('重做'); ?> - Ctrl+Y',
  36. redomac: '<?php _e('重做'); ?> - Ctrl+Shift+Z',
  37. fullscreen: '<?php _e('全屏'); ?> - Ctrl+J',
  38. exitFullscreen: '<?php _e('退出全屏'); ?> - Ctrl+E',
  39. fullscreenUnsupport: '<?php _e('此浏览器不支持全屏操作'); ?>',
  40. imagedialog: '<p><b><?php _e('插入图片'); ?></b></p><p><?php _e('请在下方的输入框内输入要插入的远程图片地址'); ?></p><p><?php _e('您也可以使用附件功能插入上传的本地图片'); ?></p>',
  41. linkdialog: '<p><b><?php _e('插入链接'); ?></b></p><p><?php _e('请在下方的输入框内输入要插入的链接地址'); ?></p>',
  42. ok: '<?php _e('确定'); ?>',
  43. cancel: '<?php _e('取消'); ?>',
  44. help: '<?php _e('Markdown语法帮助'); ?>'
  45. };
  46. var converter = new HyperDown(),
  47. editor = new Markdown.Editor(converter, '', options);
  48. // 自动跟随
  49. converter.enableHtml(true);
  50. converter.enableLine(true);
  51. reloadScroll = scrollableEditor(textarea, preview);
  52. // 修正白名单
  53. converter.hook('makeHtml', function (html) {
  54. html = html.replace('<p><!--more--></p>', '<!--more-->');
  55. if (html.indexOf('<!--more-->') > 0) {
  56. var parts = html.split(/\s*<\!\-\-more\-\->\s*/),
  57. summary = parts.shift(),
  58. details = parts.join('');
  59. html = '<div class="summary">' + summary + '</div>'
  60. + '<div class="details">' + details + '</div>';
  61. }
  62. // 替换block
  63. html = html.replace(/<(iframe|embed)\s+([^>]*)>/ig, function (all, tag, src) {
  64. if (src[src.length - 1] == '/') {
  65. src = src.substring(0, src.length - 1);
  66. }
  67. return '<div class="embed"><strong>'
  68. + tag + '</strong> : ' + $.trim(src) + '</div>';
  69. });
  70. return DOMPurify.sanitize(html, {USE_PROFILES: {html: true}});
  71. });
  72. editor.hooks.chain('onPreviewRefresh', function () {
  73. var images = $('img', preview), count = images.length;
  74. if (count == 0) {
  75. reloadScroll(true);
  76. } else {
  77. images.bind('load error', function () {
  78. count --;
  79. if (count == 0) {
  80. reloadScroll(true);
  81. }
  82. });
  83. }
  84. });
  85. <?php \Typecho\Plugin::factory('admin/editor-js.php')->markdownEditor($content); ?>
  86. var th = textarea.height(), ph = preview.height(),
  87. uploadBtn = $('<button type="button" id="btn-fullscreen-upload" class="btn btn-link">'
  88. + '<i class="i-upload"><?php _e('附件'); ?></i></button>')
  89. .prependTo('.submit .right')
  90. .click(function() {
  91. $('a', $('.typecho-option-tabs li').not('.active')).trigger('click');
  92. return false;
  93. });
  94. $('.typecho-option-tabs li').click(function () {
  95. uploadBtn.find('i').toggleClass('i-upload-active',
  96. $('#tab-files-btn', this).length > 0);
  97. });
  98. editor.hooks.chain('enterFakeFullScreen', function () {
  99. th = textarea.height();
  100. ph = preview.height();
  101. $(document.body).addClass('fullscreen');
  102. var h = $(window).height() - toolbar.outerHeight();
  103. textarea.css('height', h);
  104. preview.css('height', h);
  105. isFullScreen = true;
  106. });
  107. editor.hooks.chain('enterFullScreen', function () {
  108. $(document.body).addClass('fullscreen');
  109. var h = window.screen.height - toolbar.outerHeight();
  110. textarea.css('height', h);
  111. preview.css('height', h);
  112. isFullScreen = true;
  113. });
  114. editor.hooks.chain('exitFullScreen', function () {
  115. $(document.body).removeClass('fullscreen');
  116. textarea.height(th);
  117. preview.height(ph);
  118. isFullScreen = false;
  119. });
  120. editor.hooks.chain('commandExecuted', function () {
  121. textarea.trigger('input');
  122. });
  123. function initMarkdown() {
  124. editor.run();
  125. var imageButton = $('#wmd-image-button'),
  126. linkButton = $('#wmd-link-button');
  127. Typecho.insertFileToEditor = function (file, url, isImage) {
  128. var button = isImage ? imageButton : linkButton;
  129. options.strings[isImage ? 'imagename' : 'linkname'] = file;
  130. button.trigger('click');
  131. var checkDialog = setInterval(function () {
  132. if ($('.wmd-prompt-dialog').length > 0) {
  133. $('.wmd-prompt-dialog input').val(url).select();
  134. clearInterval(checkDialog);
  135. checkDialog = null;
  136. }
  137. }, 10);
  138. };
  139. Typecho.uploadComplete = function (file) {
  140. Typecho.insertFileToEditor(file.title, file.url, file.isImage);
  141. };
  142. // 编辑预览切换
  143. var edittab = $('.editor').prepend('<div class="wmd-edittab"><a href="#wmd-editarea" class="active"><?php _e('撰写'); ?></a><a href="#wmd-preview"><?php _e('预览'); ?></a></div>'),
  144. editarea = $(textarea.parent()).attr("id", "wmd-editarea");
  145. $(".wmd-edittab a").click(function() {
  146. $(".wmd-edittab a").removeClass('active');
  147. $(this).addClass("active");
  148. $("#wmd-editarea, #wmd-preview").addClass("wmd-hidetab");
  149. var selected_tab = $(this).attr("href"),
  150. selected_el = $(selected_tab).removeClass("wmd-hidetab");
  151. // 预览时隐藏编辑器按钮
  152. if (selected_tab == "#wmd-preview") {
  153. $("#wmd-button-row").addClass("wmd-visualhide");
  154. } else {
  155. $("#wmd-button-row").removeClass("wmd-visualhide");
  156. }
  157. // 预览和编辑窗口高度一致
  158. $("#wmd-preview").outerHeight($("#wmd-editarea").innerHeight());
  159. return false;
  160. });
  161. // 剪贴板复制图片
  162. textarea.pastableTextarea().on('pasteImage', function (e, data) {
  163. var name = data.name ? data.name.replace(/[\(\)\[\]\*#!]/g, '') : (new Date()).toISOString().replace(/\..+$/, '');
  164. if (!name.match(/\.[a-z0-9]{2,}$/i)) {
  165. var ext = data.blob.type.split('/').pop();
  166. name += '.' + ext;
  167. }
  168. Typecho.uploadFile(new File([data.blob], name), name);
  169. });
  170. }
  171. if (isMarkdown) {
  172. initMarkdown();
  173. } else {
  174. var notice = $('<div class="message notice"><?php _e('这篇文章不是由Markdown语法创建的, 继续使用Markdown编辑它吗?'); ?> '
  175. + '<button class="btn btn-xs primary yes"><?php _e('是'); ?></button> '
  176. + '<button class="btn btn-xs no"><?php _e('否'); ?></button></div>')
  177. .hide().insertBefore(textarea).slideDown();
  178. $('.yes', notice).click(function () {
  179. notice.remove();
  180. $('<input type="hidden" name="markdown" value="1" />').appendTo('.submit');
  181. initMarkdown();
  182. });
  183. $('.no', notice).click(function () {
  184. notice.remove();
  185. });
  186. }
  187. });
  188. </script>
  189. <?php endif; ?>