textext-rails 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +31 -0
- data/Rakefile +21 -0
- data/latest.tar.gz +0 -0
- data/lib/textext-rails.rb +2 -0
- data/lib/textext/rails.rb +6 -0
- data/lib/textext/rails/engine.rb +6 -0
- data/lib/textext/rails/version.rb +5 -0
- data/textext-rails.gemspec +24 -0
- data/vendor/assets/javascripts/textext.core.js +1613 -0
- data/vendor/assets/javascripts/textext.plugin.ajax.js +354 -0
- data/vendor/assets/javascripts/textext.plugin.arrow.js +106 -0
- data/vendor/assets/javascripts/textext.plugin.autocomplete.js +1057 -0
- data/vendor/assets/javascripts/textext.plugin.filter.js +242 -0
- data/vendor/assets/javascripts/textext.plugin.focus.js +174 -0
- data/vendor/assets/javascripts/textext.plugin.prompt.js +292 -0
- data/vendor/assets/javascripts/textext.plugin.suggestions.js +175 -0
- data/vendor/assets/javascripts/textext.plugin.tags.js +638 -0
- data/vendor/assets/stylesheets/arrow.png +0 -0
- data/vendor/assets/stylesheets/close.png +0 -0
- data/vendor/assets/stylesheets/textext.core.css +29 -0
- data/vendor/assets/stylesheets/textext.plugin.arrow.css +13 -0
- data/vendor/assets/stylesheets/textext.plugin.autocomplete.css +35 -0
- data/vendor/assets/stylesheets/textext.plugin.focus.css +12 -0
- data/vendor/assets/stylesheets/textext.plugin.prompt.css +16 -0
- data/vendor/assets/stylesheets/textext.plugin.tags.css +49 -0
- metadata +73 -0
@@ -0,0 +1,175 @@
|
|
1
|
+
/**
|
2
|
+
* jQuery TextExt Plugin
|
3
|
+
* http://alexgorbatchev.com/textext
|
4
|
+
*
|
5
|
+
* @version 1.2.0
|
6
|
+
* @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved.
|
7
|
+
* @license MIT License
|
8
|
+
*/
|
9
|
+
(function($)
|
10
|
+
{
|
11
|
+
/**
|
12
|
+
* Suggestions plugin allows to easily specify the list of suggestion items that the
|
13
|
+
* Autocomplete plugin would present to the user.
|
14
|
+
*
|
15
|
+
* @author agorbatchev
|
16
|
+
* @date 2011/08/18
|
17
|
+
* @id TextExtSuggestions
|
18
|
+
*/
|
19
|
+
function TextExtSuggestions() {};
|
20
|
+
|
21
|
+
$.fn.textext.TextExtSuggestions = TextExtSuggestions;
|
22
|
+
$.fn.textext.addPlugin('suggestions', TextExtSuggestions);
|
23
|
+
|
24
|
+
var p = TextExtSuggestions.prototype,
|
25
|
+
/**
|
26
|
+
* Suggestions plugin only has one option and that is to set suggestion items. It could be
|
27
|
+
* changed when passed to the `$().textext()` function. For example:
|
28
|
+
*
|
29
|
+
* $('textarea').textext({
|
30
|
+
* plugins: 'suggestions',
|
31
|
+
* suggestions: [ "item1", "item2" ]
|
32
|
+
* })
|
33
|
+
*
|
34
|
+
* @author agorbatchev
|
35
|
+
* @date 2011/08/18
|
36
|
+
* @id TextExtSuggestions.options
|
37
|
+
*/
|
38
|
+
|
39
|
+
/**
|
40
|
+
* List of items that Autocomplete plugin would display in the dropdown.
|
41
|
+
*
|
42
|
+
* @name suggestions
|
43
|
+
* @default null
|
44
|
+
* @author agorbatchev
|
45
|
+
* @date 2011/08/18
|
46
|
+
* @id TextExtSuggestions.options.suggestions
|
47
|
+
*/
|
48
|
+
OPT_SUGGESTIONS = 'suggestions',
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Suggestions plugin dispatches or reacts to the following events.
|
52
|
+
*
|
53
|
+
* @author agorbatchev
|
54
|
+
* @date 2011/08/17
|
55
|
+
* @id TextExtSuggestions.events
|
56
|
+
*/
|
57
|
+
|
58
|
+
/**
|
59
|
+
* Suggestions plugin reacts to the `getSuggestions` event and returns `suggestions` items
|
60
|
+
* from the options.
|
61
|
+
*
|
62
|
+
* @name getSuggestions
|
63
|
+
* @author agorbatchev
|
64
|
+
* @date 2011/08/19
|
65
|
+
* @id TextExtSuggestions.events.getSuggestions
|
66
|
+
*/
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Suggestions plugin triggers the `setSuggestions` event to pass its own list of `Suggestions`
|
70
|
+
* to the Autocomplete plugin.
|
71
|
+
*
|
72
|
+
* @name setSuggestions
|
73
|
+
* @author agorbatchev
|
74
|
+
* @date 2011/08/19
|
75
|
+
* @id TextExtSuggestions.events.setSuggestions
|
76
|
+
*/
|
77
|
+
|
78
|
+
/**
|
79
|
+
* Suggestions plugin reacts to the `postInit` event to pass its list of `suggestions` to the
|
80
|
+
* Autocomplete right away.
|
81
|
+
*
|
82
|
+
* @name postInit
|
83
|
+
* @author agorbatchev
|
84
|
+
* @date 2011/08/19
|
85
|
+
* @id TextExtSuggestions.events.postInit
|
86
|
+
*/
|
87
|
+
|
88
|
+
DEFAULT_OPTS = {
|
89
|
+
suggestions : null
|
90
|
+
}
|
91
|
+
;
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Initialization method called by the core during plugin instantiation.
|
95
|
+
*
|
96
|
+
* @signature TextExtSuggestions.init(core)
|
97
|
+
*
|
98
|
+
* @param core {TextExt} Instance of the TextExt core class.
|
99
|
+
*
|
100
|
+
* @author agorbatchev
|
101
|
+
* @date 2011/08/18
|
102
|
+
* @id TextExtSuggestions.init
|
103
|
+
*/
|
104
|
+
p.init = function(core)
|
105
|
+
{
|
106
|
+
var self = this;
|
107
|
+
|
108
|
+
self.baseInit(core, DEFAULT_OPTS);
|
109
|
+
|
110
|
+
self.on({
|
111
|
+
getSuggestions : self.onGetSuggestions,
|
112
|
+
postInit : self.onPostInit
|
113
|
+
});
|
114
|
+
};
|
115
|
+
|
116
|
+
/**
|
117
|
+
* Triggers `setSuggestions` and passes supplied suggestions to the Autocomplete plugin.
|
118
|
+
*
|
119
|
+
* @signature TextExtSuggestions.setSuggestions(suggestions, showHideDropdown)
|
120
|
+
*
|
121
|
+
* @param suggestions {Array} List of suggestions. With the default `ItemManager` it should
|
122
|
+
* be a list of strings.
|
123
|
+
* @param showHideDropdown {Boolean} If it's undesirable to show the dropdown right after
|
124
|
+
* suggestions are set, `false` should be passed for this argument.
|
125
|
+
*
|
126
|
+
* @author agorbatchev
|
127
|
+
* @date 2011/08/19
|
128
|
+
* @id TextExtSuggestions.setSuggestions
|
129
|
+
*/
|
130
|
+
p.setSuggestions = function(suggestions, showHideDropdown)
|
131
|
+
{
|
132
|
+
this.trigger('setSuggestions', { result : suggestions, showHideDropdown : showHideDropdown != false });
|
133
|
+
};
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Reacts to the `postInit` event and triggers `setSuggestions` event to set suggestions list
|
137
|
+
* right after initialization.
|
138
|
+
*
|
139
|
+
* @signature TextExtSuggestions.onPostInit(e)
|
140
|
+
*
|
141
|
+
* @param e {Object} jQuery event.
|
142
|
+
*
|
143
|
+
* @author agorbatchev
|
144
|
+
* @date 2011/08/19
|
145
|
+
* @id TextExtSuggestions.onPostInit
|
146
|
+
*/
|
147
|
+
p.onPostInit = function(e)
|
148
|
+
{
|
149
|
+
var self = this;
|
150
|
+
self.setSuggestions(self.opts(OPT_SUGGESTIONS), false);
|
151
|
+
};
|
152
|
+
|
153
|
+
/**
|
154
|
+
* Reacts to the `getSuggestions` event and triggers `setSuggestions` event with the list
|
155
|
+
* of `suggestions` specified in the options.
|
156
|
+
*
|
157
|
+
* @signature TextExtSuggestions.onGetSuggestions(e, data)
|
158
|
+
*
|
159
|
+
* @param e {Object} jQuery event.
|
160
|
+
* @param data {Object} Payload from the `getSuggestions` event with the user query, eg `{ query: {String} }`.
|
161
|
+
*
|
162
|
+
* @author agorbatchev
|
163
|
+
* @date 2011/08/19
|
164
|
+
* @id TextExtSuggestions.onGetSuggestions
|
165
|
+
*/
|
166
|
+
p.onGetSuggestions = function(e, data)
|
167
|
+
{
|
168
|
+
var self = this,
|
169
|
+
suggestions = self.opts(OPT_SUGGESTIONS)
|
170
|
+
;
|
171
|
+
|
172
|
+
suggestions.sort();
|
173
|
+
self.setSuggestions(self.itemManager().filter(suggestions, data.query));
|
174
|
+
};
|
175
|
+
})(jQuery);
|
@@ -0,0 +1,638 @@
|
|
1
|
+
/**
|
2
|
+
* jQuery TextExt Plugin
|
3
|
+
* http://alexgorbatchev.com/textext
|
4
|
+
*
|
5
|
+
* @version 1.2.0
|
6
|
+
* @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved.
|
7
|
+
* @license MIT License
|
8
|
+
*/
|
9
|
+
(function($)
|
10
|
+
{
|
11
|
+
/**
|
12
|
+
* Tags plugin brings in the traditional tag functionality where user can assemble and
|
13
|
+
* edit list of tags. Tags plugin works especially well together with Autocomplete, Filter,
|
14
|
+
* Suggestions and Ajax plugins to provide full spectrum of features. It can also work on
|
15
|
+
* its own and just do one thing -- tags.
|
16
|
+
*
|
17
|
+
* @author agorbatchev
|
18
|
+
* @date 2011/08/19
|
19
|
+
* @id TextExtTags
|
20
|
+
*/
|
21
|
+
function TextExtTags() {};
|
22
|
+
|
23
|
+
$.fn.textext.TextExtTags = TextExtTags;
|
24
|
+
$.fn.textext.addPlugin('tags', TextExtTags);
|
25
|
+
|
26
|
+
var p = TextExtTags.prototype,
|
27
|
+
|
28
|
+
CSS_DOT = '.',
|
29
|
+
CSS_TAGS_ON_TOP = 'text-tags-on-top',
|
30
|
+
CSS_DOT_TAGS_ON_TOP = CSS_DOT + CSS_TAGS_ON_TOP,
|
31
|
+
CSS_TAG = 'text-tag',
|
32
|
+
CSS_DOT_TAG = CSS_DOT + CSS_TAG,
|
33
|
+
CSS_TAGS = 'text-tags',
|
34
|
+
CSS_DOT_TAGS = CSS_DOT + CSS_TAGS,
|
35
|
+
|
36
|
+
/**
|
37
|
+
* Tags plugin options are grouped under `tags` when passed to the
|
38
|
+
* `$().textext()` function. For example:
|
39
|
+
*
|
40
|
+
* $('textarea').textext({
|
41
|
+
* plugins: 'tags',
|
42
|
+
* tags: {
|
43
|
+
* items: [ "tag1", "tag2" ]
|
44
|
+
* }
|
45
|
+
* })
|
46
|
+
*
|
47
|
+
* @author agorbatchev
|
48
|
+
* @date 2011/08/19
|
49
|
+
* @id TextExtTags.options
|
50
|
+
*/
|
51
|
+
|
52
|
+
/**
|
53
|
+
* This is a toggle switch to enable or disable the Tags plugin. The value is checked
|
54
|
+
* each time at the top level which allows you to toggle this setting on the fly.
|
55
|
+
*
|
56
|
+
* @name tags.enabled
|
57
|
+
* @default true
|
58
|
+
* @author agorbatchev
|
59
|
+
* @date 2011/08/19
|
60
|
+
* @id TextExtTags.options.tags.enabled
|
61
|
+
*/
|
62
|
+
OPT_ENABLED = 'tags.enabled',
|
63
|
+
|
64
|
+
/**
|
65
|
+
* Allows to specify tags which will be added to the input by default upon initialization.
|
66
|
+
* Each item in the array must be of the type that current `ItemManager` can understand.
|
67
|
+
* Default type is `String`.
|
68
|
+
*
|
69
|
+
* @name tags.items
|
70
|
+
* @default null
|
71
|
+
* @author agorbatchev
|
72
|
+
* @date 2011/08/19
|
73
|
+
* @id TextExtTags.options.tags.items
|
74
|
+
*/
|
75
|
+
OPT_ITEMS = 'tags.items',
|
76
|
+
|
77
|
+
/**
|
78
|
+
* HTML source that is used to generate a single tag.
|
79
|
+
*
|
80
|
+
* @name html.tag
|
81
|
+
* @default '<div class="text-tags"/>'
|
82
|
+
* @author agorbatchev
|
83
|
+
* @date 2011/08/19
|
84
|
+
* @id TextExtTags.options.html.tag
|
85
|
+
*/
|
86
|
+
OPT_HTML_TAG = 'html.tag',
|
87
|
+
|
88
|
+
/**
|
89
|
+
* HTML source that is used to generate container for the tags.
|
90
|
+
*
|
91
|
+
* @name html.tags
|
92
|
+
* @default '<div class="text-tag"><div class="text-button"><span class="text-label"/><a class="text-remove"/></div></div>'
|
93
|
+
* @author agorbatchev
|
94
|
+
* @date 2011/08/19
|
95
|
+
* @id TextExtTags.options.html.tags
|
96
|
+
*/
|
97
|
+
OPT_HTML_TAGS = 'html.tags',
|
98
|
+
|
99
|
+
/**
|
100
|
+
* Tags plugin dispatches or reacts to the following events.
|
101
|
+
*
|
102
|
+
* @author agorbatchev
|
103
|
+
* @date 2011/08/17
|
104
|
+
* @id TextExtTags.events
|
105
|
+
*/
|
106
|
+
|
107
|
+
/**
|
108
|
+
* Tags plugin triggers the `isTagAllowed` event before adding each tag to the tag list. Other plugins have
|
109
|
+
* an opportunity to interrupt this by setting `result` of the second argument to `false`. For example:
|
110
|
+
*
|
111
|
+
* $('textarea').textext({...}).bind('isTagAllowed', function(e, data)
|
112
|
+
* {
|
113
|
+
* if(data.tag === 'foo')
|
114
|
+
* data.result = false;
|
115
|
+
* })
|
116
|
+
*
|
117
|
+
* The second argument `data` has the following format: `{ tag : {Object}, result : {Boolean} }`. `tag`
|
118
|
+
* property is in the format that the current `ItemManager` can understand.
|
119
|
+
*
|
120
|
+
* @name isTagAllowed
|
121
|
+
* @author agorbatchev
|
122
|
+
* @date 2011/08/19
|
123
|
+
* @id TextExtTags.events.isTagAllowed
|
124
|
+
*/
|
125
|
+
EVENT_IS_TAG_ALLOWED = 'isTagAllowed',
|
126
|
+
|
127
|
+
DEFAULT_OPTS = {
|
128
|
+
tags : {
|
129
|
+
enabled : true,
|
130
|
+
items : null
|
131
|
+
},
|
132
|
+
|
133
|
+
html : {
|
134
|
+
tags : '<div class="text-tags"/>',
|
135
|
+
tag : '<div class="text-tag"><div class="text-button"><span class="text-label"/><a class="text-remove"/></div></div>'
|
136
|
+
}
|
137
|
+
}
|
138
|
+
;
|
139
|
+
|
140
|
+
/**
|
141
|
+
* Initialization method called by the core during plugin instantiation.
|
142
|
+
*
|
143
|
+
* @signature TextExtTags.init(core)
|
144
|
+
*
|
145
|
+
* @param core {TextExt} Instance of the TextExt core class.
|
146
|
+
*
|
147
|
+
* @author agorbatchev
|
148
|
+
* @date 2011/08/19
|
149
|
+
* @id TextExtTags.init
|
150
|
+
*/
|
151
|
+
p.init = function(core)
|
152
|
+
{
|
153
|
+
this.baseInit(core, DEFAULT_OPTS);
|
154
|
+
|
155
|
+
var self = this,
|
156
|
+
input = self.input(),
|
157
|
+
container
|
158
|
+
;
|
159
|
+
|
160
|
+
if(self.opts(OPT_ENABLED))
|
161
|
+
{
|
162
|
+
container = $(self.opts(OPT_HTML_TAGS));
|
163
|
+
input.after(container);
|
164
|
+
|
165
|
+
$(self).data('container', container);
|
166
|
+
|
167
|
+
self.on({
|
168
|
+
enterKeyPress : self.onEnterKeyPress,
|
169
|
+
backspaceKeyDown : self.onBackspaceKeyDown,
|
170
|
+
preInvalidate : self.onPreInvalidate,
|
171
|
+
postInit : self.onPostInit,
|
172
|
+
getFormData : self.onGetFormData
|
173
|
+
});
|
174
|
+
|
175
|
+
self.on(container, {
|
176
|
+
click : self.onClick,
|
177
|
+
mousemove : self.onContainerMouseMove
|
178
|
+
});
|
179
|
+
|
180
|
+
self.on(input, {
|
181
|
+
mousemove : self.onInputMouseMove
|
182
|
+
});
|
183
|
+
}
|
184
|
+
|
185
|
+
self._originalPadding = {
|
186
|
+
left : parseInt(input.css('paddingLeft') || 0),
|
187
|
+
top : parseInt(input.css('paddingTop') || 0)
|
188
|
+
};
|
189
|
+
|
190
|
+
self._paddingBox = {
|
191
|
+
left : 0,
|
192
|
+
top : 0
|
193
|
+
};
|
194
|
+
|
195
|
+
self.updateFormCache();
|
196
|
+
};
|
197
|
+
|
198
|
+
/**
|
199
|
+
* Returns HTML element in which all tag HTML elements are residing.
|
200
|
+
*
|
201
|
+
* @signature TextExtTags.containerElement()
|
202
|
+
*
|
203
|
+
* @author agorbatchev
|
204
|
+
* @date 2011/08/15
|
205
|
+
* @id TextExtTags.containerElement
|
206
|
+
*/
|
207
|
+
p.containerElement = function()
|
208
|
+
{
|
209
|
+
return $(this).data('container');
|
210
|
+
};
|
211
|
+
|
212
|
+
//--------------------------------------------------------------------------------
|
213
|
+
// Event handlers
|
214
|
+
|
215
|
+
/**
|
216
|
+
* Reacts to the `postInit` event triggered by the core and sets default tags
|
217
|
+
* if any were specified.
|
218
|
+
*
|
219
|
+
* @signature TextExtTags.onPostInit(e)
|
220
|
+
*
|
221
|
+
* @param e {Object} jQuery event.
|
222
|
+
*
|
223
|
+
* @author agorbatchev
|
224
|
+
* @date 2011/08/09
|
225
|
+
* @id TextExtTags.onPostInit
|
226
|
+
*/
|
227
|
+
p.onPostInit = function(e)
|
228
|
+
{
|
229
|
+
var self = this;
|
230
|
+
self.addTags(self.opts(OPT_ITEMS));
|
231
|
+
};
|
232
|
+
|
233
|
+
/**
|
234
|
+
* Reacts to the [`getFormData`][1] event triggered by the core. Returns data with the
|
235
|
+
* weight of 200 to be *greater than the Autocomplete plugin* data weight. The weights
|
236
|
+
* system is covered in greater detail in the [`getFormData`][1] event documentation.
|
237
|
+
*
|
238
|
+
* [1]: /manual/textext.html#getformdata
|
239
|
+
*
|
240
|
+
* @signature TextExtTags.onGetFormData(e, data, keyCode)
|
241
|
+
*
|
242
|
+
* @param e {Object} jQuery event.
|
243
|
+
* @param data {Object} Data object to be populated.
|
244
|
+
* @param keyCode {Number} Key code that triggered the original update request.
|
245
|
+
*
|
246
|
+
* @author agorbatchev
|
247
|
+
* @date 2011/08/22
|
248
|
+
* @id TextExtTags.onGetFormData
|
249
|
+
*/
|
250
|
+
p.onGetFormData = function(e, data, keyCode)
|
251
|
+
{
|
252
|
+
var self = this,
|
253
|
+
inputValue = keyCode === 13 ? '' : self.val(),
|
254
|
+
formValue = self._formData
|
255
|
+
;
|
256
|
+
|
257
|
+
data[200] = self.formDataObject(inputValue, formValue);
|
258
|
+
};
|
259
|
+
|
260
|
+
/**
|
261
|
+
* Returns initialization priority of the Tags plugin which is expected to be
|
262
|
+
* *less than the Autocomplete plugin* because of the dependencies. The value is
|
263
|
+
* 100.
|
264
|
+
*
|
265
|
+
* @signature TextExtTags.initPriority()
|
266
|
+
*
|
267
|
+
* @author agorbatchev
|
268
|
+
* @date 2011/08/22
|
269
|
+
* @id TextExtTags.initPriority
|
270
|
+
*/
|
271
|
+
p.initPriority = function()
|
272
|
+
{
|
273
|
+
return 100;
|
274
|
+
};
|
275
|
+
|
276
|
+
/**
|
277
|
+
* Reacts to user moving mouse over the text area when cursor is over the text
|
278
|
+
* and not over the tags. Whenever mouse cursor is over the area covered by
|
279
|
+
* tags, the tags container is flipped to be on top of the text area which
|
280
|
+
* makes all tags functional with the mouse.
|
281
|
+
*
|
282
|
+
* @signature TextExtTags.onInputMouseMove(e)
|
283
|
+
*
|
284
|
+
* @param e {Object} jQuery event.
|
285
|
+
*
|
286
|
+
* @author agorbatchev
|
287
|
+
* @date 2011/08/08
|
288
|
+
* @id TextExtTags.onInputMouseMove
|
289
|
+
*/
|
290
|
+
p.onInputMouseMove = function(e)
|
291
|
+
{
|
292
|
+
this.toggleZIndex(e);
|
293
|
+
};
|
294
|
+
|
295
|
+
/**
|
296
|
+
* Reacts to user moving mouse over the tags. Whenever the cursor moves out
|
297
|
+
* of the tags and back into where the text input is happening visually,
|
298
|
+
* the tags container is sent back under the text area which allows user
|
299
|
+
* to interact with the text using mouse cursor as expected.
|
300
|
+
*
|
301
|
+
* @signature TextExtTags.onContainerMouseMove(e)
|
302
|
+
*
|
303
|
+
* @param e {Object} jQuery event.
|
304
|
+
*
|
305
|
+
* @author agorbatchev
|
306
|
+
* @date 2011/08/08
|
307
|
+
* @id TextExtTags.onContainerMouseMove
|
308
|
+
*/
|
309
|
+
p.onContainerMouseMove = function(e)
|
310
|
+
{
|
311
|
+
this.toggleZIndex(e);
|
312
|
+
};
|
313
|
+
|
314
|
+
/**
|
315
|
+
* Reacts to the `backspaceKeyDown` event. When backspace key is pressed in an empty text field,
|
316
|
+
* deletes last tag from the list.
|
317
|
+
*
|
318
|
+
* @signature TextExtTags.onBackspaceKeyDown(e)
|
319
|
+
*
|
320
|
+
* @param e {Object} jQuery event.
|
321
|
+
*
|
322
|
+
* @author agorbatchev
|
323
|
+
* @date 2011/08/02
|
324
|
+
* @id TextExtTags.onBackspaceKeyDown
|
325
|
+
*/
|
326
|
+
p.onBackspaceKeyDown = function(e)
|
327
|
+
{
|
328
|
+
var self = this,
|
329
|
+
lastTag = self.tagElements().last()
|
330
|
+
;
|
331
|
+
|
332
|
+
if(self.val().length == 0)
|
333
|
+
self.removeTag(lastTag);
|
334
|
+
};
|
335
|
+
|
336
|
+
/**
|
337
|
+
* Reacts to the `preInvalidate` event and updates the input box to look like the tags are
|
338
|
+
* positioned inside it.
|
339
|
+
*
|
340
|
+
* @signature TextExtTags.onPreInvalidate(e)
|
341
|
+
*
|
342
|
+
* @param e {Object} jQuery event.
|
343
|
+
*
|
344
|
+
* @author agorbatchev
|
345
|
+
* @date 2011/08/19
|
346
|
+
* @id TextExtTags.onPreInvalidate
|
347
|
+
*/
|
348
|
+
p.onPreInvalidate = function(e)
|
349
|
+
{
|
350
|
+
var self = this,
|
351
|
+
lastTag = self.tagElements().last(),
|
352
|
+
pos = lastTag.position()
|
353
|
+
;
|
354
|
+
|
355
|
+
if(lastTag.length > 0)
|
356
|
+
pos.left += lastTag.innerWidth();
|
357
|
+
else
|
358
|
+
pos = self._originalPadding;
|
359
|
+
|
360
|
+
self._paddingBox = pos;
|
361
|
+
|
362
|
+
self.input().css({
|
363
|
+
paddingLeft : pos.left,
|
364
|
+
paddingTop : pos.top
|
365
|
+
});
|
366
|
+
};
|
367
|
+
|
368
|
+
/**
|
369
|
+
* Reacts to the mouse `click` event.
|
370
|
+
*
|
371
|
+
* @signature TextExtTags.onClick(e)
|
372
|
+
*
|
373
|
+
* @param e {Object} jQuery event.
|
374
|
+
*
|
375
|
+
* @author agorbatchev
|
376
|
+
* @date 2011/08/19
|
377
|
+
* @id TextExtTags.onClick
|
378
|
+
*/
|
379
|
+
p.onClick = function(e)
|
380
|
+
{
|
381
|
+
var self = this,
|
382
|
+
source = $(e.target),
|
383
|
+
focus = 0
|
384
|
+
;
|
385
|
+
|
386
|
+
if(source.is(CSS_DOT_TAGS))
|
387
|
+
{
|
388
|
+
focus = 1;
|
389
|
+
}
|
390
|
+
else if(source.is('.text-remove'))
|
391
|
+
{
|
392
|
+
self.removeTag(source.parents(CSS_DOT_TAG + ':first'));
|
393
|
+
focus = 1;
|
394
|
+
}
|
395
|
+
|
396
|
+
if(focus)
|
397
|
+
self.core().focusInput();
|
398
|
+
};
|
399
|
+
|
400
|
+
/**
|
401
|
+
* Reacts to the `enterKeyPress` event and adds whatever is currently in the text input
|
402
|
+
* as a new tag. Triggers `isTagAllowed` to check if the tag could be added first.
|
403
|
+
*
|
404
|
+
* @signature TextExtTags.onEnterKeyPress(e)
|
405
|
+
*
|
406
|
+
* @param e {Object} jQuery event.
|
407
|
+
*
|
408
|
+
* @author agorbatchev
|
409
|
+
* @date 2011/08/19
|
410
|
+
* @id TextExtTags.onEnterKeyPress
|
411
|
+
*/
|
412
|
+
p.onEnterKeyPress = function(e)
|
413
|
+
{
|
414
|
+
var self = this,
|
415
|
+
val = self.val(),
|
416
|
+
tag = self.itemManager().stringToItem(val)
|
417
|
+
;
|
418
|
+
|
419
|
+
if(self.isTagAllowed(tag))
|
420
|
+
{
|
421
|
+
self.addTags([ tag ]);
|
422
|
+
// refocus the textarea just in case it lost the focus
|
423
|
+
self.core().focusInput();
|
424
|
+
}
|
425
|
+
};
|
426
|
+
|
427
|
+
//--------------------------------------------------------------------------------
|
428
|
+
// Core functionality
|
429
|
+
|
430
|
+
/**
|
431
|
+
* Creates a cache object with all the tags currently added which will be returned
|
432
|
+
* in the `onGetFormData` handler.
|
433
|
+
*
|
434
|
+
* @signature TextExtTags.updateFormCache()
|
435
|
+
*
|
436
|
+
* @author agorbatchev
|
437
|
+
* @date 2011/08/09
|
438
|
+
* @id TextExtTags.updateFormCache
|
439
|
+
*/
|
440
|
+
p.updateFormCache = function()
|
441
|
+
{
|
442
|
+
var self = this,
|
443
|
+
result = []
|
444
|
+
;
|
445
|
+
|
446
|
+
self.tagElements().each(function()
|
447
|
+
{
|
448
|
+
result.push($(this).data(CSS_TAG));
|
449
|
+
});
|
450
|
+
|
451
|
+
// cache the results to be used in the onGetFormData
|
452
|
+
self._formData = result;
|
453
|
+
};
|
454
|
+
|
455
|
+
/**
|
456
|
+
* Toggles tag container to be on top of the text area or under based on where
|
457
|
+
* the mouse cursor is located. When cursor is above the text input and out of
|
458
|
+
* any of the tags, the tags container is sent under the text area. If cursor
|
459
|
+
* is over any of the tags, the tag container is brought to be over the text
|
460
|
+
* area.
|
461
|
+
*
|
462
|
+
* @signature TextExtTags.toggleZIndex(e)
|
463
|
+
*
|
464
|
+
* @param e {Object} jQuery event.
|
465
|
+
*
|
466
|
+
* @author agorbatchev
|
467
|
+
* @date 2011/08/08
|
468
|
+
* @id TextExtTags.toggleZIndex
|
469
|
+
*/
|
470
|
+
p.toggleZIndex = function(e)
|
471
|
+
{
|
472
|
+
var self = this,
|
473
|
+
offset = self.input().offset(),
|
474
|
+
mouseX = e.clientX - offset.left,
|
475
|
+
mouseY = e.clientY - offset.top,
|
476
|
+
box = self._paddingBox,
|
477
|
+
container = self.containerElement(),
|
478
|
+
isOnTop = container.is(CSS_DOT_TAGS_ON_TOP),
|
479
|
+
isMouseOverText = mouseX > box.left && mouseY > box.top
|
480
|
+
;
|
481
|
+
|
482
|
+
if(!isOnTop && !isMouseOverText || isOnTop && isMouseOverText)
|
483
|
+
container[(!isOnTop ? 'add' : 'remove') + 'Class'](CSS_TAGS_ON_TOP);
|
484
|
+
};
|
485
|
+
|
486
|
+
/**
|
487
|
+
* Returns all tag HTML elements.
|
488
|
+
*
|
489
|
+
* @signature TextExtTags.tagElements()
|
490
|
+
*
|
491
|
+
* @author agorbatchev
|
492
|
+
* @date 2011/08/19
|
493
|
+
* @id TextExtTags.tagElements
|
494
|
+
*/
|
495
|
+
p.tagElements = function()
|
496
|
+
{
|
497
|
+
return this.containerElement().find(CSS_DOT_TAG);
|
498
|
+
};
|
499
|
+
|
500
|
+
/**
|
501
|
+
* Wrapper around the `isTagAllowed` event which triggers it and returns `true`
|
502
|
+
* if `result` property of the second argument remains `true`.
|
503
|
+
*
|
504
|
+
* @signature TextExtTags.isTagAllowed(tag)
|
505
|
+
*
|
506
|
+
* @param tag {Object} Tag object that the current `ItemManager` can understand.
|
507
|
+
* Default is `String`.
|
508
|
+
*
|
509
|
+
* @author agorbatchev
|
510
|
+
* @date 2011/08/19
|
511
|
+
* @id TextExtTags.isTagAllowed
|
512
|
+
*/
|
513
|
+
p.isTagAllowed = function(tag)
|
514
|
+
{
|
515
|
+
var opts = { tag : tag, result : true };
|
516
|
+
this.trigger(EVENT_IS_TAG_ALLOWED, opts);
|
517
|
+
return opts.result === true;
|
518
|
+
};
|
519
|
+
|
520
|
+
/**
|
521
|
+
* Adds specified tags to the tag list. Triggers `isTagAllowed` event for each tag
|
522
|
+
* to insure that it could be added. Calls `TextExt.getFormData()` to refresh the data.
|
523
|
+
*
|
524
|
+
* @signature TextExtTags.addTags(tags)
|
525
|
+
*
|
526
|
+
* @param tags {Array} List of tags that current `ItemManager` can understand. Default
|
527
|
+
* is `String`.
|
528
|
+
*
|
529
|
+
* @author agorbatchev
|
530
|
+
* @date 2011/08/19
|
531
|
+
* @id TextExtTags.addTags
|
532
|
+
*/
|
533
|
+
p.addTags = function(tags)
|
534
|
+
{
|
535
|
+
if(!tags || tags.length == 0)
|
536
|
+
return;
|
537
|
+
|
538
|
+
var self = this,
|
539
|
+
core = self.core(),
|
540
|
+
container = self.containerElement(),
|
541
|
+
i, tag
|
542
|
+
;
|
543
|
+
|
544
|
+
for(i = 0; i < tags.length; i++)
|
545
|
+
{
|
546
|
+
tag = tags[i];
|
547
|
+
|
548
|
+
if(tag && self.isTagAllowed(tag))
|
549
|
+
container.append(self.renderTag(tag));
|
550
|
+
}
|
551
|
+
|
552
|
+
self.updateFormCache();
|
553
|
+
core.getFormData();
|
554
|
+
core.invalidateBounds();
|
555
|
+
};
|
556
|
+
|
557
|
+
/**
|
558
|
+
* Returns HTML element for the specified tag.
|
559
|
+
*
|
560
|
+
* @signature TextExtTags.getTagElement(tag)
|
561
|
+
*
|
562
|
+
* @param tag {Object} Tag object in the format that current `ItemManager` can understand.
|
563
|
+
* Default is `String`.
|
564
|
+
|
565
|
+
* @author agorbatchev
|
566
|
+
* @date 2011/08/19
|
567
|
+
* @id TextExtTags.getTagElement
|
568
|
+
*/
|
569
|
+
p.getTagElement = function(tag)
|
570
|
+
{
|
571
|
+
var self = this,
|
572
|
+
list = self.tagElements(),
|
573
|
+
i, item
|
574
|
+
;
|
575
|
+
|
576
|
+
for(i = 0; i < list.length, item = $(list[i]); i++)
|
577
|
+
if(self.itemManager().compareItems(item.data(CSS_TAG), tag))
|
578
|
+
return item;
|
579
|
+
};
|
580
|
+
|
581
|
+
/**
|
582
|
+
* Removes specified tag from the list. Calls `TextExt.getFormData()` to refresh the data.
|
583
|
+
*
|
584
|
+
* @signature TextExtTags.removeTag(tag)
|
585
|
+
*
|
586
|
+
* @param tag {Object} Tag object in the format that current `ItemManager` can understand.
|
587
|
+
* Default is `String`.
|
588
|
+
*
|
589
|
+
* @author agorbatchev
|
590
|
+
* @date 2011/08/19
|
591
|
+
* @id TextExtTags.removeTag
|
592
|
+
*/
|
593
|
+
p.removeTag = function(tag)
|
594
|
+
{
|
595
|
+
var self = this,
|
596
|
+
core = self.core(),
|
597
|
+
element
|
598
|
+
;
|
599
|
+
|
600
|
+
if(tag instanceof $)
|
601
|
+
{
|
602
|
+
element = tag;
|
603
|
+
tag = tag.data(CSS_TAG);
|
604
|
+
}
|
605
|
+
else
|
606
|
+
{
|
607
|
+
element = self.getTagElement(tag);
|
608
|
+
}
|
609
|
+
|
610
|
+
element.remove();
|
611
|
+
self.updateFormCache();
|
612
|
+
core.getFormData();
|
613
|
+
core.invalidateBounds();
|
614
|
+
};
|
615
|
+
|
616
|
+
/**
|
617
|
+
* Creates and returns new HTML element from the source code specified in the `html.tag` option.
|
618
|
+
*
|
619
|
+
* @signature TextExtTags.renderTag(tag)
|
620
|
+
*
|
621
|
+
* @param tag {Object} Tag object in the format that current `ItemManager` can understand.
|
622
|
+
* Default is `String`.
|
623
|
+
*
|
624
|
+
* @author agorbatchev
|
625
|
+
* @date 2011/08/19
|
626
|
+
* @id TextExtTags.renderTag
|
627
|
+
*/
|
628
|
+
p.renderTag = function(tag)
|
629
|
+
{
|
630
|
+
var self = this,
|
631
|
+
node = $(self.opts(OPT_HTML_TAG))
|
632
|
+
;
|
633
|
+
|
634
|
+
node.find('.text-label').text(self.itemManager().itemToString(tag));
|
635
|
+
node.data(CSS_TAG, tag);
|
636
|
+
return node;
|
637
|
+
};
|
638
|
+
})(jQuery);
|