@teleporthq/teleport-shared 0.43.71 → 0.43.75
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/__tests__/_fixtures/rich-text/README.md +6 -0
- package/__tests__/_fixtures/rich-text/help-accept-an-invitation.html +50 -0
- package/__tests__/_fixtures/rich-text/help-activate-an-appsumo-license.html +44 -0
- package/__tests__/_fixtures/rich-text/help-add-custom-code-to-your-site.html +61 -0
- package/__tests__/_fixtures/rich-text/help-connect-a-custom-domain.html +106 -0
- package/__tests__/_fixtures/rich-text/help-custom-animations-with-code.html +69 -0
- package/__tests__/_fixtures/rich-text/help-generate-a-store.html +78 -0
- package/__tests__/_fixtures/rich-text/help-keyboard-shortcuts.html +417 -0
- package/__tests__/_fixtures/rich-text/help-prompting-tips.html +82 -0
- package/__tests__/_fixtures/rich-text/help-sitemap-robots-and-llms-txt.html +82 -0
- package/__tests__/_fixtures/rich-text/help-use-a-csv-file-or-static-data.html +61 -0
- package/__tests__/_helpers/rich-text-content-runtime-emitter.ts +117 -0
- package/__tests__/function-sources.ts +30 -0
- package/__tests__/utils/content-tables.ts +69 -0
- package/__tests__/utils/rich-text-content-runtime-module.ts +115 -0
- package/__tests__/utils/rich-text-content.ts +131 -0
- package/dist/cjs/index.d.ts +4 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +7 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/page-transition/index.d.ts +1 -0
- package/dist/cjs/page-transition/index.d.ts.map +1 -1
- package/dist/cjs/page-transition/index.js +1 -0
- package/dist/cjs/page-transition/index.js.map +1 -1
- package/dist/cjs/page-transition/variant-sources.generated.d.ts +7 -0
- package/dist/cjs/page-transition/variant-sources.generated.d.ts.map +1 -0
- package/dist/cjs/page-transition/variant-sources.generated.js +14 -0
- package/dist/cjs/page-transition/variant-sources.generated.js.map +1 -0
- package/dist/cjs/scroll-scene/engine-source.d.ts.map +1 -1
- package/dist/cjs/scroll-scene/engine-source.js +2 -5
- package/dist/cjs/scroll-scene/engine-source.js.map +1 -1
- package/dist/cjs/scroll-scene/helper-sources.generated.d.ts +9 -0
- package/dist/cjs/scroll-scene/helper-sources.generated.d.ts.map +1 -0
- package/dist/cjs/scroll-scene/helper-sources.generated.js +16 -0
- package/dist/cjs/scroll-scene/helper-sources.generated.js.map +1 -0
- package/dist/cjs/scroll-scene/index.d.ts +1 -0
- package/dist/cjs/scroll-scene/index.d.ts.map +1 -1
- package/dist/cjs/scroll-scene/index.js +3 -1
- package/dist/cjs/scroll-scene/index.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils/content-tables.d.ts +78 -0
- package/dist/cjs/utils/content-tables.d.ts.map +1 -0
- package/dist/cjs/utils/content-tables.js +123 -0
- package/dist/cjs/utils/content-tables.js.map +1 -0
- package/dist/cjs/utils/rich-text-content-codegen.d.ts +20 -0
- package/dist/cjs/utils/rich-text-content-codegen.d.ts.map +1 -0
- package/dist/cjs/utils/rich-text-content-codegen.js +55 -0
- package/dist/cjs/utils/rich-text-content-codegen.js.map +1 -0
- package/dist/cjs/utils/rich-text-content-runtime-source.d.ts +2 -0
- package/dist/cjs/utils/rich-text-content-runtime-source.d.ts.map +1 -0
- package/dist/cjs/utils/rich-text-content-runtime-source.js +591 -0
- package/dist/cjs/utils/rich-text-content-runtime-source.js.map +1 -0
- package/dist/cjs/utils/rich-text-content.d.ts +150 -0
- package/dist/cjs/utils/rich-text-content.d.ts.map +1 -0
- package/dist/cjs/utils/rich-text-content.js +649 -0
- package/dist/cjs/utils/rich-text-content.js.map +1 -0
- package/dist/cjs/utils/table-access.d.ts.map +1 -1
- package/dist/cjs/utils/table-access.js +5 -7
- package/dist/cjs/utils/table-access.js.map +1 -1
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/page-transition/index.d.ts +1 -0
- package/dist/esm/page-transition/index.d.ts.map +1 -1
- package/dist/esm/page-transition/index.js +1 -0
- package/dist/esm/page-transition/index.js.map +1 -1
- package/dist/esm/page-transition/variant-sources.generated.d.ts +7 -0
- package/dist/esm/page-transition/variant-sources.generated.d.ts.map +1 -0
- package/dist/esm/page-transition/variant-sources.generated.js +11 -0
- package/dist/esm/page-transition/variant-sources.generated.js.map +1 -0
- package/dist/esm/scroll-scene/engine-source.d.ts.map +1 -1
- package/dist/esm/scroll-scene/engine-source.js +2 -5
- package/dist/esm/scroll-scene/engine-source.js.map +1 -1
- package/dist/esm/scroll-scene/helper-sources.generated.d.ts +9 -0
- package/dist/esm/scroll-scene/helper-sources.generated.d.ts.map +1 -0
- package/dist/esm/scroll-scene/helper-sources.generated.js +13 -0
- package/dist/esm/scroll-scene/helper-sources.generated.js.map +1 -0
- package/dist/esm/scroll-scene/index.d.ts +1 -0
- package/dist/esm/scroll-scene/index.d.ts.map +1 -1
- package/dist/esm/scroll-scene/index.js +1 -0
- package/dist/esm/scroll-scene/index.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils/content-tables.d.ts +78 -0
- package/dist/esm/utils/content-tables.d.ts.map +1 -0
- package/dist/esm/utils/content-tables.js +114 -0
- package/dist/esm/utils/content-tables.js.map +1 -0
- package/dist/esm/utils/rich-text-content-codegen.d.ts +20 -0
- package/dist/esm/utils/rich-text-content-codegen.d.ts.map +1 -0
- package/dist/esm/utils/rich-text-content-codegen.js +50 -0
- package/dist/esm/utils/rich-text-content-codegen.js.map +1 -0
- package/dist/esm/utils/rich-text-content-runtime-source.d.ts +2 -0
- package/dist/esm/utils/rich-text-content-runtime-source.d.ts.map +1 -0
- package/dist/esm/utils/rich-text-content-runtime-source.js +588 -0
- package/dist/esm/utils/rich-text-content-runtime-source.js.map +1 -0
- package/dist/esm/utils/rich-text-content.d.ts +150 -0
- package/dist/esm/utils/rich-text-content.d.ts.map +1 -0
- package/dist/esm/utils/rich-text-content.js +613 -0
- package/dist/esm/utils/rich-text-content.js.map +1 -0
- package/dist/esm/utils/table-access.d.ts.map +1 -1
- package/dist/esm/utils/table-access.js +5 -7
- package/dist/esm/utils/table-access.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +6 -0
- package/src/page-transition/index.ts +1 -0
- package/src/page-transition/variant-sources.generated.ts +14 -0
- package/src/scroll-scene/engine-source.ts +7 -10
- package/src/scroll-scene/helper-sources.generated.ts +18 -0
- package/src/scroll-scene/index.ts +1 -0
- package/src/utils/content-tables.ts +151 -0
- package/src/utils/rich-text-content-codegen.ts +52 -0
- package/src/utils/rich-text-content-runtime-source.ts +587 -0
- package/src/utils/rich-text-content.ts +677 -0
- package/src/utils/table-access.ts +4 -2
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The stored form of rich-text content (a blog post body, a product
|
|
4
|
+
* description) and its editor form.
|
|
5
|
+
*
|
|
6
|
+
* STORED: plain HTML — `<p>`, `<h1>`–`<h6>`, nested `<ul>`/`<ol>`, `<blockquote>`
|
|
7
|
+
* holding paragraphs, `<pre><code class="language-x">`, `<table>` with its
|
|
8
|
+
* `<thead>`/`<th>`, `<aside class="tq-callout" data-kind="note">`, the image and
|
|
9
|
+
* embed figures, and inline marks. What a published page renders and what an
|
|
10
|
+
* import writes.
|
|
11
|
+
*
|
|
12
|
+
* EDITOR: what a Quill editor can hold without rewriting it. Lists become one
|
|
13
|
+
* flat `<ol>` of `<li data-list>` lines with `ql-indent-N` for nesting, a
|
|
14
|
+
* blockquote becomes one `<blockquote>` line per paragraph, and everything Quill
|
|
15
|
+
* has no blot for — a table, a code block, a callout, a list whose items hold
|
|
16
|
+
* blocks, anything unknown — is wrapped in a PROTECTED block:
|
|
17
|
+
* `<div class="tq-protected" data-tq-protected="table" contenteditable="false">`
|
|
18
|
+
* holding the stored markup untouched. The editors register that wrapper as a
|
|
19
|
+
* block embed, so Quill treats it as one atomic unit and never looks inside.
|
|
20
|
+
*
|
|
21
|
+
* Both editors (the studio post form on the `quill` fork, the generated admin
|
|
22
|
+
* panel on react-quill-new) run `toEditorHtml` on the way in and
|
|
23
|
+
* `fromEditorHtml` on the way out. `normalizeLegacyRichTextHtml` additionally
|
|
24
|
+
* understands what the two editors wrote BEFORE this contract existed, so an
|
|
25
|
+
* older post is cleaned on its next save and renders right meanwhile — it is
|
|
26
|
+
* string-only, so the generated project can run it where there is no DOM.
|
|
27
|
+
*
|
|
28
|
+
* Emission rules (see `__tests__/_helpers/rich-text-content-runtime-emitter.ts`):
|
|
29
|
+
* the generated admin editor receives these very functions printed as a module,
|
|
30
|
+
* so an exported function may call only other exported functions and the
|
|
31
|
+
* constants below — never an import or a module-private helper.
|
|
32
|
+
*/
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.mergeBlockquoteLines = exports.rebuildQuillCodeBlockHtml = exports.rebuildQuillListHtml = exports.normalizeLegacyRichTextHtml = exports.trimEmptyEdgeParagraphs = exports.toCanonicalRichTextHtml = exports.fromEditorHtml = exports.toEditorHtml = exports.protectedKindForElement = exports.blockquoteLinesForQuill = exports.isQuillSimpleBlockquote = exports.flattenListForQuill = exports.isQuillSimpleList = exports.readInlineHtml = exports.serializeRichTextNode = exports.wrapBareBlockquoteContent = exports.normalizeLinkTargets = exports.isExternalWebLink = exports.unwrapSingleParagraphListItems = exports.stripInterBlockWhitespace = exports.isRichTextBlockElement = exports.isBlankTextNode = exports.isRichTextInlineNode = exports.hasClass = exports.buildCodeBlockHtml = exports.buildCalloutHtml = exports.isCalloutKind = exports.readProtectedBlockValue = exports.buildProtectedBlockHtml = exports.isProtectedBlockKind = exports.escapeRichTextAttribute = exports.escapeRichTextText = exports.parseRichTextFragment = exports.RICH_TEXT_BLOCK_TAGS = exports.RICH_TEXT_INLINE_TAGS = exports.QUILL_INDENT_CLASS_PREFIX = exports.QUILL_LIST_ITEM_ATTR = exports.RICH_TEXT_IMAGE_CLASS = exports.RICH_TEXT_EMBED_CLASS = exports.CALLOUT_KINDS = exports.CALLOUT_KIND_ATTR = exports.CALLOUT_CLASS = exports.PROTECTED_BLOCK_KINDS = exports.PROTECTED_BLOCK_BLOT_NAME = exports.PROTECTED_BLOCK_ATTR = exports.PROTECTED_BLOCK_CLASS = void 0;
|
|
35
|
+
exports.PROTECTED_BLOCK_CLASS = 'tq-protected';
|
|
36
|
+
exports.PROTECTED_BLOCK_ATTR = 'data-tq-protected';
|
|
37
|
+
exports.PROTECTED_BLOCK_BLOT_NAME = 'tq-protected-block';
|
|
38
|
+
exports.PROTECTED_BLOCK_KINDS = ['table', 'code', 'callout', 'list', 'quote', 'html'];
|
|
39
|
+
exports.CALLOUT_CLASS = 'tq-callout';
|
|
40
|
+
exports.CALLOUT_KIND_ATTR = 'data-kind';
|
|
41
|
+
exports.CALLOUT_KINDS = ['note', 'tip', 'important', 'warning', 'caution'];
|
|
42
|
+
/** ⛔ PAIRED with `EMBED_CLASS_NAME` in `rich-text-embeds.ts` (a test keeps them equal). */
|
|
43
|
+
exports.RICH_TEXT_EMBED_CLASS = 'tq-embed';
|
|
44
|
+
/** ⛔ PAIRED with the image blot in teleport-gui `features/blog/components/content-image-blot.ts`. */
|
|
45
|
+
exports.RICH_TEXT_IMAGE_CLASS = 'ql-content-image';
|
|
46
|
+
exports.QUILL_LIST_ITEM_ATTR = 'data-list';
|
|
47
|
+
exports.QUILL_INDENT_CLASS_PREFIX = 'ql-indent-';
|
|
48
|
+
/** Marks that can sit inside a line; anything else is a block to Quill. */
|
|
49
|
+
exports.RICH_TEXT_INLINE_TAGS = [
|
|
50
|
+
'A',
|
|
51
|
+
'ABBR',
|
|
52
|
+
'B',
|
|
53
|
+
'BR',
|
|
54
|
+
'CODE',
|
|
55
|
+
'DEL',
|
|
56
|
+
'EM',
|
|
57
|
+
'I',
|
|
58
|
+
'IMG',
|
|
59
|
+
'INS',
|
|
60
|
+
'KBD',
|
|
61
|
+
'MARK',
|
|
62
|
+
'S',
|
|
63
|
+
'SMALL',
|
|
64
|
+
'SPAN',
|
|
65
|
+
'STRIKE',
|
|
66
|
+
'STRONG',
|
|
67
|
+
'SUB',
|
|
68
|
+
'SUP',
|
|
69
|
+
'U',
|
|
70
|
+
];
|
|
71
|
+
/** Elements that stand on their own line; white space between two of them carries nothing. */
|
|
72
|
+
exports.RICH_TEXT_BLOCK_TAGS = [
|
|
73
|
+
'ARTICLE',
|
|
74
|
+
'ASIDE',
|
|
75
|
+
'BLOCKQUOTE',
|
|
76
|
+
'DD',
|
|
77
|
+
'DETAILS',
|
|
78
|
+
'DIV',
|
|
79
|
+
'DL',
|
|
80
|
+
'DT',
|
|
81
|
+
'FIGCAPTION',
|
|
82
|
+
'FIGURE',
|
|
83
|
+
'FOOTER',
|
|
84
|
+
'FORM',
|
|
85
|
+
'H1',
|
|
86
|
+
'H2',
|
|
87
|
+
'H3',
|
|
88
|
+
'H4',
|
|
89
|
+
'H5',
|
|
90
|
+
'H6',
|
|
91
|
+
'HEADER',
|
|
92
|
+
'HR',
|
|
93
|
+
'LI',
|
|
94
|
+
'MAIN',
|
|
95
|
+
'NAV',
|
|
96
|
+
'OL',
|
|
97
|
+
'P',
|
|
98
|
+
'PRE',
|
|
99
|
+
'SECTION',
|
|
100
|
+
'SUMMARY',
|
|
101
|
+
'TABLE',
|
|
102
|
+
'TBODY',
|
|
103
|
+
'TD',
|
|
104
|
+
'TFOOT',
|
|
105
|
+
'TH',
|
|
106
|
+
'THEAD',
|
|
107
|
+
'TR',
|
|
108
|
+
'UL',
|
|
109
|
+
];
|
|
110
|
+
/** Parses an HTML fragment into a detached body the way a browser would. */
|
|
111
|
+
function parseRichTextFragment(html) {
|
|
112
|
+
var doc = new DOMParser().parseFromString('<!doctype html><html><body>' + html, 'text/html');
|
|
113
|
+
return doc.body;
|
|
114
|
+
}
|
|
115
|
+
exports.parseRichTextFragment = parseRichTextFragment;
|
|
116
|
+
function escapeRichTextText(value) {
|
|
117
|
+
return String(value).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
118
|
+
}
|
|
119
|
+
exports.escapeRichTextText = escapeRichTextText;
|
|
120
|
+
function escapeRichTextAttribute(value) {
|
|
121
|
+
return escapeRichTextText(value).replace(/"/g, '"');
|
|
122
|
+
}
|
|
123
|
+
exports.escapeRichTextAttribute = escapeRichTextAttribute;
|
|
124
|
+
function isProtectedBlockKind(value) {
|
|
125
|
+
return exports.PROTECTED_BLOCK_KINDS.indexOf(String(value)) !== -1;
|
|
126
|
+
}
|
|
127
|
+
exports.isProtectedBlockKind = isProtectedBlockKind;
|
|
128
|
+
/** The editor-side wrapper for one stored block. */
|
|
129
|
+
function buildProtectedBlockHtml(kind, html) {
|
|
130
|
+
return ("<div class=\"".concat(exports.PROTECTED_BLOCK_CLASS, "\" ").concat(exports.PROTECTED_BLOCK_ATTR, "=\"").concat(kind, "\" contenteditable=\"false\">") +
|
|
131
|
+
html +
|
|
132
|
+
'</div>');
|
|
133
|
+
}
|
|
134
|
+
exports.buildProtectedBlockHtml = buildProtectedBlockHtml;
|
|
135
|
+
function readProtectedBlockValue(element) {
|
|
136
|
+
var kind = element.getAttribute(exports.PROTECTED_BLOCK_ATTR);
|
|
137
|
+
return {
|
|
138
|
+
kind: isProtectedBlockKind(kind) ? kind : 'html',
|
|
139
|
+
html: element.innerHTML,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
exports.readProtectedBlockValue = readProtectedBlockValue;
|
|
143
|
+
function isCalloutKind(value) {
|
|
144
|
+
return exports.CALLOUT_KINDS.indexOf(String(value)) !== -1;
|
|
145
|
+
}
|
|
146
|
+
exports.isCalloutKind = isCalloutKind;
|
|
147
|
+
/** The stored markup of a callout: a kind and the blocks it holds. */
|
|
148
|
+
function buildCalloutHtml(kind, innerHtml) {
|
|
149
|
+
return "<aside class=\"".concat(exports.CALLOUT_CLASS, "\" ").concat(exports.CALLOUT_KIND_ATTR, "=\"").concat(kind, "\">").concat(innerHtml, "</aside>");
|
|
150
|
+
}
|
|
151
|
+
exports.buildCalloutHtml = buildCalloutHtml;
|
|
152
|
+
/** The stored markup of a code block; `code` is already HTML-escaped when `escaped` is set. */
|
|
153
|
+
function buildCodeBlockHtml(language, code, escaped) {
|
|
154
|
+
var text = escaped ? code : escapeRichTextText(code || '');
|
|
155
|
+
var lang = String(language || '').replace(/[^\w.+#-]/g, '');
|
|
156
|
+
var classAttr = lang && lang !== 'plain' ? " class=\"language-".concat(lang, "\"") : '';
|
|
157
|
+
return "<pre><code".concat(classAttr, ">").concat(text, "</code></pre>");
|
|
158
|
+
}
|
|
159
|
+
exports.buildCodeBlockHtml = buildCodeBlockHtml;
|
|
160
|
+
function hasClass(element, className) {
|
|
161
|
+
var classes = (element.getAttribute('class') || '').split(/\s+/);
|
|
162
|
+
return classes.indexOf(className) !== -1;
|
|
163
|
+
}
|
|
164
|
+
exports.hasClass = hasClass;
|
|
165
|
+
function isRichTextInlineNode(node) {
|
|
166
|
+
if (node.nodeType === 3 || node.nodeType === 8) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
if (node.nodeType !== 1) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
return exports.RICH_TEXT_INLINE_TAGS.indexOf(node.tagName) !== -1;
|
|
173
|
+
}
|
|
174
|
+
exports.isRichTextInlineNode = isRichTextInlineNode;
|
|
175
|
+
function isBlankTextNode(node) {
|
|
176
|
+
return node.nodeType === 3 && !/\S/.test(node.nodeValue || '');
|
|
177
|
+
}
|
|
178
|
+
exports.isBlankTextNode = isBlankTextNode;
|
|
179
|
+
function isRichTextBlockElement(node) {
|
|
180
|
+
return (!!node && node.nodeType === 1 && exports.RICH_TEXT_BLOCK_TAGS.indexOf(node.tagName) !== -1);
|
|
181
|
+
}
|
|
182
|
+
exports.isRichTextBlockElement = isRichTextBlockElement;
|
|
183
|
+
/**
|
|
184
|
+
* Drops the white space that only separates blocks (the newlines a Markdown
|
|
185
|
+
* renderer puts between `<li>`s, after `</p>`) and collapses runs of it inside
|
|
186
|
+
* text to the one space they render as, so stored HTML has one spelling
|
|
187
|
+
* whatever wrote it. Everything inside `<pre>` stays.
|
|
188
|
+
*/
|
|
189
|
+
function stripInterBlockWhitespace(root) {
|
|
190
|
+
if (root.nodeType === 1 && root.tagName === 'PRE') {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
var rootIsBlock = root.nodeType !== 1 || isRichTextBlockElement(root);
|
|
194
|
+
var children = Array.prototype.slice.call(root.childNodes);
|
|
195
|
+
children.forEach(function (child) {
|
|
196
|
+
if (child.nodeType === 3) {
|
|
197
|
+
var afterBlock = isRichTextBlockElement(child.previousSibling) || (rootIsBlock && !child.previousSibling);
|
|
198
|
+
var beforeBlock = isRichTextBlockElement(child.nextSibling) || (rootIsBlock && !child.nextSibling);
|
|
199
|
+
// A run of white space renders as one space; stored HTML keeps it that way
|
|
200
|
+
// (a no-break space is not white space here).
|
|
201
|
+
var text = (child.nodeValue || '').replace(/[ \t\r\n\f]+/g, ' ');
|
|
202
|
+
if (afterBlock) {
|
|
203
|
+
text = text.replace(/^\s+/, '');
|
|
204
|
+
}
|
|
205
|
+
if (beforeBlock) {
|
|
206
|
+
text = text.replace(/\s+$/, '');
|
|
207
|
+
}
|
|
208
|
+
if (!text && (afterBlock || beforeBlock)) {
|
|
209
|
+
root.removeChild(child);
|
|
210
|
+
}
|
|
211
|
+
else if (text !== child.nodeValue) {
|
|
212
|
+
child.nodeValue = text;
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (child.nodeType === 1) {
|
|
217
|
+
stripInterBlockWhitespace(child);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
exports.stripInterBlockWhitespace = stripInterBlockWhitespace;
|
|
222
|
+
/** `<li><p>one paragraph</p></li>` means the same as `<li>one paragraph</li>`; stored HTML uses the short form. */
|
|
223
|
+
function unwrapSingleParagraphListItems(root) {
|
|
224
|
+
Array.prototype.slice.call(root.querySelectorAll('li')).forEach(function (item) {
|
|
225
|
+
var paragraphs = Array.prototype.slice
|
|
226
|
+
.call(item.children)
|
|
227
|
+
.filter(function (child) { return child.tagName === 'P'; });
|
|
228
|
+
var blocks = Array.prototype.slice
|
|
229
|
+
.call(item.children)
|
|
230
|
+
.filter(function (child) { return !isRichTextInlineNode(child); });
|
|
231
|
+
var nested = blocks.filter(function (child) { return child.tagName === 'UL' || child.tagName === 'OL'; });
|
|
232
|
+
if (paragraphs.length !== 1 || blocks.length !== 1 + nested.length) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
var paragraph = paragraphs[0];
|
|
236
|
+
while (paragraph.firstChild) {
|
|
237
|
+
item.insertBefore(paragraph.firstChild, paragraph);
|
|
238
|
+
}
|
|
239
|
+
item.removeChild(paragraph);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
exports.unwrapSingleParagraphListItems = unwrapSingleParagraphListItems;
|
|
243
|
+
/** A link to another web page: an absolute http(s) address. Everything else stays in the tab. */
|
|
244
|
+
function isExternalWebLink(href) {
|
|
245
|
+
return /^https?:\/\//i.test(String(href || '').trim());
|
|
246
|
+
}
|
|
247
|
+
exports.isExternalWebLink = isExternalWebLink;
|
|
248
|
+
/**
|
|
249
|
+
* Quill creates every link with `target="_blank"`. Stored HTML decides for
|
|
250
|
+
* itself: a link to another web page opens in a new tab, a link to a page of
|
|
251
|
+
* the same site (or a mail or phone link) opens in this one.
|
|
252
|
+
*/
|
|
253
|
+
function normalizeLinkTargets(root) {
|
|
254
|
+
Array.prototype.slice.call(root.querySelectorAll('a[href]')).forEach(function (link) {
|
|
255
|
+
if (isExternalWebLink(link.getAttribute('href') || '')) {
|
|
256
|
+
if (!link.getAttribute('target')) {
|
|
257
|
+
link.setAttribute('rel', 'noopener noreferrer');
|
|
258
|
+
link.setAttribute('target', '_blank');
|
|
259
|
+
}
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
link.removeAttribute('target');
|
|
263
|
+
link.removeAttribute('rel');
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
exports.normalizeLinkTargets = normalizeLinkTargets;
|
|
267
|
+
/** A quote holds paragraphs; bare inline content inside one becomes its single paragraph. */
|
|
268
|
+
function wrapBareBlockquoteContent(root) {
|
|
269
|
+
Array.prototype.slice.call(root.querySelectorAll('blockquote')).forEach(function (quote) {
|
|
270
|
+
var children = Array.prototype.slice.call(quote.childNodes);
|
|
271
|
+
var bare = children.filter(function (child) { return !isBlankTextNode(child); });
|
|
272
|
+
if (!bare.length || !bare.every(function (child) { return isRichTextInlineNode(child); })) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
var paragraph = quote.ownerDocument.createElement('p');
|
|
276
|
+
children.forEach(function (child) { return paragraph.appendChild(child); });
|
|
277
|
+
quote.appendChild(paragraph);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
exports.wrapBareBlockquoteContent = wrapBareBlockquoteContent;
|
|
281
|
+
/** The markup of one node as it sits in its parent: text escaped, elements whole. */
|
|
282
|
+
function serializeRichTextNode(node) {
|
|
283
|
+
if (node.nodeType === 1) {
|
|
284
|
+
return node.outerHTML;
|
|
285
|
+
}
|
|
286
|
+
if (node.nodeType === 3) {
|
|
287
|
+
return escapeRichTextText(node.nodeValue || '');
|
|
288
|
+
}
|
|
289
|
+
return '';
|
|
290
|
+
}
|
|
291
|
+
exports.serializeRichTextNode = serializeRichTextNode;
|
|
292
|
+
/**
|
|
293
|
+
* The inline markup of a list item: text and marks, a single wrapping `<p>`
|
|
294
|
+
* unwrapped, nested lists left out.
|
|
295
|
+
*/
|
|
296
|
+
function readInlineHtml(element) {
|
|
297
|
+
var html = '';
|
|
298
|
+
Array.prototype.slice.call(element.childNodes).forEach(function (node) {
|
|
299
|
+
if (node.nodeType === 1) {
|
|
300
|
+
var child = node;
|
|
301
|
+
if (child.tagName === 'UL' || child.tagName === 'OL') {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (child.tagName === 'P') {
|
|
305
|
+
html += child.innerHTML;
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
html += serializeRichTextNode(node);
|
|
310
|
+
});
|
|
311
|
+
return html.replace(/^\s+|\s+$/g, '');
|
|
312
|
+
}
|
|
313
|
+
exports.readInlineHtml = readInlineHtml;
|
|
314
|
+
/**
|
|
315
|
+
* A list Quill can hold as lines: every item is inline content (at most one
|
|
316
|
+
* `<p>` around it) followed, at most, by one nested list that is itself simple,
|
|
317
|
+
* and no `start` offset on a numbered list.
|
|
318
|
+
*/
|
|
319
|
+
function isQuillSimpleList(list) {
|
|
320
|
+
if (list.hasAttribute('start')) {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
var items = Array.prototype.slice.call(list.children);
|
|
324
|
+
for (var i = 0; i < items.length; i += 1) {
|
|
325
|
+
var item = items[i];
|
|
326
|
+
if (item.tagName !== 'LI') {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
var children = Array.prototype.slice.call(item.childNodes);
|
|
330
|
+
var paragraphs = 0;
|
|
331
|
+
var nested = null;
|
|
332
|
+
for (var j = 0; j < children.length; j += 1) {
|
|
333
|
+
var child = children[j];
|
|
334
|
+
if (isRichTextInlineNode(child)) {
|
|
335
|
+
if (nested && !isBlankTextNode(child)) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
var tag = child.tagName;
|
|
341
|
+
if (tag === 'P') {
|
|
342
|
+
paragraphs += 1;
|
|
343
|
+
if (paragraphs > 1 || nested) {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if ((tag === 'UL' || tag === 'OL') && !nested) {
|
|
349
|
+
nested = child;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
if (nested && !isQuillSimpleList(nested)) {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
exports.isQuillSimpleList = isQuillSimpleList;
|
|
361
|
+
/** One flat `<ol>` of `<li data-list>` lines, the shape Quill keeps a list in. */
|
|
362
|
+
function flattenListForQuill(list) {
|
|
363
|
+
var html = '<ol>';
|
|
364
|
+
var walk = function (node, indent) {
|
|
365
|
+
var type = node.tagName === 'OL' ? 'ordered' : 'bullet';
|
|
366
|
+
Array.prototype.slice.call(node.children).forEach(function (item) {
|
|
367
|
+
if (item.tagName !== 'LI') {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
var indentClass = indent > 0 ? " class=\"".concat(exports.QUILL_INDENT_CLASS_PREFIX).concat(indent, "\"") : '';
|
|
371
|
+
html += "<li ".concat(exports.QUILL_LIST_ITEM_ATTR, "=\"").concat(type, "\"").concat(indentClass, ">").concat(readInlineHtml(item), "</li>");
|
|
372
|
+
Array.prototype.slice.call(item.children).forEach(function (child) {
|
|
373
|
+
if (child.tagName === 'UL' || child.tagName === 'OL') {
|
|
374
|
+
walk(child, indent + 1);
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
};
|
|
379
|
+
walk(list, 0);
|
|
380
|
+
return html + '</ol>';
|
|
381
|
+
}
|
|
382
|
+
exports.flattenListForQuill = flattenListForQuill;
|
|
383
|
+
/** A blockquote Quill can hold: paragraphs (or bare inline content) only. */
|
|
384
|
+
function isQuillSimpleBlockquote(quote) {
|
|
385
|
+
var children = Array.prototype.slice.call(quote.childNodes);
|
|
386
|
+
for (var i = 0; i < children.length; i += 1) {
|
|
387
|
+
var child = children[i];
|
|
388
|
+
if (isRichTextInlineNode(child)) {
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
if (child.tagName !== 'P') {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
exports.isQuillSimpleBlockquote = isQuillSimpleBlockquote;
|
|
398
|
+
/** One `<blockquote>` line per paragraph, the shape Quill keeps a quote in. */
|
|
399
|
+
function blockquoteLinesForQuill(quote) {
|
|
400
|
+
var lines = [];
|
|
401
|
+
var pending = '';
|
|
402
|
+
var flush = function () {
|
|
403
|
+
if (/\S/.test(pending)) {
|
|
404
|
+
lines.push(pending.replace(/^\s+|\s+$/g, ''));
|
|
405
|
+
}
|
|
406
|
+
pending = '';
|
|
407
|
+
};
|
|
408
|
+
Array.prototype.slice.call(quote.childNodes).forEach(function (node) {
|
|
409
|
+
if (node.nodeType === 1 && node.tagName === 'P') {
|
|
410
|
+
flush();
|
|
411
|
+
lines.push(node.innerHTML);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
pending += serializeRichTextNode(node);
|
|
415
|
+
});
|
|
416
|
+
flush();
|
|
417
|
+
return lines.map(function (line) { return "<blockquote>".concat(line, "</blockquote>"); }).join('');
|
|
418
|
+
}
|
|
419
|
+
exports.blockquoteLinesForQuill = blockquoteLinesForQuill;
|
|
420
|
+
/** Which protected kind a stored block that Quill cannot hold gets. */
|
|
421
|
+
function protectedKindForElement(element) {
|
|
422
|
+
var tag = element.tagName;
|
|
423
|
+
if (tag === 'TABLE') {
|
|
424
|
+
return 'table';
|
|
425
|
+
}
|
|
426
|
+
if (tag === 'PRE') {
|
|
427
|
+
return 'code';
|
|
428
|
+
}
|
|
429
|
+
if (tag === 'ASIDE' && hasClass(element, exports.CALLOUT_CLASS)) {
|
|
430
|
+
return 'callout';
|
|
431
|
+
}
|
|
432
|
+
if (tag === 'UL' || tag === 'OL') {
|
|
433
|
+
return 'list';
|
|
434
|
+
}
|
|
435
|
+
if (tag === 'BLOCKQUOTE') {
|
|
436
|
+
return 'quote';
|
|
437
|
+
}
|
|
438
|
+
return 'html';
|
|
439
|
+
}
|
|
440
|
+
exports.protectedKindForElement = protectedKindForElement;
|
|
441
|
+
/**
|
|
442
|
+
* Stored HTML → what the editor is given. Every block Quill holds natively is
|
|
443
|
+
* handed over in Quill's own shape; every other block is protected.
|
|
444
|
+
*/
|
|
445
|
+
function toEditorHtml(storedHtml) {
|
|
446
|
+
var body = parseRichTextFragment(normalizeLegacyRichTextHtml(storedHtml));
|
|
447
|
+
var html = '';
|
|
448
|
+
Array.prototype.slice.call(body.childNodes).forEach(function (node) {
|
|
449
|
+
if (node.nodeType === 3) {
|
|
450
|
+
if (/\S/.test(node.nodeValue || '')) {
|
|
451
|
+
html += '<p>' + escapeRichTextText(node.nodeValue || '') + '</p>';
|
|
452
|
+
}
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (node.nodeType !== 1) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
var element = node;
|
|
459
|
+
var tag = element.tagName;
|
|
460
|
+
if (tag === 'P' || /^H[1-6]$/.test(tag)) {
|
|
461
|
+
html += element.outerHTML;
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (isRichTextInlineNode(element)) {
|
|
465
|
+
html += '<p>' + element.outerHTML + '</p>';
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (tag === 'DIV' && hasClass(element, exports.PROTECTED_BLOCK_CLASS)) {
|
|
469
|
+
html += element.outerHTML;
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
if (tag === 'FIGURE' &&
|
|
473
|
+
(hasClass(element, exports.RICH_TEXT_IMAGE_CLASS) || hasClass(element, exports.RICH_TEXT_EMBED_CLASS))) {
|
|
474
|
+
html += element.outerHTML;
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if ((tag === 'UL' || tag === 'OL') && isQuillSimpleList(element)) {
|
|
478
|
+
html += flattenListForQuill(element);
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (tag === 'BLOCKQUOTE' && isQuillSimpleBlockquote(element)) {
|
|
482
|
+
html += blockquoteLinesForQuill(element);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
html += buildProtectedBlockHtml(protectedKindForElement(element), element.outerHTML);
|
|
486
|
+
});
|
|
487
|
+
return html;
|
|
488
|
+
}
|
|
489
|
+
exports.toEditorHtml = toEditorHtml;
|
|
490
|
+
/**
|
|
491
|
+
* What the editor holds → stored HTML. Protected blocks are unwrapped, Quill's
|
|
492
|
+
* flat lists and blockquote lines are rebuilt, and Quill's own helpers are
|
|
493
|
+
* stripped. Idempotent on stored HTML.
|
|
494
|
+
*/
|
|
495
|
+
function fromEditorHtml(editorHtml) {
|
|
496
|
+
var body = parseRichTextFragment(editorHtml);
|
|
497
|
+
Array.prototype.slice
|
|
498
|
+
.call(body.querySelectorAll('.' + exports.PROTECTED_BLOCK_CLASS))
|
|
499
|
+
.forEach(function (wrapper) {
|
|
500
|
+
var parent = wrapper.parentNode;
|
|
501
|
+
if (!parent) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
while (wrapper.firstChild) {
|
|
505
|
+
parent.insertBefore(wrapper.firstChild, wrapper);
|
|
506
|
+
}
|
|
507
|
+
parent.removeChild(wrapper);
|
|
508
|
+
});
|
|
509
|
+
var normalized = parseRichTextFragment(normalizeLegacyRichTextHtml(body.innerHTML));
|
|
510
|
+
unwrapSingleParagraphListItems(normalized);
|
|
511
|
+
wrapBareBlockquoteContent(normalized);
|
|
512
|
+
normalizeLinkTargets(normalized);
|
|
513
|
+
stripInterBlockWhitespace(normalized);
|
|
514
|
+
return trimEmptyEdgeParagraphs(normalized.innerHTML);
|
|
515
|
+
}
|
|
516
|
+
exports.fromEditorHtml = fromEditorHtml;
|
|
517
|
+
/** Stored HTML in its one canonical spelling, whatever dialect it arrived in. */
|
|
518
|
+
function toCanonicalRichTextHtml(html) {
|
|
519
|
+
return fromEditorHtml(html);
|
|
520
|
+
}
|
|
521
|
+
exports.toCanonicalRichTextHtml = toCanonicalRichTextHtml;
|
|
522
|
+
/** Quill keeps an empty line as `<p><br></p>`; one at either end carries nothing. */
|
|
523
|
+
function trimEmptyEdgeParagraphs(html) {
|
|
524
|
+
return html
|
|
525
|
+
.replace(/^(?:\s*<p>(?:<br\s*\/?>|\s| )*<\/p>)+/, '')
|
|
526
|
+
.replace(/(?:<p>(?:<br\s*\/?>|\s| )*<\/p>\s*)+$/, '');
|
|
527
|
+
}
|
|
528
|
+
exports.trimEmptyEdgeParagraphs = trimEmptyEdgeParagraphs;
|
|
529
|
+
/**
|
|
530
|
+
* What the editors wrote before this contract, turned into stored HTML. String
|
|
531
|
+
* only, so a generated page can run it in `getStaticProps`:
|
|
532
|
+
* - the studio's lists: one `<ol>` of `<li data-list="bullet|ordered">` with
|
|
533
|
+
* `ql-indent-N` and an empty `<span class="ql-ui">` per line;
|
|
534
|
+
* - the studio's code blocks: `div.ql-code-block-container` of line divs;
|
|
535
|
+
* - the studio's quotes: one `<blockquote>` element per line;
|
|
536
|
+
* - the admin panel's text: every space a no-break space;
|
|
537
|
+
* - the admin panel's code blocks: `<pre data-language>` with no `<code>`.
|
|
538
|
+
* Leaves stored HTML as it is.
|
|
539
|
+
*/
|
|
540
|
+
function normalizeLegacyRichTextHtml(html) {
|
|
541
|
+
var out = String(html || '');
|
|
542
|
+
out = out.replace(/<span class="ql-ui"[^>]*>(?:<\/span>)?/g, '');
|
|
543
|
+
out = out.replace(/<(ol|ul)(\s[^>]*)?>((?:(?!<\/?(?:ol|ul)\b)[\s\S])*)<\/\1>/g, function (match, _tag, _attrs, inner) {
|
|
544
|
+
return inner.indexOf(exports.QUILL_LIST_ITEM_ATTR + '=') === -1 ? match : rebuildQuillListHtml(inner);
|
|
545
|
+
});
|
|
546
|
+
out = out.replace(/<div class="ql-code-block-container"[^>]*>((?:\s*<div class="ql-code-block"[^>]*>[\s\S]*?<\/div>)*)\s*<\/div>/g, function (_match, inner) { return rebuildQuillCodeBlockHtml(inner); });
|
|
547
|
+
out = out.replace(/<pre data-language="([^"]*)">\n?([\s\S]*?)\n?<\/pre>/g, function (_match, language, code) { return buildCodeBlockHtml(language, code, true); });
|
|
548
|
+
out = out.replace(/((?:<blockquote>(?:(?!<\/?blockquote\b)[\s\S])*<\/blockquote>\s*)+)/g, function (run) {
|
|
549
|
+
return mergeBlockquoteLines(run);
|
|
550
|
+
});
|
|
551
|
+
out = out.replace(/(\S)(?: | )(?=\S)/g, '$1 ');
|
|
552
|
+
return out;
|
|
553
|
+
}
|
|
554
|
+
exports.normalizeLegacyRichTextHtml = normalizeLegacyRichTextHtml;
|
|
555
|
+
/** The nested `<ul>`/`<ol>` that a flat run of Quill list lines means. */
|
|
556
|
+
function rebuildQuillListHtml(innerHtml) {
|
|
557
|
+
var items = [];
|
|
558
|
+
var pattern = /<li\b([^>]*)>([\s\S]*?)<\/li>/g;
|
|
559
|
+
var match = pattern.exec(innerHtml);
|
|
560
|
+
while (match) {
|
|
561
|
+
var attrs = match[1];
|
|
562
|
+
var typeMatch = /data-list="([^"]*)"/.exec(attrs);
|
|
563
|
+
var indentMatch = /ql-indent-(\d+)/.exec(attrs);
|
|
564
|
+
items.push({
|
|
565
|
+
type: typeMatch && typeMatch[1] === 'ordered' ? 'ordered' : 'bullet',
|
|
566
|
+
indent: indentMatch ? parseInt(indentMatch[1], 10) : 0,
|
|
567
|
+
html: match[2].replace(/^\s+|\s+$/g, ''),
|
|
568
|
+
});
|
|
569
|
+
match = pattern.exec(innerHtml);
|
|
570
|
+
}
|
|
571
|
+
if (!items.length) {
|
|
572
|
+
return '';
|
|
573
|
+
}
|
|
574
|
+
var render = function (from, level) {
|
|
575
|
+
var html = '';
|
|
576
|
+
var i = from;
|
|
577
|
+
var openType = '';
|
|
578
|
+
var close = function () {
|
|
579
|
+
if (openType) {
|
|
580
|
+
html += openType === 'ordered' ? '</ol>' : '</ul>';
|
|
581
|
+
openType = '';
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
while (i < items.length) {
|
|
585
|
+
var item = items[i];
|
|
586
|
+
if (item.indent < level) {
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
if (item.indent > level) {
|
|
590
|
+
// A deeper line with nothing above it reads as this level.
|
|
591
|
+
item.indent = level;
|
|
592
|
+
}
|
|
593
|
+
if (openType !== item.type) {
|
|
594
|
+
close();
|
|
595
|
+
openType = item.type;
|
|
596
|
+
html += openType === 'ordered' ? '<ol>' : '<ul>';
|
|
597
|
+
}
|
|
598
|
+
html += '<li>' + item.html;
|
|
599
|
+
i += 1;
|
|
600
|
+
if (i < items.length && items[i].indent > level) {
|
|
601
|
+
var nested = render(i, level + 1);
|
|
602
|
+
html += nested.html;
|
|
603
|
+
i = nested.next;
|
|
604
|
+
}
|
|
605
|
+
html += '</li>';
|
|
606
|
+
}
|
|
607
|
+
close();
|
|
608
|
+
return { html: html, next: i };
|
|
609
|
+
};
|
|
610
|
+
return render(0, 0).html;
|
|
611
|
+
}
|
|
612
|
+
exports.rebuildQuillListHtml = rebuildQuillListHtml;
|
|
613
|
+
/** The `<pre><code>` that a run of the studio's code-block line divs means. */
|
|
614
|
+
function rebuildQuillCodeBlockHtml(innerHtml) {
|
|
615
|
+
var lines = [];
|
|
616
|
+
var language = '';
|
|
617
|
+
var pattern = /<div class="ql-code-block"([^>]*)>([\s\S]*?)<\/div>/g;
|
|
618
|
+
var match = pattern.exec(innerHtml);
|
|
619
|
+
while (match) {
|
|
620
|
+
var languageMatch = /data-language="([^"]*)"/.exec(match[1]);
|
|
621
|
+
if (languageMatch && !language) {
|
|
622
|
+
language = languageMatch[1];
|
|
623
|
+
}
|
|
624
|
+
lines.push(match[2] === '<br>' ? '' : match[2]);
|
|
625
|
+
match = pattern.exec(innerHtml);
|
|
626
|
+
}
|
|
627
|
+
return buildCodeBlockHtml(language, lines.join('\n'), true);
|
|
628
|
+
}
|
|
629
|
+
exports.rebuildQuillCodeBlockHtml = rebuildQuillCodeBlockHtml;
|
|
630
|
+
/**
|
|
631
|
+
* One `<blockquote>` of paragraphs out of a run of single-line quotes (one line
|
|
632
|
+
* is a run too). A run whose lines already hold blocks is stored HTML and is
|
|
633
|
+
* left alone.
|
|
634
|
+
*/
|
|
635
|
+
function mergeBlockquoteLines(run) {
|
|
636
|
+
var lines = [];
|
|
637
|
+
var pattern = /<blockquote>([\s\S]*?)<\/blockquote>/g;
|
|
638
|
+
var match = pattern.exec(run);
|
|
639
|
+
while (match) {
|
|
640
|
+
if (/<(?:p|ul|ol|div|pre|table|aside|figure|h[1-6])\b/.test(match[1])) {
|
|
641
|
+
return run;
|
|
642
|
+
}
|
|
643
|
+
lines.push(match[1]);
|
|
644
|
+
match = pattern.exec(run);
|
|
645
|
+
}
|
|
646
|
+
return '<blockquote>' + lines.map(function (line) { return '<p>' + line + '</p>'; }).join('') + '</blockquote>';
|
|
647
|
+
}
|
|
648
|
+
exports.mergeBlockquoteLines = mergeBlockquoteLines;
|
|
649
|
+
//# sourceMappingURL=rich-text-content.js.map
|