Browse Source

1.add html to markdown file
2.fix indent method
2.fix some method

zhuzhuyule 7 years ago
parent
commit
5751716ebc

+ 207 - 61
views/main/CodeMirror/editor.js

@@ -24,30 +24,61 @@ module.exports = (() => {
         Enter: 'newlineAndIndentContinueMarkdownList',
         Home: 'goLineLeft',
         End: 'goLineRight',
-        Tab: function (codeMirror) {
-            codeMirror.indentSelection(parseInt(codeMirror.getOption("indentUnit")));
-        },
-        'Shift-Tab': 'indentLess',
+        'Tab':tabAdd,
+        'Shift-Tab': tabSubtract,
         'Ctrl-B': toggleBlod,
         'Ctrl-I': toggleItalic,
         'Ctrl-D': toggleDelete,
         'Ctrl-`': toggleComment,
-        'Ctrl-E': toggleBlockquote,
-        'Ctrl-Shift-E': toggleUnBlockquote,
         'Ctrl-L': toggleUnOrderedList,
         'Ctrl-Alt-L': toggleOrderedList,
-        'Ctrl-]': toggleHeader,
-        'Ctrl-[': toggleUnHeader,
+        'Ctrl-=': toggleHeader,
+        'Ctrl--': toggleUnHeader,
+        'Ctrl-]': toggleBlockquote,
+        'Ctrl-[': toggleUnBlockquote,
         'Ctrl-U': drawLink,
         'Ctrl-Alt-U': drawImageLink,
         'Ctrl-T': drawTable,
+        'Ctrl-V': pasteContent,
+        'Ctrl-Shift-V': pasteOriginContent,
         'Alt-F': formatTables
     }
 
+    /**
+     * Action for add space of "indentUnit" count.
+     */
+    function tabAdd(cm){
+        let indentCount = parseInt(cm.getOption("indentUnit")) || 4;
+        cm.indentSelection(indentCount);
+    }
+
+    /**
+     * Action for subtract space of "indentUnit" count or delete start modifier.
+     */
+    function tabSubtract(cm) {
+        const posStart = cm.getCursor('from');
+        const posEnd = cm.getCursor('to');
+        let needSubtract = true;
+        if (posStart.line === posEnd.line) {
+            let line = cm.getLine(posStart.line);
+            line.replace(/^([*+-] |\d\. )(.*)$/, (all, part1, part2) => {
+                posStart.ch -= part1.length;
+                cm.replaceRange(part2, CodeMirror.Pos(posStart.line, 0), CodeMirror.Pos(posStart.line, all.length))
+                cm.setCursor(posStart);
+                cm.focus();
+                needSubtract = false;
+            })
+        }
+        if (needSubtract) {
+            let indentCount = parseInt(cm.getOption("indentUnit")) || 4;
+            cm.indentSelection(-indentCount);
+        }
+    }
+
     /**
      * Fix shortcut. Mac use Command, others use Ctrl.
      */
-    function fixShortcut(name) {
+    function fixShortcut() {
         if (process.platform == 'drawin')
             Object.keys(keyMaps).forEach(item => {
                 if (item.indexOf('Ctrl') > -1) {
@@ -129,123 +160,176 @@ module.exports = (() => {
      * @param name
      * @private
      */
-    function _toggleLine (cm, name) {
+    function _toggleContinueLine (cm, name) {
         var startPoint = cm.getCursor('start');
         var endPoint = cm.getCursor('end');
-        // var repl = {
-        //     'header':         /^(\s*(?:[*+-] |\d\. |>+ )*(?:#+)*)(\s+.*)$/,
-        //     'quote':          /^(\s*(?:[*+-] |\d\. |>+ )*(?:>+)*)(\s.*)$/,
-        //     'unordered-list': /^(\s*(?:[*+-] |\d\. |>+ )*)(.*)$/,
-        //     'ordered-list':   /^(\s*(?:[*+-] |\d\. |>+ )*)(.*)$/,
-        //     'unheader': /^(\s*(?:[*+-] |\d\. |>+ )*#*)\#(?=\s+)/,
-        //     'unquote':  /^(\s*(?:[*+-] |\d\. |>+ )*>*)\>(?=\s+)/,
-        // };
         var map = {
             'header': '#',
             'unquote': '>',
-            'unordered-list': '*',
-            'ordered-list': '1.',
             'unheader': '#',
             'quote': '>'
         };
         //判断标识符是否可连续
-        var isAdd = name == 'header' || name == 'quote';
-        var isCancle = name == 'unheader' || name == 'unquote';
+        var isCancleAction = ['unheader', 'unquote'].indexOf(name) > -1 ;
         //操作每行的标识符
         for (var i = startPoint.line; i <= endPoint.line; i++) {
             (function (i) {
                 var text = cm.getLine(i);
-                var match = text.match(/^(\s*(?:[*+-] +|\d\. +|>+ +|#+ +)*)(.*)$/);
-                var flages = '';
+                var match = text.match(/^(\s*(?:[*+-] +|\d\. +|>+ +|#+ +)*(?:[*+-] |\d\. |>+ |#+ ))(.*)$/);
+                var flages = '';  //前置标识 集合如:>>> * 1.
+                var oldLength = 0,extend = map[name] + ' ';
                 //将整行分割为 标识符区、文本区
                 if (match !== null) {
                     flages = match[1];
                     text = match[2];
                 }
+                if( i === startPoint.line || i===endPoint.line)
+                    oldLength = flages.length;
                 //存在 标识符区域时,做去重检测(去重只检验末尾标识符(最近的添加的)是否与需要添加的标识符相同)
-                if (flages){
-                    flages.replace(/^(.*)([*+>#-]|\d\.)(\s)$/,(all,part1,part2,part3)=>{
-                        //末尾标识符与 新添加标识符 相同
-                        if (  (part2 == map[name] || ( part2.indexOf('.')>0 && map[name].indexOf('.')>0)) ){
-                            //相同标识符的状态下
-                            //可连续的标识符:将做连续添加操作
-                            //不连续的标识符:将做删除操作
-                            if (isAdd)
-                                text = part1 + part2 + map[name] + part3 + text;
-                            else
-                                text = (part1 + part3).replace(/(^| ) +$/,'$1') + text;
+                if (flages) {
+                    if (isCancleAction){
+                        extend = '';
+                        flages = flages.replace(new RegExp(map[name] + '(?=[^'+map[name]+']+$)'),'a').replace(/(^| )(a )/,'$1').replace('a','');
+                    } else {
+                        flages.replace(/^(.*(>|#))\s$/, (all, part1, part2) => {
+                            extend = '';
+                            //末尾标识符与 新添加标识符 相同
+                            if (part2 == map[name] ) {
+                                //相同标识符的状态下
+                                //可连续的标识符:将做连续添加操作
+                                flages = part1 + map[name] + ' ';
+                            } else {
+                                //不相同的标识符状态
+                                flages += map[name] + ' ';
+                            }
+                        });
+                    }
+                    flages += extend;
+                    text = flages + text;
+                }  else {
+                    //行首无标识符且当前操作不为取消操作时,添加新标识符到行首
+                    if (!isCancleAction)
+                        text = text.replace(/^(\s*)(.*)$/,(all,part1,part2)=>{
+                            flages = map[name] + ' ';
+                            return part1 + flages + part2;
+                        })
+                }
+                if( i === startPoint.line)
+                    startPoint.ch -= oldLength - flages.length;
+                if((startPoint.line !== endPoint.line || startPoint.ch !== endPoint.ch)&& i === endPoint.line)
+                    endPoint.ch -= oldLength - flages.length;
+                cm.replaceRange(text, CodeMirror.Pos(i, 0), CodeMirror.Pos(i, cm.getLine(i).length));
+            })(i);
+        }
+        cm.setSelection(startPoint,endPoint);
+        cm.focus();
+    }
+
+    function _toggleLine (cm, name) {
+        var startPoint = cm.getCursor('start');
+        var endPoint = cm.getCursor('end');
+        var map = {
+            'unordered-list': '*',
+            'ordered-list': '1.'
+        };
+        //操作每行的标识符
+        for (var i = startPoint.line; i <= endPoint.line; i++) {
+            (function (i) {
+                var text = cm.getLine(i);
+                var match = text.match(/^(\s*(?:[*+-] +|\d\. +|>+ +|#+ +)*(?:[*+-] |\d\. |>+ |#+ ))(.*)$/);
+                var modifiers = '';  //前置标识 集合如:>>> * 1.
+                var oldLength = 0,extend = map[name] + ' ';
+                //将整行分割为 标识符区、文本区
+                if (match !== null) {
+                    modifiers = match[1];
+                    text = match[2];
+                }
+                if( i === startPoint.line || i===endPoint.line)
+                    oldLength = modifiers.length;
+                //存在 标识符区域时,做去重检测(去重只检验末尾标识符(最近的添加的)是否与需要添加的标识符相同)
+                if (modifiers) {
+                    modifiers.replace(/^(.*)([*+-]|\d\.)\s$/, (all, part1, part2) => {
+                        extend = '';
+                        if(part2.length != map[name].length){
+                            modifiers =  part1 +  map[name] + ' ';
                         } else {
-                            //不相同的标识符状态
-                            //直接新增标识符到行首
-                            text = flages + map[name] + ' ' + text;
+                            modifiers = part1;
                         }
-                        return flages
                     });
+                    modifiers += extend;
+                    text = modifiers + text;
                 }  else {
                     //行首无标识符且当前操作不为取消操作时,添加新标识符到行首
-                    if (!isCancle)
-                        text = map[name] + ' ' + text;
+                        text = text.replace(/^(\s*)(.*)$/,(all,part1,part2)=>{
+                            modifiers = map[name] + ' ';
+                            return part1 + modifiers + part2;
+                        })
                 }
+                if( i === startPoint.line)
+                    startPoint.ch -= oldLength - modifiers.length;
+                if((startPoint.line !== endPoint.line || startPoint.ch !== endPoint.ch)&& i === endPoint.line)
+                    endPoint.ch -= oldLength - modifiers.length;
                 cm.replaceRange(text, CodeMirror.Pos(i, 0), CodeMirror.Pos(i, cm.getLine(i).length));
             })(i);
         }
+        cm.setSelection(startPoint,endPoint);
         cm.focus();
     }
 
     /**
      * Action for toggling blockquote.
      */
-    function toggleBlockquote (editor) {
-        _toggleLine(editor, 'quote');
+    function toggleBlockquote (cm) {
+        _toggleContinueLine(cm, 'quote');
     }
     /**
      * Action for toggling decrease blockquote.
      */
-    function toggleUnBlockquote (editor) {
-        _toggleLine(editor, 'unquote');
+    function toggleUnBlockquote (cm) {
+        _toggleContinueLine(cm, 'unquote');
     }
 
     /**
      * Action for toggling ul.
      */
-    function toggleUnOrderedList (editor) {
-        _toggleLine(editor, 'unordered-list');
+    function toggleUnOrderedList (cm) {
+        _toggleLine(cm, 'unordered-list');
     }
 
     /**
      * Action for toggling ol.
      */
-    function toggleOrderedList (editor) {
-        _toggleLine(editor, 'ordered-list');
+    function toggleOrderedList (cm) {
+        _toggleLine(cm, 'ordered-list');
     }
 
     /**
      * Action for toggling header.
      */
-    function toggleHeader (editor) {
-        _toggleLine(editor, 'header');
+    function toggleHeader (cm) {
+        _toggleContinueLine(cm, 'header');
     }
 
     /**
      * Action for toggling decrease header.
      */
-    function toggleUnHeader (editor) {
-        _toggleLine(editor, 'unheader');
+    function toggleUnHeader (cm) {
+        _toggleContinueLine(cm, 'unheader');
     }
 
     /**
      * Action for drawing a link.
      */
-    function drawLink (editor) {
-        var stat = getState(editor);
-        _replaceSelection(editor, stat.link, '[', ']()');
+    function drawLink (cm) {
+        var stat = getState(cm);
+        _replaceSelection(cm, stat.link, '[', ']()');
     }
     /**
      * Action for drawing a image link.
      */
-    function drawImageLink (editor) {
-        var stat = getState(editor);
-        _replaceSelection(editor, stat.link, '![', ']()');
+    function drawImageLink (cm) {
+        var stat = getState(cm);
+        _replaceSelection(cm, stat.link, '![', ']()');
     }
     /**
      * Action for drawing a table.
@@ -288,13 +372,75 @@ module.exports = (() => {
         cm.focus();
     }
 
+    let praseHtml;
+    /**
+     * Action for paste date what is HTML or Image.
+     */
+    function pasteContent(cm) {
+        let image = clipboard.readImage();
+        if (!image.isEmpty()) {
+            let imageTitle = cm.getSelection();
+            cm.replaceSelection(`![${imageTitle}](${imgManager.getImageOfObj(image,imageTitle)})`);
+        } else {
+            if (!praseHtml)
+                praseHtml = require('./tomarkdown');
+            let content = praseHtml(clipboard.readHTML(),{
+                converters: [
+                    {
+                        filter: 'img',
+                        replacement: function (innerHTML, node) {
+                            if (1 === node.attributes.length) {
+                                return "";
+                            }
+                            return "![](" + node.src + ")";
+                        }
+                    }
+                ], gfm: true
+            });
+            content = content.trim();
+            if (content === ''){
+                content = clipboard.readText()
+            } else {
+                // code 中 <, > 进行转义
+                var codes = content.split('```');
+                if (codes.length > 1) {
+                    for (var i = 0, iMax = codes.length; i < iMax; i++) {
+                        if (i % 2 === 1) {
+                            codes[i] = codes[i].replace(/<\/span><span style="color:#\w{6};">/g, '').replace(/</g, '<').replace(/>/g, '>');
+                        }
+                    }
+                }
+                content = codes.join('```');
+
+                // ascii 160 替换为 30
+                content = $('<div>' + content + '</div>').text().replace(/\n{2,}/g, '\n\n').replace(/ /g, ' ');
+                content = content.trim();
+            }
+            cm.replaceSelection(content)
+        }
+    }
+    /**
+     * Action for paste date what is HTML or Image.
+     */
+    function pasteOriginContent(cm) {
+        let image = clipboard.readImage();
+        if (!image.isEmpty()) {
+            let imageTitle = cm.getSelection();
+            cm.replaceSelection(`![${imageTitle}](${imgManager.getImageOfObj(image,imageTitle)})`);
+        } else {
+            cm.replaceSelection(clipboard.readText())
+        }
+    }
+
     /**
      * Action for format document tables.
      */
-    function formatTables() {
-        FormatTables.formatTables(editor);
+    function formatTables(cm) {
+        FormatTables.formatTables(cm);
     }
     fixShortcut();
+    CodeMirror.commands.pasteContent = pasteContent;
+    CodeMirror.commands.pasteOriginContent = pasteOriginContent;
     var editor = CodeMirror.fromTextArea(document.querySelector('#editor textarea'), {
         lineNumbers: false,
         mode: 'yaml-frontmatter',

+ 0 - 5
views/main/CodeMirror/formatTables.js

@@ -26,7 +26,6 @@ module.exports = (function () {
             let pos = cm.getCursor();
             let value = cm.getValue();
             value = value.replace(detectTableReg(), (table) => {
-                console.log(table)
                 return formatTable(table)
             })
             cm.setValue(value);
@@ -58,7 +57,6 @@ module.exports = (function () {
                 return cell.replace(/%7c/g, '|').replace(/%60/g, '`');
             });
         });
-        console.log(1, content);
         // Normalize the num of hyphen
         content[1] = content[1].map(cell => {
             if (/:-+:/.test(cell)) {
@@ -71,7 +69,6 @@ module.exports = (function () {
                 return '---';
             }
         });
-        console.log(2, content);
 
         let colWidth = Array(content[0].length).fill(3);
         let cn = /[\u4e00-\u9eff,。《》?;:‘“’”()【】、—]/g;
@@ -99,7 +96,6 @@ module.exports = (function () {
                 return '-'.repeat(colWidth[i]);
             }
         });
-        console.log(3, content);
 
         return content.map(row => {
             let cells = row.map((cell, i) => {
@@ -109,7 +105,6 @@ module.exports = (function () {
                 }
                 return (cell + ' '.repeat(cellLength)).slice(0, cellLength);
             });
-            console.log(4, cells);
             return '| ' + cells.join(' | ') + ' |';
         }).join('\n');
     }

+ 687 - 0
views/main/CodeMirror/tomarkdown.js

@@ -0,0 +1,687 @@
+(function(f) {
+    if (typeof exports === "object" && typeof module !== "undefined") {
+        module.exports = f()
+    } else if (typeof define === "function" && define.amd) {
+        define([], f)
+    } else {
+        var g;
+        if (typeof window !== "undefined") {
+            g = window
+        } else if (typeof global !== "undefined") {
+            g = global
+        } else if (typeof self !== "undefined") {
+            g = self
+        } else {
+            g = this
+        }
+        g.toMarkdown = f()
+    }
+})(function() {
+    var define, module, exports;
+    return (function e(t, n, r) {
+        function s(o, u) {
+            if (!n[o]) {
+                if (!t[o]) {
+                    var a = typeof require == "function" && require;
+                    if (!u && a) return a(o, !0);
+                    if (i) return i(o, !0);
+                    var f = new Error("Cannot find module '" + o + "'");
+                    throw f.code = "MODULE_NOT_FOUND", f
+                }
+                var l = n[o] = {
+                    exports: {}
+                };
+                t[o][0].call(l.exports, function(e) {
+                    var n = t[o][1][e];
+                    return s(n ? n : e)
+                }, l, l.exports, e, t, n, r)
+            }
+            return n[o].exports
+        }
+        var i = typeof require == "function" && require;
+        for (var o = 0; o < r.length; o++) s(r[o]);
+        return s
+    })({
+        1: [
+            function(require, module, exports) {
+                /*
+                 * to-markdown - an HTML to Markdown converter
+                 *
+                 * Copyright 2011+, Dom Christie
+                 * Licenced under the MIT licence
+                 *
+                 */
+                'use strict'
+                var toMarkdown
+                var converters
+                var mdConverters = require('./lib/md-converters')
+                var gfmConverters = require('./lib/gfm-converters')
+                var HtmlParser = require('./lib/html-parser')
+                var collapse = require('collapse-whitespace')
+                /*
+                 * Utilities
+                 */
+                var blocks = ['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 blocks.indexOf(node.nodeName.toLowerCase()) !== -1
+                }
+                var voids = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']
+
+                function isVoid(node) {
+                    return voids.indexOf(node.nodeName.toLowerCase()) !== -1
+                }
+
+                function htmlToDom(string) {
+                    var tree = new HtmlParser().parseFromString(string, 'text/html')
+                    collapse(tree.documentElement, isBlock)
+                    return tree
+                }
+                /*
+                 * Flattens DOM tree into single array
+                 */
+                function bfsOrder(node) {
+                    var inqueue = [node]
+                    var outqueue = []
+                    var elem
+                    var children
+                    var i
+                    while (inqueue.length > 0) {
+                        elem = inqueue.shift()
+                        outqueue.push(elem)
+                        children = elem.childNodes
+                        for (i = 0; i < children.length; i++) {
+                            if (children[i].nodeType === 1) inqueue.push(children[i])
+                        }
+                    }
+                    outqueue.shift()
+                    return outqueue
+                }
+                /*
+                 * Contructs a Markdown string of replacement text for a given node
+                 */
+                function getContent(node) {
+                    var text = ''
+                    for (var i = 0; i < node.childNodes.length; i++) {
+                        if (node.childNodes[i].nodeType === 1) {
+                            text += node.childNodes[i]._replacement
+                        } else if (node.childNodes[i].nodeType === 3) {
+                            text += node.childNodes[i].data
+                        } else continue
+                    }
+                    return text
+                }
+                /*
+                 * Returns the HTML string of an element with its contents converted
+                 */
+                function outer(node, content) {
+                    return node.cloneNode(false).outerHTML.replace('><', '>' + content + '<')
+                }
+
+                function canConvert(node, filter) {
+                    if (typeof filter === 'string') {
+                        return filter === node.nodeName.toLowerCase()
+                    }
+                    if (Array.isArray(filter)) {
+                        return filter.indexOf(node.nodeName.toLowerCase()) !== -1
+                    } else if (typeof filter === 'function') {
+                        return filter.call(toMarkdown, node)
+                    } else {
+                        throw new TypeError('`filter` needs to be a string, array, or function')
+                    }
+                }
+
+                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
+                }
+
+                function flankingWhitespace(node) {
+                    var leading = ''
+                    var trailing = ''
+                    if (!isBlock(node)) {
+                        var hasLeading = /^[ \r\n\t]/.test(node.innerHTML)
+                        var hasTrailing = /[ \r\n\t]$/.test(node.innerHTML)
+                        if (hasLeading && !isFlankedByWhitespace('left', node)) {
+                            leading = ' '
+                        }
+                        if (hasTrailing && !isFlankedByWhitespace('right', node)) {
+                            trailing = ' '
+                        }
+                    }
+                    return {
+                        leading: leading,
+                        trailing: trailing
+                    }
+                }
+                /*
+                 * Finds a Markdown converter, gets the replacement, and sets it on
+                 * `_replacement`
+                 */
+                function process(node) {
+                    var replacement
+                    var content = getContent(node)
+                    // Remove blank nodes
+                    if (!isVoid(node) && !/A|TH|TD/.test(node.nodeName) && /^\s*$/i.test(content)) {
+                        node._replacement = ''
+                        return
+                    }
+                    for (var i = 0; i < converters.length; i++) {
+                        var converter = converters[i]
+                        if (canConvert(node, converter.filter)) {
+                            if (typeof converter.replacement !== 'function') {
+                                throw new TypeError('`replacement` needs to be a function that returns a string')
+                            }
+                            var whitespace = flankingWhitespace(node)
+                            if (whitespace.leading || whitespace.trailing) {
+                                content = content.trim()
+                            }
+                            replacement = whitespace.leading + converter.replacement.call(toMarkdown, content, node) + whitespace.trailing
+                            break
+                        }
+                    }
+                    node._replacement = replacement
+                }
+                toMarkdown = function(input, options) {
+                    options = options || {}
+                    if (typeof input !== 'string') {
+                        throw new TypeError(input + ' is not a string')
+                    }
+                    // Escape potential ol triggers
+                    input = input.replace(/(\d+)\. /g, '$1\\. ')
+                    var clone = htmlToDom(input).body
+                    var nodes = bfsOrder(clone)
+                    var output
+                    converters = mdConverters.slice(0)
+                    if (options.gfm) {
+                        converters = gfmConverters.concat(converters)
+                    }
+                    if (options.converters) {
+                        converters = options.converters.concat(converters)
+                    }
+                    // Process through nodes in reverse (so deepest child elements are first).
+                    for (var i = nodes.length - 1; i >= 0; i--) {
+                        process(nodes[i])
+                    }
+                    output = getContent(clone)
+                    return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g, '').replace(/\n\s+\n/g, '\n\n').replace(/\n{3,}/g, '\n\n')
+                }
+                toMarkdown.isBlock = isBlock
+                toMarkdown.isVoid = isVoid
+                toMarkdown.outer = outer
+                module.exports = toMarkdown
+            }, {
+                "./lib/gfm-converters": 2,
+                "./lib/html-parser": 3,
+                "./lib/md-converters": 4,
+                "collapse-whitespace": 7
+            }
+        ],
+        2: [
+            function(require, module, exports) {
+                'use strict'
+
+                function cell(content, node) {
+                    var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node)
+                    var prefix = ' '
+                    if (index === 0) prefix = '| '
+                    return prefix + content + ' |'
+                }
+                var highlightRegEx = /highlight highlight-(\S+)/
+                module.exports = [{
+                    filter: 'br',
+                    replacement: function() {
+                        return '\n'
+                    }
+                }, {
+                    filter: ['del', 's', 'strike'],
+                    replacement: function(content) {
+                        return '~~' + content + '~~'
+                    }
+                }, {
+                    filter: function(node) {
+                        return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'
+                    },
+                    replacement: function(content, node) {
+                        return (node.checked ? '[x]' : '[ ]') + ' '
+                    }
+                }, {
+                    filter: ['th', 'td'],
+                    replacement: function(content, node) {
+                        return cell(content, node)
+                    }
+                }, {
+                    filter: 'tr',
+                    replacement: function(content, node) {
+                        var borderCells = ''
+                        var alignMap = {
+                            left: ':--',
+                            right: '--:',
+                            center: ':-:'
+                        }
+                        if (node.parentNode.nodeName === 'THEAD') {
+                            for (var i = 0; i < node.childNodes.length; i++) {
+                                var align = node.childNodes[i].attributes.align
+                                var border = '---'
+                                if (align) border = alignMap[align.value] || border
+                                borderCells += cell(border, node.childNodes[i])
+                            }
+                        }
+                        return '\n' + content + (borderCells ? '\n' + borderCells : '')
+                    }
+                }, {
+                    filter: 'table',
+                    replacement: function(content) {
+                        return '\n\n' + content + '\n\n'
+                    }
+                }, {
+                    filter: ['thead', 'tbody', 'tfoot'],
+                    replacement: function(content) {
+                        return content
+                    }
+                },
+                    // Fenced code blocks
+                    {
+                        filter: function(node) {
+                            return node.nodeName === 'PRE' && node.firstChild && node.firstChild.nodeName === 'CODE'
+                        },
+                        replacement: function(content, node) {
+                            return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n'
+                        }
+                    },
+                    // Syntax-highlighted code blocks
+                    {
+                        filter: function(node) {
+                            return node.nodeName === 'PRE' && node.parentNode.nodeName === 'DIV' && highlightRegEx.test(node.parentNode.className)
+                        },
+                        replacement: function(content, node) {
+                            var language = node.parentNode.className.match(highlightRegEx)[1]
+                            return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n'
+                        }
+                    }, {
+                        filter: function(node) {
+                            return node.nodeName === 'DIV' && highlightRegEx.test(node.className)
+                        },
+                        replacement: function(content) {
+                            return '\n\n' + content + '\n\n'
+                        }
+                    }
+                ]
+            }, {}
+        ],
+        3: [
+            function(require, module, exports) {
+                /*
+                 * Set up window for Node.js
+                 */
+                var _window = (typeof window !== 'undefined' ? window : this)
+                /*
+                 * Parsing HTML strings
+                 */
+                function canParseHtmlNatively() {
+                    var Parser = _window.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() {}
+                    // For Node.js environments
+                    if (typeof document === 'undefined') {
+                        var jsdom = require('jsdom')
+                        Parser.prototype.parseFromString = function(string) {
+                            return jsdom.jsdom(string, {
+                                features: {
+                                    FetchExternalResources: [],
+                                    ProcessExternalResources: false
+                                }
+                            })
+                        }
+                    } else {
+                        if (!shouldUseActiveX()) {
+                            Parser.prototype.parseFromString = function(string) {
+                                var doc = document.implementation.createHTMLDocument('')
+                                doc.open()
+                                doc.write(string)
+                                doc.close()
+                                return doc
+                            }
+                        } else {
+                            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
+                            }
+                        }
+                    }
+                    return Parser
+                }
+
+                function shouldUseActiveX() {
+                    var useActiveX = false
+                    try {
+                        document.implementation.createHTMLDocument('').open()
+                    } catch (e) {
+                        if (window.ActiveXObject) useActiveX = true
+                    }
+                    return useActiveX
+                }
+                module.exports = canParseHtmlNatively() ? _window.DOMParser : createHtmlParser()
+            }, {
+                "jsdom": 6
+            }
+        ],
+        4: [
+            function(require, module, exports) {
+                'use strict'
+                module.exports = [{
+                    filter: 'p',
+                    replacement: function(content) {
+                        return '\n\n' + content + '\n\n'
+                    }
+                }, {
+                    filter: 'br',
+                    replacement: function() {
+                        return '  \n'
+                    }
+                }, {
+                    filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
+                    replacement: function(content, node) {
+                        var hLevel = node.nodeName.charAt(1)
+                        var hPrefix = ''
+                        for (var i = 0; i < hLevel; i++) {
+                            hPrefix += '#'
+                        }
+                        return '\n\n' + hPrefix + ' ' + content + '\n\n'
+                    }
+                }, {
+                    filter: 'hr',
+                    replacement: function() {
+                        return '\n\n* * *\n\n'
+                    }
+                }, {
+                    filter: ['em', 'i'],
+                    replacement: function(content) {
+                        return '_' + content + '_'
+                    }
+                }, {
+                    filter: ['strong', 'b'],
+                    replacement: function(content) {
+                        return '**' + content + '**'
+                    }
+                },
+                    // Inline 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) {
+                            return '`' + content + '`'
+                        }
+                    }, {
+                        filter: function(node) {
+                            return node.nodeName === 'A' && node.getAttribute('href')
+                        },
+                        replacement: function(content, node) {
+                            var titlePart = node.title ? ' "' + node.title + '"' : ''
+                            return '[' + content + '](' + node.getAttribute('href') + titlePart + ')'
+                        }
+                    }, {
+                        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 + ')' : ''
+                        }
+                    },
+                    // Code blocks
+                    {
+                        filter: function(node) {
+                            return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE'
+                        },
+                        replacement: function(content, node) {
+                            return '\n\n    ' + node.firstChild.textContent.replace(/\n/g, '\n    ') + '\n\n'
+                        }
+                    }, {
+                        filter: 'blockquote',
+                        replacement: function(content) {
+                            content = content.trim()
+                            content = content.replace(/\n{3,}/g, '\n\n')
+                            content = content.replace(/^/gm, '> ')
+                            return '\n\n' + content + '\n\n'
+                        }
+                    }, {
+                        filter: 'li',
+                        replacement: function(content, node) {
+                            content = content.replace(/^\s+/, '').replace(/\n/gm, '\n    ')
+                            var prefix = '*   '
+                            var parent = node.parentNode
+                            var index = Array.prototype.indexOf.call(parent.children, node) + 1
+                            prefix = /ol/i.test(parent.nodeName) ? index + '.  ' : '*   '
+                            return prefix + content
+                        }
+                    }, {
+                        filter: ['ul', 'ol'],
+                        replacement: function(content, node) {
+                            var strings = []
+                            for (var i = 0; i < node.childNodes.length; i++) {
+                                strings.push(node.childNodes[i]._replacement)
+                            }
+                            if (/li/i.test(node.parentNode.nodeName)) {
+                                return '\n' + strings.join('\n')
+                            }
+                            return '\n\n' + strings.join('\n') + '\n\n'
+                        }
+                    }, {
+                        filter: function(node) {
+                            return this.isBlock(node)
+                        },
+                        replacement: function(content, node) {
+                            return '\n\n' + this.outer(node, content) + '\n\n'
+                        }
+                    },
+                    // Anything else!
+                    {
+                        filter: function() {
+                            return true
+                        },
+                        replacement: function(content, node) {
+                            return this.outer(node, content)
+                        }
+                    }
+                ]
+            }, {}
+        ],
+        5: [
+            function(require, module, exports) {
+                /**
+                 * This file automatically generated from `build.js`.
+                 * Do not manually edit.
+                 */
+                module.exports = ["address", "article", "aside", "audio", "blockquote", "canvas", "dd", "div", "dl", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "header", "hgroup", "hr", "main", "nav", "noscript", "ol", "output", "p", "pre", "section", "table", "tfoot", "ul", "video"];
+            }, {}
+        ],
+        6: [
+            function(require, module, exports) {}, {}
+        ],
+        7: [
+            function(require, module, exports) {
+                'use strict';
+                var voidElements = require('void-elements');
+                Object.keys(voidElements).forEach(function(name) {
+                    voidElements[name.toUpperCase()] = 1;
+                });
+                var blockElements = {};
+                require('block-elements').forEach(function(name) {
+                    blockElements[name.toUpperCase()] = 1;
+                });
+                /**
+                 * isBlockElem(node) determines if the given node is a block element.
+                 *
+                 * @param {Node} node
+                 * @return {Boolean}
+                 */
+                function isBlockElem(node) {
+                    return !!(node && blockElements[node.nodeName]);
+                }
+                /**
+                 * isVoid(node) determines if the given node is a void element.
+                 *
+                 * @param {Node} node
+                 * @return {Boolean}
+                 */
+                function isVoid(node) {
+                    return !!(node && voidElements[node.nodeName]);
+                }
+                /**
+                 * whitespace(elem [, isBlock]) removes extraneous whitespace from an
+                 * the given element. The function isBlock may optionally be passed in
+                 * to determine whether or not an element is a block element; if none
+                 * is provided, defaults to using the list of block elements provided
+                 * by the `block-elements` module.
+                 *
+                 * @param {Node} elem
+                 * @param {Function} blockTest
+                 */
+                function collapseWhitespace(elem, isBlock) {
+                    if (!elem.firstChild || elem.nodeName === 'PRE') return;
+                    if (typeof isBlock !== 'function') {
+                        isBlock = isBlockElem;
+                    }
+                    var prevText = null;
+                    var prevVoid = false;
+                    var prev = null;
+                    var node = next(prev, elem);
+                    while (node !== elem) {
+                        if (node.nodeType === 3) {
+                            // Node.TEXT_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);
+                        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) returns the next node in the sequence, given the
+                 * current and previous nodes.
+                 *
+                 * @param {Node} prev
+                 * @param {Node} current
+                 * @return {Node}
+                 */
+                function next(prev, current) {
+                    if (prev && prev.parentNode === current || current.nodeName === 'PRE') {
+                        return current.nextSibling || current.parentNode;
+                    }
+                    return current.firstChild || current.nextSibling || current.parentNode;
+                }
+                module.exports = collapseWhitespace;
+            }, {
+                "block-elements": 5,
+                "void-elements": 8
+            }
+        ],
+        8: [
+            function(require, module, exports) {
+                /**
+                 * This file automatically generated from `pre-publish.js`.
+                 * Do not manually edit.
+                 */
+                module.exports = {
+                    "area": true,
+                    "base": true,
+                    "br": true,
+                    "col": true,
+                    "embed": true,
+                    "hr": true,
+                    "img": true,
+                    "input": true,
+                    "keygen": true,
+                    "link": true,
+                    "menuitem": true,
+                    "meta": true,
+                    "param": true,
+                    "source": true,
+                    "track": true,
+                    "wbr": true
+                };
+            }, {}
+        ]
+    }, {}, [1])(1)
+});