[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

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

   1  /**
   2   * Contains logic for deleting and adding tags.
   3   *
   4   * For deleting tags it makes a request to the server to delete the tag.
   5   * For adding tags it makes a request to the server to add the tag.
   6   *
   7   * @output wp-admin/js/tags.js
   8   */
   9  
  10   /* global ajaxurl, wpAjax, showNotice, validateForm */
  11  
  12  jQuery( function($) {
  13  
  14      var addingTerm = false;
  15  
  16      /**
  17       * Adds an event handler to the delete term link on the term overview page.
  18       *
  19       * Cancels default event handling and event bubbling.
  20       *
  21       * @since 2.8.0
  22       *
  23       * @return {boolean} Always returns false to cancel the default event handling.
  24       */
  25      $( '#the-list' ).on( 'click', '.delete-tag', function() {
  26          var t = $(this), tr = t.parents('tr'), r = true, data;
  27  
  28          if ( 'undefined' != showNotice )
  29              r = showNotice.warn();
  30  
  31          if ( r ) {
  32              data = t.attr('href').replace(/[^?]*\?/, '').replace(/action=delete/, 'action=delete-tag');
  33  
  34              tr.children().css('backgroundColor', '#faafaa');
  35  
  36              // Disable pointer events and all form controls/links in the row
  37              tr.css('pointer-events', 'none');
  38              tr.find(':input, a').prop('disabled', true).attr('tabindex', -1);
  39  
  40              /**
  41               * Makes a request to the server to delete the term that corresponds to the
  42               * delete term button.
  43               *
  44               * @param {string} r The response from the server.
  45               *
  46               * @return {void}
  47               */
  48              $.post(ajaxurl, data, function(r){
  49                  var message;
  50                  if ( '1' == r ) {
  51                      $('#ajax-response').empty();
  52                      let nextFocus = tr.next( 'tr' ).find( 'a.row-title' );
  53                      let prevFocus = tr.prev( 'tr' ).find( 'a.row-title' );
  54                      // If there is neither a next row or a previous row, focus the tag input field.
  55                      if ( nextFocus.length < 1 && prevFocus.length < 1 ) {
  56                          nextFocus = $( '#tag-name' ).trigger( 'focus' );
  57                      } else {
  58                          if ( nextFocus.length < 1 ) {
  59                              nextFocus = prevFocus;
  60                          }
  61                      }
  62                      tr.fadeOut('normal', function() {
  63                          tr.remove();
  64                          updateTableNavCount();
  65                      });
  66  
  67                      /**
  68                       * Removes the term from the parent box and the tag cloud.
  69                       *
  70                       * `data.match(/tag_ID=(\d+)/)[1]` matches the term ID from the data variable.
  71                       * This term ID is then used to select the relevant HTML elements:
  72                       * The parent box and the tag cloud.
  73                       */
  74                      $('select#parent option[value="' + data.match(/tag_ID=(\d+)/)[1] + '"]').remove();
  75                      $('a.tag-link-' + data.match(/tag_ID=(\d+)/)[1]).remove();
  76                      nextFocus.trigger( 'focus' );
  77                      message = wp.i18n.__( 'The selected tag has been deleted.' );
  78  
  79                  } else if ( '-1' == r ) {
  80                      message = wp.i18n.__( 'Sorry, you are not allowed to do that.' );
  81                      $('#ajax-response').empty().append('<div class="notice notice-error"><p>' + message + '</p></div>');
  82                      resetRowAfterFailure( tr );
  83  
  84                  } else {
  85                      message = wp.i18n.__( 'An error occurred while processing your request. Please try again later.' );
  86                      $('#ajax-response').empty().append('<div class="notice notice-error"><p>' + message + '</p></div>');
  87                      resetRowAfterFailure( tr );
  88                  }
  89                  wp.a11y.speak( message, 'assertive' );
  90              });
  91          }
  92  
  93          return false;
  94      });
  95  
  96      /**
  97       * Restores the original UI state of a table row after an AJAX failure.
  98       *
  99       * @param {jQuery} tr The table row to reset.
 100       * @return {void}
 101       */
 102  	function resetRowAfterFailure( tr ) {
 103          tr.children().css( 'backgroundColor', '' );
 104          tr.css( 'pointer-events', '' );
 105          tr.find( ':input, a' ).prop( 'disabled', false ).removeAttr( 'tabindex' );
 106      }
 107  
 108      /**
 109       * Updates the item count and table navigation after a tag is added or removed.
 110       *
 111       * Tags are added and removed client-side, but the item count, the `.tablenav`
 112       * regions, the search box, and the empty-state row are otherwise only
 113       * reconciled by PHP on a full page reload. This keeps them in sync.
 114       *
 115       * @param {string} [action] Pass 'add' when a tag was added. Any other value,
 116       *                          including none, is treated as a removal.
 117       *
 118       * @return {void}
 119       */
 120  	function updateTableNavCount( action ) {
 121          var $displayingNum = $( '.tablenav-pages .displaying-num' ),
 122              currentCount   = parseInt( $displayingNum.first().text().replace( /[^0-9]/g, '' ), 10 ) || 0,
 123              itemCount      = ( 'add' === action ) ? currentCount + 1 : Math.max( currentCount - 1, 0 ),
 124              formattedCount = itemCount.toLocaleString();
 125  
 126          $displayingNum.text(
 127              wp.i18n.sprintf(
 128                  /* translators: %s: Number of items. */
 129                  wp.i18n._n( '%s item', '%s items', itemCount ),
 130                  formattedCount
 131              )
 132          );
 133  
 134          if ( itemCount < 1 ) {
 135              // No tags remain: show the empty-state row and hide the navigation.
 136              var $list = $( '#the-list' );
 137  
 138               if ( ! $list.find( 'tr.no-items' ).length ) {
 139                   var colspan = $list.closest( 'table' ).find( 'thead > tr' ).first().children( ':not(.hidden)' ).length;
 140                   $list.append(
 141                       '<tr class="no-items"><td class="colspanchange" colspan="' + colspan + '">' +
 142                       wp.i18n.__( 'No tags found.' ) +
 143                       '</td></tr>'
 144                   );
 145               }
 146              $( '.tablenav > *' ).hide();
 147              $( 'p.search-box' ).hide();
 148          } else {
 149              $( '#the-list' ).find( 'tr.no-items' ).remove();
 150              $( '.tablenav > *' ).show();
 151              $( 'p.search-box' ).show();
 152          }
 153      }
 154  
 155      /**
 156       * Adds a deletion confirmation when removing a tag.
 157       *
 158       * @since 4.8.0
 159       *
 160       * @return {void}
 161       */
 162      $( '#edittag' ).on( 'click', '.delete', function( e ) {
 163          if ( 'undefined' === typeof showNotice ) {
 164              return true;
 165          }
 166  
 167          // Confirms the deletion, a negative response means the deletion must not be executed.
 168          var response = showNotice.warn();
 169          if ( ! response ) {
 170              e.preventDefault();
 171          }
 172      });
 173  
 174      /**
 175       * Adds an event handler to the form submit on the term overview page.
 176       *
 177       * Cancels default event handling and event bubbling.
 178       *
 179       * @since 2.8.0
 180       *
 181       * @return {boolean} Always returns false to cancel the default event handling.
 182       */
 183      $('#submit').on( 'click', function(){
 184          var form = $(this).parents('form');
 185  
 186          if ( addingTerm ) {
 187              // If we're adding a term, noop the button to avoid duplicate requests.
 188              return false;
 189          }
 190  
 191          addingTerm = true;
 192          form.find( '.submit .spinner' ).addClass( 'is-active' );
 193  
 194          /**
 195           * Does a request to the server to add a new term to the database
 196           *
 197           * @param {string} r The response from the server.
 198           *
 199           * @return {void}
 200           */
 201          $.post(ajaxurl, $('#addtag').serialize(), function(r){
 202              var res, parent, term, indent, i;
 203  
 204              addingTerm = false;
 205              form.find( '.submit .spinner' ).removeClass( 'is-active' );
 206  
 207              $('#ajax-response').empty();
 208              res = wpAjax.parseAjaxResponse( r, 'ajax-response' );
 209  
 210              if ( res.errors && res.responses[0].errors[0].code === 'empty_term_name' ) {
 211                  validateForm( form );
 212              }
 213  
 214              if ( ! res || res.errors ) {
 215                  return;
 216              }
 217  
 218              parent = form.find( 'select#parent' ).val();
 219  
 220              // If the parent exists on this page, insert it below. Else insert it at the top of the list.
 221              if ( parent > 0 && $('#tag-' + parent ).length > 0 ) {
 222                  // As the parent exists, insert the version with - - - prefixed.
 223                  $( '.tags #tag-' + parent ).after( res.responses[0].supplemental.noparents );
 224              } else {
 225                  // As the parent is not visible, insert the version with Parent - Child - ThisTerm.
 226                  $( '.tags' ).prepend( res.responses[0].supplemental.parents );
 227              }
 228  
 229              $('.tags .no-items').remove();
 230  
 231              if ( form.find('select#parent') ) {
 232                  // Parents field exists, Add new term to the list.
 233                  term = res.responses[1].supplemental;
 234  
 235                  // Create an indent for the Parent field.
 236                  indent = '';
 237                  for ( i = 0; i < res.responses[1].position; i++ )
 238                      indent += '&nbsp;&nbsp;&nbsp;';
 239  
 240                  form.find( 'select#parent option:selected' ).after( '<option value="' + term.term_id + '">' + indent + term.name + '</option>' );
 241              }
 242  
 243              $('input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):visible, textarea:visible', form).val('');
 244  
 245              updateTableNavCount( 'add' );
 246          });
 247  
 248          return false;
 249      });
 250  
 251  });


Generated : Sat Jul 25 08:20:20 2026 Cross-referenced by PHPXref