浏览代码

:sparkles: #19

Van 5 年之前
父节点
当前提交
bba797d24e

+ 2 - 1
CHANGELOG.md

@@ -36,8 +36,9 @@
 * [3](https://github.com/Vanessa219/vditor/issues/3) 编辑预览同步滚动改进 `enhancement`
 * [3](https://github.com/Vanessa219/vditor/issues/3) 编辑预览同步滚动改进 `enhancement`
 * [4](https://github.com/Vanessa219/vditor/issues/4) 添加支持思维导图的功能 `enhancement`
 * [4](https://github.com/Vanessa219/vditor/issues/4) 添加支持思维导图的功能 `enhancement`
 
 
-### v1.10.8 / 2019-12-09
+### v1.10.9 / 2019-12-10
 
 
+* [19](https://github.com/Vanessa219/vditor/issues/19) CDN 切换优化 `enhancement`
 * [18](https://github.com/Vanessa219/vditor/issues/18) 菜单栏上的按钮会触发 form 提交事件 `bug`
 * [18](https://github.com/Vanessa219/vditor/issues/18) 菜单栏上的按钮会触发 form 提交事件 `bug`
 * [17](https://github.com/Vanessa219/vditor/issues/17) tip 会遮挡住输入框的上部 `enhancement`
 * [17](https://github.com/Vanessa219/vditor/issues/17) tip 会遮挡住输入框的上部 `enhancement`
 * [16](https://github.com/Vanessa219/vditor/issues/16) 复制代码按钮错误 `bug`
 * [16](https://github.com/Vanessa219/vditor/issues/16) 复制代码按钮错误 `bug`

+ 1 - 1
demo/static.html

@@ -72,7 +72,7 @@
           replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').
           replace(/[\?\\/:|<>\*\[\]\(\)\$%\{\}@~]/g, '').
           replace('/\\s/g', '')
           replace('/\\s/g', '')
       },
       },
-    }
+    },
   })
   })
 </script>
 </script>
 </body>
 </body>

文件差异内容过多而无法显示
+ 679 - 189
package-lock.json


+ 9 - 17
package.json

@@ -1,7 +1,6 @@
 {
 {
   "name": "vditor",
   "name": "vditor",
   "version": "1.10.8",
   "version": "1.10.8",
-  "cdn": "https://cdn.jsdelivr.net/npm",
   "description": "A markdown editor written in TypeScript",
   "description": "A markdown editor written in TypeScript",
   "author": " Vanessa <[email protected]> (http://vanessa.b3log.org)",
   "author": " Vanessa <[email protected]> (http://vanessa.b3log.org)",
   "homepage": "https://hacpai.com/tag/vditor",
   "homepage": "https://hacpai.com/tag/vditor",
@@ -15,24 +14,16 @@
     "src/assets/*"
     "src/assets/*"
   ],
   ],
   "dependencies": {
   "dependencies": {
-    "abcjs": "^5.8.0",
-    "diff-match-patch": "^1.0.4",
-    "echarts": "^4.2.1",
-    "highlight.js": "^9.15.9",
-    "katex": "^0.11.0",
-    "mermaid": "^8.2.3",
-    "turndown": "^5.0.3"
+    "diff-match-patch": "^1.0.4"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@babel/core": "^7.5.5",
-    "@babel/preset-env": "^7.5.5",
+    "@babel/core": "^7.7.5",
+    "@babel/preset-env": "^7.7.6",
     "@types/diff-match-patch": "^1.0.32",
     "@types/diff-match-patch": "^1.0.32",
-    "@types/echarts": "^4.1.12",
     "@types/jest": "^24.0.17",
     "@types/jest": "^24.0.17",
-    "@types/puppeteer": "^1.19.0",
+    "@types/puppeteer": "^2.0.0",
     "autoprefixer": "^9.6.1",
     "autoprefixer": "^9.6.1",
     "babel-loader": "^8.0.6",
     "babel-loader": "^8.0.6",
-    "clean-webpack-plugin": "^3.0.0",
     "copy-webpack-plugin": "^5.0.4",
     "copy-webpack-plugin": "^5.0.4",
     "css-loader": "^3.2.0",
     "css-loader": "^3.2.0",
     "file-loader": "^4.1.0",
     "file-loader": "^4.1.0",
@@ -45,16 +36,17 @@
     "optimize-css-assets-webpack-plugin": "^5.0.3",
     "optimize-css-assets-webpack-plugin": "^5.0.3",
     "postcss-loader": "^3.0.0",
     "postcss-loader": "^3.0.0",
     "puppeteer": "^1.19.0",
     "puppeteer": "^1.19.0",
+    "rimraf": "^3.0.0",
     "sass-loader": "^7.1.0",
     "sass-loader": "^7.1.0",
     "style-loader": "^1.0.0",
     "style-loader": "^1.0.0",
     "ts-jest": "^24.0.2",
     "ts-jest": "^24.0.2",
     "ts-loader": "^6.0.4",
     "ts-loader": "^6.0.4",
     "tslint": "^5.18.0",
     "tslint": "^5.18.0",
     "typescript": "^3.5.3",
     "typescript": "^3.5.3",
-    "webpack": "^4.39.1",
-    "webpack-bundle-analyzer": "^3.4.1",
-    "webpack-cli": "^3.3.6",
-    "webpack-dev-server": "^3.7.2"
+    "webpack": "^4.41.2",
+    "webpack-bundle-analyzer": "^3.6.0",
+    "webpack-cli": "^3.3.10",
+    "webpack-dev-server": "^3.9.0"
   },
   },
   "license": "MIT",
   "license": "MIT",
   "repository": "git://github.com/Vanessa219/vditor.git",
   "repository": "git://github.com/Vanessa219/vditor.git",

文件差异内容过多而无法显示
+ 2 - 0
src/js/abcjs/abcjs_basic.min.js


文件差异内容过多而无法显示
+ 22 - 0
src/js/echarts/echarts.min.js


文件差异内容过多而无法显示
+ 0 - 1
src/js/highlight.js/highlight.pack.js


文件差异内容过多而无法显示
+ 0 - 0
src/js/katex/auto-render.min.js


文件差异内容过多而无法显示
+ 1 - 0
src/js/katex/katex.min.js


文件差异内容过多而无法显示
+ 0 - 0
src/js/mermaid/mermaid.min.js


+ 909 - 0
src/js/turndown/turndown.js

@@ -0,0 +1,909 @@
+// 5.0.3
+var TurndownService = (function () {
+'use strict';
+
+function extend (destination) {
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments[i];
+    for (var key in source) {
+      if (source.hasOwnProperty(key)) destination[key] = source[key];
+    }
+  }
+  return destination
+}
+
+function repeat (character, count) {
+  return Array(count + 1).join(character)
+}
+
+var blockElements = [
+  'address', 'article', 'aside', 'audio', 'blockquote', 'body', 'canvas',
+  'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption',
+  'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+  'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav',
+  'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table',
+  'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'
+];
+
+function isBlock (node) {
+  return blockElements.indexOf(node.nodeName.toLowerCase()) !== -1
+}
+
+var voidElements = [
+  'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
+  'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'
+];
+
+function isVoid (node) {
+  return voidElements.indexOf(node.nodeName.toLowerCase()) !== -1
+}
+
+var voidSelector = voidElements.join();
+function hasVoid (node) {
+  return node.querySelector && node.querySelector(voidSelector)
+}
+
+var rules = {};
+
+rules.paragraph = {
+  filter: 'p',
+
+  replacement: function (content) {
+    return '\n\n' + content + '\n\n'
+  }
+};
+
+rules.lineBreak = {
+  filter: 'br',
+
+  replacement: function (content, node, options) {
+    return options.br + '\n'
+  }
+};
+
+rules.heading = {
+  filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
+
+  replacement: function (content, node, options) {
+    var hLevel = Number(node.nodeName.charAt(1));
+
+    if (options.headingStyle === 'setext' && hLevel < 3) {
+      var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
+      return (
+        '\n\n' + content + '\n' + underline + '\n\n'
+      )
+    } else {
+      return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
+    }
+  }
+};
+
+rules.blockquote = {
+  filter: 'blockquote',
+
+  replacement: function (content) {
+    content = content.replace(/^\n+|\n+$/g, '');
+    content = content.replace(/^/gm, '> ');
+    return '\n\n' + content + '\n\n'
+  }
+};
+
+rules.list = {
+  filter: ['ul', 'ol'],
+
+  replacement: function (content, node) {
+    var parent = node.parentNode;
+    if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
+      return '\n' + content
+    } else {
+      return '\n\n' + content + '\n\n'
+    }
+  }
+};
+
+rules.listItem = {
+  filter: 'li',
+
+  replacement: function (content, node, options) {
+    content = content
+      .replace(/^\n+/, '') // remove leading newlines
+      .replace(/\n+$/, '\n') // replace trailing newlines with just a single one
+      .replace(/\n/gm, '\n    '); // indent
+    var prefix = options.bulletListMarker + '   ';
+    var parent = node.parentNode;
+    if (parent.nodeName === 'OL') {
+      var start = parent.getAttribute('start');
+      var index = Array.prototype.indexOf.call(parent.children, node);
+      prefix = (start ? Number(start) + index : index + 1) + '.  ';
+    }
+    return (
+      prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
+    )
+  }
+};
+
+rules.indentedCodeBlock = {
+  filter: function (node, options) {
+    return (
+      options.codeBlockStyle === 'indented' &&
+      node.nodeName === 'PRE' &&
+      node.firstChild &&
+      node.firstChild.nodeName === 'CODE'
+    )
+  },
+
+  replacement: function (content, node, options) {
+    return (
+      '\n\n    ' +
+      node.firstChild.textContent.replace(/\n/g, '\n    ') +
+      '\n\n'
+    )
+  }
+};
+
+rules.fencedCodeBlock = {
+  filter: function (node, options) {
+    return (
+      options.codeBlockStyle === 'fenced' &&
+      node.nodeName === 'PRE' &&
+      node.firstChild &&
+      node.firstChild.nodeName === 'CODE'
+    )
+  },
+
+  replacement: function (content, node, options) {
+    var className = node.firstChild.className || '';
+    var language = (className.match(/language-(\S+)/) || [null, ''])[1];
+
+    return (
+      '\n\n' + options.fence + language + '\n' +
+      node.firstChild.textContent +
+      '\n' + options.fence + '\n\n'
+    )
+  }
+};
+
+rules.horizontalRule = {
+  filter: 'hr',
+
+  replacement: function (content, node, options) {
+    return '\n\n' + options.hr + '\n\n'
+  }
+};
+
+rules.inlineLink = {
+  filter: function (node, options) {
+    return (
+      options.linkStyle === 'inlined' &&
+      node.nodeName === 'A' &&
+      node.getAttribute('href')
+    )
+  },
+
+  replacement: function (content, node) {
+    var href = node.getAttribute('href');
+    var title = node.title ? ' "' + node.title + '"' : '';
+    return '[' + content + '](' + href + title + ')'
+  }
+};
+
+rules.referenceLink = {
+  filter: function (node, options) {
+    return (
+      options.linkStyle === 'referenced' &&
+      node.nodeName === 'A' &&
+      node.getAttribute('href')
+    )
+  },
+
+  replacement: function (content, node, options) {
+    var href = node.getAttribute('href');
+    var title = node.title ? ' "' + node.title + '"' : '';
+    var replacement;
+    var reference;
+
+    switch (options.linkReferenceStyle) {
+      case 'collapsed':
+        replacement = '[' + content + '][]';
+        reference = '[' + content + ']: ' + href + title;
+        break
+      case 'shortcut':
+        replacement = '[' + content + ']';
+        reference = '[' + content + ']: ' + href + title;
+        break
+      default:
+        var id = this.references.length + 1;
+        replacement = '[' + content + '][' + id + ']';
+        reference = '[' + id + ']: ' + href + title;
+    }
+
+    this.references.push(reference);
+    return replacement
+  },
+
+  references: [],
+
+  append: function (options) {
+    var references = '';
+    if (this.references.length) {
+      references = '\n\n' + this.references.join('\n') + '\n\n';
+      this.references = []; // Reset references
+    }
+    return references
+  }
+};
+
+rules.emphasis = {
+  filter: ['em', 'i'],
+
+  replacement: function (content, node, options) {
+    if (!content.trim()) return ''
+    return options.emDelimiter + content + options.emDelimiter
+  }
+};
+
+rules.strong = {
+  filter: ['strong', 'b'],
+
+  replacement: function (content, node, options) {
+    if (!content.trim()) return ''
+    return options.strongDelimiter + content + options.strongDelimiter
+  }
+};
+
+rules.code = {
+  filter: function (node) {
+    var hasSiblings = node.previousSibling || node.nextSibling;
+    var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
+
+    return node.nodeName === 'CODE' && !isCodeBlock
+  },
+
+  replacement: function (content) {
+    if (!content.trim()) return ''
+
+    var delimiter = '`';
+    var leadingSpace = '';
+    var trailingSpace = '';
+    var matches = content.match(/`+/gm);
+    if (matches) {
+      if (/^`/.test(content)) leadingSpace = ' ';
+      if (/`$/.test(content)) trailingSpace = ' ';
+      while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
+    }
+
+    return delimiter + leadingSpace + content + trailingSpace + delimiter
+  }
+};
+
+rules.image = {
+  filter: 'img',
+
+  replacement: function (content, node) {
+    var alt = node.alt || '';
+    var src = node.getAttribute('src') || '';
+    var title = node.title || '';
+    var titlePart = title ? ' "' + title + '"' : '';
+    return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
+  }
+};
+
+/**
+ * Manages a collection of rules used to convert HTML to Markdown
+ */
+
+function Rules (options) {
+  this.options = options;
+  this._keep = [];
+  this._remove = [];
+
+  this.blankRule = {
+    replacement: options.blankReplacement
+  };
+
+  this.keepReplacement = options.keepReplacement;
+
+  this.defaultRule = {
+    replacement: options.defaultReplacement
+  };
+
+  this.array = [];
+  for (var key in options.rules) this.array.push(options.rules[key]);
+}
+
+Rules.prototype = {
+  add: function (key, rule) {
+    this.array.unshift(rule);
+  },
+
+  keep: function (filter) {
+    this._keep.unshift({
+      filter: filter,
+      replacement: this.keepReplacement
+    });
+  },
+
+  remove: function (filter) {
+    this._remove.unshift({
+      filter: filter,
+      replacement: function () {
+        return ''
+      }
+    });
+  },
+
+  forNode: function (node) {
+    if (node.isBlank) return this.blankRule
+    var rule;
+
+    if ((rule = findRule(this.array, node, this.options))) return rule
+    if ((rule = findRule(this._keep, node, this.options))) return rule
+    if ((rule = findRule(this._remove, node, this.options))) return rule
+
+    return this.defaultRule
+  },
+
+  forEach: function (fn) {
+    for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
+  }
+};
+
+function findRule (rules, node, options) {
+  for (var i = 0; i < rules.length; i++) {
+    var rule = rules[i];
+    if (filterValue(rule, node, options)) return rule
+  }
+  return void 0
+}
+
+function filterValue (rule, node, options) {
+  var filter = rule.filter;
+  if (typeof filter === 'string') {
+    if (filter === node.nodeName.toLowerCase()) return true
+  } else if (Array.isArray(filter)) {
+    if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
+  } else if (typeof filter === 'function') {
+    if (filter.call(rule, node, options)) return true
+  } else {
+    throw new TypeError('`filter` needs to be a string, array, or function')
+  }
+}
+
+/**
+ * The collapseWhitespace function is adapted from collapse-whitespace
+ * by Luc Thevenard.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Luc Thevenard <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * collapseWhitespace(options) removes extraneous whitespace from an the given element.
+ *
+ * @param {Object} options
+ */
+function collapseWhitespace (options) {
+  var element = options.element;
+  var isBlock = options.isBlock;
+  var isVoid = options.isVoid;
+  var isPre = options.isPre || function (node) {
+    return node.nodeName === 'PRE'
+  };
+
+  if (!element.firstChild || isPre(element)) return
+
+  var prevText = null;
+  var prevVoid = false;
+
+  var prev = null;
+  var node = next(prev, element, isPre);
+
+  while (node !== element) {
+    if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
+      var text = node.data.replace(/[ \r\n\t]+/g, ' ');
+
+      if ((!prevText || / $/.test(prevText.data)) &&
+          !prevVoid && text[0] === ' ') {
+        text = text.substr(1);
+      }
+
+      // `text` might be empty at this point.
+      if (!text) {
+        node = remove(node);
+        continue
+      }
+
+      node.data = text;
+
+      prevText = node;
+    } else if (node.nodeType === 1) { // Node.ELEMENT_NODE
+      if (isBlock(node) || node.nodeName === 'BR') {
+        if (prevText) {
+          prevText.data = prevText.data.replace(/ $/, '');
+        }
+
+        prevText = null;
+        prevVoid = false;
+      } else if (isVoid(node)) {
+        // Avoid trimming space around non-block, non-BR void elements.
+        prevText = null;
+        prevVoid = true;
+      }
+    } else {
+      node = remove(node);
+      continue
+    }
+
+    var nextNode = next(prev, node, isPre);
+    prev = node;
+    node = nextNode;
+  }
+
+  if (prevText) {
+    prevText.data = prevText.data.replace(/ $/, '');
+    if (!prevText.data) {
+      remove(prevText);
+    }
+  }
+}
+
+/**
+ * remove(node) removes the given node from the DOM and returns the
+ * next node in the sequence.
+ *
+ * @param {Node} node
+ * @return {Node} node
+ */
+function remove (node) {
+  var next = node.nextSibling || node.parentNode;
+
+  node.parentNode.removeChild(node);
+
+  return next
+}
+
+/**
+ * next(prev, current, isPre) returns the next node in the sequence, given the
+ * current and previous nodes.
+ *
+ * @param {Node} prev
+ * @param {Node} current
+ * @param {Function} isPre
+ * @return {Node}
+ */
+function next (prev, current, isPre) {
+  if ((prev && prev.parentNode === current) || isPre(current)) {
+    return current.nextSibling || current.parentNode
+  }
+
+  return current.firstChild || current.nextSibling || current.parentNode
+}
+
+/*
+ * Set up window for Node.js
+ */
+
+var root = (typeof window !== 'undefined' ? window : {});
+
+/*
+ * Parsing HTML strings
+ */
+
+function canParseHTMLNatively () {
+  var Parser = root.DOMParser;
+  var canParse = false;
+
+  // Adapted from https://gist.github.com/1129031
+  // Firefox/Opera/IE throw errors on unsupported types
+  try {
+    // WebKit returns null on unsupported types
+    if (new Parser().parseFromString('', 'text/html')) {
+      canParse = true;
+    }
+  } catch (e) {}
+
+  return canParse
+}
+
+function createHTMLParser () {
+  var Parser = function () {};
+
+  {
+    if (shouldUseActiveX()) {
+      Parser.prototype.parseFromString = function (string) {
+        var doc = new window.ActiveXObject('htmlfile');
+        doc.designMode = 'on'; // disable on-page scripts
+        doc.open();
+        doc.write(string);
+        doc.close();
+        return doc
+      };
+    } else {
+      Parser.prototype.parseFromString = function (string) {
+        var doc = document.implementation.createHTMLDocument('');
+        doc.open();
+        doc.write(string);
+        doc.close();
+        return doc
+      };
+    }
+  }
+  return Parser
+}
+
+function shouldUseActiveX () {
+  var useActiveX = false;
+  try {
+    document.implementation.createHTMLDocument('').open();
+  } catch (e) {
+    if (window.ActiveXObject) useActiveX = true;
+  }
+  return useActiveX
+}
+
+var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
+
+function RootNode (input) {
+  var root;
+  if (typeof input === 'string') {
+    var doc = htmlParser().parseFromString(
+      // DOM parsers arrange elements in the <head> and <body>.
+      // Wrapping in a custom element ensures elements are reliably arranged in
+      // a single element.
+      '<x-turndown id="turndown-root">' + input + '</x-turndown>',
+      'text/html'
+    );
+    root = doc.getElementById('turndown-root');
+  } else {
+    root = input.cloneNode(true);
+  }
+  collapseWhitespace({
+    element: root,
+    isBlock: isBlock,
+    isVoid: isVoid
+  });
+
+  return root
+}
+
+var _htmlParser;
+function htmlParser () {
+  _htmlParser = _htmlParser || new HTMLParser();
+  return _htmlParser
+}
+
+function Node (node) {
+  node.isBlock = isBlock(node);
+  node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode;
+  node.isBlank = isBlank(node);
+  node.flankingWhitespace = flankingWhitespace(node);
+  return node
+}
+
+function isBlank (node) {
+  return (
+    ['A', 'TH', 'TD', 'IFRAME', 'SCRIPT', 'AUDIO', 'VIDEO'].indexOf(node.nodeName) === -1 &&
+    /^\s*$/i.test(node.textContent) &&
+    !isVoid(node) &&
+    !hasVoid(node)
+  )
+}
+
+function flankingWhitespace (node) {
+  var leading = '';
+  var trailing = '';
+
+  if (!node.isBlock) {
+    var hasLeading = /^[ \r\n\t]/.test(node.textContent);
+    var hasTrailing = /[ \r\n\t]$/.test(node.textContent);
+
+    if (hasLeading && !isFlankedByWhitespace('left', node)) {
+      leading = ' ';
+    }
+    if (hasTrailing && !isFlankedByWhitespace('right', node)) {
+      trailing = ' ';
+    }
+  }
+
+  return { leading: leading, trailing: trailing }
+}
+
+function isFlankedByWhitespace (side, node) {
+  var sibling;
+  var regExp;
+  var isFlanked;
+
+  if (side === 'left') {
+    sibling = node.previousSibling;
+    regExp = / $/;
+  } else {
+    sibling = node.nextSibling;
+    regExp = /^ /;
+  }
+
+  if (sibling) {
+    if (sibling.nodeType === 3) {
+      isFlanked = regExp.test(sibling.nodeValue);
+    } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
+      isFlanked = regExp.test(sibling.textContent);
+    }
+  }
+  return isFlanked
+}
+
+var reduce = Array.prototype.reduce;
+var leadingNewLinesRegExp = /^\n*/;
+var trailingNewLinesRegExp = /\n*$/;
+var escapes = [
+  [/\\/g, '\\\\'],
+  [/\*/g, '\\*'],
+  [/^-/g, '\\-'],
+  [/^\+ /g, '\\+ '],
+  [/^(=+)/g, '\\$1'],
+  [/^(#{1,6}) /g, '\\$1 '],
+  [/`/g, '\\`'],
+  [/^~~~/g, '\\~~~'],
+  [/\[/g, '\\['],
+  [/\]/g, '\\]'],
+  [/^>/g, '\\>'],
+  [/_/g, '\\_'],
+  [/^(\d+)\. /g, '$1\\. ']
+];
+
+function TurndownService (options) {
+  if (!(this instanceof TurndownService)) return new TurndownService(options)
+
+  var defaults = {
+    rules: rules,
+    headingStyle: 'setext',
+    hr: '* * *',
+    bulletListMarker: '*',
+    codeBlockStyle: 'indented',
+    fence: '```',
+    emDelimiter: '_',
+    strongDelimiter: '**',
+    linkStyle: 'inlined',
+    linkReferenceStyle: 'full',
+    br: '  ',
+    blankReplacement: function (content, node) {
+      return node.isBlock ? '\n\n' : ''
+    },
+    keepReplacement: function (content, node) {
+      return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
+    },
+    defaultReplacement: function (content, node) {
+      return node.isBlock ? '\n\n' + content + '\n\n' : content
+    }
+  };
+  this.options = extend({}, defaults, options);
+  this.rules = new Rules(this.options);
+}
+
+TurndownService.prototype = {
+  /**
+   * The entry point for converting a string or DOM node to Markdown
+   * @public
+   * @param {String|HTMLElement} input The string or DOM node to convert
+   * @returns A Markdown representation of the input
+   * @type String
+   */
+
+  turndown: function (input) {
+    if (!canConvert(input)) {
+      throw new TypeError(
+        input + ' is not a string, or an element/document/fragment node.'
+      )
+    }
+
+    if (input === '') return ''
+
+    var output = process.call(this, new RootNode(input));
+    return postProcess.call(this, output)
+  },
+
+  /**
+   * Add one or more plugins
+   * @public
+   * @param {Function|Array} plugin The plugin or array of plugins to add
+   * @returns The Turndown instance for chaining
+   * @type Object
+   */
+
+  use: function (plugin) {
+    if (Array.isArray(plugin)) {
+      for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
+    } else if (typeof plugin === 'function') {
+      plugin(this);
+    } else {
+      throw new TypeError('plugin must be a Function or an Array of Functions')
+    }
+    return this
+  },
+
+  /**
+   * Adds a rule
+   * @public
+   * @param {String} key The unique key of the rule
+   * @param {Object} rule The rule
+   * @returns The Turndown instance for chaining
+   * @type Object
+   */
+
+  addRule: function (key, rule) {
+    this.rules.add(key, rule);
+    return this
+  },
+
+  /**
+   * Keep a node (as HTML) that matches the filter
+   * @public
+   * @param {String|Array|Function} filter The unique key of the rule
+   * @returns The Turndown instance for chaining
+   * @type Object
+   */
+
+  keep: function (filter) {
+    this.rules.keep(filter);
+    return this
+  },
+
+  /**
+   * Remove a node that matches the filter
+   * @public
+   * @param {String|Array|Function} filter The unique key of the rule
+   * @returns The Turndown instance for chaining
+   * @type Object
+   */
+
+  remove: function (filter) {
+    this.rules.remove(filter);
+    return this
+  },
+
+  /**
+   * Escapes Markdown syntax
+   * @public
+   * @param {String} string The string to escape
+   * @returns A string with Markdown syntax escaped
+   * @type String
+   */
+
+  escape: function (string) {
+    return escapes.reduce(function (accumulator, escape) {
+      return accumulator.replace(escape[0], escape[1])
+    }, string)
+  }
+};
+
+/**
+ * Reduces a DOM node down to its Markdown string equivalent
+ * @private
+ * @param {HTMLElement} parentNode The node to convert
+ * @returns A Markdown representation of the node
+ * @type String
+ */
+
+function process (parentNode) {
+  var self = this;
+  return reduce.call(parentNode.childNodes, function (output, node) {
+    node = new Node(node);
+
+    var replacement = '';
+    if (node.nodeType === 3) {
+      replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
+    } else if (node.nodeType === 1) {
+      replacement = replacementForNode.call(self, node);
+    }
+
+    return join(output, replacement)
+  }, '')
+}
+
+/**
+ * Appends strings as each rule requires and trims the output
+ * @private
+ * @param {String} output The conversion output
+ * @returns A trimmed version of the ouput
+ * @type String
+ */
+
+function postProcess (output) {
+  var self = this;
+  this.rules.forEach(function (rule) {
+    if (typeof rule.append === 'function') {
+      output = join(output, rule.append(self.options));
+    }
+  });
+
+  return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
+}
+
+/**
+ * Converts an element node to its Markdown equivalent
+ * @private
+ * @param {HTMLElement} node The node to convert
+ * @returns A Markdown representation of the node
+ * @type String
+ */
+
+function replacementForNode (node) {
+  var rule = this.rules.forNode(node);
+  var content = process.call(this, node);
+  var whitespace = node.flankingWhitespace;
+  if (whitespace.leading || whitespace.trailing) content = content.trim();
+  return (
+    whitespace.leading +
+    rule.replacement(content, node, this.options) +
+    whitespace.trailing
+  )
+}
+
+/**
+ * Determines the new lines between the current output and the replacement
+ * @private
+ * @param {String} output The current conversion output
+ * @param {String} replacement The string to append to the output
+ * @returns The whitespace to separate the current output and the replacement
+ * @type String
+ */
+
+function separatingNewlines (output, replacement) {
+  var newlines = [
+    output.match(trailingNewLinesRegExp)[0],
+    replacement.match(leadingNewLinesRegExp)[0]
+  ].sort();
+  var maxNewlines = newlines[newlines.length - 1];
+  return maxNewlines.length < 2 ? maxNewlines : '\n\n'
+}
+
+function join (string1, string2) {
+  var separator = separatingNewlines(string1, string2);
+
+  // Remove trailing/leading newlines and replace with separator
+  string1 = string1.replace(trailingNewLinesRegExp, '');
+  string2 = string2.replace(leadingNewLinesRegExp, '');
+
+  return string1 + separator + string2
+}
+
+/**
+ * Determines whether an input can be converted
+ * @private
+ * @param {String|HTMLElement} input Describe this parameter
+ * @returns Describe what it returns
+ * @type String|Object|Array|Boolean|Number
+ */
+
+function canConvert (input) {
+  return (
+    input != null && (
+      typeof input === 'string' ||
+      (input.nodeType && (
+        input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
+      ))
+    )
+  )
+}
+
+return TurndownService;
+
+}());

+ 0 - 6
src/ts/constants.ts

@@ -3,9 +3,3 @@ declare const VDITOR_VERSION: string;
 const _VDITOR_VERSION = VDITOR_VERSION;
 const _VDITOR_VERSION = VDITOR_VERSION;
 
 
 export {_VDITOR_VERSION as VDITOR_VERSION};
 export {_VDITOR_VERSION as VDITOR_VERSION};
-
-declare const CDN_PATH: string;
-
-const _CDN_PATH = CDN_PATH;
-
-export {_CDN_PATH as CDN_PATH};

+ 11 - 13
src/ts/types/index.d.ts

@@ -2,19 +2,12 @@ declare module "*.svg";
 
 
 declare module "*.png";
 declare module "*.png";
 
 
-declare module "highlight.js";
-
-declare module "mermaid";
-
-declare module "abcjs/src/api/abc_tunebook_svg";
-
-declare module "katex";
-declare module "katex/contrib/auto-render/auto-render";
-
-declare module "turndown";
-
 interface ITurndown {
 interface ITurndown {
     addRule(key: string, rule: ITurndownRule): ITurndown;
     addRule(key: string, rule: ITurndownRule): ITurndown;
+
+    use(gfm: (turndownService: ITurndown) => void): void;
+
+    turndown(html: string): string;
 }
 }
 
 
 interface ITurndownRule {
 interface ITurndownRule {
@@ -65,7 +58,7 @@ interface ILute {
     Md2VditorDOM(markdown: string): string;
     Md2VditorDOM(markdown: string): string;
 }
 }
 
 
-declare var webkitAudioContext: {
+declare const webkitAudioContext: {
     prototype: AudioContext
     prototype: AudioContext
     new(contextOptions?: AudioContextOptions): AudioContext,
     new(contextOptions?: AudioContextOptions): AudioContext,
 };
 };
@@ -220,6 +213,11 @@ interface IOptions {
     select?(value: string): void;
     select?(value: string): void;
 }
 }
 
 
+interface IEChart {
+    setOption(option: any): void;
+    resize(): void;
+}
+
 interface IVditor {
 interface IVditor {
     id: string;
     id: string;
     options: IOptions;
     options: IOptions;
@@ -229,7 +227,7 @@ interface IVditor {
     currentPreviewMode: keyof IPreviewMode;
     currentPreviewMode: keyof IPreviewMode;
     devtools?: {
     devtools?: {
         element: HTMLDivElement,
         element: HTMLDivElement,
-        ASTChart: echarts.ECharts
+        ASTChart: IEChart,
         renderEchart(vditor: IVditor): void,
         renderEchart(vditor: IVditor): void,
     };
     };
     toolbar?: {
     toolbar?: {

+ 2 - 4
src/ts/util/Options.ts

@@ -1,11 +1,9 @@
-import {CDN_PATH, VDITOR_VERSION} from "../constants";
-
 export class Options {
 export class Options {
     public options: IOptions;
     public options: IOptions;
     private defaultOptions: IOptions = {
     private defaultOptions: IOptions = {
         after: undefined,
         after: undefined,
         cache: true,
         cache: true,
-        cdn: "",
+        cdn: "..",
         classes: {
         classes: {
             preview: "",
             preview: "",
         },
         },
@@ -19,7 +17,7 @@ export class Options {
                 "cold_sweat": "😰",
                 "cold_sweat": "😰",
                 "heart": "❤️",
                 "heart": "❤️",
             },
             },
-            emojiPath: `${CDN_PATH}/vditor@${VDITOR_VERSION}/dist/images/emoji`,
+            emojiPath: `../dist/images/emoji`,
         },
         },
         keymap: {
         keymap: {
             deleteLine: "⌘-Backspace",
             deleteLine: "⌘-Backspace",

+ 15 - 0
src/ts/util/addScript.ts

@@ -0,0 +1,15 @@
+export const addScript = (path: string, id: string) => {
+    if (document.getElementById(id)) {
+        return false;
+    }
+    const xhrObj = new XMLHttpRequest();
+    xhrObj.open("GET", path, false);
+    xhrObj.setRequestHeader("Accept",
+        "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01");
+    xhrObj.send("");
+    const scriptElement = document.createElement("script");
+    scriptElement.type = "text/javascript";
+    scriptElement.text = xhrObj.responseText;
+    scriptElement.id = id;
+    document.getElementsByTagName("head")[0].appendChild(scriptElement);
+};

+ 21 - 20
webpack.config.js

@@ -8,7 +8,6 @@
 const path = require('path')
 const path = require('path')
 const fs = require('fs')
 const fs = require('fs')
 const webpack = require('webpack')
 const webpack = require('webpack')
-const {CleanWebpackPlugin} = require('clean-webpack-plugin')
 const MiniCssExtractPlugin = require('mini-css-extract-plugin')
 const MiniCssExtractPlugin = require('mini-css-extract-plugin')
 const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
 const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
 const WebpackOnBuildPlugin = require('on-build-webpack')
 const WebpackOnBuildPlugin = require('on-build-webpack')
@@ -44,6 +43,12 @@ SOFTWARE.
   entryOnly: true,
   entryOnly: true,
 })
 })
 
 
+const rimraf = require('rimraf')
+
+rimraf.sync('./dist', {},() => {
+  console.log('rm dist')
+})
+
 module.exports = [
 module.exports = [
   {
   {
     mode: 'production',
     mode: 'production',
@@ -89,8 +94,6 @@ module.exports = [
       ],
       ],
     },
     },
     plugins: [
     plugins: [
-      new CleanWebpackPlugin(
-        {cleanOnceBeforeBuildPatterns: [path.join(__dirname, 'dist')]}),
       banner,
       banner,
       new MiniCssExtractPlugin({
       new MiniCssExtractPlugin({
         filename: '[name].css',
         filename: '[name].css',
@@ -109,16 +112,15 @@ module.exports = [
     output: {
     output: {
       filename: '[name].js',
       filename: '[name].js',
       path: path.resolve(__dirname, 'dist'),
       path: path.resolve(__dirname, 'dist'),
-      chunkFilename: '[name].bundle.js',
-      // pkg.cdn: https://static.hacpai.com/js/lib | https://unpkg.com | https://cdn.jsdelivr.net/npm
-      publicPath: `${pkg.cdn}/vditor@${pkg.version}/dist/`,
+      // chunkFilename: '[name].bundle.js',
+      // publicPath: `${pkg.cdn}/vditor@${pkg.version}/dist/`,
       libraryTarget: 'umd',
       libraryTarget: 'umd',
       library: 'Vditor',
       library: 'Vditor',
       libraryExport: 'default',
       libraryExport: 'default',
     },
     },
     entry: {
     entry: {
       'index.min': './src/index.ts',
       'index.min': './src/index.ts',
-      'method.min': './src/method.ts'
+      'method.min': './src/method.ts',
     },
     },
     resolve: {
     resolve: {
       extensions: ['.js', '.ts', '.svg', 'png'],
       extensions: ['.js', '.ts', '.svg', 'png'],
@@ -180,20 +182,19 @@ module.exports = [
       // new BundleAnalyzerPlugin(),
       // new BundleAnalyzerPlugin(),
       new webpack.DefinePlugin({
       new webpack.DefinePlugin({
         VDITOR_VERSION: JSON.stringify(pkg.version),
         VDITOR_VERSION: JSON.stringify(pkg.version),
-        CDN_PATH: JSON.stringify(pkg.cdn),
       }),
       }),
       banner,
       banner,
     ],
     ],
-    optimization: {
-      namedModules: true,
-      namedChunks: true,
-      splitChunks: {
-        cacheGroups: {
-          default: false,
-          vendors: {
-            test: /null/,
-          },
-        },
-      },
-    },
+    // optimization: {
+    //   namedModules: true,
+    //   namedChunks: true,
+    //   splitChunks: {
+    //     cacheGroups: {
+    //       default: false,
+    //       vendors: {
+    //         test: /null/,
+    //       },
+    //     },
+    //   },
+    // },
   }]
   }]

+ 0 - 1
webpack.start.js

@@ -119,7 +119,6 @@ module.exports = {
     }),
     }),
     new webpack.DefinePlugin({
     new webpack.DefinePlugin({
       VDITOR_VERSION: JSON.stringify(pkg.version),
       VDITOR_VERSION: JSON.stringify(pkg.version),
-      CDN_PATH: JSON.stringify(pkg.cdn),
     }),
     }),
     new CopyPlugin([
     new CopyPlugin([
       {from: 'src/images', to: 'images'},
       {from: 'src/images', to: 'images'},

部分文件因为文件数量过多而无法显示