[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/ -> shortcode.js (source)

   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  /************************************************************************/
  25  var __webpack_exports__ = {};
  26  
  27  // EXPORTS
  28  __webpack_require__.d(__webpack_exports__, {
  29    "default": () => (/* binding */ build_module)
  30  });
  31  
  32  // UNUSED EXPORTS: attrs, fromMatch, next, regexp, replace, string
  33  
  34  ;// ./node_modules/memize/dist/index.js
  35  /**
  36   * Memize options object.
  37   *
  38   * @typedef MemizeOptions
  39   *
  40   * @property {number} [maxSize] Maximum size of the cache.
  41   */
  42  
  43  /**
  44   * Internal cache entry.
  45   *
  46   * @typedef MemizeCacheNode
  47   *
  48   * @property {?MemizeCacheNode|undefined} [prev] Previous node.
  49   * @property {?MemizeCacheNode|undefined} [next] Next node.
  50   * @property {Array<*>}                   args   Function arguments for cache
  51   *                                               entry.
  52   * @property {*}                          val    Function result.
  53   */
  54  
  55  /**
  56   * Properties of the enhanced function for controlling cache.
  57   *
  58   * @typedef MemizeMemoizedFunction
  59   *
  60   * @property {()=>void} clear Clear the cache.
  61   */
  62  
  63  /**
  64   * Accepts a function to be memoized, and returns a new memoized function, with
  65   * optional options.
  66   *
  67   * @template {(...args: any[]) => any} F
  68   *
  69   * @param {F}             fn        Function to memoize.
  70   * @param {MemizeOptions} [options] Options object.
  71   *
  72   * @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
  73   */
  74  function memize(fn, options) {
  75      var size = 0;
  76  
  77      /** @type {?MemizeCacheNode|undefined} */
  78      var head;
  79  
  80      /** @type {?MemizeCacheNode|undefined} */
  81      var tail;
  82  
  83      options = options || {};
  84  
  85  	function memoized(/* ...args */) {
  86          var node = head,
  87              len = arguments.length,
  88              args,
  89              i;
  90  
  91          searchCache: while (node) {
  92              // Perform a shallow equality test to confirm that whether the node
  93              // under test is a candidate for the arguments passed. Two arrays
  94              // are shallowly equal if their length matches and each entry is
  95              // strictly equal between the two sets. Avoid abstracting to a
  96              // function which could incur an arguments leaking deoptimization.
  97  
  98              // Check whether node arguments match arguments length
  99              if (node.args.length !== arguments.length) {
 100                  node = node.next;
 101                  continue;
 102              }
 103  
 104              // Check whether node arguments match arguments values
 105              for (i = 0; i < len; i++) {
 106                  if (node.args[i] !== arguments[i]) {
 107                      node = node.next;
 108                      continue searchCache;
 109                  }
 110              }
 111  
 112              // At this point we can assume we've found a match
 113  
 114              // Surface matched node to head if not already
 115              if (node !== head) {
 116                  // As tail, shift to previous. Must only shift if not also
 117                  // head, since if both head and tail, there is no previous.
 118                  if (node === tail) {
 119                      tail = node.prev;
 120                  }
 121  
 122                  // Adjust siblings to point to each other. If node was tail,
 123                  // this also handles new tail's empty `next` assignment.
 124                  /** @type {MemizeCacheNode} */ (node.prev).next = node.next;
 125                  if (node.next) {
 126                      node.next.prev = node.prev;
 127                  }
 128  
 129                  node.next = head;
 130                  node.prev = null;
 131                  /** @type {MemizeCacheNode} */ (head).prev = node;
 132                  head = node;
 133              }
 134  
 135              // Return immediately
 136              return node.val;
 137          }
 138  
 139          // No cached value found. Continue to insertion phase:
 140  
 141          // Create a copy of arguments (avoid leaking deoptimization)
 142          args = new Array(len);
 143          for (i = 0; i < len; i++) {
 144              args[i] = arguments[i];
 145          }
 146  
 147          node = {
 148              args: args,
 149  
 150              // Generate the result from original function
 151              val: fn.apply(null, args),
 152          };
 153  
 154          // Don't need to check whether node is already head, since it would
 155          // have been returned above already if it was
 156  
 157          // Shift existing head down list
 158          if (head) {
 159              head.prev = node;
 160              node.next = head;
 161          } else {
 162              // If no head, follows that there's no tail (at initial or reset)
 163              tail = node;
 164          }
 165  
 166          // Trim tail if we're reached max size and are pending cache insertion
 167          if (size === /** @type {MemizeOptions} */ (options).maxSize) {
 168              tail = /** @type {MemizeCacheNode} */ (tail).prev;
 169              /** @type {MemizeCacheNode} */ (tail).next = null;
 170          } else {
 171              size++;
 172          }
 173  
 174          head = node;
 175  
 176          return node.val;
 177      }
 178  
 179      memoized.clear = function () {
 180          head = null;
 181          tail = null;
 182          size = 0;
 183      };
 184  
 185      // Ignore reason: There's not a clear solution to create an intersection of
 186      // the function with additional properties, where the goal is to retain the
 187      // function signature of the incoming argument and add control properties
 188      // on the return value.
 189  
 190      // @ts-ignore
 191      return memoized;
 192  }
 193  
 194  
 195  
 196  ;// ./node_modules/@wordpress/shortcode/build-module/index.js
 197  /* wp:polyfill */
 198  /**
 199   * External dependencies
 200   */
 201  
 202  
 203  
 204  /**
 205   * Find the next matching shortcode.
 206   *
 207   * @param {string} tag   Shortcode tag.
 208   * @param {string} text  Text to search.
 209   * @param {number} index Index to start search from.
 210   *
 211   * @return {import('./types').ShortcodeMatch | undefined} Matched information.
 212   */
 213  function next(tag, text, index = 0) {
 214    const re = regexp(tag);
 215    re.lastIndex = index;
 216    const match = re.exec(text);
 217    if (!match) {
 218      return;
 219    }
 220  
 221    // If we matched an escaped shortcode, try again.
 222    if ('[' === match[1] && ']' === match[7]) {
 223      return next(tag, text, re.lastIndex);
 224    }
 225    const result = {
 226      index: match.index,
 227      content: match[0],
 228      shortcode: fromMatch(match)
 229    };
 230  
 231    // If we matched a leading `[`, strip it from the match and increment the
 232    // index accordingly.
 233    if (match[1]) {
 234      result.content = result.content.slice(1);
 235      result.index++;
 236    }
 237  
 238    // If we matched a trailing `]`, strip it from the match.
 239    if (match[7]) {
 240      result.content = result.content.slice(0, -1);
 241    }
 242    return result;
 243  }
 244  
 245  /**
 246   * Replace matching shortcodes in a block of text.
 247   *
 248   * @param {string}                            tag      Shortcode tag.
 249   * @param {string}                            text     Text to search.
 250   * @param {import('./types').ReplaceCallback} callback Function to process the match and return
 251   *                                                     replacement string.
 252   *
 253   * @return {string} Text with shortcodes replaced.
 254   */
 255  function replace(tag, text, callback) {
 256    return text.replace(regexp(tag), function (match, left, $3, attrs, slash, content, closing, right) {
 257      // If both extra brackets exist, the shortcode has been properly
 258      // escaped.
 259      if (left === '[' && right === ']') {
 260        return match;
 261      }
 262  
 263      // Create the match object and pass it through the callback.
 264      const result = callback(fromMatch(arguments));
 265  
 266      // Make sure to return any of the extra brackets if they weren't used to
 267      // escape the shortcode.
 268      return result || result === '' ? left + result + right : match;
 269    });
 270  }
 271  
 272  /**
 273   * Generate a string from shortcode parameters.
 274   *
 275   * Creates a shortcode instance and returns a string.
 276   *
 277   * Accepts the same `options` as the `shortcode()` constructor, containing a
 278   * `tag` string, a string or object of `attrs`, a boolean indicating whether to
 279   * format the shortcode using a `single` tag, and a `content` string.
 280   *
 281   * @param {Object} options
 282   *
 283   * @return {string} String representation of the shortcode.
 284   */
 285  function string(options) {
 286    return new shortcode(options).string();
 287  }
 288  
 289  /**
 290   * Generate a RegExp to identify a shortcode.
 291   *
 292   * The base regex is functionally equivalent to the one found in
 293   * `get_shortcode_regex()` in `wp-includes/shortcodes.php`.
 294   *
 295   * Capture groups:
 296   *
 297   * 1. An extra `[` to allow for escaping shortcodes with double `[[]]`
 298   * 2. The shortcode name
 299   * 3. The shortcode argument list
 300   * 4. The self closing `/`
 301   * 5. The content of a shortcode when it wraps some content.
 302   * 6. The closing tag.
 303   * 7. An extra `]` to allow for escaping shortcodes with double `[[]]`
 304   *
 305   * @param {string} tag Shortcode tag.
 306   *
 307   * @return {RegExp} Shortcode RegExp.
 308   */
 309  function regexp(tag) {
 310    return new RegExp('\\[(\\[?)(' + tag + ')(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*(?:\\[(?!\\/\\2\\])[^\\[]*)*)(\\[\\/\\2\\]))?)(\\]?)', 'g');
 311  }
 312  
 313  /**
 314   * Parse shortcode attributes.
 315   *
 316   * Shortcodes accept many types of attributes. These can chiefly be divided into
 317   * named and numeric attributes:
 318   *
 319   * Named attributes are assigned on a key/value basis, while numeric attributes
 320   * are treated as an array.
 321   *
 322   * Named attributes can be formatted as either `name="value"`, `name='value'`,
 323   * or `name=value`. Numeric attributes can be formatted as `"value"` or just
 324   * `value`.
 325   *
 326   * @param {string} text Serialised shortcode attributes.
 327   *
 328   * @return {import('./types').ShortcodeAttrs} Parsed shortcode attributes.
 329   */
 330  const attrs = memize(text => {
 331    const named = {};
 332    const numeric = [];
 333  
 334    // This regular expression is reused from `shortcode_parse_atts()` in
 335    // `wp-includes/shortcodes.php`.
 336    //
 337    // Capture groups:
 338    //
 339    // 1. An attribute name, that corresponds to...
 340    // 2. a value in double quotes.
 341    // 3. An attribute name, that corresponds to...
 342    // 4. a value in single quotes.
 343    // 5. An attribute name, that corresponds to...
 344    // 6. an unquoted value.
 345    // 7. A numeric attribute in double quotes.
 346    // 8. A numeric attribute in single quotes.
 347    // 9. An unquoted numeric attribute.
 348    const pattern = /([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*'([^']*)'(?:\s|$)|([\w-]+)\s*=\s*([^\s'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|'([^']*)'(?:\s|$)|(\S+)(?:\s|$)/g;
 349  
 350    // Map zero-width spaces to actual spaces.
 351    text = text.replace(/[\u00a0\u200b]/g, ' ');
 352    let match;
 353  
 354    // Match and normalize attributes.
 355    while (match = pattern.exec(text)) {
 356      if (match[1]) {
 357        named[match[1].toLowerCase()] = match[2];
 358      } else if (match[3]) {
 359        named[match[3].toLowerCase()] = match[4];
 360      } else if (match[5]) {
 361        named[match[5].toLowerCase()] = match[6];
 362      } else if (match[7]) {
 363        numeric.push(match[7]);
 364      } else if (match[8]) {
 365        numeric.push(match[8]);
 366      } else if (match[9]) {
 367        numeric.push(match[9]);
 368      }
 369    }
 370    return {
 371      named,
 372      numeric
 373    };
 374  });
 375  
 376  /**
 377   * Generate a Shortcode Object from a RegExp match.
 378   *
 379   * Accepts a `match` object from calling `regexp.exec()` on a `RegExp` generated
 380   * by `regexp()`. `match` can also be set to the `arguments` from a callback
 381   * passed to `regexp.replace()`.
 382   *
 383   * @param {import('./types').Match} match Match array.
 384   *
 385   * @return {InstanceType<import('./types').shortcode>} Shortcode instance.
 386   */
 387  function fromMatch(match) {
 388    let type;
 389    if (match[4]) {
 390      type = 'self-closing';
 391    } else if (match[6]) {
 392      type = 'closed';
 393    } else {
 394      type = 'single';
 395    }
 396    return new shortcode({
 397      tag: match[2],
 398      attrs: match[3],
 399      type,
 400      content: match[5]
 401    });
 402  }
 403  
 404  /**
 405   * Creates a shortcode instance.
 406   *
 407   * To access a raw representation of a shortcode, pass an `options` object,
 408   * containing a `tag` string, a string or object of `attrs`, a string indicating
 409   * the `type` of the shortcode ('single', 'self-closing', or 'closed'), and a
 410   * `content` string.
 411   *
 412   * @type {import('./types').shortcode} Shortcode instance.
 413   */
 414  const shortcode = Object.assign(function (options) {
 415    const {
 416      tag,
 417      attrs: attributes,
 418      type,
 419      content
 420    } = options || {};
 421    Object.assign(this, {
 422      tag,
 423      type,
 424      content
 425    });
 426  
 427    // Ensure we have a correctly formatted `attrs` object.
 428    this.attrs = {
 429      named: {},
 430      numeric: []
 431    };
 432    if (!attributes) {
 433      return;
 434    }
 435    const attributeTypes = ['named', 'numeric'];
 436  
 437    // Parse a string of attributes.
 438    if (typeof attributes === 'string') {
 439      this.attrs = attrs(attributes);
 440      // Identify a correctly formatted `attrs` object.
 441    } else if (attributes.length === attributeTypes.length && attributeTypes.every((t, key) => t === attributes[key])) {
 442      this.attrs = attributes;
 443      // Handle a flat object of attributes.
 444    } else {
 445      Object.entries(attributes).forEach(([key, value]) => {
 446        this.set(key, value);
 447      });
 448    }
 449  }, {
 450    next,
 451    replace,
 452    string,
 453    regexp,
 454    attrs,
 455    fromMatch
 456  });
 457  Object.assign(shortcode.prototype, {
 458    /**
 459     * Get a shortcode attribute.
 460     *
 461     * Automatically detects whether `attr` is named or numeric and routes it
 462     * accordingly.
 463     *
 464     * @param {(number|string)} attr Attribute key.
 465     *
 466     * @return {string} Attribute value.
 467     */
 468    get(attr) {
 469      return this.attrs[typeof attr === 'number' ? 'numeric' : 'named'][attr];
 470    },
 471    /**
 472     * Set a shortcode attribute.
 473     *
 474     * Automatically detects whether `attr` is named or numeric and routes it
 475     * accordingly.
 476     *
 477     * @param {(number|string)} attr  Attribute key.
 478     * @param {string}          value Attribute value.
 479     *
 480     * @return {InstanceType< import('./types').shortcode >} Shortcode instance.
 481     */
 482    set(attr, value) {
 483      this.attrs[typeof attr === 'number' ? 'numeric' : 'named'][attr] = value;
 484      return this;
 485    },
 486    /**
 487     * Transform the shortcode into a string.
 488     *
 489     * @return {string} String representation of the shortcode.
 490     */
 491    string() {
 492      let text = '[' + this.tag;
 493      this.attrs.numeric.forEach(value => {
 494        if (/\s/.test(value)) {
 495          text += ' "' + value + '"';
 496        } else {
 497          text += ' ' + value;
 498        }
 499      });
 500      Object.entries(this.attrs.named).forEach(([name, value]) => {
 501        text += ' ' + name + '="' + value + '"';
 502      });
 503  
 504      // If the tag is marked as `single` or `self-closing`, close the tag and
 505      // ignore any additional content.
 506      if ('single' === this.type) {
 507        return text + ']';
 508      } else if ('self-closing' === this.type) {
 509        return text + ' /]';
 510      }
 511  
 512      // Complete the opening tag.
 513      text += ']';
 514      if (this.content) {
 515        text += this.content;
 516      }
 517  
 518      // Add the closing tag.
 519      return text + '[/' + this.tag + ']';
 520    }
 521  });
 522  /* harmony default export */ const build_module = (shortcode);
 523  
 524  (window.wp = window.wp || {}).shortcode = __webpack_exports__["default"];
 525  /******/ })()
 526  ;


Generated : Sat Feb 22 08:20:01 2025 Cross-referenced by PHPXref