You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
430 lines
11 KiB
430 lines
11 KiB
/** |
|
* @output wp-admin/js/tags-box.js |
|
*/ |
|
|
|
/* jshint curly: false, eqeqeq: false */ |
|
/* global ajaxurl, tagBox, array_unique_noempty */ |
|
|
|
( function( $ ) { |
|
var tagDelimiter = ( window.tagsSuggestL10n && window.tagsSuggestL10n.tagDelimiter ) || ','; |
|
|
|
/** |
|
* Filters unique items and returns a new array. |
|
* |
|
* Filters all items from an array into a new array containing only the unique |
|
* items. This also excludes whitespace or empty values. |
|
* |
|
* @since 2.8.0 |
|
* |
|
* @global |
|
* |
|
* @param {Array} array The array to filter through. |
|
* |
|
* @return {Array} A new array containing only the unique items. |
|
*/ |
|
window.array_unique_noempty = function( array ) { |
|
var out = []; |
|
|
|
// Trim the values and ensure they are unique. |
|
$.each( array, function( key, val ) { |
|
val = $.trim( val ); |
|
|
|
if ( val && $.inArray( val, out ) === -1 ) { |
|
out.push( val ); |
|
} |
|
} ); |
|
|
|
return out; |
|
}; |
|
|
|
/** |
|
* The TagBox object. |
|
* |
|
* Contains functions to create and manage tags that can be associated with a |
|
* post. |
|
* |
|
* @since 2.9.0 |
|
* |
|
* @global |
|
*/ |
|
window.tagBox = { |
|
/** |
|
* Cleans up tags by removing redundant characters. |
|
* |
|
* @since 2.9.0 |
|
* @memberOf tagBox |
|
* |
|
* @param {string} tags Comma separated tags that need to be cleaned up. |
|
* |
|
* @return {string} The cleaned up tags. |
|
*/ |
|
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 ( ',' !== tagDelimiter ) { |
|
tags = tags.replace( /,/g, tagDelimiter ); |
|
} |
|
|
|
return tags; |
|
}, |
|
|
|
/** |
|
* Parses tags and makes them editable. |
|
* |
|
* @since 2.9.0 |
|
* @memberOf tagBox |
|
* |
|
* @param {Object} el The tag element to retrieve the ID from. |
|
* |
|
* @return {boolean} Always returns false. |
|
*/ |
|
parseTags : function(el) { |
|
var id = el.id, |
|
num = id.split('-check-num-')[1], |
|
taxbox = $(el).closest('.tagsdiv'), |
|
thetags = taxbox.find('.the-tags'), |
|
current_tags = thetags.val().split( tagDelimiter ), |
|
new_tags = []; |
|
|
|
delete current_tags[num]; |
|
|
|
// Sanitize the current tags and push them as if they're new tags. |
|
$.each( current_tags, function( key, val ) { |
|
val = $.trim( val ); |
|
if ( val ) { |
|
new_tags.push( val ); |
|
} |
|
}); |
|
|
|
thetags.val( this.clean( new_tags.join( tagDelimiter ) ) ); |
|
|
|
this.quickClicks( taxbox ); |
|
return false; |
|
}, |
|
|
|
/** |
|
* Creates clickable links, buttons and fields for adding or editing tags. |
|
* |
|
* @since 2.9.0 |
|
* @memberOf tagBox |
|
* |
|
* @param {Object} el The container HTML element. |
|
* |
|
* @return {void} |
|
*/ |
|
quickClicks : function( el ) { |
|
var thetags = $('.the-tags', el), |
|
tagchecklist = $('.tagchecklist', el), |
|
id = $(el).attr('id'), |
|
current_tags, disabled; |
|
|
|
if ( ! thetags.length ) |
|
return; |
|
|
|
disabled = thetags.prop('disabled'); |
|
|
|
current_tags = thetags.val().split( tagDelimiter ); |
|
tagchecklist.empty(); |
|
|
|
/** |
|
* Creates a delete button if tag editing is enabled, before adding it to the tag list. |
|
* |
|
* @since 2.5.0 |
|
* @memberOf tagBox |
|
* |
|
* @param {string} key The index of the current tag. |
|
* @param {string} val The value of the current tag. |
|
* |
|
* @return {void} |
|
*/ |
|
$.each( current_tags, function( key, val ) { |
|
var listItem, xbutton; |
|
|
|
val = $.trim( val ); |
|
|
|
if ( ! val ) |
|
return; |
|
|
|
// Create a new list item, and ensure the text is properly escaped. |
|
listItem = $( '<li />' ).text( val ); |
|
|
|
// If tags editing isn't disabled, create the X button. |
|
if ( ! disabled ) { |
|
/* |
|
* Build the X buttons, hide the X icon with aria-hidden and |
|
* use visually hidden text for screen readers. |
|
*/ |
|
xbutton = $( '<button type="button" id="' + id + '-check-num-' + key + '" class="ntdelbutton">' + |
|
'<span class="remove-tag-icon" aria-hidden="true"></span>' + |
|
'<span class="screen-reader-text">' + window.tagsSuggestL10n.removeTerm + ' ' + listItem.html() + '</span>' + |
|
'</button>' ); |
|
|
|
/** |
|
* Handles the click and keypress event of the tag remove button. |
|
* |
|
* Makes sure the focus ends up in the tag input field when using |
|
* the keyboard to delete the tag. |
|
* |
|
* @since 4.2.0 |
|
* |
|
* @param {Event} e The click or keypress event to handle. |
|
* |
|
* @return {void} |
|
*/ |
|
xbutton.on( 'click keypress', function( e ) { |
|
// On click or when using the Enter/Spacebar keys. |
|
if ( 'click' === e.type || 13 === e.keyCode || 32 === e.keyCode ) { |
|
/* |
|
* When using the keyboard, move focus back to the |
|
* add new tag field. Note: when releasing the pressed |
|
* key this will fire the `keyup` event on the input. |
|
*/ |
|
if ( 13 === e.keyCode || 32 === e.keyCode ) { |
|
$( this ).closest( '.tagsdiv' ).find( 'input.newtag' ).focus(); |
|
} |
|
|
|
tagBox.userAction = 'remove'; |
|
tagBox.parseTags( this ); |
|
} |
|
}); |
|
|
|
listItem.prepend( ' ' ).prepend( xbutton ); |
|
} |
|
|
|
// Append the list item to the tag list. |
|
tagchecklist.append( listItem ); |
|
}); |
|
|
|
// The buttons list is built now, give feedback to screen reader users. |
|
tagBox.screenReadersMessage(); |
|
}, |
|
|
|
/** |
|
* Adds a new tag. |
|
* |
|
* Also ensures that the quick links are properly generated. |
|
* |
|
* @since 2.9.0 |
|
* @memberOf tagBox |
|
* |
|
* @param {Object} el The container HTML element. |
|
* @param {Object|boolean} a When this is an HTML element the text of that |
|
* element will be used for the new tag. |
|
* @param {number|boolean} f If this value is not passed then the tag input |
|
* field is focused. |
|
* |
|
* @return {boolean} Always returns false. |
|
*/ |
|
flushTags : function( el, a, f ) { |
|
var tagsval, newtags, text, |
|
tags = $( '.the-tags', el ), |
|
newtag = $( 'input.newtag', el ); |
|
|
|
a = a || false; |
|
|
|
text = a ? $(a).text() : newtag.val(); |
|
|
|
/* |
|
* Return if there's no new tag or if the input field is empty. |
|
* Note: when using the keyboard to add tags, focus is moved back to |
|
* the input field and the `keyup` event attached on this field will |
|
* fire when releasing the pressed key. Checking also for the field |
|
* emptiness avoids to set the tags and call quickClicks() again. |
|
*/ |
|
if ( 'undefined' == typeof( text ) || '' === text ) { |
|
return false; |
|
} |
|
|
|
tagsval = tags.val(); |
|
newtags = tagsval ? tagsval + tagDelimiter + text : text; |
|
|
|
newtags = this.clean( newtags ); |
|
newtags = array_unique_noempty( newtags.split( tagDelimiter ) ).join( tagDelimiter ); |
|
tags.val( newtags ); |
|
this.quickClicks( el ); |
|
|
|
if ( ! a ) |
|
newtag.val(''); |
|
if ( 'undefined' == typeof( f ) ) |
|
newtag.focus(); |
|
|
|
return false; |
|
}, |
|
|
|
/** |
|
* Retrieves the available tags and creates a tagcloud. |
|
* |
|
* Retrieves the available tags from the database and creates an interactive |
|
* tagcloud. Clicking a tag will add it. |
|
* |
|
* @since 2.9.0 |
|
* @memberOf tagBox |
|
* |
|
* @param {string} id The ID to extract the taxonomy from. |
|
* |
|
* @return {void} |
|
*/ |
|
get : function( id ) { |
|
var tax = id.substr( id.indexOf('-') + 1 ); |
|
|
|
/** |
|
* Puts a received tag cloud into a DOM element. |
|
* |
|
* The tag cloud HTML is generated on the server. |
|
* |
|
* @since 2.9.0 |
|
* |
|
* @param {number|string} r The response message from the AJAX call. |
|
* @param {string} stat The status of the AJAX request. |
|
* |
|
* @return {void} |
|
*/ |
|
$.post( ajaxurl, { 'action': 'get-tagcloud', 'tax': tax }, function( r, stat ) { |
|
if ( 0 === r || 'success' != stat ) { |
|
return; |
|
} |
|
|
|
r = $( '<div id="tagcloud-' + tax + '" class="the-tagcloud">' + r + '</div>' ); |
|
|
|
/** |
|
* Adds a new tag when a tag in the tagcloud is clicked. |
|
* |
|
* @since 2.9.0 |
|
* |
|
* @return {boolean} Returns false to prevent the default action. |
|
*/ |
|
$( 'a', r ).click( function() { |
|
tagBox.userAction = 'add'; |
|
tagBox.flushTags( $( '#' + tax ), this ); |
|
return false; |
|
}); |
|
|
|
$( '#' + id ).after( r ); |
|
}); |
|
}, |
|
|
|
/** |
|
* Track the user's last action. |
|
* |
|
* @since 4.7.0 |
|
*/ |
|
userAction: '', |
|
|
|
/** |
|
* Dispatches an audible message to screen readers. |
|
* |
|
* This will inform the user when a tag has been added or removed. |
|
* |
|
* @since 4.7.0 |
|
* |
|
* @return {void} |
|
*/ |
|
screenReadersMessage: function() { |
|
var message; |
|
|
|
switch ( this.userAction ) { |
|
case 'remove': |
|
message = window.tagsSuggestL10n.termRemoved; |
|
break; |
|
|
|
case 'add': |
|
message = window.tagsSuggestL10n.termAdded; |
|
break; |
|
|
|
default: |
|
return; |
|
} |
|
|
|
window.wp.a11y.speak( message, 'assertive' ); |
|
}, |
|
|
|
/** |
|
* Initializes the tags box by setting up the links, buttons. Sets up event |
|
* handling. |
|
* |
|
* This includes handling of pressing the enter key in the input field and the |
|
* retrieval of tag suggestions. |
|
* |
|
* @since 2.9.0 |
|
* @memberOf tagBox |
|
* |
|
* @return {void} |
|
*/ |
|
init : function() { |
|
var ajaxtag = $('div.ajaxtag'); |
|
|
|
$('.tagsdiv').each( function() { |
|
tagBox.quickClicks( this ); |
|
}); |
|
|
|
$( '.tagadd', ajaxtag ).click( function() { |
|
tagBox.userAction = 'add'; |
|
tagBox.flushTags( $( this ).closest( '.tagsdiv' ) ); |
|
}); |
|
|
|
/** |
|
* Handles pressing enter on the new tag input field. |
|
* |
|
* Prevents submitting the post edit form. Uses `keypress` to take |
|
* into account Input Method Editor (IME) converters. |
|
* |
|
* @since 2.9.0 |
|
* |
|
* @param {Event} event The keypress event that occurred. |
|
* |
|
* @return {void} |
|
*/ |
|
$( 'input.newtag', ajaxtag ).keypress( function( event ) { |
|
if ( 13 == event.which ) { |
|
tagBox.userAction = 'add'; |
|
tagBox.flushTags( $( this ).closest( '.tagsdiv' ) ); |
|
event.preventDefault(); |
|
event.stopPropagation(); |
|
} |
|
}).each( function( i, element ) { |
|
$( element ).wpTagsSuggest(); |
|
}); |
|
|
|
/** |
|
* Before a post is saved the value currently in the new tag input field will be |
|
* added as a tag. |
|
* |
|
* @since 2.9.0 |
|
* |
|
* @return {void} |
|
*/ |
|
$('#post').submit(function(){ |
|
$('div.tagsdiv').each( function() { |
|
tagBox.flushTags(this, false, 1); |
|
}); |
|
}); |
|
|
|
/** |
|
* Handles clicking on the tag cloud link. |
|
* |
|
* Makes sure the ARIA attributes are set correctly. |
|
* |
|
* @since 2.9.0 |
|
* |
|
* @return {void} |
|
*/ |
|
$('.tagcloud-link').click(function(){ |
|
// On the first click, fetch the tag cloud and insert it in the DOM. |
|
tagBox.get( $( this ).attr( 'id' ) ); |
|
// Update button state, remove previous click event and attach a new one to toggle the cloud. |
|
$( this ) |
|
.attr( 'aria-expanded', 'true' ) |
|
.unbind() |
|
.click( function() { |
|
$( this ) |
|
.attr( 'aria-expanded', 'false' === $( this ).attr( 'aria-expanded' ) ? 'true' : 'false' ) |
|
.siblings( '.the-tagcloud' ).toggle(); |
|
}); |
|
}); |
|
} |
|
}; |
|
}( jQuery ));
|
|
|