encadre

Encadre, petit framework web Python (Flask) : contrôleurs en greffons, validation, tests
git clone https://git.schurger.org/encadre.git
Log | Files | Refs

org.js (59739B)


      1 // Generated by export.rb at Fri Apr 26 15:29:06 UTC 2019
      2 /*
      3   Copyright (c) 2014 Masafumi Oyamada
      4 
      5   Permission is hereby granted, free of charge, to any person obtaining a copy
      6   of this software and associated documentation files (the "Software"), to deal
      7   in the Software without restriction, including without limitation the rights
      8   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9   copies of the Software, and to permit persons to whom the Software is
     10   furnished to do so, subject to the following conditions:
     11 
     12   The above copyright notice and this permission notice shall be included in
     13   all copies or substantial portions of the Software.
     14 
     15   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     18   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     21   THE SOFTWARE.
     22 */
     23 var Org = (function () {
     24   var exports = {};
     25 
     26   // ------------------------------------------------------------
     27   // Syntax
     28   // ------------------------------------------------------------
     29 
     30   var Syntax = {
     31     rules: {},
     32 
     33     define: function (name, syntax) {
     34       this.rules[name] = syntax;
     35       var methodName = "is" + name.substring(0, 1).toUpperCase() + name.substring(1);
     36       this[methodName] = function (line) {
     37         return this.rules[name].exec(line);
     38       };
     39     }
     40   };
     41 
     42   Syntax.define("header", /^(\*+)\s+(.*)$/); // m[1] => level, m[2] => content
     43   Syntax.define("preformatted", /^(\s*):(?: (.*)$|$)/); // m[1] => indentation, m[2] => content
     44   Syntax.define("unorderedListElement", /^(\s*)(?:-|\+|\s+\*)\s+(.*)$/); // m[1] => indentation, m[2] => content
     45   Syntax.define("orderedListElement", /^(\s*)(\d+)(?:\.|\))\s+(.*)$/); // m[1] => indentation, m[2] => number, m[3] => content
     46   Syntax.define("tableSeparator", /^(\s*)\|((?:\+|-)*?)\|?$/); // m[1] => indentation, m[2] => content
     47   Syntax.define("tableRow", /^(\s*)\|(.*?)\|?$/); // m[1] => indentation, m[2] => content
     48   Syntax.define("blank", /^$/);
     49   Syntax.define("horizontalRule", /^(\s*)-{5,}$/); //
     50   Syntax.define("directive", /^(\s*)#\+(?:(begin|end)_)?(.*)$/i); // m[1] => indentation, m[2] => type, m[3] => content
     51   Syntax.define("comment", /^(\s*)#(.*)$/);
     52   Syntax.define("line", /^(\s*)(.*)$/);
     53   Syntax.define("property", /^([A-Z]+):\s(.*)$/); // m[1] => keyword, m[2] => value
     54 
     55   // ------------------------------------------------------------
     56   // Token
     57   // ------------------------------------------------------------
     58 
     59   function Token() {
     60   }
     61 
     62   Token.prototype = {
     63     isListElement: function () {
     64       return this.type === Lexer.tokens.orderedListElement ||
     65         this.type === Lexer.tokens.unorderedListElement;
     66     },
     67 
     68     isTableElement: function () {
     69       return this.type === Lexer.tokens.tableSeparator ||
     70         this.type === Lexer.tokens.tableRow;
     71     }
     72   };
     73 
     74   // ------------------------------------------------------------
     75   // Lexer
     76   // ------------------------------------------------------------
     77 
     78   function Lexer(stream) {
     79     this.stream = stream;
     80     this.tokenStack = [];
     81   }
     82 
     83   Lexer.prototype = {
     84     tokenize: function (line) {
     85       var token = new Token();
     86       token.fromLineNumber = this.stream.lineNumber;
     87 
     88       if (Syntax.isHeader(line)) {
     89         token.type        = Lexer.tokens.header;
     90         token.indentation = 0;
     91         token.content     = RegExp.$2;
     92         // specific
     93         token.level       = RegExp.$1.length;
     94       } else if(Syntax.isProperty(line)) {
     95         token.type        = Lexer.tokens.property;
     96         token.indentation = 0;
     97         token.content     = RegExp.$2;
     98         // specific
     99         token.keyword     = RegExp.$1;
    100       } else if (Syntax.isPreformatted(line)) {
    101         token.type        = Lexer.tokens.preformatted;
    102         token.indentation = RegExp.$1.length;
    103         token.content     = RegExp.$2;
    104       } else if (Syntax.isUnorderedListElement(line)) {
    105         token.type        = Lexer.tokens.unorderedListElement;
    106         token.indentation = RegExp.$1.length;
    107         token.content     = RegExp.$2;
    108       } else if (Syntax.isOrderedListElement(line)) {
    109         token.type        = Lexer.tokens.orderedListElement;
    110         token.indentation = RegExp.$1.length;
    111         token.content     = RegExp.$3;
    112         // specific
    113         token.number      = RegExp.$2;
    114       } else if (Syntax.isTableSeparator(line)) {
    115         token.type        = Lexer.tokens.tableSeparator;
    116         token.indentation = RegExp.$1.length;
    117         token.content     = RegExp.$2;
    118       } else if (Syntax.isTableRow(line)) {
    119         token.type        = Lexer.tokens.tableRow;
    120         token.indentation = RegExp.$1.length;
    121         token.content     = RegExp.$2;
    122       } else if (Syntax.isBlank(line)) {
    123         token.type        = Lexer.tokens.blank;
    124         token.indentation = 0;
    125         token.content     = null;
    126       } else if (Syntax.isHorizontalRule(line)) {
    127         token.type        = Lexer.tokens.horizontalRule;
    128         token.indentation = RegExp.$1.length;
    129         token.content     = null;
    130       } else if (Syntax.isDirective(line)) {
    131         token.type        = Lexer.tokens.directive;
    132         token.indentation = RegExp.$1.length;
    133         token.content     = RegExp.$3;
    134         // decide directive type (begin, end or oneshot)
    135         var directiveTypeString = RegExp.$2;
    136         if (/^begin/i.test(directiveTypeString))
    137           token.beginDirective = true;
    138         else if (/^end/i.test(directiveTypeString))
    139           token.endDirective = true;
    140         else
    141           token.oneshotDirective = true;
    142       } else if (Syntax.isComment(line)) {
    143         token.type        = Lexer.tokens.comment;
    144         token.indentation = RegExp.$1.length;
    145         token.content     = RegExp.$2;
    146       } else if (Syntax.isLine(line)) {
    147         token.type        = Lexer.tokens.line;
    148         token.indentation = RegExp.$1.length;
    149         token.content     = RegExp.$2;
    150       } else {
    151         throw new Error("SyntaxError: Unknown line: " + line);
    152       }
    153 
    154       return token;
    155     },
    156 
    157     pushToken: function (token) {
    158       this.tokenStack.push(token);
    159     },
    160 
    161     pushDummyTokenByType: function (type) {
    162       var token = new Token();
    163       token.type = type;
    164       this.tokenStack.push(token);
    165     },
    166 
    167     peekStackedToken: function () {
    168       return this.tokenStack.length > 0 ?
    169         this.tokenStack[this.tokenStack.length - 1] : null;
    170     },
    171 
    172     getStackedToken: function () {
    173       return this.tokenStack.length > 0 ?
    174         this.tokenStack.pop() : null;
    175     },
    176 
    177     peekNextToken: function () {
    178       return this.peekStackedToken() ||
    179         this.tokenize(this.stream.peekNextLine());
    180     },
    181 
    182     getNextToken: function () {
    183       return this.getStackedToken() ||
    184         this.tokenize(this.stream.getNextLine());
    185     },
    186 
    187     hasNext: function () {
    188       return this.stream.hasNext();
    189     },
    190 
    191     getLineNumber: function () {
    192       return this.stream.lineNumber;
    193     }
    194   };
    195 
    196   Lexer.tokens = {};
    197   [
    198     "header",
    199     "orderedListElement",
    200     "unorderedListElement",
    201     "tableRow",
    202     "tableSeparator",
    203     "preformatted",
    204     "line",
    205     "horizontalRule",
    206     "blank",
    207     "directive",
    208     "comment",
    209     "property"
    210   ].forEach(function (tokenName, i) {
    211     Lexer.tokens[tokenName] = i;
    212   });
    213 
    214   // ------------------------------------------------------------
    215   // Exports
    216   // ------------------------------------------------------------
    217 
    218   if (typeof exports !== "undefined")
    219     exports.Lexer = Lexer;
    220 
    221   function PrototypeNode(type, children) {
    222     this.type = type;
    223     this.children = [];
    224 
    225     if (children) {
    226       for (var i = 0, len = children.length; i < len; ++i) {
    227         this.appendChild(children[i]);
    228       }
    229     }
    230   }
    231   PrototypeNode.prototype = {
    232     previousSibling: null,
    233     parent: null,
    234     get firstChild() {
    235       return this.children.length < 1 ?
    236         null : this.children[0];
    237     },
    238     get lastChild() {
    239       return this.children.length < 1 ?
    240         null : this.children[this.children.length - 1];
    241     },
    242     appendChild: function (newChild) {
    243       var previousSibling = this.children.length < 1 ?
    244             null : this.lastChild;
    245       this.children.push(newChild);
    246       newChild.previousSibling = previousSibling;
    247       newChild.parent = this;
    248     },
    249     toString: function () {
    250       var string = "<" + this.type + ">";
    251 
    252       if (typeof this.value !== "undefined") {
    253         string += " " + this.value;
    254       } else if (this.children) {
    255         string += "\n" + this.children.map(function (child, idx) {
    256           return "#" + idx + " " + child.toString();
    257         }).join("\n").split("\n").map(function (line) {
    258           return "  " + line;
    259         }).join("\n");
    260       }
    261 
    262       return string;
    263     }
    264   };
    265 
    266   var Node = {
    267     types: {},
    268 
    269     define: function (name, postProcess) {
    270       this.types[name] = name;
    271 
    272       var methodName = "create" + name.substring(0, 1).toUpperCase() + name.substring(1);
    273       var postProcessGiven = typeof postProcess === "function";
    274 
    275       this[methodName] = function (children, options) {
    276         var node = new PrototypeNode(name, children);
    277 
    278         if (postProcessGiven)
    279           postProcess(node, options || {});
    280 
    281         return node;
    282       };
    283     }
    284   };
    285 
    286   Node.define("text", function (node, options) {
    287     node.value = options.value;
    288   });
    289   Node.define("header", function (node, options) {
    290     node.level = options.level;
    291   });
    292   Node.define("property");
    293   Node.define("orderedList");
    294   Node.define("unorderedList");
    295   Node.define("definitionList");
    296   Node.define("listElement");
    297   Node.define("paragraph");
    298   Node.define("preformatted");
    299   Node.define("table");
    300   Node.define("tableRow");
    301   Node.define("tableCell");
    302   Node.define("horizontalRule");
    303   Node.define("directive");
    304 
    305   // Inline
    306   Node.define("inlineContainer");
    307 
    308   Node.define("bold");
    309   Node.define("italic");
    310   Node.define("underline");
    311   Node.define("code");
    312   Node.define("verbatim");
    313   Node.define("dashed");
    314   Node.define("link", function (node, options) {
    315     node.src = options.src;
    316   });
    317 
    318   if (typeof exports !== "undefined")
    319     exports.Node = Node;
    320 
    321   function Stream(sequence) {
    322     this.sequences = sequence.split(/\r?\n/);
    323     this.totalLines = this.sequences.length;
    324     this.lineNumber = 0;
    325   }
    326 
    327   Stream.prototype.peekNextLine = function () {
    328     return this.hasNext() ? this.sequences[this.lineNumber] : null;
    329   };
    330 
    331   Stream.prototype.getNextLine = function () {
    332     return this.hasNext() ? this.sequences[this.lineNumber++] : null;
    333   };
    334 
    335   Stream.prototype.hasNext = function () {
    336     return this.lineNumber < this.totalLines;
    337   };
    338 
    339   if (typeof exports !== "undefined") {
    340     exports.Stream = Stream;
    341   }
    342 
    343   // var Stream = require("./stream.js").Stream;
    344   // var Lexer  = require("./lexer.js").Lexer;
    345   // var Node   = require("./node.js").Node;
    346 
    347   function Parser() {
    348     this.inlineParser = new InlineParser();
    349   }
    350 
    351   Parser.parseStream = function (stream, options) {
    352     var parser = new Parser();
    353     parser.initStatus(stream, options);
    354     parser.parseNodes();
    355     return parser.nodes;
    356   };
    357 
    358   Parser.prototype = {
    359     initStatus: function (stream, options) {
    360       if (typeof stream === "string")
    361         stream = new Stream(stream);
    362       this.lexer = new Lexer(stream);
    363       this.nodes = [];
    364       this.options = {
    365         toc: true,
    366         num: true,
    367         "^": "{}",
    368         multilineCell: false
    369       };
    370       // Override option values
    371       if (options && typeof options === "object") {
    372         for (var key in options) {
    373           this.options[key] = options[key];
    374         }
    375       }
    376       this.document = {
    377         options: this.options,
    378         directiveValues: {},
    379         convert: function (ConverterClass, exportOptions) {
    380           var converter = new ConverterClass(this, exportOptions);
    381           return converter.result;
    382         }
    383       };
    384     },
    385 
    386     parse: function (stream, options) {
    387       this.initStatus(stream, options);
    388       this.parseDocument();
    389       this.document.nodes = this.nodes;
    390       return this.document;
    391     },
    392 
    393     createErrorReport: function (message) {
    394       return new Error(message + " at line " + this.lexer.getLineNumber());
    395     },
    396 
    397     skipBlank: function () {
    398       var blankToken = null;
    399       while (this.lexer.peekNextToken().type === Lexer.tokens.blank)
    400         blankToken = this.lexer.getNextToken();
    401       return blankToken;
    402     },
    403 
    404     setNodeOriginFromToken: function (node, token) {
    405       node.fromLineNumber = token.fromLineNumber;
    406       return node;
    407     },
    408 
    409     appendNode: function (newNode) {
    410       var previousSibling = this.nodes.length > 0 ? this.nodes[this.nodes.length - 1] : null;
    411       this.nodes.push(newNode);
    412       newNode.previousSibling = previousSibling;
    413     },
    414 
    415     // ------------------------------------------------------------
    416     // <Document> ::= <Element>*
    417     // ------------------------------------------------------------
    418 
    419     parseDocument: function () {
    420       this.parseTitle();
    421       this.parseNodes();
    422     },
    423 
    424     parseNodes: function () {
    425       while (this.lexer.hasNext()) {
    426         var element = this.parseElement();
    427         if (element) this.appendNode(element);
    428       }
    429     },
    430 
    431     parseTitle: function () {
    432       this.skipBlank();
    433 
    434       if (this.lexer.hasNext() &&
    435           this.lexer.peekNextToken().type === Lexer.tokens.line)
    436         this.document.title = this.createTextNode(this.lexer.getNextToken().content);
    437       else
    438         this.document.title = null;
    439 
    440       this.lexer.pushDummyTokenByType(Lexer.tokens.blank);
    441     },
    442 
    443     // ------------------------------------------------------------
    444     // <Element> ::= (<Header> | <List>
    445     //              | <Preformatted> | <Paragraph>
    446     //              | <Table>)*
    447     // ------------------------------------------------------------
    448 
    449     parseElement: function () {
    450       var element = null;
    451 
    452       switch (this.lexer.peekNextToken().type) {
    453       case Lexer.tokens.header:
    454         element = this.parseHeader();
    455         break;
    456       case Lexer.tokens.property:
    457         element = this.parseProperty();
    458         break;
    459       case Lexer.tokens.preformatted:
    460         element = this.parsePreformatted();
    461         break;
    462       case Lexer.tokens.orderedListElement:
    463       case Lexer.tokens.unorderedListElement:
    464         element = this.parseList();
    465         break;
    466       case Lexer.tokens.line:
    467         element = this.parseText();
    468         break;
    469       case Lexer.tokens.tableRow:
    470       case Lexer.tokens.tableSeparator:
    471         element = this.parseTable();
    472         break;
    473       case Lexer.tokens.blank:
    474         this.skipBlank();
    475         if (this.lexer.hasNext()) {
    476           if (this.lexer.peekNextToken().type === Lexer.tokens.line)
    477             element = this.parseParagraph();
    478           else
    479             element = this.parseElement();
    480         }
    481         break;
    482       case Lexer.tokens.horizontalRule:
    483         this.lexer.getNextToken();
    484         element = Node.createHorizontalRule();
    485         break;
    486       case Lexer.tokens.directive:
    487         element = this.parseDirective();
    488         break;
    489       case Lexer.tokens.comment:
    490         // Skip
    491         this.lexer.getNextToken();
    492         break;
    493       default:
    494         throw this.createErrorReport("Unhandled token: " + this.lexer.peekNextToken().type);
    495       }
    496 
    497       return element;
    498     },
    499 
    500     parseElementBesidesDirectiveEnd: function () {
    501       try {
    502         // Temporary, override the definition of `parseElement`
    503         this.parseElement = this.parseElementBesidesDirectiveEndBody;
    504         return this.parseElement();
    505       } finally {
    506         this.parseElement = this.originalParseElement;
    507       }
    508     },
    509 
    510     parseElementBesidesDirectiveEndBody: function () {
    511       if (this.lexer.peekNextToken().type === Lexer.tokens.directive &&
    512           this.lexer.peekNextToken().endDirective) {
    513         return null;
    514       }
    515 
    516       return this.originalParseElement();
    517     },
    518 
    519     // ------------------------------------------------------------
    520     // <Header>
    521     //
    522     // : preformatted
    523     // : block
    524     // ------------------------------------------------------------
    525 
    526     parseHeader: function () {
    527       var headerToken = this.lexer.getNextToken();
    528       var header = Node.createHeader([
    529         this.createTextNode(headerToken.content) // TODO: Parse inline markups
    530       ], { level: headerToken.level });
    531       this.setNodeOriginFromToken(header, headerToken);
    532 
    533       while(this.lexer.hasNext() && this.lexer.peekNextToken().type === Lexer.tokens.property){
    534         var property = this.parseProperty();
    535         header.appendChild(property);
    536       }
    537 
    538       return header;
    539     },
    540 
    541     parseProperty: function(rootToken){
    542       var propertyToken = this.lexer.getNextToken();
    543       var property = Node.createProperty(null);
    544       this.setNodeOriginFromToken(property, propertyToken);
    545       property.keyword = propertyToken.keyword;
    546       property.content = propertyToken.content;
    547       return property;
    548     },
    549 
    550     // ------------------------------------------------------------
    551     // <Preformatted>
    552     //
    553     // : preformatted
    554     // : block
    555     // ------------------------------------------------------------
    556 
    557     parsePreformatted: function () {
    558       var preformattedFirstToken = this.lexer.peekNextToken();
    559       var preformatted = Node.createPreformatted([]);
    560       this.setNodeOriginFromToken(preformatted, preformattedFirstToken);
    561 
    562       var textContents = [];
    563 
    564       while (this.lexer.hasNext()) {
    565         var token = this.lexer.peekNextToken();
    566         if (token.type !== Lexer.tokens.preformatted ||
    567             token.indentation < preformattedFirstToken.indentation)
    568           break;
    569         this.lexer.getNextToken();
    570         textContents.push(token.content);
    571       }
    572 
    573       preformatted.appendChild(this.createTextNode(textContents.join("\n"), true /* no emphasis */));
    574 
    575       return preformatted;
    576     },
    577 
    578     // ------------------------------------------------------------
    579     // <List>
    580     //
    581     //  - foo
    582     //    1. bar
    583     //    2. baz
    584     // ------------------------------------------------------------
    585 
    586     // XXX: not consider codes (e.g., =Foo::Bar=)
    587     definitionPattern: /^(.*?) :: *(.*)$/,
    588 
    589     parseList: function () {
    590       var rootToken = this.lexer.peekNextToken();
    591       var list;
    592       var isDefinitionList = false;
    593 
    594       if (this.definitionPattern.test(rootToken.content)) {
    595         list = Node.createDefinitionList([]);
    596         isDefinitionList = true;
    597       } else {
    598         list = rootToken.type === Lexer.tokens.unorderedListElement ?
    599           Node.createUnorderedList([]) : Node.createOrderedList([]);
    600       }
    601       this.setNodeOriginFromToken(list, rootToken);
    602 
    603       while (this.lexer.hasNext()) {
    604         var nextToken = this.lexer.peekNextToken();
    605         if (!nextToken.isListElement() || nextToken.indentation !== rootToken.indentation)
    606           break;
    607         list.appendChild(this.parseListElement(rootToken.indentation, isDefinitionList));
    608       }
    609 
    610       return list;
    611     },
    612 
    613     unknownDefinitionTerm: "???",
    614 
    615     parseListElement: function (rootIndentation, isDefinitionList) {
    616       var listElementToken = this.lexer.getNextToken();
    617       var listElement = Node.createListElement([]);
    618       this.setNodeOriginFromToken(listElement, listElementToken);
    619 
    620       listElement.isDefinitionList = isDefinitionList;
    621 
    622       if (isDefinitionList) {
    623         var match = this.definitionPattern.exec(listElementToken.content);
    624         listElement.term = [
    625           this.createTextNode(match && match[1] ? match[1] : this.unknownDefinitionTerm)
    626         ];
    627         listElement.appendChild(this.createTextNode(match ? match[2] : listElementToken.content));
    628       } else {
    629         listElement.appendChild(this.createTextNode(listElementToken.content));
    630       }
    631 
    632       while (this.lexer.hasNext()) {
    633         var blankToken = this.skipBlank();
    634         if (!this.lexer.hasNext())
    635           break;
    636 
    637         var notBlankNextToken = this.lexer.peekNextToken();
    638         if (blankToken && !notBlankNextToken.isListElement())
    639           this.lexer.pushToken(blankToken); // Recover blank token only when next line is not listElement.
    640         if (notBlankNextToken.indentation <= rootIndentation)
    641           break;                  // end of the list
    642 
    643         var element = this.parseElement(); // recursive
    644         if (element)
    645           listElement.appendChild(element);
    646       }
    647 
    648       return listElement;
    649     },
    650 
    651     // ------------------------------------------------------------
    652     // <Table> ::= <TableRow>+
    653     // ------------------------------------------------------------
    654 
    655     parseTable: function () {
    656       var nextToken = this.lexer.peekNextToken();
    657       var table = Node.createTable([]);
    658       this.setNodeOriginFromToken(table, nextToken);
    659       var sawSeparator = false;
    660 
    661       var allowMultilineCell = nextToken.type === Lexer.tokens.tableSeparator && this.options.multilineCell;
    662 
    663       while (this.lexer.hasNext() &&
    664              (nextToken = this.lexer.peekNextToken()).isTableElement()) {
    665         if (nextToken.type === Lexer.tokens.tableRow) {
    666           var tableRow = this.parseTableRow(allowMultilineCell);
    667           table.appendChild(tableRow);
    668         } else {
    669           // Lexer.tokens.tableSeparator
    670           sawSeparator = true;
    671           this.lexer.getNextToken();
    672         }
    673       }
    674 
    675       if (sawSeparator && table.children.length) {
    676         table.children[0].children.forEach(function (cell) {
    677           cell.isHeader = true;
    678         });
    679       }
    680 
    681       return table;
    682     },
    683 
    684     // ------------------------------------------------------------
    685     // <TableRow> ::= <TableCell>+
    686     // ------------------------------------------------------------
    687 
    688     parseTableRow: function (allowMultilineCell) {
    689       var tableRowTokens = [];
    690 
    691       while (this.lexer.peekNextToken().type === Lexer.tokens.tableRow) {
    692         tableRowTokens.push(this.lexer.getNextToken());
    693         if (!allowMultilineCell) {
    694           break;
    695         }
    696       }
    697 
    698       if (!tableRowTokens.length) {
    699         throw this.createErrorReport("Expected table row");
    700       }
    701 
    702       var firstTableRowToken = tableRowTokens.shift();
    703       var tableCellTexts = firstTableRowToken.content.split("|");
    704 
    705       tableRowTokens.forEach(function (rowToken) {
    706         rowToken.content.split("|").forEach(function (cellText, cellIdx) {
    707           tableCellTexts[cellIdx] = (tableCellTexts[cellIdx] || "") + "\n" + cellText;
    708         });
    709       });
    710 
    711       // TODO: Prepare two pathes: (1)
    712       var tableCells = tableCellTexts.map(
    713         // TODO: consider '|' escape?
    714         function (text) {
    715           return Node.createTableCell(Parser.parseStream(text));
    716         }, this);
    717 
    718       return this.setNodeOriginFromToken(Node.createTableRow(tableCells), firstTableRowToken);
    719     },
    720 
    721     // ------------------------------------------------------------
    722     // <Directive> ::= "#+.*"
    723     // ------------------------------------------------------------
    724 
    725     parseDirective: function () {
    726       var directiveToken = this.lexer.getNextToken();
    727       var directiveNode = this.createDirectiveNodeFromToken(directiveToken);
    728 
    729       if (directiveToken.endDirective)
    730         throw this.createErrorReport("Unmatched 'end' directive for " + directiveNode.directiveName);
    731 
    732       if (directiveToken.oneshotDirective) {
    733         this.interpretDirective(directiveNode);
    734         return directiveNode;
    735       }
    736 
    737       if (!directiveToken.beginDirective)
    738         throw this.createErrorReport("Invalid directive " + directiveNode.directiveName);
    739 
    740       // Parse begin ~ end
    741       directiveNode.children = [];
    742       if (this.isVerbatimDirective(directiveNode))
    743         return this.parseDirectiveBlockVerbatim(directiveNode);
    744       else
    745         return this.parseDirectiveBlock(directiveNode);
    746     },
    747 
    748     createDirectiveNodeFromToken: function (directiveToken) {
    749       var matched = /^[ ]*([^ ]*)[ ]*(.*)[ ]*$/.exec(directiveToken.content);
    750 
    751       var directiveNode = Node.createDirective(null);
    752       this.setNodeOriginFromToken(directiveNode, directiveToken);
    753       directiveNode.directiveName = matched[1].toLowerCase();
    754       directiveNode.directiveArguments = this.parseDirectiveArguments(matched[2]);
    755       directiveNode.directiveOptions = this.parseDirectiveOptions(matched[2]);
    756       directiveNode.directiveRawValue = matched[2];
    757 
    758       return directiveNode;
    759     },
    760 
    761     isVerbatimDirective: function (directiveNode) {
    762       var directiveName = directiveNode.directiveName;
    763       return directiveName === "src" || directiveName === "example" || directiveName === "html";
    764     },
    765 
    766     parseDirectiveBlock: function (directiveNode, verbatim) {
    767       this.lexer.pushDummyTokenByType(Lexer.tokens.blank);
    768 
    769       while (this.lexer.hasNext()) {
    770         var nextToken = this.lexer.peekNextToken();
    771         if (nextToken.type === Lexer.tokens.directive &&
    772             nextToken.endDirective &&
    773             this.createDirectiveNodeFromToken(nextToken).directiveName === directiveNode.directiveName) {
    774           // Close directive
    775           this.lexer.getNextToken();
    776           return directiveNode;
    777         }
    778         var element = this.parseElementBesidesDirectiveEnd();
    779         if (element)
    780           directiveNode.appendChild(element);
    781       }
    782 
    783       throw this.createErrorReport("Unclosed directive " + directiveNode.directiveName);
    784     },
    785 
    786     parseDirectiveBlockVerbatim: function (directiveNode) {
    787       var textContent = [];
    788 
    789       while (this.lexer.hasNext()) {
    790         var nextToken = this.lexer.peekNextToken();
    791         if (nextToken.type === Lexer.tokens.directive &&
    792             nextToken.endDirective &&
    793             this.createDirectiveNodeFromToken(nextToken).directiveName === directiveNode.directiveName) {
    794           this.lexer.getNextToken();
    795           directiveNode.appendChild(this.createTextNode(textContent.join("\n"), true));
    796           return directiveNode;
    797         }
    798         textContent.push(this.lexer.stream.getNextLine());
    799       }
    800 
    801       throw this.createErrorReport("Unclosed directive " + directiveNode.directiveName);
    802     },
    803 
    804     parseDirectiveArguments: function (parameters) {
    805       return parameters.split(/[ ]+/).filter(function (param) {
    806         return param.length && param[0] !== "-";
    807       });
    808     },
    809 
    810     parseDirectiveOptions: function (parameters) {
    811       return parameters.split(/[ ]+/).filter(function (param) {
    812         return param.length && param[0] === "-";
    813       });
    814     },
    815 
    816     interpretDirective: function (directiveNode) {
    817       // http://orgmode.org/manual/Export-options.html
    818       switch (directiveNode.directiveName) {
    819       case "options:":
    820         this.interpretOptionDirective(directiveNode);
    821         break;
    822       case "title:":
    823         this.document.title = directiveNode.directiveRawValue;
    824         break;
    825       case "author:":
    826         this.document.author = directiveNode.directiveRawValue;
    827         break;
    828       case "email:":
    829         this.document.email = directiveNode.directiveRawValue;
    830         break;
    831       default:
    832         this.document.directiveValues[directiveNode.directiveName] = directiveNode.directiveRawValue;
    833         break;
    834       }
    835     },
    836 
    837     interpretOptionDirective: function (optionDirectiveNode) {
    838       optionDirectiveNode.directiveArguments.forEach(function (pairString) {
    839         var pair = pairString.split(":");
    840         this.options[pair[0]] = this.convertLispyValue(pair[1]);
    841       }, this);
    842     },
    843 
    844     convertLispyValue: function (lispyValue) {
    845       switch (lispyValue) {
    846       case "t":
    847         return true;
    848       case "nil":
    849         return false;
    850       default:
    851         if (/^[0-9]+$/.test(lispyValue))
    852           return parseInt(lispyValue);
    853         return lispyValue;
    854       }
    855     },
    856 
    857     // ------------------------------------------------------------
    858     // <Paragraph> ::= <Blank> <Line>*
    859     // ------------------------------------------------------------
    860 
    861     parseParagraph: function () {
    862       var paragraphFisrtToken = this.lexer.peekNextToken();
    863       var paragraph = Node.createParagraph([]);
    864       this.setNodeOriginFromToken(paragraph, paragraphFisrtToken);
    865 
    866       var textContents = [];
    867 
    868       while (this.lexer.hasNext()) {
    869         var nextToken = this.lexer.peekNextToken();
    870         if (nextToken.type !== Lexer.tokens.line
    871             || nextToken.indentation < paragraphFisrtToken.indentation)
    872           break;
    873         this.lexer.getNextToken();
    874         textContents.push(nextToken.content);
    875       }
    876 
    877       paragraph.appendChild(this.createTextNode(textContents.join("\n")));
    878 
    879       return paragraph;
    880     },
    881 
    882     parseText: function (noEmphasis) {
    883       var lineToken = this.lexer.getNextToken();
    884       return this.createTextNode(lineToken.content, noEmphasis);
    885     },
    886 
    887     // ------------------------------------------------------------
    888     // <Text> (DOM Like)
    889     // ------------------------------------------------------------
    890 
    891     createTextNode: function (text, noEmphasis) {
    892       return noEmphasis ? Node.createText(null, { value: text })
    893         : this.inlineParser.parseEmphasis(text);
    894     }
    895   };
    896   Parser.prototype.originalParseElement = Parser.prototype.parseElement;
    897 
    898   // ------------------------------------------------------------
    899   // Parser for Inline Elements
    900   //
    901   // @refs org-emphasis-regexp-components
    902   // ------------------------------------------------------------
    903 
    904   function InlineParser() {
    905     this.preEmphasis     = " \t\\('\"";
    906     this.postEmphasis    = "- \t.,:!?;'\"\\)";
    907     this.borderForbidden = " \t\r\n,\"'";
    908     this.bodyRegexp      = "[\\s\\S]*?";
    909     this.markers         = "*/_=~+";
    910 
    911     this.emphasisPattern = this.buildEmphasisPattern();
    912     this.linkPattern = /\[\[([^\]]*)\](?:\[([^\]]*)\])?\]/g; // \1 => link, \2 => text
    913   }
    914 
    915   InlineParser.prototype = {
    916     parseEmphasis: function (text) {
    917       var emphasisPattern = this.emphasisPattern;
    918       emphasisPattern.lastIndex = 0;
    919 
    920       var result = [],
    921           match,
    922           previousLast = 0,
    923           savedLastIndex;
    924 
    925       while ((match = emphasisPattern.exec(text))) {
    926         var whole  = match[0];
    927         var pre    = match[1];
    928         var marker = match[2];
    929         var body   = match[3];
    930         var post   = match[4];
    931 
    932         {
    933           // parse links
    934           var matchBegin = emphasisPattern.lastIndex - whole.length;
    935           var beforeContent = text.substring(previousLast, matchBegin + pre.length);
    936           savedLastIndex = emphasisPattern.lastIndex;
    937           result.push(this.parseLink(beforeContent));
    938           emphasisPattern.lastIndex = savedLastIndex;
    939         }
    940 
    941         var bodyNode = [Node.createText(null, { value: body })];
    942         var bodyContainer = this.emphasizeElementByMarker(bodyNode, marker);
    943         result.push(bodyContainer);
    944 
    945         previousLast = emphasisPattern.lastIndex - post.length;
    946       }
    947 
    948       if (emphasisPattern.lastIndex === 0 ||
    949           emphasisPattern.lastIndex !== text.length - 1)
    950         result.push(this.parseLink(text.substring(previousLast)));
    951 
    952       if (result.length === 1) {
    953         // Avoid duplicated inline container wrapping
    954         return result[0];
    955       } else {
    956         return Node.createInlineContainer(result);
    957       }
    958     },
    959 
    960     depth: 0,
    961     parseLink: function (text) {
    962       var linkPattern = this.linkPattern;
    963       linkPattern.lastIndex = 0;
    964 
    965       var match,
    966           result = [],
    967           previousLast = 0,
    968           savedLastIndex;
    969 
    970       while ((match = linkPattern.exec(text))) {
    971         var whole = match[0];
    972         var src   = match[1];
    973         var title = match[2];
    974 
    975         // parse before content
    976         var matchBegin = linkPattern.lastIndex - whole.length;
    977         var beforeContent = text.substring(previousLast, matchBegin);
    978         result.push(Node.createText(null, { value: beforeContent }));
    979 
    980         // parse link
    981         var link = Node.createLink([]);
    982         link.src = src;
    983         if (title) {
    984           savedLastIndex = linkPattern.lastIndex;
    985           link.appendChild(this.parseEmphasis(title));
    986           linkPattern.lastIndex = savedLastIndex;
    987         } else {
    988           link.appendChild(Node.createText(null, { value: src }));
    989         }
    990         result.push(link);
    991 
    992         previousLast = linkPattern.lastIndex;
    993       }
    994 
    995       if (linkPattern.lastIndex === 0 ||
    996           linkPattern.lastIndex !== text.length - 1)
    997         result.push(Node.createText(null, { value: text.substring(previousLast) }));
    998 
    999       return Node.createInlineContainer(result);
   1000     },
   1001 
   1002     emphasizeElementByMarker: function (element, marker) {
   1003       switch (marker) {
   1004       case "*":
   1005         return Node.createBold(element);
   1006       case "/":
   1007         return Node.createItalic(element);
   1008       case "_":
   1009         return Node.createUnderline(element);
   1010       case "=":
   1011       case "~":
   1012         return Node.createCode(element);
   1013       case "+":
   1014         return Node.createDashed(element);
   1015       }
   1016     },
   1017 
   1018     buildEmphasisPattern: function () {
   1019       return new RegExp(
   1020         "([" + this.preEmphasis + "]|^|\r?\n)" +               // \1 => pre
   1021           "([" + this.markers + "])" +                         // \2 => marker
   1022           "([^" + this.borderForbidden + "]|" +                // \3 => body
   1023           "[^" + this.borderForbidden + "]" +
   1024           this.bodyRegexp +
   1025           "[^" + this.borderForbidden + "])" +
   1026           "\\2" +
   1027           "([" + this.postEmphasis +"]|$|\r?\n)",              // \4 => post
   1028           // flags
   1029           "g"
   1030       );
   1031     }
   1032   };
   1033 
   1034   if (typeof exports !== "undefined") {
   1035     exports.Parser = Parser;
   1036     exports.InlineParser = InlineParser;
   1037   }
   1038 
   1039   // var Node = require("../node.js").Node;
   1040 
   1041   function Converter() {
   1042   }
   1043 
   1044   Converter.prototype = {
   1045     exportOptions: {
   1046       headerOffset: 1,
   1047       exportFromLineNumber: false,
   1048       suppressSubScriptHandling: false,
   1049       suppressAutoLink: false,
   1050       // HTML
   1051       translateSymbolArrow: false,
   1052       suppressCheckboxHandling: false,
   1053       // { "directive:": function (node, childText, auxData) {} }
   1054       customDirectiveHandler: null,
   1055       // e.g., "org-js-"
   1056       htmlClassPrefix: null,
   1057       htmlIdPrefix: null
   1058     },
   1059 
   1060     untitled: "Untitled",
   1061     result: null,
   1062 
   1063     // TODO: Manage TODO lists
   1064 
   1065     initialize: function (orgDocument, exportOptions) {
   1066       this.orgDocument = orgDocument;
   1067       this.documentOptions = orgDocument.options || {};
   1068       this.exportOptions = exportOptions || {};
   1069 
   1070       this.headers = [];
   1071       this.headerOffset =
   1072         typeof this.exportOptions.headerOffset === "number" ? this.exportOptions.headerOffset : 1;
   1073       this.sectionNumbers = [0];
   1074     },
   1075 
   1076     createTocItem: function (headerNode, parentTocs) {
   1077       var childTocs = [];
   1078       childTocs.parent = parentTocs;
   1079       var tocItem = { headerNode: headerNode, childTocs: childTocs };
   1080       return tocItem;
   1081     },
   1082 
   1083     computeToc: function (exportTocLevel) {
   1084       if (typeof exportTocLevel !== "number")
   1085         exportTocLevel = Infinity;
   1086 
   1087       var toc = [];
   1088       toc.parent = null;
   1089 
   1090       var previousLevel = 1;
   1091       var currentTocs = toc;  // first
   1092 
   1093       for (var i = 0; i < this.headers.length; ++i) {
   1094         var headerNode = this.headers[i];
   1095 
   1096         if (headerNode.level > exportTocLevel)
   1097           continue;
   1098 
   1099         var levelDiff = headerNode.level - previousLevel;
   1100         if (levelDiff > 0) {
   1101           for (var j = 0; j < levelDiff; ++j) {
   1102             if (currentTocs.length === 0) {
   1103               // Create a dummy tocItem
   1104               var dummyHeader = Node.createHeader([], {
   1105                 level: previousLevel + j
   1106               });
   1107               dummyHeader.sectionNumberText = "";
   1108               currentTocs.push(this.createTocItem(dummyHeader, currentTocs));
   1109             }
   1110             currentTocs = currentTocs[currentTocs.length - 1].childTocs;
   1111           }
   1112         } else if (levelDiff < 0) {
   1113           levelDiff = -levelDiff;
   1114           for (var k = 0; k < levelDiff; ++k) {
   1115             currentTocs = currentTocs.parent;
   1116           }
   1117         }
   1118 
   1119         currentTocs.push(this.createTocItem(headerNode, currentTocs));
   1120 
   1121         previousLevel = headerNode.level;
   1122       }
   1123 
   1124       return toc;
   1125     },
   1126 
   1127     convertNode: function (node, recordHeader, insideCodeElement) {
   1128       if (!insideCodeElement) {
   1129         if (node.type === Node.types.directive) {
   1130           if (node.directiveName === "example" ||
   1131               node.directiveName === "src") {
   1132             insideCodeElement = true;
   1133           }
   1134         } else if (node.type === Node.types.preformatted) {
   1135           insideCodeElement = true;
   1136         }
   1137       }
   1138 
   1139       if (typeof node === "string") {
   1140         node = Node.createText(null, { value: node });
   1141       }
   1142 
   1143       var childText = node.children ? this.convertNodesInternal(node.children, recordHeader, insideCodeElement) : "";
   1144       var text;
   1145 
   1146       var auxData = this.computeAuxDataForNode(node);
   1147 
   1148       switch (node.type) {
   1149       case Node.types.header:
   1150         // Parse task status
   1151         var taskStatus = null;
   1152         var _match = childText.match(/^[A-Z]{3,}\s+/);
   1153         if(_match && _match[0]){
   1154           taskStatus = _match[0].trim().toLowerCase();
   1155         }
   1156 
   1157         // Compute section number
   1158         var sectionNumberText = null;
   1159         if (recordHeader) {
   1160           var thisHeaderLevel = node.level;
   1161           var previousHeaderLevel = this.sectionNumbers.length;
   1162           if (thisHeaderLevel > previousHeaderLevel) {
   1163             // Fill missing section number
   1164             var levelDiff = thisHeaderLevel - previousHeaderLevel;
   1165             for (var j = 0; j < levelDiff; ++j) {
   1166               this.sectionNumbers[thisHeaderLevel - 1 - j] = 0; // Extend
   1167             }
   1168           } else if (thisHeaderLevel < previousHeaderLevel) {
   1169             this.sectionNumbers.length = thisHeaderLevel; // Collapse
   1170           }
   1171           this.sectionNumbers[thisHeaderLevel - 1]++;
   1172           if (this.documentOptions.num)
   1173               sectionNumberText = this.sectionNumbers.join(".");
   1174           node.sectionNumberText = sectionNumberText; // Can be used in ToC
   1175         }
   1176 
   1177         text = this.convertHeader(node, childText, auxData,
   1178                                   taskStatus, sectionNumberText);
   1179 
   1180         if (recordHeader)
   1181           this.headers.push(node);
   1182         break;
   1183       case Node.types.orderedList:
   1184         text = this.convertOrderedList(node, childText, auxData);
   1185         break;
   1186       case Node.types.unorderedList:
   1187         text = this.convertUnorderedList(node, childText, auxData);
   1188         break;
   1189       case Node.types.definitionList:
   1190         text = this.convertDefinitionList(node, childText, auxData);
   1191         break;
   1192       case Node.types.listElement:
   1193         if (node.isDefinitionList) {
   1194           var termText = this.convertNodesInternal(node.term, recordHeader, insideCodeElement);
   1195           text = this.convertDefinitionItem(node, childText, auxData,
   1196                                             termText, childText);
   1197         } else {
   1198           text = this.convertListItem(node, childText, auxData);
   1199         }
   1200         break;
   1201       case Node.types.paragraph:
   1202         text = this.convertParagraph(node, childText, auxData);
   1203         break;
   1204       case Node.types.preformatted:
   1205         text = this.convertPreformatted(node, childText, auxData);
   1206         break;
   1207       case Node.types.table:
   1208         text = this.convertTable(node, childText, auxData);
   1209         break;
   1210       case Node.types.tableRow:
   1211         text = this.convertTableRow(node, childText, auxData);
   1212         break;
   1213       case Node.types.tableCell:
   1214         if (node.isHeader) {
   1215           if (childText)
   1216             text = this.convertTableHeader(node, childText, auxData);
   1217         } else
   1218           text = this.convertTableCell(node, childText, auxData);
   1219         break;
   1220       case Node.types.horizontalRule:
   1221         text = this.convertHorizontalRule(node, childText, auxData);
   1222         break;
   1223         // ============================================================ //
   1224         // Inline
   1225         // ============================================================ //
   1226       case Node.types.inlineContainer:
   1227         text = this.convertInlineContainer(node, childText, auxData);
   1228         break;
   1229       case Node.types.bold:
   1230         text = this.convertBold(node, childText, auxData);
   1231         break;
   1232       case Node.types.italic:
   1233         text = this.convertItalic(node, childText, auxData);
   1234         break;
   1235       case Node.types.underline:
   1236         text = this.convertUnderline(node, childText, auxData);
   1237         break;
   1238       case Node.types.code:
   1239         text = this.convertCode(node, childText, auxData);
   1240         break;
   1241       case Node.types.dashed:
   1242         text = this.convertDashed(node, childText, auxData);
   1243         break;
   1244       case Node.types.link:
   1245         text = this.convertLink(node, childText, auxData);
   1246         break;
   1247       case Node.types.property:
   1248         text = this.convertProperty(node, childText, auxData);
   1249         break;
   1250       case Node.types.directive:
   1251         switch (node.directiveName) {
   1252         case "quote":
   1253           text = this.convertQuote(node, childText, auxData);
   1254           break;
   1255         case "example":
   1256           text = this.convertExample(node, childText, auxData);
   1257           break;
   1258         case "src":
   1259           text = this.convertSrc(node, childText, auxData);
   1260           break;
   1261         case "html":
   1262         case "html:":
   1263           text = this.convertHTML(node, childText, auxData);
   1264           break;
   1265         default:
   1266           if (this.exportOptions.customDirectiveHandler &&
   1267               this.exportOptions.customDirectiveHandler[node.directiveName]) {
   1268             text = this.exportOptions.customDirectiveHandler[node.directiveName](
   1269               node, childText, auxData
   1270             );
   1271           } else {
   1272             text = childText;
   1273           }
   1274         }
   1275         break;
   1276       case Node.types.text:
   1277         text = this.convertText(node.value, insideCodeElement);
   1278         break;
   1279       default:
   1280         throw Error("Unknown node type: " + node.type);
   1281       }
   1282 
   1283       if (typeof this.postProcess === "function") {
   1284         text = this.postProcess(node, text, insideCodeElement);
   1285       }
   1286 
   1287       return text;
   1288     },
   1289 
   1290     convertText: function (text, insideCodeElement) {
   1291       var escapedText = this.escapeSpecialChars(text, insideCodeElement);
   1292 
   1293       if (!this.exportOptions.suppressSubScriptHandling && !insideCodeElement) {
   1294         escapedText = this.makeSubscripts(escapedText, insideCodeElement);
   1295       }
   1296       if (!this.exportOptions.suppressAutoLink) {
   1297         escapedText = this.linkURL(escapedText);
   1298       }
   1299 
   1300       return escapedText;
   1301     },
   1302 
   1303     // By default, ignore html
   1304     convertHTML: function (node, childText, auxData) {
   1305       return childText;
   1306     },
   1307 
   1308     convertNodesInternal: function (nodes, recordHeader, insideCodeElement) {
   1309       var nodesTexts = [];
   1310       for (var i = 0; i < nodes.length; ++i) {
   1311         var node = nodes[i];
   1312         var nodeText = this.convertNode(node, recordHeader, insideCodeElement);
   1313         nodesTexts.push(nodeText);
   1314       }
   1315       return this.combineNodesTexts(nodesTexts);
   1316     },
   1317 
   1318     convertHeaderBlock: function (headerBlock, recordHeader) {
   1319       throw Error("convertHeaderBlock is not implemented");
   1320     },
   1321 
   1322     convertHeaderTree: function (headerTree, recordHeader) {
   1323       return this.convertHeaderBlock(headerTree, recordHeader);
   1324     },
   1325 
   1326     convertNodesToHeaderTree: function (nodes, nextBlockBegin, blockHeader) {
   1327       var childBlocks = [];
   1328       var childNodes = [];
   1329 
   1330       if (typeof nextBlockBegin === "undefined") {
   1331         nextBlockBegin = 0;
   1332       }
   1333       if (typeof blockHeader === "undefined") {
   1334         blockHeader = null;
   1335       }
   1336 
   1337       for (var i = nextBlockBegin; i < nodes.length;) {
   1338         var node = nodes[i];
   1339 
   1340         var isHeader = node.type === Node.types.header;
   1341 
   1342         if (!isHeader) {
   1343           childNodes.push(node);
   1344           i = i + 1;
   1345           continue;
   1346         }
   1347 
   1348         // Header
   1349         if (blockHeader && node.level <= blockHeader.level) {
   1350           // Finish Block
   1351           break;
   1352         } else {
   1353           // blockHeader.level < node.level
   1354           // Begin child block
   1355           var childBlock = this.convertNodesToHeaderTree(nodes, i + 1, node);
   1356           childBlocks.push(childBlock);
   1357           i = childBlock.nextIndex;
   1358         }
   1359       }
   1360 
   1361       // Finish block
   1362       return {
   1363         header: blockHeader,
   1364         childNodes: childNodes,
   1365         nextIndex: i,
   1366         childBlocks: childBlocks
   1367       };
   1368     },
   1369 
   1370     convertNodes: function (nodes, recordHeader, insideCodeElement) {
   1371       return this.convertNodesInternal(nodes, recordHeader, insideCodeElement);
   1372     },
   1373 
   1374     combineNodesTexts: function (nodesTexts) {
   1375       return nodesTexts.join("");
   1376     },
   1377 
   1378     getNodeTextContent: function (node) {
   1379       if (node.type === Node.types.text)
   1380         return this.escapeSpecialChars(node.value);
   1381       else
   1382         return node.children ? node.children.map(this.getNodeTextContent, this).join("") : "";
   1383     },
   1384 
   1385     // @Override
   1386     escapeSpecialChars: function (text) {
   1387       throw Error("Implement escapeSpecialChars");
   1388     },
   1389 
   1390     // http://daringfireball.net/2010/07/improved_regex_for_matching_urls
   1391     urlPattern: /\b(?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’])/ig,
   1392 
   1393     // @Override
   1394     linkURL: function (text) {
   1395       var self = this;
   1396       return text.replace(this.urlPattern, function (matched) {
   1397         if (matched.indexOf("://") < 0)
   1398           matched = "http://" + matched;
   1399         return self.makeLink(matched);
   1400       });
   1401     },
   1402 
   1403     makeLink: function (url) {
   1404       throw Error("Implement makeLink");
   1405     },
   1406 
   1407     makeSubscripts: function (text) {
   1408       if (this.documentOptions["^"] === "{}")
   1409         return text.replace(/\b([^_ \t]*)_{([^}]*)}/g,
   1410                             this.makeSubscript);
   1411       else if (this.documentOptions["^"])
   1412         return text.replace(/\b([^_ \t]*)_([^_]*)\b/g,
   1413                             this.makeSubscript);
   1414       else
   1415         return text;
   1416     },
   1417 
   1418     makeSubscript: function (match, body, subscript) {
   1419       throw Error("Implement makeSubscript");
   1420     },
   1421 
   1422     stripParametersFromURL: function (url) {
   1423       return url.replace(/\?.*$/, "");
   1424     },
   1425 
   1426     imageExtensionPattern: new RegExp("(" + [
   1427       "bmp", "png", "jpeg", "jpg", "gif", "tiff",
   1428       "tif", "xbm", "xpm", "pbm", "pgm", "ppm", "svg"
   1429     ].join("|") + ")$", "i")
   1430   };
   1431 
   1432   if (typeof exports !== "undefined")
   1433     exports.Converter = Converter;
   1434 
   1435   // var Converter = require("./converter.js").Converter;
   1436   // var Node = require("../node.js").Node;
   1437 
   1438   function ConverterHTML(orgDocument, exportOptions) {
   1439     this.initialize(orgDocument, exportOptions);
   1440     this.result = this.convert();
   1441   }
   1442 
   1443   ConverterHTML.prototype = {
   1444     __proto__: Converter.prototype,
   1445 
   1446     convert: function () {
   1447       var title = this.orgDocument.title ? this.convertNode(this.orgDocument.title) : this.untitled;
   1448       var titleHTML = this.tag("h" + Math.max(Number(this.headerOffset), 1), title);
   1449       var contentHTML = this.convertNodes(this.orgDocument.nodes, true /* record headers */);
   1450       var toc = '';
   1451       var tocHTML = '';
   1452       if (this.documentOptions.toc) {
   1453         toc = this.computeToc(this.documentOptions["toc"]);
   1454         tocHTML = this.tocToHTML(toc);
   1455       }
   1456       return {
   1457         title: title,
   1458         titleHTML: titleHTML,
   1459         contentHTML: contentHTML,
   1460         tocHTML: tocHTML,
   1461         toc: toc,
   1462         toString: function () {
   1463           return titleHTML + tocHTML + "\n" + contentHTML;
   1464         }
   1465       };
   1466     },
   1467 
   1468     tocToHTML: function (toc) {
   1469       function tocToHTMLFunction(tocList) {
   1470         var html = "";
   1471         for (var i = 0; i < tocList.length; ++i) {
   1472           var tocItem = tocList[i];
   1473           var sectionNumberText = tocItem.headerNode.sectionNumberText;
   1474           var sectionNumber = this.documentOptions.num ?
   1475                 this.inlineTag("span", sectionNumberText, {
   1476                   "class": "section-number"
   1477                 }) : "";
   1478           var header = this.getNodeTextContent(tocItem.headerNode);
   1479           var headerLink = this.inlineTag("a", sectionNumber + header, {
   1480             href: "#header-" + sectionNumberText.replace(/\./g, "-")
   1481           });
   1482           var subList = tocItem.childTocs.length ? tocToHTMLFunction.call(this, tocItem.childTocs) : "";
   1483           html += this.tag("li", headerLink + subList);
   1484         }
   1485         return this.tag("ul", html);
   1486       }
   1487 
   1488       return tocToHTMLFunction.call(this, toc);
   1489     },
   1490 
   1491     computeAuxDataForNode: function (node) {
   1492       while (node.parent &&
   1493              node.parent.type === Node.types.inlineContainer) {
   1494         node = node.parent;
   1495       }
   1496       var attributesNode = node.previousSibling;
   1497       var attributesText = "";
   1498       while (attributesNode &&
   1499              attributesNode.type === Node.types.directive &&
   1500              attributesNode.directiveName === "attr_html:") {
   1501         attributesText += attributesNode.directiveRawValue + " ";
   1502         attributesNode = attributesNode.previousSibling;
   1503       }
   1504       return attributesText;
   1505     },
   1506 
   1507     // Method to construct org-js generated class
   1508     orgClassName: function (className) {
   1509       return this.exportOptions.htmlClassPrefix ?
   1510         this.exportOptions.htmlClassPrefix + className
   1511         : className;
   1512     },
   1513 
   1514     // Method to construct org-js generated id
   1515     orgId: function (id) {
   1516       return this.exportOptions.htmlIdPrefix ?
   1517         this.exportOptions.htmlIdPrefix + id
   1518         : id;
   1519     },
   1520 
   1521     // ----------------------------------------------------
   1522     // Node conversion
   1523     // ----------------------------------------------------
   1524 
   1525     convertHeader: function (node, childText, auxData,
   1526                              taskStatus, sectionNumberText) {
   1527       var headerAttributes = {};
   1528 
   1529       if (taskStatus) {
   1530         childText = this.inlineTag("span", childText.substring(0, 4), {
   1531           "class": "task-status " + taskStatus
   1532         }) + childText.substring(5);
   1533       }
   1534 
   1535       if (sectionNumberText) {
   1536         childText = this.inlineTag("span", sectionNumberText, {
   1537           "class": "section-number"
   1538         }) + childText;
   1539         headerAttributes["id"] = "header-" + sectionNumberText.replace(/\./g, "-");
   1540       }
   1541 
   1542       if (taskStatus)
   1543         headerAttributes["class"] = "task-status " + taskStatus;
   1544 
   1545       return this.tag("h" + (this.headerOffset + node.level),
   1546                       childText, headerAttributes, auxData);
   1547     },
   1548 
   1549     convertOrderedList: function (node, childText, auxData) {
   1550       return this.tag("ol", childText, null, auxData);
   1551     },
   1552 
   1553     convertUnorderedList: function (node, childText, auxData) {
   1554       return this.tag("ul", childText, null, auxData);
   1555     },
   1556 
   1557     convertDefinitionList: function (node, childText, auxData) {
   1558       return this.tag("dl", childText, null, auxData);
   1559     },
   1560 
   1561     convertDefinitionItem: function (node, childText, auxData,
   1562                                      term, definition) {
   1563       return this.tag("dt", term) + this.tag("dd", definition);
   1564     },
   1565 
   1566     convertListItem: function (node, childText, auxData) {
   1567       if (this.exportOptions.suppressCheckboxHandling) {
   1568         return this.tag("li", childText, null, auxData);
   1569       } else {
   1570         var listItemAttributes = {};
   1571         var listItemText = childText;
   1572         // Embed checkbox
   1573         if (/^\s*\[(X| |-)\]([\s\S]*)/.exec(listItemText)) {
   1574           listItemText = RegExp.$2 ;
   1575           var checkboxIndicator = RegExp.$1;
   1576 
   1577           var checkboxAttributes = { type: "checkbox" };
   1578           switch (checkboxIndicator) {
   1579           case "X":
   1580             checkboxAttributes["checked"] = "true";
   1581             listItemAttributes["data-checkbox-status"] = "done";
   1582             break;
   1583           case "-":
   1584             listItemAttributes["data-checkbox-status"] = "intermediate";
   1585             break;
   1586           default:
   1587             listItemAttributes["data-checkbox-status"] = "undone";
   1588             break;
   1589           }
   1590 
   1591           listItemText = this.inlineTag("input", null, checkboxAttributes) + listItemText;
   1592         }
   1593 
   1594         return this.tag("li", listItemText, listItemAttributes, auxData);
   1595       }
   1596     },
   1597 
   1598     convertParagraph: function (node, childText, auxData) {
   1599       return this.tag("p", childText, null, auxData);
   1600     },
   1601 
   1602     convertPreformatted: function (node, childText, auxData) {
   1603       return this.tag("pre", childText, null, auxData);
   1604     },
   1605 
   1606     convertTable: function (node, childText, auxData) {
   1607       return this.tag("table", this.tag("tbody", childText), null, auxData);
   1608     },
   1609 
   1610     convertTableRow: function (node, childText, auxData) {
   1611       return this.tag("tr", childText);
   1612     },
   1613 
   1614     convertTableHeader: function (node, childText, auxData) {
   1615       return this.tag("th", childText);
   1616     },
   1617 
   1618     convertTableCell: function (node, childText, auxData) {
   1619       return this.tag("td", childText);
   1620     },
   1621 
   1622     convertHorizontalRule: function (node, childText, auxData) {
   1623       return this.tag("hr", null, null, auxData);
   1624     },
   1625 
   1626     convertInlineContainer: function (node, childText, auxData) {
   1627       return childText;
   1628     },
   1629 
   1630     convertBold: function (node, childText, auxData) {
   1631       return this.inlineTag("b", childText);
   1632     },
   1633 
   1634     convertItalic: function (node, childText, auxData) {
   1635       return this.inlineTag("i", childText);
   1636     },
   1637 
   1638     convertUnderline: function (node, childText, auxData) {
   1639       return this.inlineTag("span", childText, {
   1640         style: "text-decoration:underline;"
   1641       });
   1642     },
   1643 
   1644     convertCode: function (node, childText, auxData) {
   1645       return this.inlineTag("code", childText);
   1646     },
   1647 
   1648     convertDashed: function (node, childText, auxData) {
   1649       return this.inlineTag("del", childText);
   1650     },
   1651 
   1652     convertLink: function (node, childText, auxData) {
   1653       var srcParameterStripped = this.stripParametersFromURL(node.src);
   1654       if (this.imageExtensionPattern.exec(srcParameterStripped)) {
   1655         var imgText = this.getNodeTextContent(node);
   1656         return this.inlineTag("img", null, {
   1657           src: node.src,
   1658           alt: imgText,
   1659           title: imgText
   1660         }, auxData);
   1661       } else {
   1662         return this.inlineTag("a", childText, { href: node.src });
   1663       }
   1664     },
   1665 
   1666     convertQuote: function (node, childText, auxData) {
   1667       return this.tag("blockquote", childText, null, auxData);
   1668     },
   1669 
   1670     convertExample: function (node, childText, auxData) {
   1671       return this.tag("pre", childText, null, auxData);
   1672     },
   1673 
   1674     convertSrc: function (node, childText, auxData) {
   1675       var codeLanguage = node.directiveArguments.length
   1676             ? node.directiveArguments[0]
   1677             : "unknown";
   1678       childText = this.tag("code", childText, {
   1679         "class": "language-" + codeLanguage
   1680       }, auxData);
   1681       return this.tag("pre", childText, {
   1682         "class": "prettyprint"
   1683       });
   1684     },
   1685 
   1686     // @override
   1687     convertHTML: function (node, childText, auxData) {
   1688       if (node.directiveName === "html:") {
   1689         return node.directiveRawValue;
   1690       } else if (node.directiveName === "html") {
   1691         return node.children.map(function (textNode) {
   1692           return textNode.value;
   1693         }).join("\n");
   1694       } else {
   1695         return childText;
   1696       }
   1697     },
   1698 
   1699     // @implement
   1700     convertHeaderBlock: function (headerBlock, level, index) {
   1701       level = level || 0;
   1702       index = index || 0;
   1703 
   1704       var contents = [];
   1705 
   1706       var headerNode = headerBlock.header;
   1707       if (headerNode) {
   1708         contents.push(this.convertNode(headerNode));
   1709       }
   1710 
   1711       var blockContent = this.convertNodes(headerBlock.childNodes);
   1712       contents.push(blockContent);
   1713 
   1714       var childBlockContent = headerBlock.childBlocks
   1715             .map(function (block, idx) {
   1716               return this.convertHeaderBlock(block, level + 1, idx);
   1717             }, this)
   1718             .join("\n");
   1719       contents.push(childBlockContent);
   1720 
   1721       var contentsText = contents.join("\n");
   1722 
   1723       if (headerNode) {
   1724         return this.tag("section", "\n" + contents.join("\n"), {
   1725           "class": "block block-level-" + level
   1726         });
   1727       } else {
   1728         return contentsText;
   1729       }
   1730     },
   1731 
   1732     // ----------------------------------------------------
   1733     // Supplemental methods
   1734     // ----------------------------------------------------
   1735 
   1736     replaceMap: {
   1737       // [replacing pattern, predicate]
   1738       "&": ["&#38;", null],
   1739       "<": ["&#60;", null],
   1740       ">": ["&#62;", null],
   1741       '"': ["&#34;", null],
   1742       "'": ["&#39;", null],
   1743       "->": ["&#10132;", function (text, insideCodeElement) {
   1744         return this.exportOptions.translateSymbolArrow && !insideCodeElement;
   1745       }]
   1746     },
   1747 
   1748     replaceRegexp: null,
   1749 
   1750     // @implement @override
   1751     escapeSpecialChars: function (text, insideCodeElement) {
   1752       if (!this.replaceRegexp) {
   1753         this.replaceRegexp = new RegExp(Object.keys(this.replaceMap).join("|"), "g");
   1754       }
   1755 
   1756       var replaceMap = this.replaceMap;
   1757       var self = this;
   1758       return text.replace(this.replaceRegexp, function (matched) {
   1759         if (!replaceMap[matched]) {
   1760           throw Error("escapeSpecialChars: Invalid match");
   1761         }
   1762 
   1763         var predicate = replaceMap[matched][1];
   1764         if (typeof predicate === "function" &&
   1765             !predicate.call(self, text, insideCodeElement)) {
   1766           // Not fullfill the predicate
   1767           return matched;
   1768         }
   1769 
   1770         return replaceMap[matched][0];
   1771       });
   1772     },
   1773 
   1774     // @implement
   1775     postProcess: function (node, currentText, insideCodeElement) {
   1776       if (this.exportOptions.exportFromLineNumber &&
   1777           typeof node.fromLineNumber === "number") {
   1778         // Wrap with line number information
   1779         currentText = this.inlineTag("div", currentText, {
   1780           "data-line-number": node.fromLineNumber
   1781         });
   1782       }
   1783       return currentText;
   1784     },
   1785 
   1786     // @implement
   1787     makeLink: function (url) {
   1788       return "<a href=\"" + url + "\">" + decodeURIComponent(url) + "</a>";
   1789     },
   1790 
   1791     // @implement
   1792     makeSubscript: function (match, body, subscript) {
   1793       return "<span class=\"org-subscript-parent\">" +
   1794         body +
   1795         "</span><span class=\"org-subscript-child\">" +
   1796         subscript +
   1797         "</span>";
   1798     },
   1799 
   1800     // ----------------------------------------------------
   1801     // Specific methods
   1802     // ----------------------------------------------------
   1803 
   1804     attributesObjectToString: function (attributesObject) {
   1805       var attributesString = "";
   1806       for (var attributeName in attributesObject) {
   1807         if (attributesObject.hasOwnProperty(attributeName)) {
   1808           var attributeValue = attributesObject[attributeName];
   1809           // To avoid id/class name conflicts with other frameworks,
   1810           // users can add arbitrary prefix to org-js generated
   1811           // ids/classes via exportOptions.
   1812           if (attributeName === "class") {
   1813             attributeValue = this.orgClassName(attributeValue);
   1814           } else if (attributeName === "id") {
   1815             attributeValue = this.orgId(attributeValue);
   1816           }
   1817           attributesString += " " + attributeName + "=\"" + attributeValue + "\"";
   1818         }
   1819       }
   1820       return attributesString;
   1821     },
   1822 
   1823     inlineTag: function (name, innerText, attributesObject, auxAttributesText) {
   1824       attributesObject = attributesObject || {};
   1825 
   1826       var htmlString = "<" + name;
   1827       // TODO: check duplicated attributes
   1828       if (auxAttributesText)
   1829         htmlString += " " + auxAttributesText;
   1830       htmlString += this.attributesObjectToString(attributesObject);
   1831 
   1832       if (innerText === null)
   1833         return htmlString + "/>";
   1834 
   1835       htmlString += ">" + innerText + "</" + name + ">";
   1836 
   1837       return htmlString;
   1838     },
   1839 
   1840     tag: function (name, innerText, attributesObject, auxAttributesText) {
   1841       return this.inlineTag(name, innerText, attributesObject, auxAttributesText) + "\n";
   1842     }
   1843   };
   1844 
   1845   if (typeof exports !== "undefined")
   1846     exports.ConverterHTML = ConverterHTML;
   1847 
   1848   return exports;
   1849 })();
   1850 
   1851 Object.assign(exports, Org)