right-rails 1.1.0 → 1.2.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/CHANGELOG +5 -0
- data/lib/right_rails/helpers/forms.rb +81 -47
- data/lib/right_rails/helpers.rb +9 -0
- data/public/javascripts/right/autocompleter-src.js +1 -1
- data/public/javascripts/right/autocompleter.js +1 -1
- data/public/javascripts/right/billboard-src.js +1 -1
- data/public/javascripts/right/billboard.js +1 -1
- data/public/javascripts/right/calendar-src.js +1 -1
- data/public/javascripts/right/calendar.js +1 -1
- data/public/javascripts/right/casting-src.js +183 -0
- data/public/javascripts/right/casting.js +7 -0
- data/public/javascripts/right/colorpicker-src.js +1 -1
- data/public/javascripts/right/colorpicker.js +1 -1
- data/public/javascripts/right/dialog-src.js +1 -1
- data/public/javascripts/right/dialog.js +1 -1
- data/public/javascripts/right/dnd-src.js +20 -20
- data/public/javascripts/right/dnd.js +2 -2
- data/public/javascripts/right/in-edit-src.js +1 -1
- data/public/javascripts/right/in-edit.js +1 -1
- data/public/javascripts/right/lightbox-src.js +24 -5
- data/public/javascripts/right/lightbox.js +2 -2
- data/public/javascripts/right/rails-src.js +1 -1
- data/public/javascripts/right/rails.js +1 -1
- data/public/javascripts/right/rater-src.js +1 -1
- data/public/javascripts/right/rater.js +1 -1
- data/public/javascripts/right/resizable-src.js +29 -3
- data/public/javascripts/right/resizable.js +2 -2
- data/public/javascripts/right/selectable-src.js +1 -1
- data/public/javascripts/right/selectable.js +1 -1
- data/public/javascripts/right/slider-src.js +5 -5
- data/public/javascripts/right/slider.js +2 -2
- data/public/javascripts/right/sortable-src.js +1 -1
- data/public/javascripts/right/sortable.js +1 -1
- data/public/javascripts/right/tabs-src.js +8 -6
- data/public/javascripts/right/tabs.js +2 -2
- data/public/javascripts/right/tags-src.js +745 -0
- data/public/javascripts/right/tags.js +7 -0
- data/public/javascripts/right/tooltips-src.js +1 -1
- data/public/javascripts/right/tooltips.js +1 -1
- data/public/javascripts/right/uploader-src.js +4 -3
- data/public/javascripts/right/uploader.js +2 -2
- data/public/javascripts/right-safe-src.js +2 -2
- data/public/javascripts/right-safe.js +2 -2
- data/public/javascripts/right-src.js +60 -47
- data/public/javascripts/right.js +2 -2
- data/spec/lib/right_rails/helpers/forms_spec.rb +67 -40
- metadata +10 -15
@@ -0,0 +1,745 @@
|
|
1
|
+
/**
|
2
|
+
* RightJS-UI Tags v2.2.1
|
3
|
+
* http://rightjs.org/ui/tags
|
4
|
+
*
|
5
|
+
* Copyright (C) 2011 Nikolay Nemshilov
|
6
|
+
*/
|
7
|
+
var Tags = RightJS.Tags = (function(RightJS) {
|
8
|
+
/**
|
9
|
+
* This module defines the basic widgets constructor
|
10
|
+
* it creates an abstract proxy with the common functionality
|
11
|
+
* which then we reuse and override in the actual widgets
|
12
|
+
*
|
13
|
+
* Copyright (C) 2010-2011 Nikolay Nemshilov
|
14
|
+
*/
|
15
|
+
|
16
|
+
/**
|
17
|
+
* The widget units constructor
|
18
|
+
*
|
19
|
+
* @param String tag-name or Object methods
|
20
|
+
* @param Object methods
|
21
|
+
* @return Widget wrapper
|
22
|
+
*/
|
23
|
+
function Widget(tag_name, methods) {
|
24
|
+
if (!methods) {
|
25
|
+
methods = tag_name;
|
26
|
+
tag_name = 'DIV';
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* An Abstract Widget Unit
|
31
|
+
*
|
32
|
+
* Copyright (C) 2010 Nikolay Nemshilov
|
33
|
+
*/
|
34
|
+
var AbstractWidget = new RightJS.Class(RightJS.Element.Wrappers[tag_name] || RightJS.Element, {
|
35
|
+
/**
|
36
|
+
* The common constructor
|
37
|
+
*
|
38
|
+
* @param Object options
|
39
|
+
* @param String optional tag name
|
40
|
+
* @return void
|
41
|
+
*/
|
42
|
+
initialize: function(key, options) {
|
43
|
+
this.key = key;
|
44
|
+
var args = [{'class': 'rui-' + key}];
|
45
|
+
|
46
|
+
// those two have different constructors
|
47
|
+
if (!(this instanceof RightJS.Input || this instanceof RightJS.Form)) {
|
48
|
+
args.unshift(tag_name);
|
49
|
+
}
|
50
|
+
this.$super.apply(this, args);
|
51
|
+
|
52
|
+
if (RightJS.isString(options)) {
|
53
|
+
options = RightJS.$(options);
|
54
|
+
}
|
55
|
+
|
56
|
+
// if the options is another element then
|
57
|
+
// try to dynamically rewrap it with our widget
|
58
|
+
if (options instanceof RightJS.Element) {
|
59
|
+
this._ = options._;
|
60
|
+
if ('$listeners' in options) {
|
61
|
+
options.$listeners = options.$listeners;
|
62
|
+
}
|
63
|
+
options = {};
|
64
|
+
}
|
65
|
+
this.setOptions(options, this);
|
66
|
+
|
67
|
+
return (RightJS.Wrapper.Cache[RightJS.$uid(this._)] = this);
|
68
|
+
},
|
69
|
+
|
70
|
+
// protected
|
71
|
+
|
72
|
+
/**
|
73
|
+
* Catches the options
|
74
|
+
*
|
75
|
+
* @param Object user-options
|
76
|
+
* @param Element element with contextual options
|
77
|
+
* @return void
|
78
|
+
*/
|
79
|
+
setOptions: function(options, element) {
|
80
|
+
if (element) {
|
81
|
+
options = RightJS.Object.merge(options, new Function("return "+(
|
82
|
+
element.get('data-'+ this.key) || '{}'
|
83
|
+
))());
|
84
|
+
}
|
85
|
+
|
86
|
+
if (options) {
|
87
|
+
RightJS.Options.setOptions.call(this, RightJS.Object.merge(this.options, options));
|
88
|
+
}
|
89
|
+
|
90
|
+
return this;
|
91
|
+
}
|
92
|
+
});
|
93
|
+
|
94
|
+
/**
|
95
|
+
* Creating the actual widget class
|
96
|
+
*
|
97
|
+
*/
|
98
|
+
var Klass = new RightJS.Class(AbstractWidget, methods);
|
99
|
+
|
100
|
+
// creating the widget related shortcuts
|
101
|
+
RightJS.Observer.createShortcuts(Klass.prototype, Klass.EVENTS || RightJS([]));
|
102
|
+
|
103
|
+
return Klass;
|
104
|
+
}
|
105
|
+
|
106
|
+
|
107
|
+
/**
|
108
|
+
* The tags widget initialization script
|
109
|
+
*
|
110
|
+
* Copyright (C) 2011 Nikolay Nemshilov
|
111
|
+
*/
|
112
|
+
var R = RightJS,
|
113
|
+
$ = RightJS.$,
|
114
|
+
$w = RightJS.$w,
|
115
|
+
Class = RightJS.Class,
|
116
|
+
Input = RightJS.Input,
|
117
|
+
Element = RightJS.Element;
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
/**
|
124
|
+
* The main unit for the Tags widget
|
125
|
+
*
|
126
|
+
* Copyright (C) 2011 Nikolay Nemshilov
|
127
|
+
*/
|
128
|
+
var Tags = new Widget('INPUT', {
|
129
|
+
extend: {
|
130
|
+
version: '2.2.1',
|
131
|
+
|
132
|
+
EVENTS: $w('add remove'),
|
133
|
+
|
134
|
+
Options: {
|
135
|
+
tags: [], // the tags list
|
136
|
+
vertical: false, // use a vertical tags list
|
137
|
+
|
138
|
+
allowNew: true, // allow new tags to be created
|
139
|
+
nocase: true, // caseinsensitive
|
140
|
+
autocomplete: true, // autocomplete the user's input
|
141
|
+
|
142
|
+
separator: ',', // the tokens separator
|
143
|
+
|
144
|
+
cssRule: 'input[data-tags]' // the autoinitialization css-rule
|
145
|
+
},
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Rescans and initializes the input elements in the area
|
149
|
+
*
|
150
|
+
* @param {Wrapper} optional scope
|
151
|
+
* @return void
|
152
|
+
*/
|
153
|
+
rescan: function(scope) {
|
154
|
+
$(scope || document).find(Tags.Options.cssRule).each(function(input) {
|
155
|
+
if (!(input instanceof Tags)) {
|
156
|
+
input = new Tags(input);
|
157
|
+
}
|
158
|
+
});
|
159
|
+
}
|
160
|
+
},
|
161
|
+
|
162
|
+
/**
|
163
|
+
* Basic constructor
|
164
|
+
*
|
165
|
+
* @param {Input} element
|
166
|
+
* @param {Object} options
|
167
|
+
* @return void
|
168
|
+
*/
|
169
|
+
initialize: function(element, options) {
|
170
|
+
// trying to extract a plain list of tags
|
171
|
+
var tags = R(R(''+ $(element).get('data-tags')).trim());
|
172
|
+
|
173
|
+
if (tags.startsWith('[') && tags.endsWith(']')) {
|
174
|
+
if (!options) { options = {}; }
|
175
|
+
options.tags = new Function('return '+tags)();
|
176
|
+
}
|
177
|
+
|
178
|
+
this
|
179
|
+
.$super('tags', element)
|
180
|
+
.setOptions(options);
|
181
|
+
|
182
|
+
if (RightJS.Browser.OLD) {
|
183
|
+
this.setStyle({color: this.getStyle('backgroundColor')});
|
184
|
+
}
|
185
|
+
|
186
|
+
this.container = new Element('div', {'class': 'rui-tags'}).insertTo(this, 'after');
|
187
|
+
|
188
|
+
this.list = new Tags.List(this);
|
189
|
+
this.input = new Tags.Input(this);
|
190
|
+
this.completer = new Tags.Completer(this);
|
191
|
+
|
192
|
+
this.onFocus(function() { this.input.focus(); });
|
193
|
+
|
194
|
+
// reinitializing with default values
|
195
|
+
this.setValue(this._.value);
|
196
|
+
},
|
197
|
+
|
198
|
+
/**
|
199
|
+
* Overloading the method so that it updated the visible list as well
|
200
|
+
*
|
201
|
+
* @param {String|Array} string tokens
|
202
|
+
* @return {Tags} this
|
203
|
+
*/
|
204
|
+
setValue: function(tags) {
|
205
|
+
if (isString(tags)) {
|
206
|
+
tags = R(tags.split(this.options.separator))
|
207
|
+
.map('trim').reject('blank');
|
208
|
+
}
|
209
|
+
|
210
|
+
// merging the tags into the known list
|
211
|
+
this.options.tags = R(this.options.tags).merge(tags);
|
212
|
+
|
213
|
+
// repopulating the list
|
214
|
+
this.list.setTags(tags);
|
215
|
+
|
216
|
+
// setting the internal value
|
217
|
+
return this.$super(tags.join(this.options.separator + ' '));
|
218
|
+
}
|
219
|
+
});
|
220
|
+
|
221
|
+
|
222
|
+
/**
|
223
|
+
* The tags list element custom wrapper
|
224
|
+
*
|
225
|
+
* Copyright (C) 2011 Nikolay Nemshilov
|
226
|
+
*/
|
227
|
+
Tags.List = new Class(Element, {
|
228
|
+
|
229
|
+
/**
|
230
|
+
* Constructor, creates the list and places where it supposed to be
|
231
|
+
*
|
232
|
+
* @param {Tags} tags instance
|
233
|
+
* @return void
|
234
|
+
*/
|
235
|
+
initialize: function(main) {
|
236
|
+
this.main = main;
|
237
|
+
|
238
|
+
this.$super('ul', {'class': 'list'});
|
239
|
+
this.insertTo(main.container);
|
240
|
+
|
241
|
+
if (this.main.options.vertical) {
|
242
|
+
this.addClass('vertical');
|
243
|
+
}
|
244
|
+
|
245
|
+
function double_styles(name) {
|
246
|
+
return main.getStyle(name).replace(
|
247
|
+
/[\d\.]+/, function(m) { return parseFloat(m) * 2; }
|
248
|
+
);
|
249
|
+
}
|
250
|
+
|
251
|
+
this.setStyle({
|
252
|
+
fontSize: main.getStyle('fontSize'),
|
253
|
+
fontFamily: main.getStyle('fontFamily'),
|
254
|
+
fontWeight: main.getStyle('fontWeight'),
|
255
|
+
letterSpacing: main.getStyle('letterSpacing'),
|
256
|
+
paddingTop: double_styles('borderTopWidth'),
|
257
|
+
paddingLeft: double_styles('borderLeftWidth'),
|
258
|
+
paddingRight: double_styles('borderRightWidth'),
|
259
|
+
paddingBottom: main.getStyle('borderBottomWidth')
|
260
|
+
});
|
261
|
+
|
262
|
+
// frakking Opera '0em' sizes bug fallback
|
263
|
+
if (main.getStyle('fontSize') === '0em') {
|
264
|
+
this.setStyle({fontSize: '1em'});
|
265
|
+
}
|
266
|
+
|
267
|
+
this.setWidth(main.size().x);
|
268
|
+
this.reposition(true);
|
269
|
+
|
270
|
+
this.onClick(this._click);
|
271
|
+
},
|
272
|
+
|
273
|
+
/**
|
274
|
+
* Sets a list of tags
|
275
|
+
*
|
276
|
+
* @param {Array} tags
|
277
|
+
* @return {Tags.List} this
|
278
|
+
*/
|
279
|
+
setTags: function(tags) {
|
280
|
+
tags.uniq().each(this.clean().addTag, this);
|
281
|
+
|
282
|
+
return this;
|
283
|
+
},
|
284
|
+
|
285
|
+
/**
|
286
|
+
* Returns a list of tags on the list
|
287
|
+
*
|
288
|
+
* @return {Array} of tokens
|
289
|
+
*/
|
290
|
+
getTags: function() {
|
291
|
+
return this.find('div.text').map('text');
|
292
|
+
},
|
293
|
+
|
294
|
+
/**
|
295
|
+
* adds the tag to the list
|
296
|
+
*
|
297
|
+
* @param {String} tag
|
298
|
+
* @return {Tags.List} this
|
299
|
+
*/
|
300
|
+
addTag: function(tag) {
|
301
|
+
if (this._allowed(tag)) {
|
302
|
+
this
|
303
|
+
.append(
|
304
|
+
'<li>'+
|
305
|
+
'<div class="text">'+ R(tag).trim() +'</div>'+
|
306
|
+
'<div class="close">×</div>' +
|
307
|
+
'</li>'
|
308
|
+
).reposition();
|
309
|
+
|
310
|
+
this.main.fire('add', {tag: tag});
|
311
|
+
}
|
312
|
+
|
313
|
+
this.main._.value = this.getTags().join(
|
314
|
+
this.main.options.separator + ' '
|
315
|
+
);
|
316
|
+
|
317
|
+
return this;
|
318
|
+
},
|
319
|
+
|
320
|
+
/**
|
321
|
+
* Removes the last item from the list
|
322
|
+
*
|
323
|
+
* @return {Tags.List} this
|
324
|
+
*/
|
325
|
+
removeLast: function() {
|
326
|
+
var item = this.find('li').last();
|
327
|
+
|
328
|
+
if (item) {
|
329
|
+
this._remove(item);
|
330
|
+
}
|
331
|
+
|
332
|
+
return this;
|
333
|
+
},
|
334
|
+
|
335
|
+
/**
|
336
|
+
* Adjusts the original input field size and
|
337
|
+
* places the list right above it,
|
338
|
+
* in case if the list will start folding
|
339
|
+
*
|
340
|
+
* @return {Tags.List} this
|
341
|
+
*/
|
342
|
+
reposition: function(force) {
|
343
|
+
var size = this.size().y, main = this.main.size().y, style;
|
344
|
+
|
345
|
+
if (size !== main || force === true) {
|
346
|
+
this.main.setHeight(size);
|
347
|
+
|
348
|
+
style = this._.style;
|
349
|
+
|
350
|
+
style.top = '0px';
|
351
|
+
style.left = '0px';
|
352
|
+
|
353
|
+
size = this.position();
|
354
|
+
main = this.main.position();
|
355
|
+
|
356
|
+
style.top = main.y - size.y + 'px';
|
357
|
+
style.left = main.x - size.x + 'px';
|
358
|
+
}
|
359
|
+
|
360
|
+
return this;
|
361
|
+
},
|
362
|
+
|
363
|
+
// private
|
364
|
+
|
365
|
+
// catches the clicks on the list
|
366
|
+
_click: function(event) {
|
367
|
+
if (event.target.hasClass('close')) {
|
368
|
+
this._remove(event.target.parent());
|
369
|
+
} else {
|
370
|
+
this.main.input.focus();
|
371
|
+
}
|
372
|
+
},
|
373
|
+
|
374
|
+
// checks if the tag is allowed to be added to the list
|
375
|
+
_allowed: function(tag) {
|
376
|
+
var tags = this.getTags(),
|
377
|
+
options = this.main.options,
|
378
|
+
casesensitive = !options.nocase;
|
379
|
+
|
380
|
+
return !(casesensitive ? tags.include(tag) :
|
381
|
+
tags.map('toLowerCase').include(tag.toLowerCase())
|
382
|
+
) && (
|
383
|
+
options.allowNew || (
|
384
|
+
casesensitive ? tags.include(tag) :
|
385
|
+
options.tags.map('toLowerCase').include(tag.toLowerCase())
|
386
|
+
)
|
387
|
+
);
|
388
|
+
},
|
389
|
+
|
390
|
+
// removes an item out of the list
|
391
|
+
_remove: function(item) {
|
392
|
+
var tag = item.first('div.text').text();
|
393
|
+
|
394
|
+
this.main.setValue(
|
395
|
+
this.getTags().without(tag)
|
396
|
+
);
|
397
|
+
|
398
|
+
this.main.fire('remove', {tag: tag});
|
399
|
+
}
|
400
|
+
|
401
|
+
});
|
402
|
+
|
403
|
+
/**
|
404
|
+
* The 'fake' input field element
|
405
|
+
*
|
406
|
+
* Copyright (C) 2011 Nikolay Nemshilov
|
407
|
+
*/
|
408
|
+
Tags.Input = new Class(Input, {
|
409
|
+
|
410
|
+
/**
|
411
|
+
* Constructor
|
412
|
+
*
|
413
|
+
* @param {Tabs} the main object
|
414
|
+
* @return void
|
415
|
+
*/
|
416
|
+
initialize: function(main) {
|
417
|
+
this.main = main;
|
418
|
+
this.list = main.list;
|
419
|
+
|
420
|
+
this.$super({type: 'text', size: 1});
|
421
|
+
this.onKeydown(this._keydown);
|
422
|
+
this.onKeyup(this._keyup);
|
423
|
+
this.onBlur(this._blur);
|
424
|
+
this.insertTo(main.list);
|
425
|
+
|
426
|
+
// used to dynamically measure the size of the field
|
427
|
+
this.meter = new Element('div', {
|
428
|
+
'class': 'meter',
|
429
|
+
'style': {
|
430
|
+
whiteSpace: 'nowrap',
|
431
|
+
position: 'absolute',
|
432
|
+
left: '-99999em'
|
433
|
+
}
|
434
|
+
}).insertTo(this, 'after');
|
435
|
+
},
|
436
|
+
|
437
|
+
/**
|
438
|
+
* Inserting itself into the tags list on the 'focus' call
|
439
|
+
*
|
440
|
+
* @return {Tags.Input} this
|
441
|
+
*/
|
442
|
+
focus: function() {
|
443
|
+
this.main.list.append(this, this.meter).reposition();
|
444
|
+
return this.$super();
|
445
|
+
},
|
446
|
+
|
447
|
+
/**
|
448
|
+
* Resets the input field state
|
449
|
+
*
|
450
|
+
* @return {Tags.Input} this
|
451
|
+
*/
|
452
|
+
reset: function() {
|
453
|
+
this.remove();
|
454
|
+
this.meter.remove();
|
455
|
+
this.list.reposition();
|
456
|
+
this._.value = '';
|
457
|
+
|
458
|
+
return this;
|
459
|
+
},
|
460
|
+
|
461
|
+
// private
|
462
|
+
|
463
|
+
_keydown: function(event) {
|
464
|
+
if (event.keyCode === 8 && this._.value === '') {
|
465
|
+
this.list.removeLast(); // deleting the last tag with backspace
|
466
|
+
this.focus();
|
467
|
+
} else if (event.keyCode === 13) {
|
468
|
+
event.preventDefault(); // preventing the for to go off on Enter
|
469
|
+
}
|
470
|
+
},
|
471
|
+
|
472
|
+
_keyup: function(event) {
|
473
|
+
if (!R([9, 27, 37, 38, 39, 40, 13]).include(event.keyCode)) {
|
474
|
+
if (this._.value.indexOf(this.main.options.separator) !== -1) {
|
475
|
+
this._add();
|
476
|
+
this.focus();
|
477
|
+
} else {
|
478
|
+
this._resize();
|
479
|
+
this.main.completer.suggest(this._.value);
|
480
|
+
}
|
481
|
+
}
|
482
|
+
},
|
483
|
+
|
484
|
+
_blur: function(event) {
|
485
|
+
if (this.main.completer.hidden() && this._.value !== '') {
|
486
|
+
this._add();
|
487
|
+
this.reset();
|
488
|
+
}
|
489
|
+
},
|
490
|
+
|
491
|
+
// resizes the field to fit the text
|
492
|
+
_resize: function() {
|
493
|
+
this.meter.html(this._.value + 'xx');
|
494
|
+
this._.style.width = this.meter.size().x + 'px';
|
495
|
+
this.list.reposition();
|
496
|
+
},
|
497
|
+
|
498
|
+
// makes a tag out of the current value
|
499
|
+
_add: function() {
|
500
|
+
var value = this._.value.replace(this.main.options.separator, '');
|
501
|
+
this._.value = '';
|
502
|
+
|
503
|
+
if (!(/^\s*$/).test(value)) {
|
504
|
+
this.list.addTag(value);
|
505
|
+
}
|
506
|
+
|
507
|
+
if (this.main.completer.visible()) {
|
508
|
+
this.main.completer.hide();
|
509
|
+
}
|
510
|
+
}
|
511
|
+
|
512
|
+
});
|
513
|
+
|
514
|
+
/**
|
515
|
+
* The tags completer popup menu
|
516
|
+
*
|
517
|
+
* Copyright (C) 2011 Nikolay Nemshilov
|
518
|
+
*/
|
519
|
+
Tags.Completer = new Class(Element, {
|
520
|
+
|
521
|
+
extend: {
|
522
|
+
current: null // currently visible list reference
|
523
|
+
},
|
524
|
+
|
525
|
+
/**
|
526
|
+
* Constructor
|
527
|
+
*
|
528
|
+
* @param {Tags} main object
|
529
|
+
* @return void
|
530
|
+
*/
|
531
|
+
initialize: function(main) {
|
532
|
+
this.main = main;
|
533
|
+
this.list = main.list;
|
534
|
+
this.input = main.input;
|
535
|
+
|
536
|
+
this.$super('ul', {'class': 'completer'});
|
537
|
+
this.addClass('rui-dd-menu');
|
538
|
+
this.insertTo(main.container);
|
539
|
+
|
540
|
+
this.onClick(this._click);
|
541
|
+
},
|
542
|
+
|
543
|
+
/**
|
544
|
+
* Starts the suggesting process
|
545
|
+
*
|
546
|
+
*/
|
547
|
+
suggest: function(value) {
|
548
|
+
if (!(/^\s*$/).test(value) && this.main.options.autocomplete) {
|
549
|
+
var tags = this._filter(this.main.options.tags, value);
|
550
|
+
|
551
|
+
if (tags.length !== 0) {
|
552
|
+
this.html(tags.map(function(tag) {
|
553
|
+
return '<li>'+ tag.replace(value, '<b>'+ value + '</b>') +'</li>';
|
554
|
+
}).join(''));
|
555
|
+
|
556
|
+
this.picked = false;
|
557
|
+
|
558
|
+
return this.show();
|
559
|
+
}
|
560
|
+
}
|
561
|
+
|
562
|
+
return this.hide();
|
563
|
+
},
|
564
|
+
|
565
|
+
/**
|
566
|
+
* Overloading the method so it appeared right below the input field
|
567
|
+
*
|
568
|
+
* @return {Tags.Completer} this
|
569
|
+
*/
|
570
|
+
show: function() {
|
571
|
+
var input = this.input.dimensions(),
|
572
|
+
style = this._.style,
|
573
|
+
pos;
|
574
|
+
|
575
|
+
style.display = 'block';
|
576
|
+
|
577
|
+
style.top = '0px';
|
578
|
+
style.left = '0px';
|
579
|
+
|
580
|
+
pos = this.position();
|
581
|
+
|
582
|
+
style.left = input.left - pos.x + 'px';
|
583
|
+
style.top = input.top - pos.y + input.height + 'px';
|
584
|
+
|
585
|
+
return (Tags.Completer.current = this);
|
586
|
+
},
|
587
|
+
|
588
|
+
/**
|
589
|
+
* Hides the list of suggestions
|
590
|
+
*
|
591
|
+
* @return {Tags.Completer} this
|
592
|
+
*/
|
593
|
+
hide: function() {
|
594
|
+
this._.innerHTML = '';
|
595
|
+
this._.style.display = 'none';
|
596
|
+
|
597
|
+
Tags.Completer.current = null;
|
598
|
+
|
599
|
+
return this;
|
600
|
+
},
|
601
|
+
|
602
|
+
|
603
|
+
/**
|
604
|
+
* Highlights the next item on the list
|
605
|
+
*
|
606
|
+
* @return {Tags.Completer} this
|
607
|
+
*/
|
608
|
+
next: function() {
|
609
|
+
var item = this.first('.current');
|
610
|
+
|
611
|
+
if (item) { item = item.next(); }
|
612
|
+
if (!item) { item = this.first(); }
|
613
|
+
if (item) { item.radioClass('current'); }
|
614
|
+
|
615
|
+
return this;
|
616
|
+
},
|
617
|
+
|
618
|
+
/**
|
619
|
+
* Highlights the previous item on the list
|
620
|
+
*
|
621
|
+
* @return {Tags.Completer} this
|
622
|
+
*/
|
623
|
+
prev: function() {
|
624
|
+
var item = this.first('.current');
|
625
|
+
|
626
|
+
if (item) { item = item.prev(); }
|
627
|
+
if (!item) { item = this.children().last(); }
|
628
|
+
if (item) { item.radioClass('current'); }
|
629
|
+
|
630
|
+
return this;
|
631
|
+
},
|
632
|
+
|
633
|
+
/**
|
634
|
+
* Copies the picked item data into the input field
|
635
|
+
* and hides the list
|
636
|
+
*
|
637
|
+
* @return {Tags.Completer} this
|
638
|
+
*/
|
639
|
+
done: function() {
|
640
|
+
var item = this.first('.current');
|
641
|
+
|
642
|
+
if (item) {
|
643
|
+
this.list.addTag(item.text());
|
644
|
+
this.input.reset().focus();
|
645
|
+
}
|
646
|
+
|
647
|
+
return this.hide();
|
648
|
+
},
|
649
|
+
|
650
|
+
// private
|
651
|
+
|
652
|
+
// handles mouse clicks on the list
|
653
|
+
_click: function(event) {
|
654
|
+
var item = event.find('li');
|
655
|
+
|
656
|
+
if (item) {
|
657
|
+
item.radioClass('current');
|
658
|
+
}
|
659
|
+
|
660
|
+
this.done();
|
661
|
+
},
|
662
|
+
|
663
|
+
// finds an appropriate list of tags for the suggestion
|
664
|
+
_filter: function(tags, value) {
|
665
|
+
var used = this.list.getTags(),
|
666
|
+
nocase = this.main.options.nocase;
|
667
|
+
|
668
|
+
if (nocase) {
|
669
|
+
used = used.map('toLowerCase');
|
670
|
+
value = value.toLowerCase();
|
671
|
+
}
|
672
|
+
|
673
|
+
return tags.filter(function(tag) {
|
674
|
+
var low_tag = nocase ? tag.toLowerCase() : tag;
|
675
|
+
|
676
|
+
return low_tag.indexOf(value) !== -1 && !used.include(low_tag);
|
677
|
+
});
|
678
|
+
}
|
679
|
+
});
|
680
|
+
|
681
|
+
/**
|
682
|
+
* Document - on-load hook
|
683
|
+
*
|
684
|
+
* Copyright (C) 2011 Nikolay Nemshilov
|
685
|
+
*/
|
686
|
+
$(document).on({
|
687
|
+
/**
|
688
|
+
* Triggers autoinitialization when the document is loaded
|
689
|
+
*
|
690
|
+
* @return void
|
691
|
+
*/
|
692
|
+
ready: function() {
|
693
|
+
Tags.rescan();
|
694
|
+
},
|
695
|
+
|
696
|
+
/**
|
697
|
+
* Handles the suggestions list navigation
|
698
|
+
*
|
699
|
+
* @param {Event} event
|
700
|
+
* @return void
|
701
|
+
*/
|
702
|
+
keydown: function(event) {
|
703
|
+
var list = Tags.Completer.current,
|
704
|
+
keys = {
|
705
|
+
13: 'done', // Enter
|
706
|
+
27: 'hide', // Escape
|
707
|
+
38: 'prev', // Up
|
708
|
+
40: 'next' // Down
|
709
|
+
};
|
710
|
+
|
711
|
+
if (list !== null && event.keyCode in keys) {
|
712
|
+
event.stop();
|
713
|
+
list[keys[event.keyCode]]();
|
714
|
+
}
|
715
|
+
},
|
716
|
+
|
717
|
+
/**
|
718
|
+
* Hides the completer menu by an outer click
|
719
|
+
*
|
720
|
+
* @param {Event} click
|
721
|
+
* @return void
|
722
|
+
*/
|
723
|
+
click: function(event) {
|
724
|
+
if (Tags.Completer.current) {
|
725
|
+
Tags.Completer.current.hide();
|
726
|
+
}
|
727
|
+
}
|
728
|
+
|
729
|
+
});
|
730
|
+
|
731
|
+
var embed_style = document.createElement('style'),
|
732
|
+
embed_rules = document.createTextNode("*.rui-dd-menu, *.rui-dd-menu li{margin:0;padding:0;border:none;background:none;list-style:none;font-weight:normal;float:none} *.rui-dd-menu{display:none;position:absolute;z-index:9999;background:white;border:1px solid #BBB;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;box-shadow:#DDD .2em .2em .4em;-moz-box-shadow:#DDD .2em .2em .4em;-webkit-box-shadow:#DDD .2em .2em .4em} *.rui-dd-menu li{padding:.2em .4em;border-top:none;border-bottom:none;cursor:pointer} *.rui-dd-menu li.current{background:#DDD} *.rui-dd-menu li:hover{background:#EEE}dl.rui-dd-menu dt{padding:.3em .5em;cursor:default;font-weight:bold;font-style:italic;color:#444;background:#EEE}dl.rui-dd-menu dd li{padding-left:1.5em}div.rui-tags,div.rui-tags ul.list,div.rui-tags ul.list *{position:static;top:auto;left:auto;right:auto;bottom:auto;float:none;margin:0;padding:0;border:none;background:none;display:block}input[data-tags],input.rui-tags{color:transparent;color:rgba(0,0,0,0)}div.rui-tags{position:absolute;display:inline}div.rui-tags ul.list{position:absolute;overflow:hidden;min-height:1.3em}div.rui-tags ul.list li{display:inline-block; *display:inline; *zoom:1;position:relative;cursor:default;margin-right:.1em;margin-bottom:.1em;padding:0 .5em;padding-right:1.1em;background:#ddd;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;vertical-align:top}div.rui-tags ul.list li div.text{position:inline}div.rui-tags ul.list li div.close{margin-left:.25em;cursor:pointer;font-family:Arial;font-weight:normal;opacity:0.5;position:absolute;right:.25em;top:0.04em}div.rui-tags ul.list li div.close:hover{opacity:1}div.rui-tags ul.vertical li{display:block}div.rui-tags ul.list input{width:auto;height:auto;display:inline-block; *display:inline; *zoom:1;width:1em;outline:none;vertical-align:top;font-family:inherit;font-size:inherit;font-weight:inherit;letter-spacing:inherit}");
|
733
|
+
|
734
|
+
embed_style.type = 'text/css';
|
735
|
+
document.getElementsByTagName('head')[0].appendChild(embed_style);
|
736
|
+
|
737
|
+
if(embed_style.styleSheet) {
|
738
|
+
embed_style.styleSheet.cssText = embed_rules.nodeValue;
|
739
|
+
} else {
|
740
|
+
embed_style.appendChild(embed_rules);
|
741
|
+
}
|
742
|
+
|
743
|
+
|
744
|
+
return Tags;
|
745
|
+
})(RightJS);
|