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