gitlabhq/vendor/assets/javascripts/jquery.tagify.js
2011-11-04 09:44:43 +02:00

143 lines
3.8 KiB
JavaScript

/* Author: Alicia Liu */
(function ($) {
$.widget("ui.tagify", {
options: {
delimiters: [13, 188], // what user can type to complete a tag in char codes: [enter], [comma]
outputDelimiter: ',', // delimiter for tags in original input field
cssClass: 'tagify-container', // CSS class to style the tagify div and tags, see stylesheet
addTagPrompt: 'add tags' // placeholder text
},
_create: function() {
var self = this,
el = self.element,
opts = self.options;
this.tags = [];
// hide text field and replace with a div that contains it's own input field for entering tags
this.tagInput = $("<input type='text'>")
.attr( 'placeholder', opts.addTagPrompt )
.keypress( function(e) {
var $this = $(this),
pressed = e.which;
for ( i in opts.delimiters ) {
if (pressed == opts.delimiters[i]) {
self.add( $this.val() );
e.preventDefault();
return false;
}
}
})
// for some reason, in Safari, backspace is only recognized on keyup
.keyup( function(e) {
var $this = $(this),
pressed = e.which;
// if backspace is hit with no input, remove the last tag
if (pressed == 8) { // backspace
if ( $this.val() == "" ) {
self.remove();
return false;
}
return;
}
});
this.tagDiv = $("<div></div>")
.addClass( opts.cssClass )
.click( function() {
$(this).children('input').focus();
})
.append( this.tagInput )
.insertAfter( el.hide() );
// if the field isn't empty, parse the field for tags, and prepopulate existing tags
var initVal = $.trim( el.val() );
if ( initVal ) {
var initTags = initVal.split( opts.outputDelimiter );
$.each( initTags, function(i, tag) {
self.add( tag );
});
}
},
_setOption: function( key, value ) {
options.key = value;
},
// add a tag, public function
add: function(text) {
var self = this;
text = text || self.tagInput.val();
if (text) {
var tagIndex = self.tags.length;
var removeButton = $("<a href='#'>x</a>")
.click( function() {
self.remove( tagIndex );
return false;
});
var newTag = $("<span></span>")
.text( text )
.append( removeButton );
self.tagInput.before( newTag );
self.tags.push( text );
self.tagInput.val('');
}
},
// remove a tag by index, public function
// if index is blank, remove the last tag
remove: function( tagIndex ) {
var self = this;
if ( tagIndex == null || tagIndex === (self.tags.length - 1) ) {
this.tagDiv.children("span").last().remove();
self.tags.pop();
}
if ( typeof(tagIndex) == 'number' ) {
// otherwise just hide this tag, and we don't mess up the index
this.tagDiv.children( "span:eq(" + tagIndex + ")" ).hide();
// we rely on the serialize function to remove null values
delete( self.tags[tagIndex] );
}
},
// serialize the tags with the given delimiter, and write it back into the tagified field
serialize: function() {
var self = this;
var delim = self.options.outputDelimiter;
var tagsStr = self.tags.join( delim );
// our tags might have deleted entries, remove them here
var dupes = new RegExp(delim + delim + '+', 'g'); // regex: /,,+/g
var ends = new RegExp('^' + delim + '|' + delim + '$', 'g'); // regex: /^,|,$/g
var outputStr = tagsStr.replace( dupes, delim ).replace(ends, '');
self.element.val(outputStr);
return outputStr;
},
inputField: function() {
return this.tagInput;
},
containerDiv: function() {
return this.tagDiv;
},
// remove the div, and show original input
destroy: function() {
$.Widget.prototype.destroy.apply(this);
this.tagDiv.remove();
this.element.show();
}
});
})(jQuery);