[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

   1  /**
   2   * Default settings for jQuery UI Autocomplete for use with non-hierarchical taxonomies.
   3   *
   4   * @output wp-admin/js/tags-suggest.js
   5   *
   6   * @param {JQueryStatic} $ The jQuery object.
   7   */
   8  ( function( $ ) {
   9      var tempID = 0;
  10      var separator = wp.i18n._x( ',', 'tag delimiter' ) || ',';
  11      var __ = wp.i18n.__,
  12          _n = wp.i18n._n,
  13          sprintf = wp.i18n.sprintf;
  14  
  15  	function split( val ) {
  16          return val.split( new RegExp( separator + '\\s*' ) );
  17      }
  18  
  19  	function getLast( term ) {
  20          return split( term ).pop();
  21      }
  22  
  23      /**
  24       * Add UI Autocomplete to an input or textarea element with presets for use
  25       * with non-hierarchical taxonomies.
  26       *
  27       * Example: `$( element ).wpTagsSuggest( options )`.
  28       *
  29       * The taxonomy can be passed in a `data-wp-taxonomy` attribute on the element or
  30       * can be in `options.taxonomy`.
  31       *
  32       * @since 4.7.0
  33       *
  34       * @param {Object} options Options that are passed to UI Autocomplete. Can be used to override the default settings.
  35       * @return {Object} jQuery instance.
  36       */
  37      $.fn.wpTagsSuggest = function( options ) {
  38          var cache;
  39          var last;
  40          var $element = $( this );
  41  
  42          // Do not initialize if the element doesn't exist.
  43          if ( ! $element.length ) {
  44              return this;
  45          }
  46  
  47          options = options || {};
  48  
  49          var taxonomy = options.taxonomy || $element.attr( 'data-wp-taxonomy' ) || 'post_tag';
  50  
  51          delete( options.taxonomy );
  52  
  53          options = $.extend( {
  54              source: function( request, response ) {
  55                  var term;
  56  
  57                  if ( last === request.term ) {
  58                      response( cache );
  59                      return;
  60                  }
  61  
  62                  term = getLast( request.term );
  63  
  64                  $.get( window.ajaxurl, {
  65                      action: 'ajax-tag-search',
  66                      tax: taxonomy,
  67                      q: term,
  68                      number: 20
  69                  } ).always( function() {
  70                      $element.removeClass( 'ui-autocomplete-loading' ); // UI fails to remove this sometimes?
  71                  } ).done( function( data ) {
  72                      var tagName;
  73                      var tags = [];
  74  
  75                      if ( data ) {
  76                          data = data.split( '\n' );
  77  
  78                          for ( tagName in data ) {
  79                              var id = ++tempID;
  80  
  81                              tags.push({
  82                                  id: id,
  83                                  name: data[tagName]
  84                              });
  85                          }
  86  
  87                          cache = tags;
  88                          response( tags );
  89                      } else {
  90                          response( tags );
  91                      }
  92                  } );
  93  
  94                  last = request.term;
  95              },
  96              focus: function( event, ui ) {
  97                  $element.attr( 'aria-activedescendant', 'wp-tags-autocomplete-' + ui.item.id );
  98  
  99                  // Don't empty the input field when using the arrow keys
 100                  // to highlight items. See api.jqueryui.com/autocomplete/#event-focus
 101                  event.preventDefault();
 102              },
 103              select: function( event, ui ) {
 104                  var tags = split( $element.val() );
 105                  // Remove the last user input.
 106                  tags.pop();
 107                  // Append the new tag and an empty element to get one more separator at the end.
 108                  tags.push( ui.item.name, '' );
 109  
 110                  $element.val( tags.join( separator + ' ' ) );
 111  
 112                  if ( $.ui.keyCode.TAB === event.keyCode ) {
 113                      // Audible confirmation message when a tag has been selected.
 114                      window.wp.a11y.speak( wp.i18n.__( 'Term selected.' ), 'assertive' );
 115                      event.preventDefault();
 116                  } else if ( $.ui.keyCode.ENTER === event.keyCode ) {
 117                      // If we're in the edit post Tags meta box, add the tag.
 118                      if ( window.tagBox ) {
 119                          window.tagBox.userAction = 'add';
 120                          window.tagBox.flushTags( $( this ).closest( '.tagsdiv' ) );
 121                      }
 122  
 123                      // Do not close Quick Edit / Bulk Edit.
 124                      event.preventDefault();
 125                      event.stopPropagation();
 126                  }
 127  
 128                  return false;
 129              },
 130              open: function() {
 131                  $element.attr( 'aria-expanded', 'true' );
 132              },
 133              close: function() {
 134                  $element.attr( 'aria-expanded', 'false' );
 135              },
 136              minLength: 2,
 137              position: {
 138                  my: 'left top+2',
 139                  at: 'left bottom',
 140                  collision: 'none'
 141              },
 142              messages: {
 143                  noResults: __( 'No results found.' ),
 144                  results: function( number ) {
 145                      return sprintf(
 146                          /* translators: %d: Number of search results found. */
 147                          _n(
 148                              '%d result found. Use up and down arrow keys to navigate.',
 149                              '%d results found. Use up and down arrow keys to navigate.',
 150                              number
 151                          ),
 152                          number
 153                      );
 154                  }
 155              }
 156          }, options );
 157  
 158          $element.on( 'keydown', function() {
 159              $element.removeAttr( 'aria-activedescendant' );
 160          } );
 161  
 162          $element.autocomplete( options );
 163  
 164          // Ensure the autocomplete instance exists.
 165          if ( ! $element.autocomplete( 'instance' ) ) {
 166              return this;
 167          }
 168  
 169          $element.autocomplete( 'instance' )._renderItem = function( ul, item ) {
 170              return $( '<li role="option" id="wp-tags-autocomplete-' + item.id + '">' )
 171                  .text( item.name )
 172                  .appendTo( ul );
 173          };
 174  
 175          $element.attr( {
 176              'role': 'combobox',
 177              'aria-autocomplete': 'list',
 178              'aria-expanded': 'false',
 179              'aria-owns': $element.autocomplete( 'widget' ).attr( 'id' )
 180          } )
 181          .on( 'focus', function() {
 182              var inputValue = split( $element.val() ).pop();
 183  
 184              // Don't trigger a search if the field is empty.
 185              // Also, avoids screen readers announce `No search results`.
 186              if ( inputValue ) {
 187                  $element.autocomplete( 'search' );
 188              }
 189          } );
 190  
 191          // Returns a jQuery object containing the menu element.
 192          $element.autocomplete( 'widget' )
 193              .addClass( 'wp-tags-autocomplete' )
 194              .attr( 'role', 'listbox' )
 195              .removeAttr( 'tabindex' ) // Remove the `tabindex=0` attribute added by jQuery UI.
 196  
 197              /*
 198               * Looks like Safari and VoiceOver need an `aria-selected` attribute. See ticket #33301.
 199               * The `menufocus` and `menublur` events are the same events used to add and remove
 200               * the `ui-state-focus` CSS class on the menu items. See jQuery UI Menu Widget.
 201               */
 202              .on( 'menufocus', function( event, ui ) {
 203                  ui.item.attr( 'aria-selected', 'true' );
 204              })
 205              .on( 'menublur', function() {
 206                  // The `menublur` event returns an object where the item is `null`,
 207                  // so we need to find the active item with other means.
 208                  $( this ).find( '[aria-selected="true"]' ).removeAttr( 'aria-selected' );
 209              });
 210  
 211          return this;
 212      };
 213  
 214  }( jQuery ) );


Generated : Thu Sep 3 08:20:25 2026 Cross-referenced by PHPXref