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