execonvert 0.4.0
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.
- package/CHANGELOG.md +79 -0
- package/README.md +194 -0
- package/THIRD_PARTY_NOTICES.md +42 -0
- package/bin/execonvert.js +21 -0
- package/dist/cli/app/public/THIRD_PARTY_NOTICES.md +32 -0
- package/dist/cli/app/public/base.elpx +0 -0
- package/dist/cli/app/public/exe_math_assets.zip +0 -0
- package/dist/cli/app/public/exelearning/app/common/common_i18n.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/exe_powered_logo/exe_powered_logo.png +0 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.ca.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.de.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.en.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.eo.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.es.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.eu.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.gl.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.it.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.pt.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.ro.js +79 -0
- package/dist/cli/app/public/exelearning/app/common/i18n/common_i18n.va.js +79 -0
- package/dist/cli/app/public/exelearning/bundles/common.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/content-css.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/idevices.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/libs.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/manifest.json +110 -0
- package/dist/cli/app/public/exelearning/bundles/themes/base.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/themes/flux.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/themes/neo.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/themes/nova.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/themes/universal.zip +0 -0
- package/dist/cli/app/public/exelearning/bundles/themes/zen.zip +0 -0
- package/dist/cli/app/public/exelearning/exporters.bundle.js +12638 -0
- package/dist/cli/app/public/exelearning/importers.bundle.js +14061 -0
- package/dist/cli/app/public/exelearning/runtime-source.json +10 -0
- package/dist/cli/app/public/favicon.svg +11 -0
- package/dist/cli/app/public/idevices/text/text.css +16 -0
- package/dist/cli/app/public/idevices/text/text.html +3 -0
- package/dist/cli/app/public/idevices/text/text.js +291 -0
- package/dist/cli/app/public/info/cli.html +955 -0
- package/dist/cli/app/public/info/docx.svg +7 -0
- package/dist/cli/app/public/info/elpx-icon.png +0 -0
- package/dist/cli/app/public/info/exe-old.png +0 -0
- package/dist/cli/app/public/info/execonvert-cli-icon.svg +16 -0
- package/dist/cli/app/public/info/execonvert-icon.svg +11 -0
- package/dist/cli/app/public/info/index.html +723 -0
- package/dist/cli/app/public/info/markdown.svg +1 -0
- package/dist/cli/app/public/info/pdf.svg +14 -0
- package/dist/cli/app/public/libs/exe_math/LICENSE +202 -0
- package/dist/cli/app/public/libs/exe_math/a11y/assistive-mml.js +1 -0
- package/dist/cli/app/public/libs/exe_math/a11y/complexity.js +1 -0
- package/dist/cli/app/public/libs/exe_math/a11y/explorer.js +1 -0
- package/dist/cli/app/public/libs/exe_math/a11y/semantic-enrich.js +1 -0
- package/dist/cli/app/public/libs/exe_math/a11y/speech.js +1 -0
- package/dist/cli/app/public/libs/exe_math/a11y/sre.js +1 -0
- package/dist/cli/app/public/libs/exe_math/adaptors/jsdom.js +1 -0
- package/dist/cli/app/public/libs/exe_math/adaptors/linkedom.js +1 -0
- package/dist/cli/app/public/libs/exe_math/adaptors/liteDOM.js +1 -0
- package/dist/cli/app/public/libs/exe_math/core.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/asciimath.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/mml/entities.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/mml/extensions/mml3.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/mml/extensions/mml3.sef.json +1 -0
- package/dist/cli/app/public/libs/exe_math/input/mml.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/action.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/ams.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/amscd.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/autoload.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/bbm.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/bboldx.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/bbox.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/begingroup.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/boldsymbol.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/braket.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/bussproofs.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/cancel.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/cases.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/centernot.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/color.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/colortbl.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/colorv2.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/configmacros.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/dsfont.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/empheq.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/enclose.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/extpfeil.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/gensymb.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/html.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/mathtools.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/mhchem.js +34 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/newcommand.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/noerrors.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/noundefined.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/physics.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/require.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/setoptions.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/tagformat.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/texhtml.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/textcomp.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/textmacros.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/unicode.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/units.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/upgreek.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex/extensions/verb.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex-base.js +1 -0
- package/dist/cli/app/public/libs/exe_math/input/tex.js +1 -0
- package/dist/cli/app/public/libs/exe_math/loader.js +1 -0
- package/dist/cli/app/public/libs/exe_math/output/chtml.js +1 -0
- package/dist/cli/app/public/libs/exe_math/output/svg.js +1 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/af.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/base.json +137 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/ca.json +140 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/da.json +140 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/de.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/en.json +158 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/es.json +140 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/euro.json +32 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/fr.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/hi.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/it.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/ko.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/nb.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/nemeth.json +125 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/nn.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/mathmaps/sv.json +146 -0
- package/dist/cli/app/public/libs/exe_math/sre/require.d.mts +1 -0
- package/dist/cli/app/public/libs/exe_math/sre/require.mjs +2 -0
- package/dist/cli/app/public/libs/exe_math/sre/speech-worker.js +1 -0
- package/dist/cli/app/public/libs/exe_math/startup.js +1 -0
- package/dist/cli/app/public/libs/exe_math/tex-mml-svg.js +1 -0
- package/dist/cli/app/public/libs/exe_math/ui/lazy.js +1 -0
- package/dist/cli/app/public/libs/exe_math/ui/menu.js +1 -0
- package/dist/cli/app/public/libs/exe_math/ui/safe.js +1 -0
- package/dist/cli/cli/execonvert.js +807 -0
- package/dist/cli/cli/runtime.js +237 -0
- package/dist/cli/package.json +3 -0
- package/dist/cli/src/converter.js +5078 -0
- package/dist/cli/src/docx-import.js +1121 -0
- package/dist/cli/src/elpx-markdown.js +201 -0
- package/dist/cli/src/i18n.js +485 -0
- package/dist/cli/src/index.js +1 -0
- package/dist/cli/src/legacy-elp.js +846 -0
- package/dist/cli/src/markdown-import.js +26 -0
- package/package.json +68 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import TurndownService from 'turndown';
|
|
2
|
+
// @ts-expect-error turndown-plugin-gfm does not ship TypeScript declarations.
|
|
3
|
+
import { gfm } from 'turndown-plugin-gfm';
|
|
4
|
+
import { convertElpxToHtml } from './converter.js';
|
|
5
|
+
export async function convertElpxToMarkdown(file, options, onProgress) {
|
|
6
|
+
const htmlResult = await convertElpxToHtml(file, {
|
|
7
|
+
selectedPageIds: options.selectedPageIds,
|
|
8
|
+
// Markdown should be generated from the stable exported source, not from rendered browser output.
|
|
9
|
+
useRenderedPages: false,
|
|
10
|
+
}, onProgress);
|
|
11
|
+
onProgress?.({ phase: 'render', message: 'Convirtiendo HTML a Markdown...', messageKey: 'progress.htmlToMarkdown' });
|
|
12
|
+
const markdown = normalizeGeneratedMarkdown(convertHtmlDocumentToMarkdown(htmlResult.html, options));
|
|
13
|
+
return {
|
|
14
|
+
blob: new Blob([markdown], { type: 'text/markdown;charset=utf-8' }),
|
|
15
|
+
filename: toMarkdownFilename(file.name),
|
|
16
|
+
pageCount: htmlResult.pageCount,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function normalizeGeneratedMarkdown(markdown) {
|
|
20
|
+
return markdown
|
|
21
|
+
.replace(/\n{2,}\d+\n{2,}(?=#{3,6}\s)/g, '\n\n')
|
|
22
|
+
.replace(/[ \t]+\n/g, '\n')
|
|
23
|
+
.replace(/\n{3,}/g, '\n\n');
|
|
24
|
+
}
|
|
25
|
+
function convertHtmlDocumentToMarkdown(html, options) {
|
|
26
|
+
const document = new DOMParser().parseFromString(html, 'text/html');
|
|
27
|
+
const root = document.body;
|
|
28
|
+
const title = root.querySelector('h1')?.textContent?.trim() || '';
|
|
29
|
+
const subtitle = root.querySelector('.project-subtitle')?.textContent?.trim() || '';
|
|
30
|
+
const sections = Array.from(root.querySelectorAll('section.page'));
|
|
31
|
+
const turndown = createTurndownService(options);
|
|
32
|
+
const parts = [];
|
|
33
|
+
if (title) {
|
|
34
|
+
parts.push(`**${title}**`);
|
|
35
|
+
}
|
|
36
|
+
if (subtitle) {
|
|
37
|
+
parts.push(`_${subtitle}_`);
|
|
38
|
+
}
|
|
39
|
+
if (sections.length === 0) {
|
|
40
|
+
const markdown = turndownFragment(root, turndown, options).trim();
|
|
41
|
+
if (markdown) {
|
|
42
|
+
parts.push(markdown);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
for (const section of sections) {
|
|
47
|
+
const sectionMarkdown = turndownFragment(section, turndown, options).trim();
|
|
48
|
+
if (sectionMarkdown) {
|
|
49
|
+
parts.push(sectionMarkdown);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return parts.filter(Boolean).join('\n\n').trimEnd() + '\n';
|
|
54
|
+
}
|
|
55
|
+
function createTurndownService(options) {
|
|
56
|
+
const turndown = new TurndownService({
|
|
57
|
+
headingStyle: 'atx',
|
|
58
|
+
codeBlockStyle: 'fenced',
|
|
59
|
+
bulletListMarker: '-',
|
|
60
|
+
emDelimiter: '_',
|
|
61
|
+
strongDelimiter: '**',
|
|
62
|
+
});
|
|
63
|
+
turndown.use(gfm);
|
|
64
|
+
turndown.addRule('imageHandling', {
|
|
65
|
+
filter: 'img',
|
|
66
|
+
replacement: (_content, node) => {
|
|
67
|
+
const element = node;
|
|
68
|
+
const alt = element.getAttribute('alt') || 'Imagen';
|
|
69
|
+
const src = element.getAttribute('src') || '';
|
|
70
|
+
if (!options.includeImages) {
|
|
71
|
+
return alt ? `_${alt}_` : '';
|
|
72
|
+
}
|
|
73
|
+
return src ? `` : alt;
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
turndown.addRule('sectionRule', {
|
|
77
|
+
filter: 'section',
|
|
78
|
+
replacement: (content) => `\n\n${content.trim()}\n\n`,
|
|
79
|
+
});
|
|
80
|
+
return turndown;
|
|
81
|
+
}
|
|
82
|
+
function turndownFragment(root, turndown, options) {
|
|
83
|
+
const clone = root.cloneNode(true);
|
|
84
|
+
const tableTokens = replaceTablesWithMarkdownTokens(clone, options);
|
|
85
|
+
let markdown = turndown.turndown(clone.innerHTML);
|
|
86
|
+
for (const [token, tableMarkdown] of tableTokens) {
|
|
87
|
+
markdown = markdown.replace(token, `\n\n${tableMarkdown}\n\n`);
|
|
88
|
+
}
|
|
89
|
+
return markdown;
|
|
90
|
+
}
|
|
91
|
+
function toMarkdownFilename(inputName) {
|
|
92
|
+
const stem = inputName.replace(/\.[^.]+$/, '') || 'documento';
|
|
93
|
+
return `${stem}.md`;
|
|
94
|
+
}
|
|
95
|
+
function replaceTablesWithMarkdownTokens(root, options) {
|
|
96
|
+
const cellTurndown = createTurndownService(options);
|
|
97
|
+
const tokens = new Map();
|
|
98
|
+
const tables = Array.from(root.querySelectorAll('table')).reverse();
|
|
99
|
+
tables.forEach((table, index) => {
|
|
100
|
+
const markdown = tableElementToMarkdown(table, cellTurndown);
|
|
101
|
+
const token = `EXE_MD_TABLE_${index}_${Math.random().toString(36).slice(2, 10)}`;
|
|
102
|
+
tokens.set(token, markdown);
|
|
103
|
+
table.replaceWith(root.ownerDocument.createTextNode(token));
|
|
104
|
+
});
|
|
105
|
+
return tokens;
|
|
106
|
+
}
|
|
107
|
+
function tableElementToMarkdown(table, cellTurndown) {
|
|
108
|
+
const rows = extractTableRows(table, cellTurndown);
|
|
109
|
+
if (rows.length === 0) {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
const columnCount = Math.max(...rows.map(row => row.length));
|
|
113
|
+
if (columnCount === 0) {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
const normalizedRows = rows.map(row => {
|
|
117
|
+
const padded = row.slice();
|
|
118
|
+
while (padded.length < columnCount) {
|
|
119
|
+
padded.push('');
|
|
120
|
+
}
|
|
121
|
+
return padded;
|
|
122
|
+
});
|
|
123
|
+
const header = normalizedRows[0];
|
|
124
|
+
const body = normalizedRows.slice(1);
|
|
125
|
+
const separator = header.map(() => '---');
|
|
126
|
+
const lines = [
|
|
127
|
+
`| ${header.join(' | ')} |`,
|
|
128
|
+
`| ${separator.join(' | ')} |`,
|
|
129
|
+
...body.map(row => `| ${row.join(' | ')} |`),
|
|
130
|
+
];
|
|
131
|
+
return lines.join('\n');
|
|
132
|
+
}
|
|
133
|
+
function extractTableRows(table, cellTurndown) {
|
|
134
|
+
const view = table.ownerDocument.defaultView;
|
|
135
|
+
const HTMLElementCtor = view?.HTMLElement;
|
|
136
|
+
const HTMLTableRowElementCtor = view?.HTMLTableRowElement;
|
|
137
|
+
const HTMLTableCellElementCtor = view?.HTMLTableCellElement;
|
|
138
|
+
const rowGroups = Array.from(table.children).filter((child) => {
|
|
139
|
+
const isElement = HTMLElementCtor ? child instanceof HTMLElementCtor : child.nodeType === 1;
|
|
140
|
+
return isElement && ['thead', 'tbody', 'tfoot'].includes(child.tagName.toLowerCase());
|
|
141
|
+
});
|
|
142
|
+
const directRows = rowGroups.length > 0
|
|
143
|
+
? rowGroups.flatMap(group => Array.from(group.children))
|
|
144
|
+
: Array.from(table.children);
|
|
145
|
+
const tableRows = directRows.filter((row) => {
|
|
146
|
+
if (HTMLTableRowElementCtor) {
|
|
147
|
+
return row instanceof HTMLTableRowElementCtor;
|
|
148
|
+
}
|
|
149
|
+
return row.nodeType === 1 && row.tagName.toLowerCase() === 'tr';
|
|
150
|
+
});
|
|
151
|
+
const grid = [];
|
|
152
|
+
for (const rowElement of tableRows) {
|
|
153
|
+
const rowIndex = grid.length;
|
|
154
|
+
const row = grid[rowIndex] || [];
|
|
155
|
+
let columnIndex = 0;
|
|
156
|
+
while (row[columnIndex] !== undefined) {
|
|
157
|
+
columnIndex += 1;
|
|
158
|
+
}
|
|
159
|
+
for (const cell of Array.from(rowElement.children)) {
|
|
160
|
+
const isTableCell = HTMLTableCellElementCtor
|
|
161
|
+
? cell instanceof HTMLTableCellElementCtor
|
|
162
|
+
: cell.nodeType === 1 && /^(td|th)$/i.test(cell.tagName);
|
|
163
|
+
if (!isTableCell) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const tableCell = cell;
|
|
167
|
+
while (row[columnIndex] !== undefined) {
|
|
168
|
+
columnIndex += 1;
|
|
169
|
+
}
|
|
170
|
+
const colspan = Math.max(1, Number.parseInt(tableCell.getAttribute('colspan') || '1', 10) || 1);
|
|
171
|
+
const rowspan = Math.max(1, Number.parseInt(tableCell.getAttribute('rowspan') || '1', 10) || 1);
|
|
172
|
+
const content = normalizeTableCell(cellToMarkdown(tableCell, cellTurndown));
|
|
173
|
+
for (let rowOffset = 0; rowOffset < rowspan; rowOffset += 1) {
|
|
174
|
+
const targetRow = grid[rowIndex + rowOffset] || [];
|
|
175
|
+
grid[rowIndex + rowOffset] = targetRow;
|
|
176
|
+
for (let colOffset = 0; colOffset < colspan; colOffset += 1) {
|
|
177
|
+
targetRow[columnIndex + colOffset] = rowOffset === 0 && colOffset === 0 ? content : '';
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
columnIndex += colspan;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return grid.filter(row => row.some(cell => cell !== undefined && cell !== ''));
|
|
184
|
+
}
|
|
185
|
+
function cellToMarkdown(cell, cellTurndown) {
|
|
186
|
+
const clone = cell.cloneNode(true);
|
|
187
|
+
for (const nestedTable of Array.from(clone.querySelectorAll('table'))) {
|
|
188
|
+
nestedTable.replaceWith(clone.ownerDocument.createTextNode(normalizeTableCell(nestedTable.textContent || '')));
|
|
189
|
+
}
|
|
190
|
+
return cellTurndown.turndown(clone.innerHTML);
|
|
191
|
+
}
|
|
192
|
+
function normalizeTableCell(value) {
|
|
193
|
+
return value
|
|
194
|
+
.replace(/\r/g, '')
|
|
195
|
+
.replace(/\n{2,}/g, '<br><br>')
|
|
196
|
+
.replace(/\n/g, '<br>')
|
|
197
|
+
.replace(/\s+/g, ' ')
|
|
198
|
+
.replace(/<br>(?:\s*<br>)+/g, '<br><br>')
|
|
199
|
+
.replace(/\|/g, '\\|')
|
|
200
|
+
.trim();
|
|
201
|
+
}
|