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