PluginProbe
Gutenberg / 12.1.0
Gutenberg v12.1.0
23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 7.4.0 All 402 releases
gutenberg / build / autop / index.js

index.js in Gutenberg 12.1.0, at build/autop/index.js

442 lines 15.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (function() { // webpackBootstrap
2 /******/ "use strict";
3 /******/ // The require scope
4 /******/ var __webpack_require__ = {};
5 /******/
6 /************************************************************************/
7 /******/ /* webpack/runtime/define property getters */
8 /******/ !function() {
9 /******/ // define getter functions for harmony exports
10 /******/ __webpack_require__.d = function(exports, definition) {
11 /******/ for(var key in definition) {
12 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
13 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
14 /******/ }
15 /******/ }
16 /******/ };
17 /******/ }();
18 /******/
19 /******/ /* webpack/runtime/hasOwnProperty shorthand */
20 /******/ !function() {
21 /******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
22 /******/ }();
23 /******/
24 /******/ /* webpack/runtime/make namespace object */
25 /******/ !function() {
26 /******/ // define __esModule on exports
27 /******/ __webpack_require__.r = function(exports) {
28 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
29 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
30 /******/ }
31 /******/ Object.defineProperty(exports, '__esModule', { value: true });
32 /******/ };
33 /******/ }();
34 /******/
35 /************************************************************************/
36 var __webpack_exports__ = {};
37 __webpack_require__.r(__webpack_exports__);
38 /* harmony export */ __webpack_require__.d(__webpack_exports__, {
39 /* harmony export */ "autop": function() { return /* binding */ autop; },
40 /* harmony export */ "removep": function() { return /* binding */ removep; }
41 /* harmony export */ });
42 /**
43 * The regular expression for an HTML element.
44 *
45 * @type {RegExp}
46 */
47 const htmlSplitRegex = (() => {
48 /* eslint-disable no-multi-spaces */
49 const comments = '!' + // Start of comment, after the <.
50 '(?:' + // Unroll the loop: Consume everything until --> is found.
51 '-(?!->)' + // Dash not followed by end of comment.
52 '[^\\-]*' + // Consume non-dashes.
53 ')*' + // Loop possessively.
54 '(?:-->)?'; // End of comment. If not found, match all input.
55
56 const cdata = '!\\[CDATA\\[' + // Start of comment, after the <.
57 '[^\\]]*' + // Consume non-].
58 '(?:' + // Unroll the loop: Consume everything until ]]> is found.
59 '](?!]>)' + // One ] not followed by end of comment.
60 '[^\\]]*' + // Consume non-].
61 ')*?' + // Loop possessively.
62 '(?:]]>)?'; // End of comment. If not found, match all input.
63
64 const escaped = '(?=' + // Is the element escaped?
65 '!--' + '|' + '!\\[CDATA\\[' + ')' + '((?=!-)' + // If yes, which type?
66 comments + '|' + cdata + ')';
67 const regex = '(' + // Capture the entire match.
68 '<' + // Find start of element.
69 '(' + // Conditional expression follows.
70 escaped + // Find end of escaped element.
71 '|' + // ... else ...
72 '[^>]*>?' + // Find end of normal element.
73 ')' + ')';
74 return new RegExp(regex);
75 /* eslint-enable no-multi-spaces */
76 })();
77 /**
78 * Separate HTML elements and comments from the text.
79 *
80 * @param {string} input The text which has to be formatted.
81 *
82 * @return {string[]} The formatted text.
83 */
84
85
86 function htmlSplit(input) {
87 const parts = [];
88 let workingInput = input;
89 let match;
90
91 while (match = workingInput.match(htmlSplitRegex)) {
92 // The `match` result, when invoked on a RegExp with the `g` flag (`/foo/g`) will not include `index`.
93 // If the `g` flag is omitted, `index` is included.
94 // `htmlSplitRegex` does not have the `g` flag so we can assert it will have an index number.
95 // Assert `match.index` is a number.
96 const index =
97 /** @type {number} */
98 match.index;
99 parts.push(workingInput.slice(0, index));
100 parts.push(match[0]);
101 workingInput = workingInput.slice(index + match[0].length);
102 }
103
104 if (workingInput.length) {
105 parts.push(workingInput);
106 }
107
108 return parts;
109 }
110 /**
111 * Replace characters or phrases within HTML elements only.
112 *
113 * @param {string} haystack The text which has to be formatted.
114 * @param {Record<string,string>} replacePairs In the form {from: 'to', …}.
115 *
116 * @return {string} The formatted text.
117 */
118
119
120 function replaceInHtmlTags(haystack, replacePairs) {
121 // Find all elements.
122 const textArr = htmlSplit(haystack);
123 let changed = false; // Extract all needles.
124
125 const needles = Object.keys(replacePairs); // Loop through delimiters (elements) only.
126
127 for (let i = 1; i < textArr.length; i += 2) {
128 for (let j = 0; j < needles.length; j++) {
129 const needle = needles[j];
130
131 if (-1 !== textArr[i].indexOf(needle)) {
132 textArr[i] = textArr[i].replace(new RegExp(needle, 'g'), replacePairs[needle]);
133 changed = true; // After one strtr() break out of the foreach loop and look at next element.
134
135 break;
136 }
137 }
138 }
139
140 if (changed) {
141 haystack = textArr.join('');
142 }
143
144 return haystack;
145 }
146 /**
147 * Replaces double line-breaks with paragraph elements.
148 *
149 * A group of regex replaces used to identify text formatted with newlines and
150 * replace double line-breaks with HTML paragraph tags. The remaining line-
151 * breaks after conversion become `<br />` tags, unless br is set to 'false'.
152 *
153 * @param {string} text The text which has to be formatted.
154 * @param {boolean} br Optional. If set, will convert all remaining line-
155 * breaks after paragraphing. Default true.
156 *
157 * @example
158 *```js
159 * import { autop } from '@wordpress/autop';
160 * autop( 'my text' ); // "<p>my text</p>"
161 * ```
162 *
163 * @return {string} Text which has been converted into paragraph tags.
164 */
165
166
167 function autop(text) {
168 let br = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
169 const preTags = [];
170
171 if (text.trim() === '') {
172 return '';
173 } // Just to make things a little easier, pad the end.
174
175
176 text = text + '\n';
177 /*
178 * Pre tags shouldn't be touched by autop.
179 * Replace pre tags with placeholders and bring them back after autop.
180 */
181
182 if (text.indexOf('<pre') !== -1) {
183 const textParts = text.split('</pre>');
184 const lastText = textParts.pop();
185 text = '';
186
187 for (let i = 0; i < textParts.length; i++) {
188 const textPart = textParts[i];
189 const start = textPart.indexOf('<pre'); // Malformed html?
190
191 if (start === -1) {
192 text += textPart;
193 continue;
194 }
195
196 const name = '<pre wp-pre-tag-' + i + '></pre>';
197 preTags.push([name, textPart.substr(start) + '</pre>']);
198 text += textPart.substr(0, start) + name;
199 }
200
201 text += lastText;
202 } // Change multiple <br>s into two line breaks, which will turn into paragraphs.
203
204
205 text = text.replace(/<br\s*\/?>\s*<br\s*\/?>/g, '\n\n');
206 const allBlocks = '(?:table|thead|tfoot|caption|col|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|form|map|area|blockquote|address|math|style|p|h[1-6]|hr|fieldset|legend|section|article|aside|hgroup|header|footer|nav|figure|figcaption|details|menu|summary)'; // Add a double line break above block-level opening tags.
207
208 text = text.replace(new RegExp('(<' + allBlocks + '[\\s/>])', 'g'), '\n\n$1'); // Add a double line break below block-level closing tags.
209
210 text = text.replace(new RegExp('(</' + allBlocks + '>)', 'g'), '$1\n\n'); // Standardize newline characters to "\n".
211
212 text = text.replace(/\r\n|\r/g, '\n'); // Find newlines in all elements and add placeholders.
213
214 text = replaceInHtmlTags(text, {
215 '\n': ' <!-- wpnl --> '
216 }); // Collapse line breaks before and after <option> elements so they don't get autop'd.
217
218 if (text.indexOf('<option') !== -1) {
219 text = text.replace(/\s*<option/g, '<option');
220 text = text.replace(/<\/option>\s*/g, '</option>');
221 }
222 /*
223 * Collapse line breaks inside <object> elements, before <param> and <embed> elements
224 * so they don't get autop'd.
225 */
226
227
228 if (text.indexOf('</object>') !== -1) {
229 text = text.replace(/(<object[^>]*>)\s*/g, '$1');
230 text = text.replace(/\s*<\/object>/g, '</object>');
231 text = text.replace(/\s*(<\/?(?:param|embed)[^>]*>)\s*/g, '$1');
232 }
233 /*
234 * Collapse line breaks inside <audio> and <video> elements,
235 * before and after <source> and <track> elements.
236 */
237
238
239 if (text.indexOf('<source') !== -1 || text.indexOf('<track') !== -1) {
240 text = text.replace(/([<\[](?:audio|video)[^>\]]*[>\]])\s*/g, '$1');
241 text = text.replace(/\s*([<\[]\/(?:audio|video)[>\]])/g, '$1');
242 text = text.replace(/\s*(<(?:source|track)[^>]*>)\s*/g, '$1');
243 } // Collapse line breaks before and after <figcaption> elements.
244
245
246 if (text.indexOf('<figcaption') !== -1) {
247 text = text.replace(/\s*(<figcaption[^>]*>)/, '$1');
248 text = text.replace(/<\/figcaption>\s*/, '</figcaption>');
249 } // Remove more than two contiguous line breaks.
250
251
252 text = text.replace(/\n\n+/g, '\n\n'); // Split up the contents into an array of strings, separated by double line breaks.
253
254 const texts = text.split(/\n\s*\n/).filter(Boolean); // Reset text prior to rebuilding.
255
256 text = ''; // Rebuild the content as a string, wrapping every bit with a <p>.
257
258 texts.forEach(textPiece => {
259 text += '<p>' + textPiece.replace(/^\n*|\n*$/g, '') + '</p>\n';
260 }); // Under certain strange conditions it could create a P of entirely whitespace.
261
262 text = text.replace(/<p>\s*<\/p>/g, ''); // Add a closing <p> inside <div>, <address>, or <form> tag if missing.
263
264 text = text.replace(/<p>([^<]+)<\/(div|address|form)>/g, '<p>$1</p></$2>'); // If an opening or closing block element tag is wrapped in a <p>, unwrap it.
265
266 text = text.replace(new RegExp('<p>\\s*(</?' + allBlocks + '[^>]*>)\\s*</p>', 'g'), '$1'); // In some cases <li> may get wrapped in <p>, fix them.
267
268 text = text.replace(/<p>(<li.+?)<\/p>/g, '$1'); // If a <blockquote> is wrapped with a <p>, move it inside the <blockquote>.
269
270 text = text.replace(/<p><blockquote([^>]*)>/gi, '<blockquote$1><p>');
271 text = text.replace(/<\/blockquote><\/p>/g, '</p></blockquote>'); // If an opening or closing block element tag is preceded by an opening <p> tag, remove it.
272
273 text = text.replace(new RegExp('<p>\\s*(</?' + allBlocks + '[^>]*>)', 'g'), '$1'); // If an opening or closing block element tag is followed by a closing <p> tag, remove it.
274
275 text = text.replace(new RegExp('(</?' + allBlocks + '[^>]*>)\\s*</p>', 'g'), '$1'); // Optionally insert line breaks.
276
277 if (br) {
278 // Replace newlines that shouldn't be touched with a placeholder.
279 text = text.replace(/<(script|style).*?<\/\\1>/g, match => match[0].replace(/\n/g, '<WPPreserveNewline />')); // Normalize <br>
280
281 text = text.replace(/<br>|<br\/>/g, '<br />'); // Replace any new line characters that aren't preceded by a <br /> with a <br />.
282
283 text = text.replace(/(<br \/>)?\s*\n/g, (a, b) => b ? a : '<br />\n'); // Replace newline placeholders with newlines.
284
285 text = text.replace(/<WPPreserveNewline \/>/g, '\n');
286 } // If a <br /> tag is after an opening or closing block tag, remove it.
287
288
289 text = text.replace(new RegExp('(</?' + allBlocks + '[^>]*>)\\s*<br />', 'g'), '$1'); // If a <br /> tag is before a subset of opening or closing block tags, remove it.
290
291 text = text.replace(/<br \/>(\s*<\/?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)/g, '$1');
292 text = text.replace(/\n<\/p>$/g, '</p>'); // Replace placeholder <pre> tags with their original content.
293
294 preTags.forEach(preTag => {
295 const [name, original] = preTag;
296 text = text.replace(name, original);
297 }); // Restore newlines in all elements.
298
299 if (-1 !== text.indexOf('<!-- wpnl -->')) {
300 text = text.replace(/\s?<!-- wpnl -->\s?/g, '\n');
301 }
302
303 return text;
304 }
305 /**
306 * Replaces `<p>` tags with two line breaks. "Opposite" of autop().
307 *
308 * Replaces `<p>` tags with two line breaks except where the `<p>` has attributes.
309 * Unifies whitespace. Indents `<li>`, `<dt>` and `<dd>` for better readability.
310 *
311 * @param {string} html The content from the editor.
312 *
313 * @example
314 * ```js
315 * import { removep } from '@wordpress/autop';
316 * removep( '<p>my text</p>' ); // "my text"
317 * ```
318 *
319 * @return {string} The content with stripped paragraph tags.
320 */
321
322 function removep(html) {
323 const blocklist = 'blockquote|ul|ol|li|dl|dt|dd|table|thead|tbody|tfoot|tr|th|td|h[1-6]|fieldset|figure';
324 const blocklist1 = blocklist + '|div|p';
325 const blocklist2 = blocklist + '|pre';
326 /** @type {string[]} */
327
328 const preserve = [];
329 let preserveLinebreaks = false;
330 let preserveBr = false;
331
332 if (!html) {
333 return '';
334 } // Protect script and style tags.
335
336
337 if (html.indexOf('<script') !== -1 || html.indexOf('<style') !== -1) {
338 html = html.replace(/<(script|style)[^>]*>[\s\S]*?<\/\1>/g, match => {
339 preserve.push(match);
340 return '<wp-preserve>';
341 });
342 } // Protect pre tags.
343
344
345 if (html.indexOf('<pre') !== -1) {
346 preserveLinebreaks = true;
347 html = html.replace(/<pre[^>]*>[\s\S]+?<\/pre>/g, a => {
348 a = a.replace(/<br ?\/?>(\r\n|\n)?/g, '<wp-line-break>');
349 a = a.replace(/<\/?p( [^>]*)?>(\r\n|\n)?/g, '<wp-line-break>');
350 return a.replace(/\r?\n/g, '<wp-line-break>');
351 });
352 } // Remove line breaks but keep <br> tags inside image captions.
353
354
355 if (html.indexOf('[caption') !== -1) {
356 preserveBr = true;
357 html = html.replace(/\[caption[\s\S]+?\[\/caption\]/g, a => {
358 return a.replace(/<br([^>]*)>/g, '<wp-temp-br$1>').replace(/[\r\n\t]+/, '');
359 });
360 } // Normalize white space characters before and after block tags.
361
362
363 html = html.replace(new RegExp('\\s*</(' + blocklist1 + ')>\\s*', 'g'), '</$1>\n');
364 html = html.replace(new RegExp('\\s*<((?:' + blocklist1 + ')(?: [^>]*)?)>', 'g'), '\n<$1>'); // Mark </p> if it has any attributes.
365
366 html = html.replace(/(<p [^>]+>[\s\S]*?)<\/p>/g, '$1</p#>'); // Preserve the first <p> inside a <div>.
367
368 html = html.replace(/<div( [^>]*)?>\s*<p>/gi, '<div$1>\n\n'); // Remove paragraph tags.
369
370 html = html.replace(/\s*<p>/gi, '');
371 html = html.replace(/\s*<\/p>\s*/gi, '\n\n'); // Normalize white space chars and remove multiple line breaks.
372
373 html = html.replace(/\n[\s\u00a0]+\n/g, '\n\n'); // Replace <br> tags with line breaks.
374
375 html = html.replace(/(\s*)<br ?\/?>\s*/gi, (_, space) => {
376 if (space && space.indexOf('\n') !== -1) {
377 return '\n\n';
378 }
379
380 return '\n';
381 }); // Fix line breaks around <div>.
382
383 html = html.replace(/\s*<div/g, '\n<div');
384 html = html.replace(/<\/div>\s*/g, '</div>\n'); // Fix line breaks around caption shortcodes.
385
386 html = html.replace(/\s*\[caption([^\[]+)\[\/caption\]\s*/gi, '\n\n[caption$1[/caption]\n\n');
387 html = html.replace(/caption\]\n\n+\[caption/g, 'caption]\n\n[caption'); // Pad block elements tags with a line break.
388
389 html = html.replace(new RegExp('\\s*<((?:' + blocklist2 + ')(?: [^>]*)?)\\s*>', 'g'), '\n<$1>');
390 html = html.replace(new RegExp('\\s*</(' + blocklist2 + ')>\\s*', 'g'), '</$1>\n'); // Indent <li>, <dt> and <dd> tags.
391
392 html = html.replace(/<((li|dt|dd)[^>]*)>/g, ' \t<$1>'); // Fix line breaks around <select> and <option>.
393
394 if (html.indexOf('<option') !== -1) {
395 html = html.replace(/\s*<option/g, '\n<option');
396 html = html.replace(/\s*<\/select>/g, '\n</select>');
397 } // Pad <hr> with two line breaks.
398
399
400 if (html.indexOf('<hr') !== -1) {
401 html = html.replace(/\s*<hr( [^>]*)?>\s*/g, '\n\n<hr$1>\n\n');
402 } // Remove line breaks in <object> tags.
403
404
405 if (html.indexOf('<object') !== -1) {
406 html = html.replace(/<object[\s\S]+?<\/object>/g, a => {
407 return a.replace(/[\r\n]+/g, '');
408 });
409 } // Unmark special paragraph closing tags.
410
411
412 html = html.replace(/<\/p#>/g, '</p>\n'); // Pad remaining <p> tags whit a line break.
413
414 html = html.replace(/\s*(<p [^>]+>[\s\S]*?<\/p>)/g, '\n$1'); // Trim.
415
416 html = html.replace(/^\s+/, '');
417 html = html.replace(/[\s\u00a0]+$/, '');
418
419 if (preserveLinebreaks) {
420 html = html.replace(/<wp-line-break>/g, '\n');
421 }
422
423 if (preserveBr) {
424 html = html.replace(/<wp-temp-br([^>]*)>/g, '<br$1>');
425 } // Restore preserved tags.
426
427
428 if (preserve.length) {
429 html = html.replace(/<wp-preserve>/g, () => {
430 return (
431 /** @type {string} */
432 preserve.shift()
433 );
434 });
435 }
436
437 return html;
438 }
439 //# sourceMappingURL=index.js.map
440 (window.wp = window.wp || {}).autop = __webpack_exports__;
441 /******/ })()
442 ;