[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 /******/ (() => { // webpackBootstrap 2 /******/ "use strict"; 3 /******/ // The require scope 4 /******/ var __webpack_require__ = {}; 5 /******/ 6 /************************************************************************/ 7 /******/ /* webpack/runtime/define property getters */ 8 /******/ (() => { 9 /******/ // define getter functions for harmony exports 10 /******/ __webpack_require__.d = (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 /******/ (() => { 21 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 22 /******/ })(); 23 /******/ 24 /******/ /* webpack/runtime/make namespace object */ 25 /******/ (() => { 26 /******/ // define __esModule on exports 27 /******/ __webpack_require__.r = (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 */ parse: () => (/* binding */ parse) 40 /* harmony export */ }); 41 /** 42 * @type {string} 43 */ 44 let document; 45 /** 46 * @type {number} 47 */ 48 let offset; 49 /** 50 * @type {ParsedBlock[]} 51 */ 52 let output; 53 /** 54 * @type {ParsedFrame[]} 55 */ 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 88 /** 89 * Matches block comment delimiters 90 * 91 * While most of this pattern is straightforward the attribute parsing 92 * incorporates a tricks to make sure we don't choke on specific input 93 * 94 * - since JavaScript has no possessive quantifier or atomic grouping 95 * we are emulating it with a trick 96 * 97 * we want a possessive quantifier or atomic group to prevent backtracking 98 * on the `}`s should we fail to match the remainder of the pattern 99 * 100 * we can emulate this with a positive lookahead and back reference 101 * (a++)*c === ((?=(a+))\1)*c 102 * 103 * let's examine an example: 104 * - /(a+)*c/.test('aaaaaaaaaaaaad') fails after over 49,000 steps 105 * - /(a++)*c/.test('aaaaaaaaaaaaad') fails after 85 steps 106 * - /(?>a+)*c/.test('aaaaaaaaaaaaad') fails after 126 steps 107 * 108 * this is because the possessive `++` and the atomic group `(?>)` 109 * tell the engine that all those `a`s belong together as a single group 110 * and so it won't split it up when stepping backwards to try and match 111 * 112 * if we use /((?=(a+))\1)*c/ then we get the same behavior as the atomic group 113 * or possessive and prevent the backtracking because the `a+` is matched but 114 * not captured. thus, we find the long string of `a`s and remember it, then 115 * reference it as a whole unit inside our pattern 116 * 117 * @see http://instanceof.me/post/52245507631/regex-emulate-atomic-grouping-with-lookahead 118 * @see http://blog.stevenlevithan.com/archives/mimic-atomic-groups 119 * @see https://javascript.info/regexp-infinite-backtracking-problem 120 * 121 * once browsers reliably support atomic grouping or possessive 122 * quantifiers natively we should remove this trick and simplify 123 * 124 * @type {RegExp} 125 * 126 * @since 3.8.0 127 * @since 4.6.1 added optimization to prevent backtracking on attribute parsing 128 */ 129 const tokenizer = /<!--\s+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)\s+({(?:(?=([^}]+|}+(?=})|(?!}\s+\/?-->)[^])*)\5|[^]*?)}\s+)?(\/)?-->/g; 130 131 /** 132 * Constructs a block object. 133 * 134 * @param {string|null} blockName 135 * @param {Attributes} attrs 136 * @param {ParsedBlock[]} innerBlocks 137 * @param {string} innerHTML 138 * @param {string[]} innerContent 139 * @return {ParsedBlock} The block object. 140 */ 141 function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) { 142 return { 143 blockName, 144 attrs, 145 innerBlocks, 146 innerHTML, 147 innerContent 148 }; 149 } 150 151 /** 152 * Constructs a freeform block object. 153 * 154 * @param {string} innerHTML 155 * @return {ParsedBlock} The freeform block object. 156 */ 157 function Freeform(innerHTML) { 158 return Block(null, {}, [], innerHTML, [innerHTML]); 159 } 160 161 /** 162 * Constructs a frame object. 163 * 164 * @param {ParsedBlock} block 165 * @param {number} tokenStart 166 * @param {number} tokenLength 167 * @param {number} prevOffset 168 * @param {number|null} leadingHtmlStart 169 * @return {ParsedFrame} The frame object. 170 */ 171 function Frame(block, tokenStart, tokenLength, prevOffset, leadingHtmlStart) { 172 return { 173 block, 174 tokenStart, 175 tokenLength, 176 prevOffset: prevOffset || tokenStart + tokenLength, 177 leadingHtmlStart 178 }; 179 } 180 181 /** 182 * Parser function, that converts input HTML into a block based structure. 183 * 184 * @param {string} doc The HTML document to parse. 185 * 186 * @example 187 * Input post: 188 * ```html 189 * <!-- wp:columns {"columns":3} --> 190 * <div class="wp-block-columns has-3-columns"><!-- wp:column --> 191 * <div class="wp-block-column"><!-- wp:paragraph --> 192 * <p>Left</p> 193 * <!-- /wp:paragraph --></div> 194 * <!-- /wp:column --> 195 * 196 * <!-- wp:column --> 197 * <div class="wp-block-column"><!-- wp:paragraph --> 198 * <p><strong>Middle</strong></p> 199 * <!-- /wp:paragraph --></div> 200 * <!-- /wp:column --> 201 * 202 * <!-- wp:column --> 203 * <div class="wp-block-column"></div> 204 * <!-- /wp:column --></div> 205 * <!-- /wp:columns --> 206 * ``` 207 * 208 * Parsing code: 209 * ```js 210 * import { parse } from '@wordpress/block-serialization-default-parser'; 211 * 212 * parse( post ) === [ 213 * { 214 * blockName: "core/columns", 215 * attrs: { 216 * columns: 3 217 * }, 218 * innerBlocks: [ 219 * { 220 * blockName: "core/column", 221 * attrs: null, 222 * innerBlocks: [ 223 * { 224 * blockName: "core/paragraph", 225 * attrs: null, 226 * innerBlocks: [], 227 * innerHTML: "\n<p>Left</p>\n" 228 * } 229 * ], 230 * innerHTML: '\n<div class="wp-block-column"></div>\n' 231 * }, 232 * { 233 * blockName: "core/column", 234 * attrs: null, 235 * innerBlocks: [ 236 * { 237 * blockName: "core/paragraph", 238 * attrs: null, 239 * innerBlocks: [], 240 * innerHTML: "\n<p><strong>Middle</strong></p>\n" 241 * } 242 * ], 243 * innerHTML: '\n<div class="wp-block-column"></div>\n' 244 * }, 245 * { 246 * blockName: "core/column", 247 * attrs: null, 248 * innerBlocks: [], 249 * innerHTML: '\n<div class="wp-block-column"></div>\n' 250 * } 251 * ], 252 * innerHTML: '\n<div class="wp-block-columns has-3-columns">\n\n\n\n</div>\n' 253 * } 254 * ]; 255 * ``` 256 * @return {ParsedBlock[]} A block-based representation of the input HTML. 257 */ 258 const parse = doc => { 259 document = doc; 260 offset = 0; 261 output = []; 262 stack = []; 263 tokenizer.lastIndex = 0; 264 do { 265 // twiddle our thumbs 266 } while (proceed()); 267 return output; 268 }; 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 */ 275 function proceed() { 276 const stackDepth = stack.length; 277 const next = nextToken(); 278 const [tokenType, blockName, attrs, startOffset, tokenLength] = next; 279 280 // We may have some HTML soup before the next block. 281 const leadingHtmlStart = startOffset > offset ? offset : null; 282 switch (tokenType) { 283 case 'no-more-tokens': 284 // If not in a block then flush output. 285 if (0 === stackDepth) { 286 addFreeform(); 287 return false; 288 } 289 290 // Otherwise we have a problem 291 // This is an error 292 // we have options 293 // - treat it all as freeform text 294 // - assume an implicit closer (easiest when not nesting) 295 296 // For the easy case we'll assume an implicit closer. 297 if (1 === stackDepth) { 298 addBlockFromStack(); 299 return false; 300 } 301 302 // For the nested case where it's more difficult we'll 303 // have to assume that multiple closers are missing 304 // and so we'll collapse the whole stack piecewise. 305 while (0 < stack.length) { 306 addBlockFromStack(); 307 } 308 return false; 309 case 'void-block': 310 // easy case is if we stumbled upon a void block 311 // in the top-level of the document. 312 if (0 === stackDepth) { 313 if (null !== leadingHtmlStart) { 314 output.push(Freeform(document.substr(leadingHtmlStart, startOffset - leadingHtmlStart))); 315 } 316 output.push(Block(blockName, attrs, [], '', [])); 317 offset = startOffset + tokenLength; 318 return true; 319 } 320 321 // Otherwise we found an inner block. 322 addInnerBlock(Block(blockName, attrs, [], '', []), startOffset, tokenLength); 323 offset = startOffset + tokenLength; 324 return true; 325 case 'block-opener': 326 // Track all newly-opened blocks on the stack. 327 stack.push(Frame(Block(blockName, attrs, [], '', []), startOffset, tokenLength, startOffset + tokenLength, leadingHtmlStart)); 328 offset = startOffset + tokenLength; 329 return true; 330 case 'block-closer': 331 // If we're missing an opener we're in trouble 332 // This is an error. 333 if (0 === stackDepth) { 334 // We have options 335 // - assume an implicit opener 336 // - assume _this_ is the opener 337 // - give up and close out the document. 338 addFreeform(); 339 return false; 340 } 341 342 // If we're not nesting then this is easy - close the block. 343 if (1 === stackDepth) { 344 addBlockFromStack(startOffset); 345 offset = startOffset + tokenLength; 346 return true; 347 } 348 349 // Otherwise we're nested and we have to close out the current 350 // block and add it as a innerBlock to the parent. 351 const stackTop = /** @type {ParsedFrame} */stack.pop(); 352 const html = document.substr(stackTop.prevOffset, startOffset - stackTop.prevOffset); 353 stackTop.block.innerHTML += html; 354 stackTop.block.innerContent.push(html); 355 stackTop.prevOffset = startOffset + tokenLength; 356 addInnerBlock(stackTop.block, stackTop.tokenStart, stackTop.tokenLength, startOffset + tokenLength); 357 offset = startOffset + tokenLength; 358 return true; 359 default: 360 // This is an error. 361 addFreeform(); 362 return false; 363 } 364 } 365 366 /** 367 * Parse JSON if valid, otherwise return null 368 * 369 * Note that JSON coming from the block comment 370 * delimiters is constrained to be an object 371 * and cannot be things like `true` or `null` 372 * 373 * @param {string} input JSON input string to parse 374 * @return {Object|null} parsed JSON if valid 375 */ 376 function parseJSON(input) { 377 try { 378 return JSON.parse(input); 379 } catch (e) { 380 return null; 381 } 382 } 383 384 /** 385 * Finds the next token in the document. 386 * 387 * @return {Token} The next matched token. 388 */ 389 function nextToken() { 390 // Aye the magic 391 // we're using a single RegExp to tokenize the block comment delimiters 392 // we're also using a trick here because the only difference between a 393 // block opener and a block closer is the leading `/` before `wp:` (and 394 // a closer has no attributes). we can trap them both and process the 395 // match back in JavaScript to see which one it was. 396 const matches = tokenizer.exec(document); 397 398 // We have no more tokens. 399 if (null === matches) { 400 return ['no-more-tokens', '', null, 0, 0]; 401 } 402 const startedAt = matches.index; 403 const [match, closerMatch, namespaceMatch, nameMatch, attrsMatch /* Internal/unused. */,, voidMatch] = matches; 404 const length = match.length; 405 const isCloser = !!closerMatch; 406 const isVoid = !!voidMatch; 407 const namespace = namespaceMatch || 'core/'; 408 const name = namespace + nameMatch; 409 const hasAttrs = !!attrsMatch; 410 const attrs = hasAttrs ? parseJSON(attrsMatch) : {}; 411 412 // This state isn't allowed 413 // This is an error. 414 if (isCloser && (isVoid || hasAttrs)) { 415 // We can ignore them since they don't hurt anything 416 // we may warn against this at some point or reject it. 417 } 418 if (isVoid) { 419 return ['void-block', name, attrs, startedAt, length]; 420 } 421 if (isCloser) { 422 return ['block-closer', name, null, startedAt, length]; 423 } 424 return ['block-opener', name, attrs, startedAt, length]; 425 } 426 427 /** 428 * Adds a freeform block to the output. 429 * 430 * @param {number} [rawLength] 431 */ 432 function addFreeform(rawLength) { 433 const length = rawLength ? rawLength : document.length - offset; 434 if (0 === length) { 435 return; 436 } 437 output.push(Freeform(document.substr(offset, length))); 438 } 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 */ 448 function addInnerBlock(block, tokenStart, tokenLength, lastOffset) { 449 const parent = stack[stack.length - 1]; 450 parent.block.innerBlocks.push(block); 451 const html = document.substr(parent.prevOffset, tokenStart - parent.prevOffset); 452 if (html) { 453 parent.block.innerHTML += html; 454 parent.block.innerContent.push(html); 455 } 456 parent.block.innerContent.push(null); 457 parent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength; 458 } 459 460 /** 461 * Adds block from the stack to the output. 462 * 463 * @param {number} [endOffset] 464 */ 465 function addBlockFromStack(endOffset) { 466 const { 467 block, 468 leadingHtmlStart, 469 prevOffset, 470 tokenStart 471 } = /** @type {ParsedFrame} */stack.pop(); 472 const html = endOffset ? document.substr(prevOffset, endOffset - prevOffset) : document.substr(prevOffset); 473 if (html) { 474 block.innerHTML += html; 475 block.innerContent.push(html); 476 } 477 if (null !== leadingHtmlStart) { 478 output.push(Freeform(document.substr(leadingHtmlStart, tokenStart - leadingHtmlStart))); 479 } 480 output.push(block); 481 } 482 483 (window.wp = window.wp || {}).blockSerializationDefaultParser = __webpack_exports__; 484 /******/ })() 485 ;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Sat Nov 23 08:20:01 2024 | Cross-referenced by PHPXref |