[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-admin/js/ -> tags-box.js (source)

   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( '&nbsp;' ).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 ));


Generated : Mon Mar 18 08:20:01 2024 Cross-referenced by PHPXref