1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
/* 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);
|