diff --git a/src/wp-admin/includes/class-wp-posts-list-table.php b/src/wp-admin/includes/class-wp-posts-list-table.php index 506dded3fd..983a274f85 100644 --- a/src/wp-admin/includes/class-wp-posts-list-table.php +++ b/src/wp-admin/includes/class-wp-posts-list-table.php @@ -1550,10 +1550,13 @@ class WP_Posts_List_Table extends WP_List_Table { - cap->assign_terms ) ) : ?> + cap->assign_terms ) ) : + $taxonomy_name = esc_attr( $taxonomy->name ); + + ?> diff --git a/src/wp-admin/includes/meta-boxes.php b/src/wp-admin/includes/meta-boxes.php index b345e6f7ec..98e20de417 100644 --- a/src/wp-admin/includes/meta-boxes.php +++ b/src/wp-admin/includes/meta-boxes.php @@ -431,7 +431,7 @@ function post_tags_meta_box( $post, $box ) {
labels->separate_items_with_commas; ?>
diff --git a/src/wp-admin/js/inline-edit-post.js b/src/wp-admin/js/inline-edit-post.js index 3a65805e3e..9582707479 100644 --- a/src/wp-admin/js/inline-edit-post.js +++ b/src/wp-admin/js/inline-edit-post.js @@ -83,7 +83,7 @@ inlineEditPost = { }, setBulk : function(){ - var te = '', type = this.type, tax, c = true; + var te = '', type = this.type, c = true; this.revert(); $( '#bulk-edit td' ).attr( 'colspan', $( 'th:visible, td:visible', '.widefat:first thead' ).length ); @@ -114,9 +114,9 @@ inlineEditPost = { // enable autocomplete for tags if ( 'post' === type ) { - // support multi taxonomies? - tax = 'post_tag'; - $('tr.inline-editor textarea[name="tax_input['+tax+']"]').suggest( ajaxurl + '?action=ajax-tag-search&tax=' + tax, { delay: 500, minchars: 2, multiple: true, multipleSep: inlineEditL10n.comma } ); + $( 'tr.inline-editor textarea[data-wp-taxonomy]' ).each( function ( i, element ) { + $( element ).wpTagsSuggest(); + } ); } $('html, body').animate( { scrollTop: 0 }, 'fast' ); }, @@ -196,7 +196,7 @@ inlineEditPost = { textarea.val(terms); } - textarea.suggest( ajaxurl + '?action=ajax-tag-search&tax=' + taxname, { delay: 500, minchars: 2, multiple: true, multipleSep: inlineEditL10n.comma } ); + textarea.wpTagsSuggest(); }); // handle the post status diff --git a/src/wp-admin/js/tags-box.js b/src/wp-admin/js/tags-box.js index af823ac4e6..d4cad9fb24 100644 --- a/src/wp-admin/js/tags-box.js +++ b/src/wp-admin/js/tags-box.js @@ -4,6 +4,8 @@ var tagBox, array_unique_noempty; ( function( $ ) { + var tagDelimiter = ( window.tagsSuggestL10n && window.tagsSuggestL10n.tagDelimiter ) || ','; + // Return an array with any duplicate, whitespace or empty values removed array_unique_noempty = function( array ) { var out = []; @@ -20,13 +22,17 @@ var tagBox, array_unique_noempty; }; tagBox = { - clean : function(tags) { - var comma = window.tagsBoxL10n.tagDelimiter; - if ( ',' !== comma ) - tags = tags.replace(new RegExp(comma, 'g'), ','); + clean : function( tags ) { + if ( ',' !== tagDelimiter ) { + tags = tags.replace( new RegExp( tagDelimiter, 'g' ), ',' ); + } + tags = tags.replace(/\s*,\s*/g, ',').replace(/,+/g, ',').replace(/[,\s]+$/, '').replace(/^[,\s]+/, ''); - if ( ',' !== comma ) - tags = tags.replace(/,/g, comma); + + if ( ',' !== tagDelimiter ) { + tags = tags.replace( /,/g, tagDelimiter ); + } + return tags; }, @@ -35,8 +41,7 @@ var tagBox, array_unique_noempty; num = id.split('-check-num-')[1], taxbox = $(el).closest('.tagsdiv'), thetags = taxbox.find('.the-tags'), - comma = window.tagsBoxL10n.tagDelimiter, - current_tags = thetags.val().split( comma ), + current_tags = thetags.val().split( tagDelimiter ), new_tags = []; delete current_tags[num]; @@ -48,7 +53,7 @@ var tagBox, array_unique_noempty; } }); - thetags.val( this.clean( new_tags.join( comma ) ) ); + thetags.val( this.clean( new_tags.join( tagDelimiter ) ) ); this.quickClicks( taxbox ); return false; @@ -65,7 +70,7 @@ var tagBox, array_unique_noempty; disabled = thetags.prop('disabled'); - current_tags = thetags.val().split( window.tagsBoxL10n.tagDelimiter ); + current_tags = thetags.val().split( tagDelimiter ); tagchecklist.empty(); $.each( current_tags, function( key, val ) { @@ -106,8 +111,7 @@ var tagBox, array_unique_noempty; flushTags : function( el, a, f ) { var tagsval, newtags, text, tags = $( '.the-tags', el ), - newtag = $( 'input.newtag', el ), - comma = window.tagsBoxL10n.tagDelimiter; + newtag = $( 'input.newtag', el ); a = a || false; @@ -118,10 +122,10 @@ var tagBox, array_unique_noempty; } tagsval = tags.val(); - newtags = tagsval ? tagsval + comma + text : text; + newtags = tagsval ? tagsval + tagDelimiter + text : text; newtags = this.clean( newtags ); - newtags = array_unique_noempty( newtags.split( comma ) ).join( comma ); + newtags = array_unique_noempty( newtags.split( tagDelimiter ) ).join( tagDelimiter ); tags.val( newtags ); this.quickClicks( el ); @@ -153,32 +157,29 @@ var tagBox, array_unique_noempty; }, init : function() { - var t = this, ajaxtag = $('div.ajaxtag'); + var ajaxtag = $('div.ajaxtag'); $('.tagsdiv').each( function() { - tagBox.quickClicks(this); + tagBox.quickClicks( this ); }); - $('.tagadd', ajaxtag).click(function(){ - t.flushTags( $(this).closest('.tagsdiv') ); + $( '.tagadd', ajaxtag ).click( function() { + tagBox.flushTags( $( this ).closest( '.tagsdiv' ) ); }); - $('input.newtag', ajaxtag).keyup(function(e){ - if ( 13 == e.which ) { - tagBox.flushTags( $(this).closest('.tagsdiv') ); - return false; + $( 'input.newtag', ajaxtag ).keyup( function( event ) { + if ( 13 == event.which ) { + tagBox.flushTags( $( this ).closest( '.tagsdiv' ) ); + event.preventDefault(); + event.stopPropagation(); } - }).keypress(function(e){ - if ( 13 == e.which ) { - e.preventDefault(); - return false; + }).keypress( function( event ) { + if ( 13 == event.which ) { + event.preventDefault(); + event.stopPropagation(); } - }).each( function() { - var tax = $(this).closest('div.tagsdiv').attr('id'); - $(this).suggest( - ajaxurl + '?action=ajax-tag-search&tax=' + tax, - { delay: 500, minchars: 2, multiple: true, multipleSep: window.tagsBoxL10n.tagDelimiter } - ); + }).each( function( i, element ) { + $( element ).wpTagsSuggest(); }); // save tags on post save/publish diff --git a/src/wp-admin/js/tags-suggest.js b/src/wp-admin/js/tags-suggest.js new file mode 100644 index 0000000000..b9e1632120 --- /dev/null +++ b/src/wp-admin/js/tags-suggest.js @@ -0,0 +1,167 @@ +( function( $ ) { + var tempID = 0; + var separator = ( window.tagsSuggestL10n && window.tagsSuggestL10n.tagDelimiter ) || ','; + + function split( val ) { + return val.split( new RegExp( separator + '\\s*' ) ); + } + + function getLast( term ) { + return split( term ).pop(); + } + + $.fn.wpTagsSuggest = function( options ) { + var cache; + var last; + var $element = $( this ); + + options = options || {}; + + var taxonomy = options.taxonomy || $element.attr( 'data-wp-taxonomy' ) || 'post_tag'; + + delete( options.taxonomy ); + + options = $.extend( { + source: function( request, response ) { + var term; + + if ( last === request.term ) { + response( cache ); + return; + } + + term = getLast( request.term ); + + $.get( window.ajaxurl, { + action: 'ajax-tag-search', + tax: taxonomy, + q: term + } ).always( function() { + $element.removeClass( 'ui-autocomplete-loading' ); // UI fails to remove this sometimes? + } ).done( function( data ) { + var value; + var terms = []; + + if ( data ) { + data = data.split( '\n' ); + + for ( value in data ) { + var id = ++tempID; + + terms.push({ + id: id, + name: data[value] + }); + } + + cache = terms; + response( terms ); + } else { + response( terms ); + } + } ); + + last = request.term; + }, + focus: function( event, ui ) { + $element.attr( 'aria-activedescendant', 'wp-tags-autocomplete-' + ui.item.id ); + + // Don't empty the input field when using the arrow keys to + // highlight items. See api.jqueryui.com/autocomplete/#event-focus + event.preventDefault(); + }, + select: function( event, ui ) { + var tags = split( $element.val() ); + // Remove the last user input. + tags.pop(); + // Append the new tag and an empty element to get one more separator at the end. + tags.push( ui.item.name, '' ); + + $element.val( tags.join( separator + ' ' ) ); + + if ( $.ui.keyCode.TAB === event.keyCode ) { + if ( typeof window.uiAutocompleteL10n !== 'undefined' ) { + // Audible confirmation message when a tag has been selected. + window.wp.a11y.speak( window.uiAutocompleteL10n.itemSelected ); + } + + event.preventDefault(); + } else if ( $.ui.keyCode.ENTER === event.keyCode ) { + // Do not close Quick Edit / Bulk Edit + event.preventDefault(); + event.stopPropagation(); + } + + return false; + }, + open: function() { + $element.attr( 'aria-expanded', 'true' ); + }, + close: function() { + $element.attr( 'aria-expanded', 'false' ); + }, + minLength: 2, + position: { + my: 'left top+2' + }, + messages: { + noResults: ( typeof window.uiAutocompleteL10n !== 'undefined' ) ? window.uiAutocompleteL10n.noResults : '', + results: function( number ) { + if ( typeof window.uiAutocompleteL10n !== 'undefined' ) { + if ( number > 1 ) { + return window.uiAutocompleteL10n.manyResults.replace( '%d', number ); + } + + return window.uiAutocompleteL10n.oneResult; + } + } + } + }, options ); + + $element.on( 'keydown', function() { + $element.removeAttr( 'aria-activedescendant' ); + } ) + .autocomplete( options ) + .autocomplete( 'instance' )._renderItem = function( ul, item ) { + return $( '