浏览代码

Merge branch 'develop'

Estevao Soares dos Santos 7 年之前
父节点
当前提交
62270d4a4b

+ 3 - 2
.appveyor.yml

@@ -17,7 +17,8 @@ environment:
       platform: x64
     - nodejs_version: "10"
       platform: x64
-
+cache:
+  - node_modules
 install:
   # Use version based on tag
   - ps: $env:package_version = (Get-Content -Raw -Path package.json | ConvertFrom-Json).version
@@ -26,7 +27,6 @@ install:
   # install node
   # Get the latest stable version of Node.js or io.js
   - ps: Install-Product node $env:nodejs_version
-
   # install grunt-cli globally
   - npm install -g grunt-cli
   # install modules
@@ -35,6 +35,7 @@ install:
 test_script:
   # Output useful info for debugging
   - node --version && npm --version
+  - ps: grunt test
 
 # Don't actually build.
 build: off

+ 1 - 1
.travis.yml

@@ -7,7 +7,7 @@ node_js:
 before_install:
   - npm install -g grunt-cli
 
-#travis build  speed up
+# travis build  speed up
 sudo: false
 cache:
   directories:

+ 1 - 1
Gruntfile.js

@@ -24,7 +24,7 @@ module.exports = function (grunt) {
           'src/showdown.js',
           'src/helpers.js',
           'src/subParsers/makehtml/*.js',
-          'src/subParsers/makemd/*.js',
+          'src/subParsers/makemarkdown/*.js',
           'src/converter.js',
           'src/loader.js'
         ],

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


+ 4 - 4
package.json

@@ -40,7 +40,7 @@
   },
   "devDependencies": {
     "chai": "4.1.x",
-    "grunt": "^1.0.1",
+    "grunt": "^1.0.3",
     "grunt-contrib-clean": "1.1.x",
     "grunt-contrib-concat": "1.0.x",
     "grunt-contrib-jshint": "1.1.x",
@@ -55,11 +55,11 @@
     "quiet-grunt": "0.2.x",
     "semver": "5.4.x",
     "semver-sort": "0.0.x",
-    "sinon": "5.0.x",
-    "source-map-support": "0.5.x"
+    "sinon": "^5.1.1",
+    "source-map-support": "^0.5.6"
   },
   "dependencies": {
     "jsdom": "^10.0.0",
-    "yargs": "^11.0.0"
+    "yargs": "^11.1.0"
   }
 }

+ 4 - 451
src/converter.js

@@ -362,7 +362,9 @@ showdown.Converter = function (converterOptions) {
     var doc = showdown.helper.document.createElement('div');
     doc.innerHTML = src;
 
-    var preList = substitutePreCodeTags(doc);
+    var globals = {
+      preList: substitutePreCodeTags(doc)
+    };
 
     // remove all newlines and collapse spaces
     clean(doc);
@@ -375,456 +377,7 @@ showdown.Converter = function (converterOptions) {
         mdDoc = '';
 
     for (var i = 0; i < nodes.length; i++) {
-      mdDoc += parseNode(nodes[i]);
-    }
-
-
-    function parseNode (node, spansOnly) {
-
-      spansOnly = spansOnly || false;
-
-      var txt = '';
-
-      // edge case of text without wrapper paragraph
-      if (node.nodeType === 3) {
-        return parseTxt(node);
-      }
-
-      // HTML comment
-      if (node.nodeType === 8) {
-        return '<!--' + node.data + '-->\n\n';
-      }
-
-      // process only node elements
-      if (node.nodeType !== 1) {
-        return '';
-      }
-
-      var tagName = node.tagName.toLowerCase();
-
-      switch (tagName) {
-
-        //
-        // BLOCKS
-        //
-        case 'h1':
-          if (!spansOnly) { txt = parseHeader(node, 1) + '\n\n'; }
-          break;
-        case 'h2':
-          if (!spansOnly) { txt = parseHeader(node, 2) + '\n\n'; }
-          break;
-        case 'h3':
-          if (!spansOnly) { txt = parseHeader(node, 3) + '\n\n'; }
-          break;
-        case 'h4':
-          if (!spansOnly) { txt = parseHeader(node, 4) + '\n\n'; }
-          break;
-        case 'h5':
-          if (!spansOnly) { txt = parseHeader(node, 5) + '\n\n'; }
-          break;
-        case 'h6':
-          if (!spansOnly) { txt = parseHeader(node, 6) + '\n\n'; }
-          break;
-
-        case 'p':
-          if (!spansOnly) { txt = parseParagraph(node) + '\n\n'; }
-          break;
-
-        case 'blockquote':
-          if (!spansOnly) { txt = parseBlockquote(node) + '\n\n'; }
-          break;
-
-        case 'hr':
-          if (!spansOnly) { txt = parseHr(node) + '\n\n'; }
-          break;
-
-        case 'ol':
-          if (!spansOnly) { txt = parseList(node, 'ol') + '\n\n'; }
-          break;
-
-        case 'ul':
-          if (!spansOnly) { txt = parseList(node, 'ul') + '\n\n'; }
-          break;
-
-        case 'precode':
-          if (!spansOnly) { txt = parsePreCode(node) + '\n\n'; }
-          break;
-
-        case 'pre':
-          if (!spansOnly) { txt = parsePre(node) + '\n\n'; }
-          break;
-
-        case 'table':
-          if (!spansOnly) { txt = parseTable(node) + '\n\n'; }
-          break;
-
-        //
-        // SPANS
-        //
-        case 'code':
-          txt = parseCodeSpan(node);
-          break;
-
-        case 'em':
-        case 'i':
-          txt = parseEmphasis(node);
-          break;
-
-        case 'strong':
-        case 'b':
-          txt = parseStrong(node);
-          break;
-
-        case 'del':
-          txt = parseDel(node);
-          break;
-
-        case 'a':
-          txt = parseLinks(node);
-          break;
-
-        case 'img':
-          txt = parseImage(node);
-          break;
-
-        default:
-          txt = node.outerHTML + '\n\n';
-      }
-
-      // common normalization
-
-
-      return txt;
-    }
-
-    function parseTxt (node) {
-      var txt = node.nodeValue;
-
-      // multiple spaces are collapsed
-      txt = txt.replace(/ +/g, ' ');
-
-      // replace the custom ¨NBSP; with a space
-      txt = txt.replace(/¨NBSP;/g, ' ');
-
-      // ", <, > and & should replace escaped html entities
-      txt = showdown.helper.unescapeHTMLEntities(txt);
-
-      // escape markdown magic characters
-      // emphasis, strong and strikethrough - can appear everywhere
-      // we also escape pipe (|) because of tables
-      // and escape ` because of code blocks and spans
-      txt = txt.replace(/([*_~|`])/g, '\\$1');
-
-      // escape > because of blockquotes
-      txt = txt.replace(/^(\s*)>/g, '\\$1>');
-
-      // hash character, only troublesome at the beginning of a line because of headers
-      txt = txt.replace(/^#/gm, '\\#');
-
-      // horizontal rules
-      txt = txt.replace(/^(\s*)([-=]{3,})(\s*)$/, '$1\\$2$3');
-
-      // dot, because of ordered lists, only troublesome at the beginning of a line when preceded by an integer
-      txt = txt.replace(/^( {0,3}\d+)\./gm, '$1\\.');
-
-      // +, * and -, at the beginning of a line becomes a list, so we need to escape them also (asterisk was already escaped)
-      txt = txt.replace(/^( {0,3})([+-])/gm, '$1\\$2');
-
-      // images and links, ] followed by ( is problematic, so we escape it
-      txt = txt.replace(/]([\s]*)\(/g, '\\]$1\\(');
-
-      // reference URIs must also be escaped
-      txt = txt.replace(/^ {0,3}\[([\S \t]*?)]:/gm, '\\[$1]:');
-
-      return txt;
-    }
-
-    function parseList (node, type) {
-      var txt = '';
-      if (!node.hasChildNodes()) {
-        return '';
-      }
-      var listItems       = node.childNodes,
-          listItemsLenght = listItems.length,
-          listNum = node.getAttribute('start') || 1;
-
-      for (var i = 0; i < listItemsLenght; ++i) {
-        if (typeof listItems[i].tagName === 'undefined' || listItems[i].tagName.toLowerCase() !== 'li') {
-          continue;
-        }
-
-        // define the bullet to use in list
-        var bullet = '';
-        if (type === 'ol') {
-          bullet = listNum.toString() + '. ';
-        } else {
-          bullet = '- ';
-        }
-
-        // parse list item
-        txt += bullet + parseListItem(listItems[i]);
-        ++listNum;
-      }
-
-      return txt.trim();
-    }
-
-    function parseListItem (node) {
-      var listItemTxt = '';
-
-      var children = node.childNodes,
-          childrenLenght = children.length;
-
-      for (var i = 0; i < childrenLenght; ++i) {
-        listItemTxt += parseNode(children[i]);
-      }
-      // if it's only one liner, we need to add a newline at the end
-      if (!/\n$/.test(listItemTxt)) {
-        listItemTxt += '\n';
-      } else {
-        // it's multiparagraph, so we need to indent
-        listItemTxt = listItemTxt
-          .split('\n')
-          .join('\n    ')
-          .replace(/^ {4}$/gm, '')
-          .replace(/\n\n+/g, '\n\n');
-      }
-
-      return listItemTxt;
-    }
-
-    function parseHr () {
-      return '---';
-    }
-
-    function parseBlockquote (node) {
-      var txt = '';
-      if (node.hasChildNodes()) {
-        var children = node.childNodes,
-            childrenLength = children.length;
-
-        for (var i = 0; i < childrenLength; ++i) {
-          var innerTxt = parseNode(children[i]);
-
-          if (innerTxt === '') {
-            continue;
-          }
-          txt += innerTxt;
-        }
-      }
-      // cleanup
-      txt = txt.trim();
-      txt = '> ' + txt.split('\n').join('\n> ');
-      return txt;
-    }
-
-    function parseCodeSpan (node) {
-      return '`' + node.innerHTML + '`';
-    }
-
-    function parseStrong (node) {
-      var txt = '';
-      if (node.hasChildNodes()) {
-        txt += '**';
-        var children = node.childNodes,
-            childrenLength = children.length;
-        for (var i = 0; i < childrenLength; ++i) {
-          txt += parseNode(children[i]);
-        }
-        txt += '**';
-      }
-      return txt;
-    }
-
-    function parseEmphasis (node) {
-      var txt = '';
-      if (node.hasChildNodes()) {
-        txt += '*';
-        var children = node.childNodes,
-            childrenLength = children.length;
-        for (var i = 0; i < childrenLength; ++i) {
-          txt += parseNode(children[i]);
-        }
-        txt += '*';
-      }
-      return txt;
-    }
-
-    function parseDel (node) {
-      var txt = '';
-      if (node.hasChildNodes()) {
-        txt += '~~';
-        var children = node.childNodes,
-            childrenLength = children.length;
-        for (var i = 0; i < childrenLength; ++i) {
-          txt += parseNode(children[i]);
-        }
-        txt += '~~';
-      }
-      return txt;
-    }
-
-    function parseLinks (node) {
-      var txt = '';
-      if (node.hasChildNodes() && node.hasAttribute('href')) {
-        var children = node.childNodes,
-            childrenLength = children.length;
-        txt = '[';
-        for (var i = 0; i < childrenLength; ++i) {
-          txt += parseNode(children[i]);
-        }
-        txt += '](';
-        txt += '<' + node.getAttribute('href') + '>';
-        if (node.hasAttribute('title')) {
-          txt += ' "' + node.getAttribute('title') + '"';
-        }
-        txt += ')';
-      }
-      return txt;
-    }
-
-    function parseImage (node) {
-      var txt = '';
-      if (node.hasAttribute('src')) {
-        txt += '![' + node.getAttribute('alt') + '](';
-        txt += '<' + node.getAttribute('src') + '>';
-        if (node.hasAttribute('width') && node.hasAttribute('height')) {
-          txt += ' =' + node.getAttribute('width') + 'x' + node.getAttribute('height');
-        }
-
-        if (node.hasAttribute('title')) {
-          txt += ' "' + node.getAttribute('title') + '"';
-        }
-        txt += ')';
-      }
-      return txt;
-    }
-
-    function parseHeader (node, headerLevel) {
-      var headerMark = new Array(headerLevel + 1).join('#'),
-          txt = '';
-
-      if (node.hasChildNodes()) {
-        txt = headerMark + ' ';
-        var children = node.childNodes,
-            childrenLength = children.length;
-
-        for (var i = 0; i < childrenLength; ++i) {
-          txt += parseNode(children[i]);
-        }
-      }
-      return txt;
-    }
-
-    function parseParagraph (node) {
-      var txt = '';
-      if (node.hasChildNodes()) {
-        var children = node.childNodes,
-            childrenLength = children.length;
-        for (var i = 0; i < childrenLength; ++i) {
-          txt += parseNode(children[i]);
-        }
-      }
-
-      // some text normalization
-      txt = txt.trim();
-
-      return txt;
-    }
-
-    function parsePreCode (node) {
-      var lang = node.getAttribute('language'),
-          num  = node.getAttribute('precodenum');
-      return '```' + lang + '\n' + preList[num] + '\n```';
-    }
-
-    function parsePre (node) {
-      var num  = node.getAttribute('prenum');
-      return '<pre>' + preList[num] + '</pre>';
-    }
-
-    function parseTable (node) {
-
-      var txt = '',
-          tableArray = [[], []],
-          headings   = node.querySelectorAll('thead>tr>th'),
-          rows       = node.querySelectorAll('tbody>tr'),
-          i, ii;
-      for (i = 0; i < headings.length; ++i) {
-        var headContent = parseTableCell(headings[i]),
-            allign = '---';
-
-        if (headings[i].hasAttribute('style')) {
-          var style = headings[i].getAttribute('style').toLowerCase().replace(/\s/g, '');
-          switch (style) {
-            case 'text-align:left;':
-              allign = ':---';
-              break;
-            case 'text-align:right;':
-              allign = '---:';
-              break;
-            case 'text-align:center;':
-              allign = ':---:';
-              break;
-          }
-        }
-        tableArray[0][i] = headContent.trim();
-        tableArray[1][i] = allign;
-      }
-
-      for (i = 0; i < rows.length; ++i) {
-        var r = tableArray.push([]) - 1,
-            cols = rows[i].getElementsByTagName('td');
-
-        for (ii = 0; ii < headings.length; ++ii) {
-          var cellContent = ' ';
-          if (typeof cols[ii] !== 'undefined') {
-            cellContent = parseTableCell(cols[ii]);
-          }
-          tableArray[r].push(cellContent);
-        }
-      }
-
-      var cellSpacesCount = 3;
-      for (i = 0; i < tableArray.length; ++i) {
-        for (ii = 0; ii < tableArray[i].length; ++ii) {
-          var strLen = tableArray[i][ii].length;
-          if (strLen > cellSpacesCount) {
-            cellSpacesCount = strLen;
-          }
-        }
-      }
-
-      for (i = 0; i < tableArray.length; ++i) {
-        for (ii = 0; ii < tableArray[i].length; ++ii) {
-          if (i === 1) {
-            if (tableArray[i][ii].slice(-1) === ':') {
-              tableArray[i][ii] = showdown.helper.padEnd(tableArray[i][ii].slice(-1), cellSpacesCount - 1, '-') + ':';
-            } else {
-              tableArray[i][ii] = showdown.helper.padEnd(tableArray[i][ii], cellSpacesCount, '-');
-            }
-          } else {
-            tableArray[i][ii] = showdown.helper.padEnd(tableArray[i][ii], cellSpacesCount);
-          }
-        }
-        txt += '| ' + tableArray[i].join(' | ') + ' |\n';
-      }
-
-      return txt.trim();
-    }
-
-    function parseTableCell (node) {
-      var txt = '';
-      if (!node.hasChildNodes()) {
-        return '';
-      }
-      var children = node.childNodes,
-          childrenLength = children.length;
-
-      for (var i = 0; i < childrenLength; ++i) {
-        txt += parseNode(children[i], true);
-      }
-      return txt.trim();
+      mdDoc += showdown.subParser('makeMarkdown.node')(nodes[i], globals);
     }
 
     function clean (node) {

+ 2 - 0
src/showdown.js

@@ -180,6 +180,8 @@ showdown.subParser = function (name, func) {
         throw Error('SubParser named ' + name + ' not registered!');
       }
     }
+  } else {
+    throw Error('showdown.subParser function first argument must be a string (the name of the subparser)');
   }
 };
 

+ 20 - 0
src/subParsers/makemarkdown/anchors.js

@@ -0,0 +1,20 @@
+showdown.subParser('makeMarkdown.anchors', function (node, globals) {
+  'use strict';
+
+  var txt = '';
+  if (node.hasChildNodes() && node.hasAttribute('href')) {
+    var children = node.childNodes,
+        childrenLength = children.length;
+    txt = '[';
+    for (var i = 0; i < childrenLength; ++i) {
+      txt += showdown.subParser('makeMarkdown.node')(children[i], globals);
+    }
+    txt += '](';
+    txt += '<' + node.getAttribute('href') + '>';
+    if (node.hasAttribute('title')) {
+      txt += ' "' + node.getAttribute('title') + '"';
+    }
+    txt += ')';
+  }
+  return txt;
+});

+ 22 - 0
src/subParsers/makemarkdown/blockquote.js

@@ -0,0 +1,22 @@
+showdown.subParser('makeMarkdown.blockquote', function (node, globals) {
+  'use strict';
+
+  var txt = '';
+  if (node.hasChildNodes()) {
+    var children = node.childNodes,
+        childrenLength = children.length;
+
+    for (var i = 0; i < childrenLength; ++i) {
+      var innerTxt = showdown.subParser('makeMarkdown.node')(children[i], globals);
+
+      if (innerTxt === '') {
+        continue;
+      }
+      txt += innerTxt;
+    }
+  }
+  // cleanup
+  txt = txt.trim();
+  txt = '> ' + txt.split('\n').join('\n> ');
+  return txt;
+});

+ 7 - 0
src/subParsers/makemarkdown/codeBlock.js

@@ -0,0 +1,7 @@
+showdown.subParser('makeMarkdown.codeBlock', function (node, globals) {
+  'use strict';
+
+  var lang = node.getAttribute('language'),
+      num  = node.getAttribute('precodenum');
+  return '```' + lang + '\n' + globals.preList[num] + '\n```';
+});

+ 5 - 0
src/subParsers/makemarkdown/codeSpan.js

@@ -0,0 +1,5 @@
+showdown.subParser('makeMarkdown.codeSpan', function (node) {
+  'use strict';
+
+  return '`' + node.innerHTML + '`';
+});

+ 15 - 0
src/subParsers/makemarkdown/emphasis.js

@@ -0,0 +1,15 @@
+showdown.subParser('makeMarkdown.emphasis', function (node, globals) {
+  'use strict';
+
+  var txt = '';
+  if (node.hasChildNodes()) {
+    txt += '*';
+    var children = node.childNodes,
+        childrenLength = children.length;
+    for (var i = 0; i < childrenLength; ++i) {
+      txt += showdown.subParser('makeMarkdown.node')(children[i], globals);
+    }
+    txt += '*';
+  }
+  return txt;
+});

+ 17 - 0
src/subParsers/makemarkdown/header.js

@@ -0,0 +1,17 @@
+showdown.subParser('makeMarkdown.header', function (node, globals, headerLevel) {
+  'use strict';
+
+  var headerMark = new Array(headerLevel + 1).join('#'),
+      txt = '';
+
+  if (node.hasChildNodes()) {
+    txt = headerMark + ' ';
+    var children = node.childNodes,
+        childrenLength = children.length;
+
+    for (var i = 0; i < childrenLength; ++i) {
+      txt += showdown.subParser('makeMarkdown.node')(children[i], globals);
+    }
+  }
+  return txt;
+});

+ 5 - 0
src/subParsers/makemarkdown/hr.js

@@ -0,0 +1,5 @@
+showdown.subParser('makeMarkdown.hr', function () {
+  'use strict';
+
+  return '---';
+});

+ 18 - 0
src/subParsers/makemarkdown/image.js

@@ -0,0 +1,18 @@
+showdown.subParser('makeMarkdown.image', function (node) {
+  'use strict';
+
+  var txt = '';
+  if (node.hasAttribute('src')) {
+    txt += '![' + node.getAttribute('alt') + '](';
+    txt += '<' + node.getAttribute('src') + '>';
+    if (node.hasAttribute('width') && node.hasAttribute('height')) {
+      txt += ' =' + node.getAttribute('width') + 'x' + node.getAttribute('height');
+    }
+
+    if (node.hasAttribute('title')) {
+      txt += ' "' + node.getAttribute('title') + '"';
+    }
+    txt += ')';
+  }
+  return txt;
+});

+ 31 - 0
src/subParsers/makemarkdown/list.js

@@ -0,0 +1,31 @@
+showdown.subParser('makeMarkdown.list', function (node, globals, type) {
+  'use strict';
+
+  var txt = '';
+  if (!node.hasChildNodes()) {
+    return '';
+  }
+  var listItems       = node.childNodes,
+      listItemsLenght = listItems.length,
+      listNum = node.getAttribute('start') || 1;
+
+  for (var i = 0; i < listItemsLenght; ++i) {
+    if (typeof listItems[i].tagName === 'undefined' || listItems[i].tagName.toLowerCase() !== 'li') {
+      continue;
+    }
+
+    // define the bullet to use in list
+    var bullet = '';
+    if (type === 'ol') {
+      bullet = listNum.toString() + '. ';
+    } else {
+      bullet = '- ';
+    }
+
+    // parse list item
+    txt += bullet + showdown.subParser('makeMarkdown.listItem')(listItems[i], globals);
+    ++listNum;
+  }
+
+  return txt.trim();
+});

+ 25 - 0
src/subParsers/makemarkdown/listItem.js

@@ -0,0 +1,25 @@
+showdown.subParser('makeMarkdown.listItem', function (node, globals) {
+  'use strict';
+
+  var listItemTxt = '';
+
+  var children = node.childNodes,
+      childrenLenght = children.length;
+
+  for (var i = 0; i < childrenLenght; ++i) {
+    listItemTxt += showdown.subParser('makeMarkdown.node')(children[i], globals);
+  }
+  // if it's only one liner, we need to add a newline at the end
+  if (!/\n$/.test(listItemTxt)) {
+    listItemTxt += '\n';
+  } else {
+    // it's multiparagraph, so we need to indent
+    listItemTxt = listItemTxt
+      .split('\n')
+      .join('\n    ')
+      .replace(/^ {4}$/gm, '')
+      .replace(/\n\n+/g, '\n\n');
+  }
+
+  return listItemTxt;
+});

+ 120 - 0
src/subParsers/makemarkdown/node.js

@@ -0,0 +1,120 @@
+
+
+showdown.subParser('makeMarkdown.node', function (node, globals, spansOnly) {
+  'use strict';
+
+  spansOnly = spansOnly || false;
+
+  var txt = '';
+
+  // edge case of text without wrapper paragraph
+  if (node.nodeType === 3) {
+    return showdown.subParser('makeMarkdown.txt')(node, globals);
+  }
+
+  // HTML comment
+  if (node.nodeType === 8) {
+    return '<!--' + node.data + '-->\n\n';
+  }
+
+  // process only node elements
+  if (node.nodeType !== 1) {
+    return '';
+  }
+
+  var tagName = node.tagName.toLowerCase();
+
+  switch (tagName) {
+
+    //
+    // BLOCKS
+    //
+    case 'h1':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.header')(node, globals, 1) + '\n\n'; }
+      break;
+    case 'h2':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.header')(node, globals, 2) + '\n\n'; }
+      break;
+    case 'h3':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.header')(node, globals, 3) + '\n\n'; }
+      break;
+    case 'h4':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.header')(node, globals, 4) + '\n\n'; }
+      break;
+    case 'h5':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.header')(node, globals, 5) + '\n\n'; }
+      break;
+    case 'h6':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.header')(node, globals, 6) + '\n\n'; }
+      break;
+
+    case 'p':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.paragraph')(node, globals) + '\n\n'; }
+      break;
+
+    case 'blockquote':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.blockquote')(node, globals) + '\n\n'; }
+      break;
+
+    case 'hr':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.hr')(node, globals) + '\n\n'; }
+      break;
+
+    case 'ol':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.list')(node, globals, 'ol') + '\n\n'; }
+      break;
+
+    case 'ul':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.list')(node, globals, 'ul') + '\n\n'; }
+      break;
+
+    case 'precode':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.codeBlock')(node, globals) + '\n\n'; }
+      break;
+
+    case 'pre':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.pre')(node, globals) + '\n\n'; }
+      break;
+
+    case 'table':
+      if (!spansOnly) { txt = showdown.subParser('makeMarkdown.table')(node, globals) + '\n\n'; }
+      break;
+
+    //
+    // SPANS
+    //
+    case 'code':
+      txt = showdown.subParser('makeMarkdown.codeSpan')(node, globals);
+      break;
+
+    case 'em':
+    case 'i':
+      txt = showdown.subParser('makeMarkdown.emphasis')(node, globals);
+      break;
+
+    case 'strong':
+    case 'b':
+      txt = showdown.subParser('makeMarkdown.strong')(node, globals);
+      break;
+
+    case 'del':
+      txt = showdown.subParser('makeMarkdown.strikethrough')(node, globals);
+      break;
+
+    case 'a':
+      txt = showdown.subParser('makeMarkdown.anchors')(node, globals);
+      break;
+
+    case 'img':
+      txt = showdown.subParser('makeMarkdown.image')(node, globals);
+      break;
+
+    default:
+      txt = node.outerHTML + '\n\n';
+  }
+
+  // common normalization
+  // TODO eventually
+
+  return txt;
+});

+ 17 - 0
src/subParsers/makemarkdown/paragraph.js

@@ -0,0 +1,17 @@
+showdown.subParser('makeMarkdown.paragraph', function (node, globals) {
+  'use strict';
+
+  var txt = '';
+  if (node.hasChildNodes()) {
+    var children = node.childNodes,
+        childrenLength = children.length;
+    for (var i = 0; i < childrenLength; ++i) {
+      txt += showdown.subParser('makeMarkdown.node')(children[i], globals);
+    }
+  }
+
+  // some text normalization
+  txt = txt.trim();
+
+  return txt;
+});

+ 6 - 0
src/subParsers/makemarkdown/pre.js

@@ -0,0 +1,6 @@
+showdown.subParser('makeMarkdown.pre', function (node, globals) {
+  'use strict';
+
+  var num  = node.getAttribute('prenum');
+  return '<pre>' + globals.preList[num] + '</pre>';
+});

+ 15 - 0
src/subParsers/makemarkdown/strikethrough.js

@@ -0,0 +1,15 @@
+showdown.subParser('makeMarkdown.strikethrough', function (node, globals) {
+  'use strict';
+
+  var txt = '';
+  if (node.hasChildNodes()) {
+    txt += '~~';
+    var children = node.childNodes,
+        childrenLength = children.length;
+    for (var i = 0; i < childrenLength; ++i) {
+      txt += showdown.subParser('makeMarkdown.node')(children[i], globals);
+    }
+    txt += '~~';
+  }
+  return txt;
+});

+ 15 - 0
src/subParsers/makemarkdown/strong.js

@@ -0,0 +1,15 @@
+showdown.subParser('makeMarkdown.strong', function (node, globals) {
+  'use strict';
+
+  var txt = '';
+  if (node.hasChildNodes()) {
+    txt += '**';
+    var children = node.childNodes,
+        childrenLength = children.length;
+    for (var i = 0; i < childrenLength; ++i) {
+      txt += showdown.subParser('makeMarkdown.node')(children[i], globals);
+    }
+    txt += '**';
+  }
+  return txt;
+});

+ 70 - 0
src/subParsers/makemarkdown/table.js

@@ -0,0 +1,70 @@
+showdown.subParser('makeMarkdown.table', function (node, globals) {
+  'use strict';
+
+  var txt = '',
+      tableArray = [[], []],
+      headings   = node.querySelectorAll('thead>tr>th'),
+      rows       = node.querySelectorAll('tbody>tr'),
+      i, ii;
+  for (i = 0; i < headings.length; ++i) {
+    var headContent = showdown.subParser('makeMarkdown.tableCell')(headings[i], globals),
+        allign = '---';
+
+    if (headings[i].hasAttribute('style')) {
+      var style = headings[i].getAttribute('style').toLowerCase().replace(/\s/g, '');
+      switch (style) {
+        case 'text-align:left;':
+          allign = ':---';
+          break;
+        case 'text-align:right;':
+          allign = '---:';
+          break;
+        case 'text-align:center;':
+          allign = ':---:';
+          break;
+      }
+    }
+    tableArray[0][i] = headContent.trim();
+    tableArray[1][i] = allign;
+  }
+
+  for (i = 0; i < rows.length; ++i) {
+    var r = tableArray.push([]) - 1,
+        cols = rows[i].getElementsByTagName('td');
+
+    for (ii = 0; ii < headings.length; ++ii) {
+      var cellContent = ' ';
+      if (typeof cols[ii] !== 'undefined') {
+        cellContent = showdown.subParser('makeMarkdown.tableCell')(cols[ii], globals);
+      }
+      tableArray[r].push(cellContent);
+    }
+  }
+
+  var cellSpacesCount = 3;
+  for (i = 0; i < tableArray.length; ++i) {
+    for (ii = 0; ii < tableArray[i].length; ++ii) {
+      var strLen = tableArray[i][ii].length;
+      if (strLen > cellSpacesCount) {
+        cellSpacesCount = strLen;
+      }
+    }
+  }
+
+  for (i = 0; i < tableArray.length; ++i) {
+    for (ii = 0; ii < tableArray[i].length; ++ii) {
+      if (i === 1) {
+        if (tableArray[i][ii].slice(-1) === ':') {
+          tableArray[i][ii] = showdown.helper.padEnd(tableArray[i][ii].slice(-1), cellSpacesCount - 1, '-') + ':';
+        } else {
+          tableArray[i][ii] = showdown.helper.padEnd(tableArray[i][ii], cellSpacesCount, '-');
+        }
+      } else {
+        tableArray[i][ii] = showdown.helper.padEnd(tableArray[i][ii], cellSpacesCount);
+      }
+    }
+    txt += '| ' + tableArray[i].join(' | ') + ' |\n';
+  }
+
+  return txt.trim();
+});

+ 15 - 0
src/subParsers/makemarkdown/tableCell.js

@@ -0,0 +1,15 @@
+showdown.subParser('makeMarkdown.tableCell', function (node, globals) {
+  'use strict';
+
+  var txt = '';
+  if (!node.hasChildNodes()) {
+    return '';
+  }
+  var children = node.childNodes,
+      childrenLength = children.length;
+
+  for (var i = 0; i < childrenLength; ++i) {
+    txt += showdown.subParser('makeMarkdown.node')(children[i], globals, true);
+  }
+  return txt.trim();
+});

+ 43 - 0
src/subParsers/makemarkdown/txt.js

@@ -0,0 +1,43 @@
+showdown.subParser('makeMarkdown.txt', function (node) {
+  'use strict';
+
+  var txt = node.nodeValue;
+
+  // multiple spaces are collapsed
+  txt = txt.replace(/ +/g, ' ');
+
+  // replace the custom ¨NBSP; with a space
+  txt = txt.replace(/¨NBSP;/g, ' ');
+
+  // ", <, > and & should replace escaped html entities
+  txt = showdown.helper.unescapeHTMLEntities(txt);
+
+  // escape markdown magic characters
+  // emphasis, strong and strikethrough - can appear everywhere
+  // we also escape pipe (|) because of tables
+  // and escape ` because of code blocks and spans
+  txt = txt.replace(/([*_~|`])/g, '\\$1');
+
+  // escape > because of blockquotes
+  txt = txt.replace(/^(\s*)>/g, '\\$1>');
+
+  // hash character, only troublesome at the beginning of a line because of headers
+  txt = txt.replace(/^#/gm, '\\#');
+
+  // horizontal rules
+  txt = txt.replace(/^(\s*)([-=]{3,})(\s*)$/, '$1\\$2$3');
+
+  // dot, because of ordered lists, only troublesome at the beginning of a line when preceded by an integer
+  txt = txt.replace(/^( {0,3}\d+)\./gm, '$1\\.');
+
+  // +, * and -, at the beginning of a line becomes a list, so we need to escape them also (asterisk was already escaped)
+  txt = txt.replace(/^( {0,3})([+-])/gm, '$1\\$2');
+
+  // images and links, ] followed by ( is problematic, so we escape it
+  txt = txt.replace(/]([\s]*)\(/g, '\\]$1\\(');
+
+  // reference URIs must also be escaped
+  txt = txt.replace(/^ {0,3}\[([\S \t]*?)]:/gm, '\\[$1]:');
+
+  return txt;
+});

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