lightview 1.8.1-b → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +15 -16
  2. package/docs/CNAME +1 -0
  3. package/docs/api.html +674 -0
  4. package/docs/blank.html +10 -0
  5. package/docs/comparedto.html +89 -0
  6. package/docs/components/chart-repl.html +69 -0
  7. package/{components/chart → docs/components}/chart.html +2 -2
  8. package/{components → docs/components}/components.js +3 -3
  9. package/docs/components/contents.html +17 -0
  10. package/docs/components/gantt-repl.html +61 -0
  11. package/{components/gantt → docs/components}/gantt.html +3 -3
  12. package/docs/components/gauge-repl.html +66 -0
  13. package/{components/gauge → docs/components}/gauge.html +2 -2
  14. package/docs/components/orgchart-repl.html +64 -0
  15. package/{components/orgchart → docs/components}/orgchart.html +2 -2
  16. package/docs/components/repl-as-src.html +17 -0
  17. package/docs/components/repl-repl.html +95 -0
  18. package/docs/components/repl.html +527 -0
  19. package/docs/components/timeline-repl.html +72 -0
  20. package/{components/timeline → docs/components}/timeline.html +2 -2
  21. package/docs/components.html +14 -0
  22. package/docs/css/highlightjs.min.css +9 -0
  23. package/docs/css/tutorial.css +35 -0
  24. package/docs/examples/anchor.html +11 -0
  25. package/{examples → docs/examples}/chart.html +2 -2
  26. package/{examples → docs/examples}/counter.html +1 -1
  27. package/{examples → docs/examples}/counter.test.mjs +0 -0
  28. package/{examples → docs/examples}/counter2.html +1 -1
  29. package/{examples → docs/examples}/directives.html +1 -1
  30. package/{examples → docs/examples}/foreign.html +1 -1
  31. package/{examples → docs/examples}/forgeinform.html +1 -1
  32. package/{examples → docs/examples}/form.html +1 -1
  33. package/{examples → docs/examples}/gauge.html +2 -2
  34. package/{examples → docs/examples}/invalid-template-literals.html +1 -1
  35. package/{examples → docs/examples}/medium/remote.html +1 -1
  36. package/{examples → docs/examples}/message.html +0 -0
  37. package/{examples → docs/examples}/nested.html +1 -1
  38. package/{examples → docs/examples}/object-bound-form.html +0 -0
  39. package/{examples → docs/examples}/remote-server.js +0 -0
  40. package/{examples → docs/examples}/remote.html +2 -2
  41. package/{examples → docs/examples}/remote.json +0 -0
  42. package/{examples → docs/examples}/scratch.html +1 -1
  43. package/docs/examples/sensors/index.html +44 -0
  44. package/{examples → docs/examples}/sensors/sensor-server.js +0 -0
  45. package/{examples → docs/examples}/shared.html +0 -0
  46. package/{examples → docs/examples}/template.html +1 -1
  47. package/{examples → docs/examples}/timeline.html +2 -2
  48. package/docs/examples/todo.html +40 -0
  49. package/docs/examples/top.html +10 -0
  50. package/{examples → docs/examples}/types.html +1 -1
  51. package/{examples → docs/examples}/xor.html +1 -1
  52. package/docs/examples.html +25 -0
  53. package/docs/index.html +44 -0
  54. package/docs/javascript/codejar.min.js +8 -0
  55. package/docs/javascript/highlightjs.min.js +1173 -0
  56. package/docs/javascript/isomorphic-git.js +9 -0
  57. package/docs/javascript/json5.min.js +1 -0
  58. package/docs/javascript/lightning-fs.js +1 -0
  59. package/docs/javascript/lightview.js +1285 -0
  60. package/docs/javascript/marked.min.js +6 -0
  61. package/docs/javascript/peerjs.min.js +70 -0
  62. package/docs/javascript/turndown.js +973 -0
  63. package/docs/javascript/types.js +606 -0
  64. package/docs/javascript/utils.js +45 -0
  65. package/docs/lightview.html +63 -0
  66. package/docs/old_index.html +965 -0
  67. package/docs/old_index.md +1132 -0
  68. package/docs/slidein.html +51 -0
  69. package/docs/tutorial/0-getting-started.html +67 -0
  70. package/docs/tutorial/1-intro-to-variables.html +103 -0
  71. package/docs/tutorial/10-template-components.html +80 -0
  72. package/docs/tutorial/11-linked-components.html +76 -0
  73. package/docs/tutorial/12-imported-components.html +67 -0
  74. package/docs/tutorial/13-input-binding.html +94 -0
  75. package/docs/tutorial/14-automatic-variable-creation.html +74 -0
  76. package/docs/tutorial/15-form-binding.html +110 -0
  77. package/docs/tutorial/16-if-directive.html +60 -0
  78. package/docs/tutorial/17-loop-directives.html +83 -0
  79. package/docs/tutorial/18-sanitizing-and-escaping-input.html +79 -0
  80. package/docs/tutorial/2-imported-and-exported-variables.html +80 -0
  81. package/docs/tutorial/3-data-types.html +89 -0
  82. package/docs/tutorial/4-extended-data-types.html +83 -0
  83. package/docs/tutorial/5-extended-functional-types.html +96 -0
  84. package/docs/tutorial/5.1-extended-functional-types.html +79 -0
  85. package/docs/tutorial/5.2-extended-functional-types.html +70 -0
  86. package/docs/tutorial/6-conventional-javascript.html +75 -0
  87. package/docs/tutorial/7-monitoring-with-observers.html +107 -0
  88. package/docs/tutorial/8-event-listeners.html +65 -0
  89. package/docs/tutorial/9-intro-to-components.html +91 -0
  90. package/docs/tutorial/contents.html +32 -0
  91. package/docs/tutorial/my-component.html +29 -0
  92. package/docs/tutorial/remote-value.json +4 -0
  93. package/docs/websiterepl.html +46 -0
  94. package/lightview.js +430 -340
  95. package/lightview.min.js +1 -0
  96. package/lightview_good.js +1267 -0
  97. package/lightview_optimized.js +1274 -0
  98. package/package.json +1 -1
  99. package/repl_hold.html +320 -0
  100. package/test/basic.html +15 -4
  101. package/test/basic.test.mjs +1 -1
  102. package/test/extended.html +1 -1
  103. package/types.js +109 -36
  104. package/components/chart/example.html +0 -32
  105. package/components/chart.html +0 -83
  106. package/components/gantt/example.html +0 -22
  107. package/components/gauge/example.html +0 -28
  108. package/components/gauge.html +0 -60
  109. package/components/orgchart/example.html +0 -25
  110. package/components/repl/code-editor.html +0 -64
  111. package/components/repl/editor.html +0 -37
  112. package/components/repl/editorjs-inline-tool/index.js +0 -3
  113. package/components/repl/editorjs-inline-tool/inline-tools.js +0 -28
  114. package/components/repl/editorjs-inline-tool/tool.js +0 -175
  115. package/components/repl/repl-with-wysiwyg.html +0 -355
  116. package/components/repl/repl.html +0 -345
  117. package/components/repl/sup.js +0 -44
  118. package/components/repl/wysiwyg-repl.html +0 -258
  119. package/components/timeline/example.html +0 -33
  120. package/components/timeline.html +0 -81
  121. package/examples/anchor.html +0 -11
  122. package/examples/sensors/index.html +0 -30
  123. package/examples/todo.html +0 -38
  124. package/examples/top.html +0 -10
  125. package/sites/client.html +0 -48
  126. package/sites/index.html +0 -247
@@ -0,0 +1,973 @@
1
+ var TurndownService = (function () {
2
+ 'use strict';
3
+
4
+ function extend (destination) {
5
+ for (var i = 1; i < arguments.length; i++) {
6
+ var source = arguments[i];
7
+ for (var key in source) {
8
+ if (source.hasOwnProperty(key)) destination[key] = source[key];
9
+ }
10
+ }
11
+ return destination
12
+ }
13
+
14
+ function repeat (character, count) {
15
+ return Array(count + 1).join(character)
16
+ }
17
+
18
+ function trimLeadingNewlines (string) {
19
+ return string.replace(/^\n*/, '')
20
+ }
21
+
22
+ function trimTrailingNewlines (string) {
23
+ // avoid match-at-end regexp bottleneck, see #370
24
+ var indexEnd = string.length;
25
+ while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--;
26
+ return string.substring(0, indexEnd)
27
+ }
28
+
29
+ var blockElements = [
30
+ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS',
31
+ 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE',
32
+ 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER',
33
+ 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES',
34
+ 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD',
35
+ 'TFOOT', 'TH', 'THEAD', 'TR', 'UL'
36
+ ];
37
+
38
+ function isBlock (node) {
39
+ return is(node, blockElements)
40
+ }
41
+
42
+ var voidElements = [
43
+ 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT',
44
+ 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'
45
+ ];
46
+
47
+ function isVoid (node) {
48
+ return is(node, voidElements)
49
+ }
50
+
51
+ function hasVoid (node) {
52
+ return has(node, voidElements)
53
+ }
54
+
55
+ var meaningfulWhenBlankElements = [
56
+ 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT',
57
+ 'AUDIO', 'VIDEO'
58
+ ];
59
+
60
+ function isMeaningfulWhenBlank (node) {
61
+ return is(node, meaningfulWhenBlankElements)
62
+ }
63
+
64
+ function hasMeaningfulWhenBlank (node) {
65
+ return has(node, meaningfulWhenBlankElements)
66
+ }
67
+
68
+ function is (node, tagNames) {
69
+ return tagNames.indexOf(node.nodeName) >= 0
70
+ }
71
+
72
+ function has (node, tagNames) {
73
+ return (
74
+ node.getElementsByTagName &&
75
+ tagNames.some(function (tagName) {
76
+ return node.getElementsByTagName(tagName).length
77
+ })
78
+ )
79
+ }
80
+
81
+ var rules = {};
82
+
83
+ rules.paragraph = {
84
+ filter: 'p',
85
+
86
+ replacement: function (content) {
87
+ return '\n\n' + content + '\n\n'
88
+ }
89
+ };
90
+
91
+ rules.lineBreak = {
92
+ filter: 'br',
93
+
94
+ replacement: function (content, node, options) {
95
+ return options.br + '\n'
96
+ }
97
+ };
98
+
99
+ rules.heading = {
100
+ filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
101
+
102
+ replacement: function (content, node, options) {
103
+ var hLevel = Number(node.nodeName.charAt(1));
104
+
105
+ if (options.headingStyle === 'setext' && hLevel < 3) {
106
+ var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
107
+ return (
108
+ '\n\n' + content + '\n' + underline + '\n\n'
109
+ )
110
+ } else {
111
+ return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
112
+ }
113
+ }
114
+ };
115
+
116
+ rules.blockquote = {
117
+ filter: 'blockquote',
118
+
119
+ replacement: function (content) {
120
+ content = content.replace(/^\n+|\n+$/g, '');
121
+ content = content.replace(/^/gm, '> ');
122
+ return '\n\n' + content + '\n\n'
123
+ }
124
+ };
125
+
126
+ rules.list = {
127
+ filter: ['ul', 'ol'],
128
+
129
+ replacement: function (content, node) {
130
+ var parent = node.parentNode;
131
+ if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
132
+ return '\n' + content
133
+ } else {
134
+ return '\n\n' + content + '\n\n'
135
+ }
136
+ }
137
+ };
138
+
139
+ rules.listItem = {
140
+ filter: 'li',
141
+
142
+ replacement: function (content, node, options) {
143
+ content = content
144
+ .replace(/^\n+/, '') // remove leading newlines
145
+ .replace(/\n+$/, '\n') // replace trailing newlines with just a single one
146
+ .replace(/\n/gm, '\n '); // indent
147
+ var prefix = options.bulletListMarker + ' ';
148
+ var parent = node.parentNode;
149
+ if (parent.nodeName === 'OL') {
150
+ var start = parent.getAttribute('start');
151
+ var index = Array.prototype.indexOf.call(parent.children, node);
152
+ prefix = (start ? Number(start) + index : index + 1) + '. ';
153
+ }
154
+ return (
155
+ prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
156
+ )
157
+ }
158
+ };
159
+
160
+ rules.indentedCodeBlock = {
161
+ filter: function (node, options) {
162
+ return (
163
+ options.codeBlockStyle === 'indented' &&
164
+ node.nodeName === 'PRE' &&
165
+ node.firstChild &&
166
+ node.firstChild.nodeName === 'CODE'
167
+ )
168
+ },
169
+
170
+ replacement: function (content, node, options) {
171
+ return (
172
+ '\n\n ' +
173
+ node.firstChild.textContent.replace(/\n/g, '\n ') +
174
+ '\n\n'
175
+ )
176
+ }
177
+ };
178
+
179
+ rules.fencedCodeBlock = {
180
+ filter: function (node, options) {
181
+ return (
182
+ options.codeBlockStyle === 'fenced' &&
183
+ node.nodeName === 'PRE' &&
184
+ node.firstChild &&
185
+ node.firstChild.nodeName === 'CODE'
186
+ )
187
+ },
188
+
189
+ replacement: function (content, node, options) {
190
+ var className = node.firstChild.getAttribute('class') || '';
191
+ var language = (className.match(/language-(\S+)/) || [null, ''])[1];
192
+ var code = node.firstChild.textContent;
193
+
194
+ var fenceChar = options.fence.charAt(0);
195
+ var fenceSize = 3;
196
+ var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');
197
+
198
+ var match;
199
+ while ((match = fenceInCodeRegex.exec(code))) {
200
+ if (match[0].length >= fenceSize) {
201
+ fenceSize = match[0].length + 1;
202
+ }
203
+ }
204
+
205
+ var fence = repeat(fenceChar, fenceSize);
206
+
207
+ return (
208
+ '\n\n' + fence + language + '\n' +
209
+ code.replace(/\n$/, '') +
210
+ '\n' + fence + '\n\n'
211
+ )
212
+ }
213
+ };
214
+
215
+ rules.horizontalRule = {
216
+ filter: 'hr',
217
+
218
+ replacement: function (content, node, options) {
219
+ return '\n\n' + options.hr + '\n\n'
220
+ }
221
+ };
222
+
223
+ rules.inlineLink = {
224
+ filter: function (node, options) {
225
+ return (
226
+ options.linkStyle === 'inlined' &&
227
+ node.nodeName === 'A' &&
228
+ node.getAttribute('href')
229
+ )
230
+ },
231
+
232
+ replacement: function (content, node) {
233
+ var href = node.getAttribute('href');
234
+ var title = cleanAttribute(node.getAttribute('title'));
235
+ if (title) title = ' "' + title + '"';
236
+ return '[' + content + '](' + href + title + ')'
237
+ }
238
+ };
239
+
240
+ rules.referenceLink = {
241
+ filter: function (node, options) {
242
+ return (
243
+ options.linkStyle === 'referenced' &&
244
+ node.nodeName === 'A' &&
245
+ node.getAttribute('href')
246
+ )
247
+ },
248
+
249
+ replacement: function (content, node, options) {
250
+ var href = node.getAttribute('href');
251
+ var title = cleanAttribute(node.getAttribute('title'));
252
+ if (title) title = ' "' + title + '"';
253
+ var replacement;
254
+ var reference;
255
+
256
+ switch (options.linkReferenceStyle) {
257
+ case 'collapsed':
258
+ replacement = '[' + content + '][]';
259
+ reference = '[' + content + ']: ' + href + title;
260
+ break
261
+ case 'shortcut':
262
+ replacement = '[' + content + ']';
263
+ reference = '[' + content + ']: ' + href + title;
264
+ break
265
+ default:
266
+ var id = this.references.length + 1;
267
+ replacement = '[' + content + '][' + id + ']';
268
+ reference = '[' + id + ']: ' + href + title;
269
+ }
270
+
271
+ this.references.push(reference);
272
+ return replacement
273
+ },
274
+
275
+ references: [],
276
+
277
+ append: function (options) {
278
+ var references = '';
279
+ if (this.references.length) {
280
+ references = '\n\n' + this.references.join('\n') + '\n\n';
281
+ this.references = []; // Reset references
282
+ }
283
+ return references
284
+ }
285
+ };
286
+
287
+ rules.emphasis = {
288
+ filter: ['em', 'i'],
289
+
290
+ replacement: function (content, node, options) {
291
+ if (!content.trim()) return ''
292
+ return options.emDelimiter + content + options.emDelimiter
293
+ }
294
+ };
295
+
296
+ rules.strong = {
297
+ filter: ['strong', 'b'],
298
+
299
+ replacement: function (content, node, options) {
300
+ if (!content.trim()) return ''
301
+ return options.strongDelimiter + content + options.strongDelimiter
302
+ }
303
+ };
304
+
305
+ rules.code = {
306
+ filter: function (node) {
307
+ var hasSiblings = node.previousSibling || node.nextSibling;
308
+ var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
309
+
310
+ return node.nodeName === 'CODE' && !isCodeBlock
311
+ },
312
+
313
+ replacement: function (content) {
314
+ if (!content) return ''
315
+ content = content.replace(/\r?\n|\r/g, ' ');
316
+
317
+ var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? ' ' : '';
318
+ var delimiter = '`';
319
+ var matches = content.match(/`+/gm) || [];
320
+ while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
321
+
322
+ return delimiter + extraSpace + content + extraSpace + delimiter
323
+ }
324
+ };
325
+
326
+ rules.image = {
327
+ filter: 'img',
328
+
329
+ replacement: function (content, node) {
330
+ var alt = cleanAttribute(node.getAttribute('alt'));
331
+ var src = node.getAttribute('src') || '';
332
+ var title = cleanAttribute(node.getAttribute('title'));
333
+ var titlePart = title ? ' "' + title + '"' : '';
334
+ return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
335
+ }
336
+ };
337
+
338
+ function cleanAttribute (attribute) {
339
+ return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
340
+ }
341
+
342
+ /**
343
+ * Manages a collection of rules used to convert HTML to Markdown
344
+ */
345
+
346
+ function Rules (options) {
347
+ this.options = options;
348
+ this._keep = [];
349
+ this._remove = [];
350
+
351
+ this.blankRule = {
352
+ replacement: options.blankReplacement
353
+ };
354
+
355
+ this.keepReplacement = options.keepReplacement;
356
+
357
+ this.defaultRule = {
358
+ replacement: options.defaultReplacement
359
+ };
360
+
361
+ this.array = [];
362
+ for (var key in options.rules) this.array.push(options.rules[key]);
363
+ }
364
+
365
+ Rules.prototype = {
366
+ add: function (key, rule) {
367
+ this.array.unshift(rule);
368
+ },
369
+
370
+ keep: function (filter) {
371
+ this._keep.unshift({
372
+ filter: filter,
373
+ replacement: this.keepReplacement
374
+ });
375
+ },
376
+
377
+ remove: function (filter) {
378
+ this._remove.unshift({
379
+ filter: filter,
380
+ replacement: function () {
381
+ return ''
382
+ }
383
+ });
384
+ },
385
+
386
+ forNode: function (node) {
387
+ if (node.isBlank) return this.blankRule
388
+ var rule;
389
+
390
+ if ((rule = findRule(this.array, node, this.options))) return rule
391
+ if ((rule = findRule(this._keep, node, this.options))) return rule
392
+ if ((rule = findRule(this._remove, node, this.options))) return rule
393
+
394
+ return this.defaultRule
395
+ },
396
+
397
+ forEach: function (fn) {
398
+ for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
399
+ }
400
+ };
401
+
402
+ function findRule (rules, node, options) {
403
+ for (var i = 0; i < rules.length; i++) {
404
+ var rule = rules[i];
405
+ if (filterValue(rule, node, options)) return rule
406
+ }
407
+ return void 0
408
+ }
409
+
410
+ function filterValue (rule, node, options) {
411
+ var filter = rule.filter;
412
+ if (typeof filter === 'string') {
413
+ if (filter === node.nodeName.toLowerCase()) return true
414
+ } else if (Array.isArray(filter)) {
415
+ if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
416
+ } else if (typeof filter === 'function') {
417
+ if (filter.call(rule, node, options)) return true
418
+ } else {
419
+ throw new TypeError('`filter` needs to be a string, array, or function')
420
+ }
421
+ }
422
+
423
+ /**
424
+ * The collapseWhitespace function is adapted from collapse-whitespace
425
+ * by Luc Thevenard.
426
+ *
427
+ * The MIT License (MIT)
428
+ *
429
+ * Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>
430
+ *
431
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
432
+ * of this software and associated documentation files (the "Software"), to deal
433
+ * in the Software without restriction, including without limitation the rights
434
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
435
+ * copies of the Software, and to permit persons to whom the Software is
436
+ * furnished to do so, subject to the following conditions:
437
+ *
438
+ * The above copyright notice and this permission notice shall be included in
439
+ * all copies or substantial portions of the Software.
440
+ *
441
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
442
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
443
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
444
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
445
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
446
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
447
+ * THE SOFTWARE.
448
+ */
449
+
450
+ /**
451
+ * collapseWhitespace(options) removes extraneous whitespace from an the given element.
452
+ *
453
+ * @param {Object} options
454
+ */
455
+ function collapseWhitespace (options) {
456
+ var element = options.element;
457
+ var isBlock = options.isBlock;
458
+ var isVoid = options.isVoid;
459
+ var isPre = options.isPre || function (node) {
460
+ return node.nodeName === 'PRE'
461
+ };
462
+
463
+ if (!element.firstChild || isPre(element)) return
464
+
465
+ var prevText = null;
466
+ var keepLeadingWs = false;
467
+
468
+ var prev = null;
469
+ var node = next(prev, element, isPre);
470
+
471
+ while (node !== element) {
472
+ if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
473
+ var text = node.data.replace(/[ \r\n\t]+/g, ' ');
474
+
475
+ if ((!prevText || / $/.test(prevText.data)) &&
476
+ !keepLeadingWs && text[0] === ' ') {
477
+ text = text.substr(1);
478
+ }
479
+
480
+ // `text` might be empty at this point.
481
+ if (!text) {
482
+ node = remove(node);
483
+ continue
484
+ }
485
+
486
+ node.data = text;
487
+
488
+ prevText = node;
489
+ } else if (node.nodeType === 1) { // Node.ELEMENT_NODE
490
+ if (isBlock(node) || node.nodeName === 'BR') {
491
+ if (prevText) {
492
+ prevText.data = prevText.data.replace(/ $/, '');
493
+ }
494
+
495
+ prevText = null;
496
+ keepLeadingWs = false;
497
+ } else if (isVoid(node) || isPre(node)) {
498
+ // Avoid trimming space around non-block, non-BR void elements and inline PRE.
499
+ prevText = null;
500
+ keepLeadingWs = true;
501
+ } else if (prevText) {
502
+ // Drop protection if set previously.
503
+ keepLeadingWs = false;
504
+ }
505
+ } else {
506
+ node = remove(node);
507
+ continue
508
+ }
509
+
510
+ var nextNode = next(prev, node, isPre);
511
+ prev = node;
512
+ node = nextNode;
513
+ }
514
+
515
+ if (prevText) {
516
+ prevText.data = prevText.data.replace(/ $/, '');
517
+ if (!prevText.data) {
518
+ remove(prevText);
519
+ }
520
+ }
521
+ }
522
+
523
+ /**
524
+ * remove(node) removes the given node from the DOM and returns the
525
+ * next node in the sequence.
526
+ *
527
+ * @param {Node} node
528
+ * @return {Node} node
529
+ */
530
+ function remove (node) {
531
+ var next = node.nextSibling || node.parentNode;
532
+
533
+ node.parentNode.removeChild(node);
534
+
535
+ return next
536
+ }
537
+
538
+ /**
539
+ * next(prev, current, isPre) returns the next node in the sequence, given the
540
+ * current and previous nodes.
541
+ *
542
+ * @param {Node} prev
543
+ * @param {Node} current
544
+ * @param {Function} isPre
545
+ * @return {Node}
546
+ */
547
+ function next (prev, current, isPre) {
548
+ if ((prev && prev.parentNode === current) || isPre(current)) {
549
+ return current.nextSibling || current.parentNode
550
+ }
551
+
552
+ return current.firstChild || current.nextSibling || current.parentNode
553
+ }
554
+
555
+ /*
556
+ * Set up window for Node.js
557
+ */
558
+
559
+ var root = (typeof window !== 'undefined' ? window : {});
560
+
561
+ /*
562
+ * Parsing HTML strings
563
+ */
564
+
565
+ function canParseHTMLNatively () {
566
+ var Parser = root.DOMParser;
567
+ var canParse = false;
568
+
569
+ // Adapted from https://gist.github.com/1129031
570
+ // Firefox/Opera/IE throw errors on unsupported types
571
+ try {
572
+ // WebKit returns null on unsupported types
573
+ if (new Parser().parseFromString('', 'text/html')) {
574
+ canParse = true;
575
+ }
576
+ } catch (e) {}
577
+
578
+ return canParse
579
+ }
580
+
581
+ function createHTMLParser () {
582
+ var Parser = function () {};
583
+
584
+ {
585
+ if (shouldUseActiveX()) {
586
+ Parser.prototype.parseFromString = function (string) {
587
+ var doc = new window.ActiveXObject('htmlfile');
588
+ doc.designMode = 'on'; // disable on-page scripts
589
+ doc.open();
590
+ doc.write(string);
591
+ doc.close();
592
+ return doc
593
+ };
594
+ } else {
595
+ Parser.prototype.parseFromString = function (string) {
596
+ var doc = document.implementation.createHTMLDocument('');
597
+ doc.open();
598
+ doc.write(string);
599
+ doc.close();
600
+ return doc
601
+ };
602
+ }
603
+ }
604
+ return Parser
605
+ }
606
+
607
+ function shouldUseActiveX () {
608
+ var useActiveX = false;
609
+ try {
610
+ document.implementation.createHTMLDocument('').open();
611
+ } catch (e) {
612
+ if (window.ActiveXObject) useActiveX = true;
613
+ }
614
+ return useActiveX
615
+ }
616
+
617
+ var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
618
+
619
+ function RootNode (input, options) {
620
+ var root;
621
+ if (typeof input === 'string') {
622
+ var doc = htmlParser().parseFromString(
623
+ // DOM parsers arrange elements in the <head> and <body>.
624
+ // Wrapping in a custom element ensures elements are reliably arranged in
625
+ // a single element.
626
+ '<x-turndown id="turndown-root">' + input + '</x-turndown>',
627
+ 'text/html'
628
+ );
629
+ root = doc.getElementById('turndown-root');
630
+ } else {
631
+ root = input.cloneNode(true);
632
+ }
633
+ collapseWhitespace({
634
+ element: root,
635
+ isBlock: isBlock,
636
+ isVoid: isVoid,
637
+ isPre: options.preformattedCode ? isPreOrCode : null
638
+ });
639
+
640
+ return root
641
+ }
642
+
643
+ var _htmlParser;
644
+ function htmlParser () {
645
+ _htmlParser = _htmlParser || new HTMLParser();
646
+ return _htmlParser
647
+ }
648
+
649
+ function isPreOrCode (node) {
650
+ return node.nodeName === 'PRE' || node.nodeName === 'CODE'
651
+ }
652
+
653
+ function Node (node, options) {
654
+ node.isBlock = isBlock(node);
655
+ node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode;
656
+ node.isBlank = isBlank(node);
657
+ node.flankingWhitespace = flankingWhitespace(node, options);
658
+ return node
659
+ }
660
+
661
+ function isBlank (node) {
662
+ return (
663
+ !isVoid(node) &&
664
+ !isMeaningfulWhenBlank(node) &&
665
+ /^\s*$/i.test(node.textContent) &&
666
+ !hasVoid(node) &&
667
+ !hasMeaningfulWhenBlank(node)
668
+ )
669
+ }
670
+
671
+ function flankingWhitespace (node, options) {
672
+ if (node.isBlock || (options.preformattedCode && node.isCode)) {
673
+ return { leading: '', trailing: '' }
674
+ }
675
+
676
+ var edges = edgeWhitespace(node.textContent);
677
+
678
+ // abandon leading ASCII WS if left-flanked by ASCII WS
679
+ if (edges.leadingAscii && isFlankedByWhitespace('left', node, options)) {
680
+ edges.leading = edges.leadingNonAscii;
681
+ }
682
+
683
+ // abandon trailing ASCII WS if right-flanked by ASCII WS
684
+ if (edges.trailingAscii && isFlankedByWhitespace('right', node, options)) {
685
+ edges.trailing = edges.trailingNonAscii;
686
+ }
687
+
688
+ return { leading: edges.leading, trailing: edges.trailing }
689
+ }
690
+
691
+ function edgeWhitespace (string) {
692
+ var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/);
693
+ return {
694
+ leading: m[1], // whole string for whitespace-only strings
695
+ leadingAscii: m[2],
696
+ leadingNonAscii: m[3],
697
+ trailing: m[4], // empty for whitespace-only strings
698
+ trailingNonAscii: m[5],
699
+ trailingAscii: m[6]
700
+ }
701
+ }
702
+
703
+ function isFlankedByWhitespace (side, node, options) {
704
+ var sibling;
705
+ var regExp;
706
+ var isFlanked;
707
+
708
+ if (side === 'left') {
709
+ sibling = node.previousSibling;
710
+ regExp = / $/;
711
+ } else {
712
+ sibling = node.nextSibling;
713
+ regExp = /^ /;
714
+ }
715
+
716
+ if (sibling) {
717
+ if (sibling.nodeType === 3) {
718
+ isFlanked = regExp.test(sibling.nodeValue);
719
+ } else if (options.preformattedCode && sibling.nodeName === 'CODE') {
720
+ isFlanked = false;
721
+ } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
722
+ isFlanked = regExp.test(sibling.textContent);
723
+ }
724
+ }
725
+ return isFlanked
726
+ }
727
+
728
+ var reduce = Array.prototype.reduce;
729
+ var escapes = [
730
+ [/\\/g, '\\\\'],
731
+ [/\*/g, '\\*'],
732
+ [/^-/g, '\\-'],
733
+ [/^\+ /g, '\\+ '],
734
+ [/^(=+)/g, '\\$1'],
735
+ [/^(#{1,6}) /g, '\\$1 '],
736
+ [/`/g, '\\`'],
737
+ [/^~~~/g, '\\~~~'],
738
+ [/\[/g, '\\['],
739
+ [/\]/g, '\\]'],
740
+ [/^>/g, '\\>'],
741
+ [/_/g, '\\_'],
742
+ [/^(\d+)\. /g, '$1\\. ']
743
+ ];
744
+
745
+ function TurndownService (options) {
746
+ if (!(this instanceof TurndownService)) return new TurndownService(options)
747
+
748
+ var defaults = {
749
+ rules: rules,
750
+ headingStyle: 'setext',
751
+ hr: '* * *',
752
+ bulletListMarker: '*',
753
+ codeBlockStyle: 'indented',
754
+ fence: '```',
755
+ emDelimiter: '_',
756
+ strongDelimiter: '**',
757
+ linkStyle: 'inlined',
758
+ linkReferenceStyle: 'full',
759
+ br: ' ',
760
+ preformattedCode: false,
761
+ blankReplacement: function (content, node) {
762
+ return node.isBlock ? '\n\n' : ''
763
+ },
764
+ keepReplacement: function (content, node) {
765
+ return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
766
+ },
767
+ defaultReplacement: function (content, node) {
768
+ return node.isBlock ? '\n\n' + content + '\n\n' : content
769
+ }
770
+ };
771
+ this.options = extend({}, defaults, options);
772
+ this.rules = new Rules(this.options);
773
+ }
774
+
775
+ TurndownService.prototype = {
776
+ /**
777
+ * The entry point for converting a string or DOM node to Markdown
778
+ * @public
779
+ * @param {String|HTMLElement} input The string or DOM node to convert
780
+ * @returns A Markdown representation of the input
781
+ * @type String
782
+ */
783
+
784
+ turndown: function (input) {
785
+ if (!canConvert(input)) {
786
+ throw new TypeError(
787
+ input + ' is not a string, or an element/document/fragment node.'
788
+ )
789
+ }
790
+
791
+ if (input === '') return ''
792
+
793
+ var output = process.call(this, new RootNode(input, this.options));
794
+ return postProcess.call(this, output)
795
+ },
796
+
797
+ /**
798
+ * Add one or more plugins
799
+ * @public
800
+ * @param {Function|Array} plugin The plugin or array of plugins to add
801
+ * @returns The Turndown instance for chaining
802
+ * @type Object
803
+ */
804
+
805
+ use: function (plugin) {
806
+ if (Array.isArray(plugin)) {
807
+ for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
808
+ } else if (typeof plugin === 'function') {
809
+ plugin(this);
810
+ } else {
811
+ throw new TypeError('plugin must be a Function or an Array of Functions')
812
+ }
813
+ return this
814
+ },
815
+
816
+ /**
817
+ * Adds a rule
818
+ * @public
819
+ * @param {String} key The unique key of the rule
820
+ * @param {Object} rule The rule
821
+ * @returns The Turndown instance for chaining
822
+ * @type Object
823
+ */
824
+
825
+ addRule: function (key, rule) {
826
+ this.rules.add(key, rule);
827
+ return this
828
+ },
829
+
830
+ /**
831
+ * Keep a node (as HTML) that matches the filter
832
+ * @public
833
+ * @param {String|Array|Function} filter The unique key of the rule
834
+ * @returns The Turndown instance for chaining
835
+ * @type Object
836
+ */
837
+
838
+ keep: function (filter) {
839
+ this.rules.keep(filter);
840
+ return this
841
+ },
842
+
843
+ /**
844
+ * Remove a node that matches the filter
845
+ * @public
846
+ * @param {String|Array|Function} filter The unique key of the rule
847
+ * @returns The Turndown instance for chaining
848
+ * @type Object
849
+ */
850
+
851
+ remove: function (filter) {
852
+ this.rules.remove(filter);
853
+ return this
854
+ },
855
+
856
+ /**
857
+ * Escapes Markdown syntax
858
+ * @public
859
+ * @param {String} string The string to escape
860
+ * @returns A string with Markdown syntax escaped
861
+ * @type String
862
+ */
863
+
864
+ escape: function (string) {
865
+ return escapes.reduce(function (accumulator, escape) {
866
+ return accumulator.replace(escape[0], escape[1])
867
+ }, string)
868
+ }
869
+ };
870
+
871
+ /**
872
+ * Reduces a DOM node down to its Markdown string equivalent
873
+ * @private
874
+ * @param {HTMLElement} parentNode The node to convert
875
+ * @returns A Markdown representation of the node
876
+ * @type String
877
+ */
878
+
879
+ function process (parentNode) {
880
+ var self = this;
881
+ return reduce.call(parentNode.childNodes, function (output, node) {
882
+ node = new Node(node, self.options);
883
+
884
+ var replacement = '';
885
+ if (node.nodeType === 3) {
886
+ replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
887
+ } else if (node.nodeType === 1) {
888
+ replacement = replacementForNode.call(self, node);
889
+ }
890
+
891
+ return join(output, replacement)
892
+ }, '')
893
+ }
894
+
895
+ /**
896
+ * Appends strings as each rule requires and trims the output
897
+ * @private
898
+ * @param {String} output The conversion output
899
+ * @returns A trimmed version of the ouput
900
+ * @type String
901
+ */
902
+
903
+ function postProcess (output) {
904
+ var self = this;
905
+ this.rules.forEach(function (rule) {
906
+ if (typeof rule.append === 'function') {
907
+ output = join(output, rule.append(self.options));
908
+ }
909
+ });
910
+
911
+ return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
912
+ }
913
+
914
+ /**
915
+ * Converts an element node to its Markdown equivalent
916
+ * @private
917
+ * @param {HTMLElement} node The node to convert
918
+ * @returns A Markdown representation of the node
919
+ * @type String
920
+ */
921
+
922
+ function replacementForNode (node) {
923
+ var rule = this.rules.forNode(node);
924
+ var content = process.call(this, node);
925
+ var whitespace = node.flankingWhitespace;
926
+ if (whitespace.leading || whitespace.trailing) content = content.trim();
927
+ return (
928
+ whitespace.leading +
929
+ rule.replacement(content, node, this.options) +
930
+ whitespace.trailing
931
+ )
932
+ }
933
+
934
+ /**
935
+ * Joins replacement to the current output with appropriate number of new lines
936
+ * @private
937
+ * @param {String} output The current conversion output
938
+ * @param {String} replacement The string to append to the output
939
+ * @returns Joined output
940
+ * @type String
941
+ */
942
+
943
+ function join (output, replacement) {
944
+ var s1 = trimTrailingNewlines(output);
945
+ var s2 = trimLeadingNewlines(replacement);
946
+ var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
947
+ var separator = '\n\n'.substring(0, nls);
948
+
949
+ return s1 + separator + s2
950
+ }
951
+
952
+ /**
953
+ * Determines whether an input can be converted
954
+ * @private
955
+ * @param {String|HTMLElement} input Describe this parameter
956
+ * @returns Describe what it returns
957
+ * @type String|Object|Array|Boolean|Number
958
+ */
959
+
960
+ function canConvert (input) {
961
+ return (
962
+ input != null && (
963
+ typeof input === 'string' ||
964
+ (input.nodeType && (
965
+ input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
966
+ ))
967
+ )
968
+ )
969
+ }
970
+
971
+ return TurndownService;
972
+
973
+ }());