[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
1 /** 2 * @output wp-admin/js/tags-box.js 3 */ 4 5 /* jshint curly: false, eqeqeq: false */ 6 /* global ajaxurl, tagBox, array_unique_noempty */ 7 8 ( function( $ ) { 9 var tagDelimiter = wp.i18n._x( ',', 'tag delimiter' ) || ','; 10 11 /** 12 * Filters unique items and returns a new array. 13 * 14 * Filters all items from an array into a new array containing only the unique 15 * items. This also excludes whitespace or empty values. 16 * 17 * @since 2.8.0 18 * 19 * @global 20 * 21 * @param {Array} array The array to filter through. 22 * 23 * @return {Array} A new array containing only the unique items. 24 */ 25 window.array_unique_noempty = function( array ) { 26 var out = []; 27 28 // Trim the values and ensure they are unique. 29 $.each( array, function( key, val ) { 30 val = val || ''; 31 val = val.trim(); 32 33 if ( val && $.inArray( val, out ) === -1 ) { 34 out.push( val ); 35 } 36 } ); 37 38 return out; 39 }; 40 41 /** 42 * The TagBox object. 43 * 44 * Contains functions to create and manage tags that can be associated with a 45 * post. 46 * 47 * @since 2.9.0 48 * 49 * @global 50 */ 51 window.tagBox = { 52 /** 53 * Cleans up tags by removing redundant characters. 54 * 55 * @since 2.9.0 56 * 57 * @memberOf tagBox 58 * 59 * @param {string} tags Comma separated tags that need to be cleaned up. 60 * 61 * @return {string} The cleaned up tags. 62 */ 63 clean : function( tags ) { 64 if ( ',' !== tagDelimiter ) { 65 tags = tags.replace( new RegExp( tagDelimiter, 'g' ), ',' ); 66 } 67 68 tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, ''); 69 70 if ( ',' !== tagDelimiter ) { 71 tags = tags.replace( /,/g, tagDelimiter ); 72 } 73 74 return tags; 75 }, 76 77 /** 78 * Parses tags and makes them editable. 79 * 80 * @since 2.9.0 81 * 82 * @memberOf tagBox 83 * 84 * @param {Object} el The tag element to retrieve the ID from. 85 * 86 * @return {boolean} Always returns false. 87 */ 88 parseTags : function(el) { 89 var id = el.id, 90 num = id.split('-check-num-')[1], 91 taxbox = $(el).closest('.tagsdiv'), 92 thetags = taxbox.find('.the-tags'), 93 current_tags = thetags.val().split( tagDelimiter ), 94 new_tags = []; 95 96 delete current_tags[num]; 97 98 // Sanitize the current tags and push them as if they're new tags. 99 $.each( current_tags, function( key, val ) { 100 val = val || ''; 101 val = val.trim(); 102 if ( val ) { 103 new_tags.push( val ); 104 } 105 }); 106 107 thetags.val( this.clean( new_tags.join( tagDelimiter ) ) ); 108 109 this.quickClicks( taxbox ); 110 return false; 111 }, 112 113 /** 114 * Creates clickable links, buttons and fields for adding or editing tags. 115 * 116 * @since 2.9.0 117 * 118 * @memberOf tagBox 119 * 120 * @param {Object} el The container HTML element. 121 * 122 * @return {void} 123 */ 124 quickClicks : function( el ) { 125 var thetags = $('.the-tags', el), 126 tagchecklist = $('.tagchecklist', el), 127 id = $(el).attr('id'), 128 current_tags, disabled; 129 130 if ( ! thetags.length ) 131 return; 132 133 disabled = thetags.prop('disabled'); 134 135 current_tags = thetags.val().split( tagDelimiter ); 136 tagchecklist.empty(); 137 138 /** 139 * Creates a delete button if tag editing is enabled, before adding it to the tag list. 140 * 141 * @since 2.5.0 142 * 143 * @memberOf tagBox 144 * 145 * @param {string} key The index of the current tag. 146 * @param {string} val The value of the current tag. 147 * 148 * @return {void} 149 */ 150 $.each( current_tags, function( key, val ) { 151 var listItem, xbutton; 152 153 val = val || ''; 154 val = val.trim(); 155 156 if ( ! val ) 157 return; 158 159 // Create a new list item, and ensure the text is properly escaped. 160 listItem = $( '<li />' ).text( val ); 161 162 // If tags editing isn't disabled, create the X button. 163 if ( ! disabled ) { 164 /* 165 * Build the X buttons, hide the X icon with aria-hidden and 166 * use visually hidden text for screen readers. 167 */ 168 xbutton = $( '<button type="button" id="' + id + '-check-num-' + key + '" class="ntdelbutton">' + 169 '<span class="remove-tag-icon" aria-hidden="true"></span>' + 170 '<span class="screen-reader-text">' + wp.i18n.__( 'Remove term:' ) + ' ' + listItem.html() + '</span>' + 171 '</button>' ); 172 173 /** 174 * Handles the click and keypress event of the tag remove button. 175 * 176 * Makes sure the focus ends up in the tag input field when using 177 * the keyboard to delete the tag. 178 * 179 * @since 4.2.0 180 * 181 * @param {Event} e The click or keypress event to handle. 182 * 183 * @return {void} 184 */ 185 xbutton.on( 'click keypress', function( e ) { 186 // On click or when using the Enter/Spacebar keys. 187 if ( 'click' === e.type || 13 === e.keyCode || 32 === e.keyCode ) { 188 /* 189 * When using the keyboard, move focus back to the 190 * add new tag field. Note: when releasing the pressed 191 * key this will fire the `keyup` event on the input. 192 */ 193 if ( 13 === e.keyCode || 32 === e.keyCode ) { 194 $( this ).closest( '.tagsdiv' ).find( 'input.newtag' ).trigger( 'focus' ); 195 } 196 197 tagBox.userAction = 'remove'; 198 tagBox.parseTags( this ); 199 } 200 }); 201 202 listItem.prepend( ' ' ).prepend( xbutton ); 203 } 204 205 // Append the list item to the tag list. 206 tagchecklist.append( listItem ); 207 }); 208 209 // The buttons list is built now, give feedback to screen reader users. 210 tagBox.screenReadersMessage(); 211 }, 212 213 /** 214 * Adds a new tag. 215 * 216 * Also ensures that the quick links are properly generated. 217 * 218 * @since 2.9.0 219 * 220 * @memberOf tagBox 221 * 222 * @param {Object} el The container HTML element. 223 * @param {Object|boolean} a When this is an HTML element the text of that 224 * element will be used for the new tag. 225 * @param {number|boolean} f If this value is not passed then the tag input 226 * field is focused. 227 * 228 * @return {boolean} Always returns false. 229 */ 230 flushTags : function( el, a, f ) { 231 var tagsval, newtags, text, 232 tags = $( '.the-tags', el ), 233 newtag = $( 'input.newtag', el ); 234 235 a = a || false; 236 237 text = a ? $(a).text() : newtag.val(); 238 239 /* 240 * Return if there's no new tag or if the input field is empty. 241 * Note: when using the keyboard to add tags, focus is moved back to 242 * the input field and the `keyup` event attached on this field will 243 * fire when releasing the pressed key. Checking also for the field 244 * emptiness avoids to set the tags and call quickClicks() again. 245 */ 246 if ( 'undefined' == typeof( text ) || '' === text ) { 247 return false; 248 } 249 250 tagsval = tags.val(); 251 newtags = tagsval ? tagsval + tagDelimiter + text : text; 252 253 newtags = this.clean( newtags ); 254 newtags = array_unique_noempty( newtags.split( tagDelimiter ) ).join( tagDelimiter ); 255 tags.val( newtags ); 256 this.quickClicks( el ); 257 258 if ( ! a ) 259 newtag.val(''); 260 if ( 'undefined' == typeof( f ) ) 261 newtag.trigger( 'focus' ); 262 263 return false; 264 }, 265 266 /** 267 * Retrieves the available tags and creates a tagcloud. 268 * 269 * Retrieves the available tags from the database and creates an interactive 270 * tagcloud. Clicking a tag will add it. 271 * 272 * @since 2.9.0 273 * 274 * @memberOf tagBox 275 * 276 * @param {string} id The ID to extract the taxonomy from. 277 * 278 * @return {void} 279 */ 280 get : function( id ) { 281 var tax = id.substr( id.indexOf('-') + 1 ); 282 283 /** 284 * Puts a received tag cloud into a DOM element. 285 * 286 * The tag cloud HTML is generated on the server. 287 * 288 * @since 2.9.0 289 * 290 * @param {number|string} r The response message from the Ajax call. 291 * @param {string} stat The status of the Ajax request. 292 * 293 * @return {void} 294 */ 295 $.post( ajaxurl, { 'action': 'get-tagcloud', 'tax': tax }, function( r, stat ) { 296 if ( 0 === r || 'success' != stat ) { 297 return; 298 } 299 300 r = $( '<div id="tagcloud-' + tax + '" class="the-tagcloud">' + r + '</div>' ); 301 302 /** 303 * Adds a new tag when a tag in the tagcloud is clicked. 304 * 305 * @since 2.9.0 306 * 307 * @return {boolean} Returns false to prevent the default action. 308 */ 309 $( 'a', r ).on( 'click', function() { 310 tagBox.userAction = 'add'; 311 tagBox.flushTags( $( '#' + tax ), this ); 312 return false; 313 }); 314 315 $( '#' + id ).after( r ); 316 }); 317 }, 318 319 /** 320 * Track the user's last action. 321 * 322 * @since 4.7.0 323 */ 324 userAction: '', 325 326 /** 327 * Dispatches an audible message to screen readers. 328 * 329 * This will inform the user when a tag has been added or removed. 330 * 331 * @since 4.7.0 332 * 333 * @return {void} 334 */ 335 screenReadersMessage: function() { 336 var message; 337 338 switch ( this.userAction ) { 339 case 'remove': 340 message = wp.i18n.__( 'Term removed.' ); 341 break; 342 343 case 'add': 344 message = wp.i18n.__( 'Term added.' ); 345 break; 346 347 default: 348 return; 349 } 350 351 window.wp.a11y.speak( message, 'assertive' ); 352 }, 353 354 /** 355 * Initializes the tags box by setting up the links, buttons. Sets up event 356 * handling. 357 * 358 * This includes handling of pressing the enter key in the input field and the 359 * retrieval of tag suggestions. 360 * 361 * @since 2.9.0 362 * 363 * @memberOf tagBox 364 * 365 * @return {void} 366 */ 367 init : function() { 368 var ajaxtag = $('div.ajaxtag'); 369 370 $('.tagsdiv').each( function() { 371 tagBox.quickClicks( this ); 372 }); 373 374 $( '.tagadd', ajaxtag ).on( 'click', function() { 375 tagBox.userAction = 'add'; 376 tagBox.flushTags( $( this ).closest( '.tagsdiv' ) ); 377 }); 378 379 /** 380 * Handles pressing enter on the new tag input field. 381 * 382 * Prevents submitting the post edit form. Uses `keypress` to take 383 * into account Input Method Editor (IME) converters. 384 * 385 * @since 2.9.0 386 * 387 * @param {Event} event The keypress event that occurred. 388 * 389 * @return {void} 390 */ 391 $( 'input.newtag', ajaxtag ).on( 'keypress', function( event ) { 392 if ( 13 == event.which ) { 393 tagBox.userAction = 'add'; 394 tagBox.flushTags( $( this ).closest( '.tagsdiv' ) ); 395 event.preventDefault(); 396 event.stopPropagation(); 397 } 398 }).each( function( i, element ) { 399 $( element ).wpTagsSuggest(); 400 }); 401 402 /** 403 * Before a post is saved the value currently in the new tag input field will be 404 * added as a tag. 405 * 406 * @since 2.9.0 407 * 408 * @return {void} 409 */ 410 $('#post').on( 'submit', function(){ 411 $('div.tagsdiv').each( function() { 412 tagBox.flushTags(this, false, 1); 413 }); 414 }); 415 416 /** 417 * Handles clicking on the tag cloud link. 418 * 419 * Makes sure the ARIA attributes are set correctly. 420 * 421 * @since 2.9.0 422 * 423 * @return {void} 424 */ 425 $('.tagcloud-link').on( 'click', function(){ 426 // On the first click, fetch the tag cloud and insert it in the DOM. 427 tagBox.get( $( this ).attr( 'id' ) ); 428 // Update button state, remove previous click event and attach a new one to toggle the cloud. 429 $( this ) 430 .attr( 'aria-expanded', 'true' ) 431 .off() 432 .on( 'click', function() { 433 $( this ) 434 .attr( 'aria-expanded', 'false' === $( this ).attr( 'aria-expanded' ) ? 'true' : 'false' ) 435 .siblings( '.the-tagcloud' ).toggle(); 436 }); 437 }); 438 } 439 }; 440 }( jQuery ));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Dec 22 01:00:02 2024 | Cross-referenced by PHPXref 0.7.1 |