1 /******/ (function() { // webpackBootstrap |
1 /******/ (() => { // webpackBootstrap |
2 /******/ "use strict"; |
2 /******/ "use strict"; |
3 /******/ // The require scope |
3 /******/ // The require scope |
4 /******/ var __webpack_require__ = {}; |
4 /******/ var __webpack_require__ = {}; |
5 /******/ |
5 /******/ |
6 /************************************************************************/ |
6 /************************************************************************/ |
7 /******/ /* webpack/runtime/define property getters */ |
7 /******/ /* webpack/runtime/define property getters */ |
8 /******/ !function() { |
8 /******/ (() => { |
9 /******/ // define getter functions for harmony exports |
9 /******/ // define getter functions for harmony exports |
10 /******/ __webpack_require__.d = function(exports, definition) { |
10 /******/ __webpack_require__.d = (exports, definition) => { |
11 /******/ for(var key in definition) { |
11 /******/ for(var key in definition) { |
12 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { |
12 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { |
13 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); |
13 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); |
14 /******/ } |
14 /******/ } |
15 /******/ } |
15 /******/ } |
16 /******/ }; |
16 /******/ }; |
17 /******/ }(); |
17 /******/ })(); |
18 /******/ |
18 /******/ |
19 /******/ /* webpack/runtime/hasOwnProperty shorthand */ |
19 /******/ /* webpack/runtime/hasOwnProperty shorthand */ |
20 /******/ !function() { |
20 /******/ (() => { |
21 /******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } |
21 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) |
22 /******/ }(); |
22 /******/ })(); |
23 /******/ |
23 /******/ |
24 /******/ /* webpack/runtime/make namespace object */ |
24 /******/ /* webpack/runtime/make namespace object */ |
25 /******/ !function() { |
25 /******/ (() => { |
26 /******/ // define __esModule on exports |
26 /******/ // define __esModule on exports |
27 /******/ __webpack_require__.r = function(exports) { |
27 /******/ __webpack_require__.r = (exports) => { |
28 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { |
28 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { |
29 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); |
29 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); |
30 /******/ } |
30 /******/ } |
31 /******/ Object.defineProperty(exports, '__esModule', { value: true }); |
31 /******/ Object.defineProperty(exports, '__esModule', { value: true }); |
32 /******/ }; |
32 /******/ }; |
33 /******/ }(); |
33 /******/ })(); |
34 /******/ |
34 /******/ |
35 /************************************************************************/ |
35 /************************************************************************/ |
36 var __webpack_exports__ = {}; |
36 var __webpack_exports__ = {}; |
37 __webpack_require__.r(__webpack_exports__); |
37 __webpack_require__.r(__webpack_exports__); |
38 /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
38 /* harmony export */ __webpack_require__.d(__webpack_exports__, { |
39 /* harmony export */ "parse": function() { return /* binding */ parse; } |
39 /* harmony export */ parse: () => (/* binding */ parse) |
40 /* harmony export */ }); |
40 /* harmony export */ }); |
|
41 /** |
|
42 * @type {string} |
|
43 */ |
41 let document; |
44 let document; |
|
45 /** |
|
46 * @type {number} |
|
47 */ |
42 let offset; |
48 let offset; |
|
49 /** |
|
50 * @type {ParsedBlock[]} |
|
51 */ |
43 let output; |
52 let output; |
|
53 /** |
|
54 * @type {ParsedFrame[]} |
|
55 */ |
44 let stack; |
56 let stack; |
|
57 |
|
58 /** |
|
59 * @typedef {Object|null} Attributes |
|
60 */ |
|
61 |
|
62 /** |
|
63 * @typedef {Object} ParsedBlock |
|
64 * @property {string|null} blockName Block name. |
|
65 * @property {Attributes} attrs Block attributes. |
|
66 * @property {ParsedBlock[]} innerBlocks Inner blocks. |
|
67 * @property {string} innerHTML Inner HTML. |
|
68 * @property {Array<string|null>} innerContent Inner content. |
|
69 */ |
|
70 |
|
71 /** |
|
72 * @typedef {Object} ParsedFrame |
|
73 * @property {ParsedBlock} block Block. |
|
74 * @property {number} tokenStart Token start. |
|
75 * @property {number} tokenLength Token length. |
|
76 * @property {number} prevOffset Previous offset. |
|
77 * @property {number|null} leadingHtmlStart Leading HTML start. |
|
78 */ |
|
79 |
|
80 /** |
|
81 * @typedef {'no-more-tokens'|'void-block'|'block-opener'|'block-closer'} TokenType |
|
82 */ |
|
83 |
|
84 /** |
|
85 * @typedef {[TokenType, string, Attributes, number, number]} Token |
|
86 */ |
|
87 |
45 /** |
88 /** |
46 * Matches block comment delimiters |
89 * Matches block comment delimiters |
47 * |
90 * |
48 * While most of this pattern is straightforward the attribute parsing |
91 * While most of this pattern is straightforward the attribute parsing |
49 * incorporates a tricks to make sure we don't choke on specific input |
92 * incorporates a tricks to make sure we don't choke on specific input |
182 * ], |
251 * ], |
183 * innerHTML: '\n<div class="wp-block-columns has-3-columns">\n\n\n\n</div>\n' |
252 * innerHTML: '\n<div class="wp-block-columns has-3-columns">\n\n\n\n</div>\n' |
184 * } |
253 * } |
185 * ]; |
254 * ]; |
186 * ``` |
255 * ``` |
187 * @return {Array} A block-based representation of the input HTML. |
256 * @return {ParsedBlock[]} A block-based representation of the input HTML. |
188 */ |
257 */ |
189 |
|
190 |
|
191 const parse = doc => { |
258 const parse = doc => { |
192 document = doc; |
259 document = doc; |
193 offset = 0; |
260 offset = 0; |
194 output = []; |
261 output = []; |
195 stack = []; |
262 stack = []; |
196 tokenizer.lastIndex = 0; |
263 tokenizer.lastIndex = 0; |
197 |
264 do { |
198 do {// twiddle our thumbs |
265 // twiddle our thumbs |
199 } while (proceed()); |
266 } while (proceed()); |
200 |
|
201 return output; |
267 return output; |
202 }; |
268 }; |
203 |
269 |
|
270 /** |
|
271 * Parses the next token in the input document. |
|
272 * |
|
273 * @return {boolean} Returns true when there is more tokens to parse. |
|
274 */ |
204 function proceed() { |
275 function proceed() { |
|
276 const stackDepth = stack.length; |
205 const next = nextToken(); |
277 const next = nextToken(); |
206 const [tokenType, blockName, attrs, startOffset, tokenLength] = next; |
278 const [tokenType, blockName, attrs, startOffset, tokenLength] = next; |
207 const stackDepth = stack.length; // We may have some HTML soup before the next block. |
279 |
208 |
280 // We may have some HTML soup before the next block. |
209 const leadingHtmlStart = startOffset > offset ? offset : null; |
281 const leadingHtmlStart = startOffset > offset ? offset : null; |
210 |
|
211 switch (tokenType) { |
282 switch (tokenType) { |
212 case 'no-more-tokens': |
283 case 'no-more-tokens': |
213 // If not in a block then flush output. |
284 // If not in a block then flush output. |
214 if (0 === stackDepth) { |
285 if (0 === stackDepth) { |
215 addFreeform(); |
286 addFreeform(); |
216 return false; |
287 return false; |
217 } // Otherwise we have a problem |
288 } |
|
289 |
|
290 // Otherwise we have a problem |
218 // This is an error |
291 // This is an error |
219 // we have options |
292 // we have options |
220 // - treat it all as freeform text |
293 // - treat it all as freeform text |
221 // - assume an implicit closer (easiest when not nesting) |
294 // - assume an implicit closer (easiest when not nesting) |
|
295 |
222 // For the easy case we'll assume an implicit closer. |
296 // For the easy case we'll assume an implicit closer. |
223 |
|
224 |
|
225 if (1 === stackDepth) { |
297 if (1 === stackDepth) { |
226 addBlockFromStack(); |
298 addBlockFromStack(); |
227 return false; |
299 return false; |
228 } // For the nested case where it's more difficult we'll |
300 } |
|
301 |
|
302 // For the nested case where it's more difficult we'll |
229 // have to assume that multiple closers are missing |
303 // have to assume that multiple closers are missing |
230 // and so we'll collapse the whole stack piecewise. |
304 // and so we'll collapse the whole stack piecewise. |
231 |
|
232 |
|
233 while (0 < stack.length) { |
305 while (0 < stack.length) { |
234 addBlockFromStack(); |
306 addBlockFromStack(); |
235 } |
307 } |
236 |
|
237 return false; |
308 return false; |
238 |
|
239 case 'void-block': |
309 case 'void-block': |
240 // easy case is if we stumbled upon a void block |
310 // easy case is if we stumbled upon a void block |
241 // in the top-level of the document. |
311 // in the top-level of the document. |
242 if (0 === stackDepth) { |
312 if (0 === stackDepth) { |
243 if (null !== leadingHtmlStart) { |
313 if (null !== leadingHtmlStart) { |
244 output.push(Freeform(document.substr(leadingHtmlStart, startOffset - leadingHtmlStart))); |
314 output.push(Freeform(document.substr(leadingHtmlStart, startOffset - leadingHtmlStart))); |
245 } |
315 } |
246 |
|
247 output.push(Block(blockName, attrs, [], '', [])); |
316 output.push(Block(blockName, attrs, [], '', [])); |
248 offset = startOffset + tokenLength; |
317 offset = startOffset + tokenLength; |
249 return true; |
318 return true; |
250 } // Otherwise we found an inner block. |
319 } |
251 |
320 |
252 |
321 // Otherwise we found an inner block. |
253 addInnerBlock(Block(blockName, attrs, [], '', []), startOffset, tokenLength); |
322 addInnerBlock(Block(blockName, attrs, [], '', []), startOffset, tokenLength); |
254 offset = startOffset + tokenLength; |
323 offset = startOffset + tokenLength; |
255 return true; |
324 return true; |
256 |
|
257 case 'block-opener': |
325 case 'block-opener': |
258 // Track all newly-opened blocks on the stack. |
326 // Track all newly-opened blocks on the stack. |
259 stack.push(Frame(Block(blockName, attrs, [], '', []), startOffset, tokenLength, startOffset + tokenLength, leadingHtmlStart)); |
327 stack.push(Frame(Block(blockName, attrs, [], '', []), startOffset, tokenLength, startOffset + tokenLength, leadingHtmlStart)); |
260 offset = startOffset + tokenLength; |
328 offset = startOffset + tokenLength; |
261 return true; |
329 return true; |
262 |
|
263 case 'block-closer': |
330 case 'block-closer': |
264 // If we're missing an opener we're in trouble |
331 // If we're missing an opener we're in trouble |
265 // This is an error. |
332 // This is an error. |
266 if (0 === stackDepth) { |
333 if (0 === stackDepth) { |
267 // We have options |
334 // We have options |
268 // - assume an implicit opener |
335 // - assume an implicit opener |
269 // - assume _this_ is the opener |
336 // - assume _this_ is the opener |
270 // - give up and close out the document. |
337 // - give up and close out the document. |
271 addFreeform(); |
338 addFreeform(); |
272 return false; |
339 return false; |
273 } // If we're not nesting then this is easy - close the block. |
340 } |
274 |
341 |
275 |
342 // If we're not nesting then this is easy - close the block. |
276 if (1 === stackDepth) { |
343 if (1 === stackDepth) { |
277 addBlockFromStack(startOffset); |
344 addBlockFromStack(startOffset); |
278 offset = startOffset + tokenLength; |
345 offset = startOffset + tokenLength; |
279 return true; |
346 return true; |
280 } // Otherwise we're nested and we have to close out the current |
347 } |
|
348 |
|
349 // Otherwise we're nested and we have to close out the current |
281 // block and add it as a innerBlock to the parent. |
350 // block and add it as a innerBlock to the parent. |
282 |
351 const stackTop = /** @type {ParsedFrame} */stack.pop(); |
283 |
|
284 const stackTop = stack.pop(); |
|
285 const html = document.substr(stackTop.prevOffset, startOffset - stackTop.prevOffset); |
352 const html = document.substr(stackTop.prevOffset, startOffset - stackTop.prevOffset); |
286 stackTop.block.innerHTML += html; |
353 stackTop.block.innerHTML += html; |
287 stackTop.block.innerContent.push(html); |
354 stackTop.block.innerContent.push(html); |
288 stackTop.prevOffset = startOffset + tokenLength; |
355 stackTop.prevOffset = startOffset + tokenLength; |
289 addInnerBlock(stackTop.block, stackTop.tokenStart, stackTop.tokenLength, startOffset + tokenLength); |
356 addInnerBlock(stackTop.block, stackTop.tokenStart, stackTop.tokenLength, startOffset + tokenLength); |
290 offset = startOffset + tokenLength; |
357 offset = startOffset + tokenLength; |
291 return true; |
358 return true; |
292 |
|
293 default: |
359 default: |
294 // This is an error. |
360 // This is an error. |
295 addFreeform(); |
361 addFreeform(); |
296 return false; |
362 return false; |
297 } |
363 } |
298 } |
364 } |
|
365 |
299 /** |
366 /** |
300 * Parse JSON if valid, otherwise return null |
367 * Parse JSON if valid, otherwise return null |
301 * |
368 * |
302 * Note that JSON coming from the block comment |
369 * Note that JSON coming from the block comment |
303 * delimiters is constrained to be an object |
370 * delimiters is constrained to be an object |
304 * and cannot be things like `true` or `null` |
371 * and cannot be things like `true` or `null` |
305 * |
372 * |
306 * @param {string} input JSON input string to parse |
373 * @param {string} input JSON input string to parse |
307 * @return {Object|null} parsed JSON if valid |
374 * @return {Object|null} parsed JSON if valid |
308 */ |
375 */ |
309 |
|
310 |
|
311 function parseJSON(input) { |
376 function parseJSON(input) { |
312 try { |
377 try { |
313 return JSON.parse(input); |
378 return JSON.parse(input); |
314 } catch (e) { |
379 } catch (e) { |
315 return null; |
380 return null; |
316 } |
381 } |
317 } |
382 } |
318 |
383 |
|
384 /** |
|
385 * Finds the next token in the document. |
|
386 * |
|
387 * @return {Token} The next matched token. |
|
388 */ |
319 function nextToken() { |
389 function nextToken() { |
320 // Aye the magic |
390 // Aye the magic |
321 // we're using a single RegExp to tokenize the block comment delimiters |
391 // we're using a single RegExp to tokenize the block comment delimiters |
322 // we're also using a trick here because the only difference between a |
392 // we're also using a trick here because the only difference between a |
323 // block opener and a block closer is the leading `/` before `wp:` (and |
393 // block opener and a block closer is the leading `/` before `wp:` (and |
324 // a closer has no attributes). we can trap them both and process the |
394 // a closer has no attributes). we can trap them both and process the |
325 // match back in JavaScript to see which one it was. |
395 // match back in JavaScript to see which one it was. |
326 const matches = tokenizer.exec(document); // We have no more tokens. |
396 const matches = tokenizer.exec(document); |
327 |
397 |
|
398 // We have no more tokens. |
328 if (null === matches) { |
399 if (null === matches) { |
329 return ['no-more-tokens']; |
400 return ['no-more-tokens', '', null, 0, 0]; |
330 } |
401 } |
331 |
|
332 const startedAt = matches.index; |
402 const startedAt = matches.index; |
333 const [match, closerMatch, namespaceMatch, nameMatch, attrsMatch |
403 const [match, closerMatch, namespaceMatch, nameMatch, attrsMatch /* Internal/unused. */,, voidMatch] = matches; |
334 /* Internal/unused. */ |
|
335 ,, voidMatch] = matches; |
|
336 const length = match.length; |
404 const length = match.length; |
337 const isCloser = !!closerMatch; |
405 const isCloser = !!closerMatch; |
338 const isVoid = !!voidMatch; |
406 const isVoid = !!voidMatch; |
339 const namespace = namespaceMatch || 'core/'; |
407 const namespace = namespaceMatch || 'core/'; |
340 const name = namespace + nameMatch; |
408 const name = namespace + nameMatch; |
341 const hasAttrs = !!attrsMatch; |
409 const hasAttrs = !!attrsMatch; |
342 const attrs = hasAttrs ? parseJSON(attrsMatch) : {}; // This state isn't allowed |
410 const attrs = hasAttrs ? parseJSON(attrsMatch) : {}; |
|
411 |
|
412 // This state isn't allowed |
343 // This is an error. |
413 // This is an error. |
344 |
414 if (isCloser && (isVoid || hasAttrs)) { |
345 if (isCloser && (isVoid || hasAttrs)) {// We can ignore them since they don't hurt anything |
415 // We can ignore them since they don't hurt anything |
346 // we may warn against this at some point or reject it. |
416 // we may warn against this at some point or reject it. |
347 } |
417 } |
348 |
|
349 if (isVoid) { |
418 if (isVoid) { |
350 return ['void-block', name, attrs, startedAt, length]; |
419 return ['void-block', name, attrs, startedAt, length]; |
351 } |
420 } |
352 |
|
353 if (isCloser) { |
421 if (isCloser) { |
354 return ['block-closer', name, null, startedAt, length]; |
422 return ['block-closer', name, null, startedAt, length]; |
355 } |
423 } |
356 |
|
357 return ['block-opener', name, attrs, startedAt, length]; |
424 return ['block-opener', name, attrs, startedAt, length]; |
358 } |
425 } |
359 |
426 |
|
427 /** |
|
428 * Adds a freeform block to the output. |
|
429 * |
|
430 * @param {number} [rawLength] |
|
431 */ |
360 function addFreeform(rawLength) { |
432 function addFreeform(rawLength) { |
361 const length = rawLength ? rawLength : document.length - offset; |
433 const length = rawLength ? rawLength : document.length - offset; |
362 |
|
363 if (0 === length) { |
434 if (0 === length) { |
364 return; |
435 return; |
365 } |
436 } |
366 |
|
367 output.push(Freeform(document.substr(offset, length))); |
437 output.push(Freeform(document.substr(offset, length))); |
368 } |
438 } |
369 |
439 |
|
440 /** |
|
441 * Adds inner block to the parent block. |
|
442 * |
|
443 * @param {ParsedBlock} block |
|
444 * @param {number} tokenStart |
|
445 * @param {number} tokenLength |
|
446 * @param {number} [lastOffset] |
|
447 */ |
370 function addInnerBlock(block, tokenStart, tokenLength, lastOffset) { |
448 function addInnerBlock(block, tokenStart, tokenLength, lastOffset) { |
371 const parent = stack[stack.length - 1]; |
449 const parent = stack[stack.length - 1]; |
372 parent.block.innerBlocks.push(block); |
450 parent.block.innerBlocks.push(block); |
373 const html = document.substr(parent.prevOffset, tokenStart - parent.prevOffset); |
451 const html = document.substr(parent.prevOffset, tokenStart - parent.prevOffset); |
374 |
|
375 if (html) { |
452 if (html) { |
376 parent.block.innerHTML += html; |
453 parent.block.innerHTML += html; |
377 parent.block.innerContent.push(html); |
454 parent.block.innerContent.push(html); |
378 } |
455 } |
379 |
|
380 parent.block.innerContent.push(null); |
456 parent.block.innerContent.push(null); |
381 parent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength; |
457 parent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength; |
382 } |
458 } |
383 |
459 |
|
460 /** |
|
461 * Adds block from the stack to the output. |
|
462 * |
|
463 * @param {number} [endOffset] |
|
464 */ |
384 function addBlockFromStack(endOffset) { |
465 function addBlockFromStack(endOffset) { |
385 const { |
466 const { |
386 block, |
467 block, |
387 leadingHtmlStart, |
468 leadingHtmlStart, |
388 prevOffset, |
469 prevOffset, |
389 tokenStart |
470 tokenStart |
390 } = stack.pop(); |
471 } = /** @type {ParsedFrame} */stack.pop(); |
391 const html = endOffset ? document.substr(prevOffset, endOffset - prevOffset) : document.substr(prevOffset); |
472 const html = endOffset ? document.substr(prevOffset, endOffset - prevOffset) : document.substr(prevOffset); |
392 |
|
393 if (html) { |
473 if (html) { |
394 block.innerHTML += html; |
474 block.innerHTML += html; |
395 block.innerContent.push(html); |
475 block.innerContent.push(html); |
396 } |
476 } |
397 |
|
398 if (null !== leadingHtmlStart) { |
477 if (null !== leadingHtmlStart) { |
399 output.push(Freeform(document.substr(leadingHtmlStart, tokenStart - leadingHtmlStart))); |
478 output.push(Freeform(document.substr(leadingHtmlStart, tokenStart - leadingHtmlStart))); |
400 } |
479 } |
401 |
|
402 output.push(block); |
480 output.push(block); |
403 } |
481 } |
404 |
482 |
405 (window.wp = window.wp || {}).blockSerializationDefaultParser = __webpack_exports__; |
483 (window.wp = window.wp || {}).blockSerializationDefaultParser = __webpack_exports__; |
406 /******/ })() |
484 /******/ })() |