right-rails 0.6.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/CHANGELOG +8 -0
  2. data/README.rdoc +71 -0
  3. data/Rakefile +144 -14
  4. data/generators/right_rails/right_rails_generator.rb +18 -21
  5. data/init.rb +11 -32
  6. data/lib/generators/right_rails/right_rails_generator.rb +27 -0
  7. data/lib/generators/right_rails/templates/iframed.html.erb +10 -0
  8. data/lib/right-rails.rb +1 -1
  9. data/lib/right_rails/config.rb +278 -0
  10. data/lib/right_rails/controller_extensions.rb +10 -5
  11. data/lib/right_rails/helpers/basic.rb +10 -66
  12. data/lib/right_rails/helpers/forms.rb +141 -139
  13. data/lib/right_rails/helpers/misc.rb +45 -67
  14. data/lib/right_rails/helpers/rails.rb +40 -105
  15. data/lib/right_rails/helpers.rb +364 -1
  16. data/lib/right_rails/java_script_generator.rb +34 -24
  17. data/lib/right_rails.rb +6 -1
  18. data/{images → public/images}/colorpicker.png +0 -0
  19. data/{images → public/images}/resizable.png +0 -0
  20. data/public/javascripts/right/autocompleter-src.js +612 -0
  21. data/public/javascripts/right/autocompleter.js +18 -0
  22. data/public/javascripts/right/calendar-src.js +1448 -0
  23. data/public/javascripts/right/calendar.js +36 -0
  24. data/public/javascripts/right/colorpicker-src.js +967 -0
  25. data/public/javascripts/right/colorpicker.js +26 -0
  26. data/{javascripts/right-dnd-src.js → public/javascripts/right/dnd-src.js} +86 -52
  27. data/public/javascripts/right/dnd.js +20 -0
  28. data/{javascripts/right-effects-src.js → public/javascripts/right/effects-src.js} +90 -45
  29. data/public/javascripts/right/effects.js +17 -0
  30. data/{javascripts/right-ui-i18n-de.js → public/javascripts/right/i18n/de.js} +7 -7
  31. data/{javascripts/right-ui-i18n-en-us.js → public/javascripts/right/i18n/en-us.js} +1 -1
  32. data/{javascripts/right-ui-i18n-es.js → public/javascripts/right/i18n/es.js} +7 -7
  33. data/{javascripts/right-ui-i18n-fr.js → public/javascripts/right/i18n/fr.js} +7 -7
  34. data/{javascripts/right-ui-i18n-hu.js → public/javascripts/right/i18n/hu.js} +7 -7
  35. data/{javascripts/right-ui-i18n-jp.js → public/javascripts/right/i18n/jp.js} +7 -7
  36. data/{javascripts/right-ui-i18n-nl.js → public/javascripts/right/i18n/nl.js} +7 -7
  37. data/{javascripts/right-ui-i18n-pt-br.js → public/javascripts/right/i18n/pt-br.js} +7 -7
  38. data/{javascripts/right-ui-i18n-ru.js → public/javascripts/right/i18n/ru.js} +7 -7
  39. data/{javascripts/right-ui-i18n-ua.js → public/javascripts/right/i18n/ua.js} +17 -12
  40. data/public/javascripts/right/in-edit-src.js +352 -0
  41. data/public/javascripts/right/in-edit.js +13 -0
  42. data/public/javascripts/right/json-src.js +160 -0
  43. data/public/javascripts/right/json.js +10 -0
  44. data/public/javascripts/right/lightbox-src.js +881 -0
  45. data/public/javascripts/right/lightbox.js +24 -0
  46. data/{javascripts/right-rails-src.js → public/javascripts/right/rails-src.js} +195 -171
  47. data/public/javascripts/right/rails.js +14 -0
  48. data/public/javascripts/right/rater-src.js +366 -0
  49. data/public/javascripts/right/rater.js +13 -0
  50. data/public/javascripts/right/resizable-src.js +420 -0
  51. data/public/javascripts/right/resizable.js +15 -0
  52. data/public/javascripts/right/selectable-src.js +687 -0
  53. data/public/javascripts/right/selectable.js +22 -0
  54. data/public/javascripts/right/slider-src.js +377 -0
  55. data/public/javascripts/right/slider.js +14 -0
  56. data/public/javascripts/right/sortable-src.js +392 -0
  57. data/public/javascripts/right/sortable.js +16 -0
  58. data/public/javascripts/right/tabs-src.js +1123 -0
  59. data/public/javascripts/right/tabs.js +29 -0
  60. data/public/javascripts/right/tooltip-src.js +307 -0
  61. data/public/javascripts/right/tooltip.js +12 -0
  62. data/public/javascripts/right/uploader-src.js +283 -0
  63. data/public/javascripts/right/uploader.js +13 -0
  64. data/{javascripts → public/javascripts}/right-olds-src.js +134 -186
  65. data/public/javascripts/right-olds.js +18 -0
  66. data/public/javascripts/right-safe-src.js +161 -0
  67. data/public/javascripts/right-safe.js +8 -0
  68. data/{javascripts → public/javascripts}/right-src.js +2558 -1750
  69. data/public/javascripts/right.js +92 -0
  70. data/spec/lib/right_rails/config_spec.rb +133 -0
  71. data/spec/lib/right_rails/controller_extensions_spec.rb +1 -1
  72. data/spec/lib/right_rails/helpers/basic_spec.rb +77 -66
  73. data/spec/lib/right_rails/helpers/forms_spec.rb +231 -33
  74. data/spec/lib/right_rails/helpers/misc_spec.rb +94 -26
  75. data/spec/lib/right_rails/helpers/rails_spec.rb +42 -7
  76. data/spec/lib/right_rails/helpers_spec.rb +125 -0
  77. data/spec/lib/right_rails/java_script_generator_spec.rb +30 -0
  78. data/spec/rcov.opts +3 -0
  79. data/spec/spec_helper.rb +12 -7
  80. metadata +70 -61
  81. data/README.textile +0 -69
  82. data/javascripts/right-autocompleter-src.js +0 -318
  83. data/javascripts/right-autocompleter.js +0 -9
  84. data/javascripts/right-behavior-src.js +0 -261
  85. data/javascripts/right-behavior.js +0 -8
  86. data/javascripts/right-calendar-src.js +0 -946
  87. data/javascripts/right-calendar.js +0 -9
  88. data/javascripts/right-colorpicker-src.js +0 -635
  89. data/javascripts/right-colorpicker.js +0 -9
  90. data/javascripts/right-dnd.js +0 -9
  91. data/javascripts/right-effects.js +0 -6
  92. data/javascripts/right-events-src.js +0 -321
  93. data/javascripts/right-events.js +0 -6
  94. data/javascripts/right-in-edit-src.js +0 -194
  95. data/javascripts/right-in-edit.js +0 -6
  96. data/javascripts/right-json-src.js +0 -141
  97. data/javascripts/right-json.js +0 -6
  98. data/javascripts/right-lightbox-src.js +0 -651
  99. data/javascripts/right-lightbox.js +0 -9
  100. data/javascripts/right-olds.js +0 -9
  101. data/javascripts/right-rails.js +0 -9
  102. data/javascripts/right-rater-src.js +0 -253
  103. data/javascripts/right-rater.js +0 -9
  104. data/javascripts/right-resizable-src.js +0 -336
  105. data/javascripts/right-resizable.js +0 -9
  106. data/javascripts/right-selectable-src.js +0 -565
  107. data/javascripts/right-selectable.js +0 -7
  108. data/javascripts/right-slider-src.js +0 -288
  109. data/javascripts/right-slider.js +0 -7
  110. data/javascripts/right-sortable-src.js +0 -225
  111. data/javascripts/right-sortable.js +0 -9
  112. data/javascripts/right-tabs-src.js +0 -937
  113. data/javascripts/right-tabs.js +0 -6
  114. data/javascripts/right-tooltips-src.js +0 -195
  115. data/javascripts/right-tooltips.js +0 -9
  116. data/javascripts/right-uploader-src.js +0 -167
  117. data/javascripts/right-uploader.js +0 -9
  118. data/javascripts/right.js +0 -7
@@ -0,0 +1,687 @@
1
+ /**
2
+ * Selectable unit for RightJS
3
+ * http://rightjs.org/ui/selectable
4
+ *
5
+ * Copyright (C) 2009-2010 Nikolay Nemshilov
6
+ */
7
+ var Selectable = RightJS.Selectable = (function(document, 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 Nikolay Nemshilov
14
+ */
15
+
16
+ /**
17
+ * The filenames to include
18
+ *
19
+ * Copyright (C) 2010 Nikolay Nemshilov
20
+ */
21
+ var R = RightJS,
22
+ $ = RightJS.$,
23
+ $$ = RightJS.$$,
24
+ $w = RightJS.$w,
25
+ $E = RightJS.$E,
26
+ $A = RightJS.$A,
27
+ isHash = RightJS.isHash,
28
+ isArray = RightJS.isArray,
29
+ isString = RightJS.isString,
30
+ isNumber = RightJS.isNumber,
31
+ defined = RightJS.defined,
32
+ Input = RightJS.Input,
33
+ Element = RightJS.Element;
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+ /**
43
+ * The widget units constructor
44
+ *
45
+ * @param String tag-name or Object methods
46
+ * @param Object methods
47
+ * @return Widget wrapper
48
+ */
49
+ function Widget(tag_name, methods) {
50
+ if (!methods) {
51
+ methods = tag_name;
52
+ tag_name = 'DIV';
53
+ }
54
+
55
+ /**
56
+ * An Abstract Widget Unit
57
+ *
58
+ * Copyright (C) 2010 Nikolay Nemshilov
59
+ */
60
+ var AbstractWidget = new RightJS.Wrapper(RightJS.Element.Wrappers[tag_name] || RightJS.Element, {
61
+ /**
62
+ * The common constructor
63
+ *
64
+ * @param Object options
65
+ * @param String optional tag name
66
+ * @return void
67
+ */
68
+ initialize: function(key, options) {
69
+ this.key = key;
70
+ var args = [{'class': 'rui-' + key}];
71
+
72
+ // those two have different constructors
73
+ if (!(this instanceof RightJS.Input || this instanceof RightJS.Form)) {
74
+ args.unshift(tag_name);
75
+ }
76
+ this.$super.apply(this, args);
77
+
78
+ if (RightJS.isString(options)) {
79
+ options = RightJS.$(options);
80
+ }
81
+
82
+ // if the options is another element then
83
+ // try to dynamically rewrap it with our widget
84
+ if (options instanceof RightJS.Element) {
85
+ this._ = options._;
86
+ if ('$listeners' in options) {
87
+ options.$listeners = options.$listeners;
88
+ }
89
+ options = {};
90
+ }
91
+ this.setOptions(options, this);
92
+ return this;
93
+ },
94
+
95
+ // protected
96
+
97
+ /**
98
+ * Catches the options
99
+ *
100
+ * @param Object user-options
101
+ * @param Element element with contextual options
102
+ * @return void
103
+ */
104
+ setOptions: function(options, element) {
105
+ element = element || this;
106
+ RightJS.Options.setOptions.call(this,
107
+ RightJS.Object.merge(options, eval("("+(
108
+ element.get('data-'+ this.key) || '{}'
109
+ )+")"))
110
+ );
111
+ return this;
112
+ }
113
+ });
114
+
115
+ /**
116
+ * Creating the actual widget class
117
+ *
118
+ */
119
+ var Klass = new RightJS.Wrapper(AbstractWidget, methods);
120
+
121
+ // creating the widget related shortcuts
122
+ RightJS.Observer.createShortcuts(Klass.prototype, Klass.EVENTS || []);
123
+
124
+ return Klass;
125
+ }
126
+
127
+
128
+ /**
129
+ * Same as the assignable, only it doesn't work with popups
130
+ * instead it simply updates the assigned unit value/content
131
+ *
132
+ * Copyright (C) 2010 Nikolay Nemshilov
133
+ */
134
+ var Updater = {
135
+
136
+ /**
137
+ * Assigns the unit to work with an input element
138
+ *
139
+ * @param mixed element reference
140
+ * @return Rater this
141
+ */
142
+ assignTo: function(element) {
143
+ var assign = R(function(element, event) {
144
+ if ((element = $(element))) {
145
+ element[element.setValue ? 'setValue' : 'update'](event.target.getValue());
146
+ }
147
+ }).curry(element);
148
+
149
+ var connect = R(function(element, object) {
150
+ element = $(element);
151
+ if (element && element.onChange) {
152
+ element.onChange(R(function() {
153
+ this.setValue(element.value());
154
+ }).bind(object));
155
+ }
156
+ }).curry(element);
157
+
158
+ if ($(element)) {
159
+ assign({target: this});
160
+ connect(this);
161
+ } else {
162
+ $(document).onReady(R(function() {
163
+ assign({target: this});
164
+ connect(this);
165
+ }.bind(this)));
166
+ }
167
+
168
+ return this.onChange(assign);
169
+ }
170
+ };
171
+
172
+
173
+ /**
174
+ * Selectable unit main script
175
+ *
176
+ * Copyright (C) 2009-2010 Nikolay Nemshilov
177
+ */
178
+ var Selectable = new Widget('UL', {
179
+ include: Updater,
180
+
181
+ extend: {
182
+ version: '2.0.0',
183
+
184
+ EVENTS: $w('change select unselect disable enable hover leave show hide'),
185
+
186
+ Options: {
187
+ options: null, // a hash of key-value pairs
188
+ selected: null, // an array of selected keys
189
+ disabled: null, // an array of disabled keys
190
+
191
+ multiple: true, // a flag if it shoulde a multiselect or a single select widget
192
+
193
+ fxName: 'slide', // the drop-down options list fx-name null, 'slide', 'fade'
194
+ fxDuration: 'short', // the drop-down options list fx-duration
195
+
196
+ update: null, // a field to be assigned to
197
+ parseIds: false, // if it should parse integer ids out of the keys
198
+
199
+ limit: null, // put some number if you'd like to limit the number of selected items
200
+
201
+ hCont : '•' // single-selectable handle content
202
+ },
203
+
204
+ // converting normal select boxes into selectables
205
+ rescan: function(context) {
206
+ $(context||document).find('.rui-selectable').each(function(element) {
207
+ if (!(element instanceof Selectable)) {
208
+ new Selectable(element);
209
+ }
210
+ });
211
+ }
212
+ },
213
+
214
+ /**
215
+ * Basic constructor
216
+ *
217
+ * @param mixed reference to an element or the options hash
218
+ * @param Object options hash
219
+ */
220
+ initialize: function() {
221
+ var args = $A(arguments).compact(), options = args.pop(),
222
+ element = args.pop(), selectbox;
223
+
224
+ // figuring out the arguments
225
+ if (!isHash(options) || options instanceof Element) {
226
+ element = $(element || options);
227
+ options = {};
228
+ }
229
+
230
+ // converting the selectboxes
231
+ if (element && element instanceof Input) {
232
+ options = this.harvestOptions(selectbox = element);
233
+ element = options;
234
+ }
235
+
236
+ // main initialization
237
+ this
238
+ .$super('selectable', element)
239
+ .setOptions(options)
240
+ .on({
241
+ mousedown: this._mousedown,
242
+ mouseover: this._mouseover,
243
+ mouseout: this._mouseout,
244
+ mouseup: this._mouseup,
245
+ click: this._click,
246
+
247
+ select: this._change,
248
+ unselect: this._change
249
+ });
250
+
251
+ if (this.empty()) { this.build(); }
252
+
253
+ // applying the rest of the options
254
+ options = this.options;
255
+
256
+ // single-select options additional features
257
+ if (!options.multiple || this.hasClass('rui-selectable-single')) {
258
+ this.isSingle = true;
259
+ this.addClass('rui-selectable-single');
260
+ this.buildSingle();
261
+
262
+ if (options.selected === null) {
263
+ this.select(this.items()[0]);
264
+ }
265
+ }
266
+
267
+ if (options.disabled) { this.disable(options.disabled); }
268
+ if (options.selected) { this.select(options.selected); }
269
+ if (options.update) { this.assignTo(options.update); }
270
+
271
+ // replacing the selectboxes with the selectables
272
+ if (selectbox) {
273
+ this.assignTo(selectbox).insertTo(selectbox, 'before');
274
+
275
+ // hidding it in the hidden layer so it was sent with the form
276
+ selectbox.wrap($E('div', {
277
+ style: 'position:absolute;z-index:-1;visibility:hidden;width:0;height:0;overflow:hidden'
278
+ }));
279
+ }
280
+ },
281
+
282
+ /**
283
+ * Sets the value
284
+ *
285
+ * @param Array of selectee keys
286
+ * @return Selectable this
287
+ */
288
+ setValue: function(value) {
289
+ // parsing the value
290
+ if (isString(value)) {
291
+ value = value.split(',').map('trim')
292
+ .filter(function(s) { return !s.blank(); });
293
+ }
294
+
295
+ // resetting the selections
296
+ this.items().each('removeClass', 'rui-selectable-selected');
297
+
298
+ return this.select(value);
299
+ },
300
+
301
+ /**
302
+ * Returns the list of selected items
303
+ *
304
+ * @return Array of selectees
305
+ */
306
+ getValue: function() {
307
+ if (this.isSingle) {
308
+ var item = this.items().first('hasClass', 'rui-selectable-selected');
309
+ return item ? this.itemValue(item) : null;
310
+ } else {
311
+ return this.items().filter('hasClass', 'rui-selectable-selected').map(function(item) {
312
+ return this.itemValue(item);
313
+ }, this);
314
+ }
315
+ },
316
+
317
+ /**
318
+ * disables the given key or keys
319
+ * NOTE: if no keys specified, then all the items will be disabled
320
+ *
321
+ * @param mixed optional key or keys to disable
322
+ * @return Selectable this
323
+ */
324
+ disable: function(keys) {
325
+ this.mapOrAll(keys).each(function(item) {
326
+ this.fire('disable', item.addClass('rui-selectable-disabled'));
327
+ }, this);
328
+ return this;
329
+ },
330
+
331
+ /**
332
+ * disables the given key or keys
333
+ * NOTE: if no keys specified, then all the items will be enabled
334
+ *
335
+ * @param mixed optional key or keys to enable
336
+ * @return Selectable this
337
+ */
338
+ enable: function(keys) {
339
+ this.mapOrAll(keys).each(function(item) {
340
+ this.fire('enable', item.removeClass('rui-selectable-disabled'));
341
+ }, this);
342
+ return this;
343
+ },
344
+
345
+ /**
346
+ * Checks if the given key or keys are disabled
347
+ * NOTE: if no keys specified, then will check if all the items are disabled
348
+ *
349
+ * @param mixed optional key or keys to enable
350
+ * @return Selectable this
351
+ */
352
+ disabled: function(keys) {
353
+ return this.mapOrAll(keys).every('hasClass', 'rui-selectable-disabled');
354
+ },
355
+
356
+ /**
357
+ * selects item(s) that refers to the given key or keys
358
+ *
359
+ * @param mixed key or keys
360
+ * @return Selectable this
361
+ */
362
+ select: function(keys) {
363
+ var items = this.mapEnabled(keys), selected_class = 'rui-selectable-selected';
364
+
365
+ if (this.isSingle && items) {
366
+ this.items().each('removeClass', selected_class);
367
+ items = R([items[0]]);
368
+ }
369
+
370
+ // applying the selection limit if ncessary
371
+ if (!this.isSingle && this.options.limit) {
372
+ var selected = this.items().filter('hasClass', selected_class), clean = [];
373
+ while (items.length && (selected.length + clean.length) < this.options.limit) {
374
+ var item = items.shift();
375
+ if (!selected.include(item)) {
376
+ clean.push(item);
377
+ }
378
+ }
379
+ items = clean;
380
+ }
381
+
382
+ items.each(function(item) {
383
+ this.fire('select', item.addClass(selected_class));
384
+ }, this);
385
+
386
+ return this;
387
+ },
388
+
389
+ /**
390
+ * Unselects item(s) that refers to the given key or keys
391
+ *
392
+ * @param mixed key or keys
393
+ * @return Selectable this
394
+ */
395
+ unselect: function(keys) {
396
+ var prev_value = this.getValue();
397
+
398
+ this.mapEnabled(keys).each(function(item) {
399
+ this.fire('unselect', item.removeClass('rui-selectable-selected'));
400
+ }, this);
401
+
402
+ return this;
403
+ },
404
+
405
+ /**
406
+ * Checks if item(s) are selected
407
+ *
408
+ * @param mixed key or keys
409
+ * @return Boolean check result
410
+ */
411
+ selected: function(keys) {
412
+ return this.mapEnabled(keys).every('hasClass', 'rui-selectable-selected');
413
+ },
414
+
415
+ /**
416
+ * Overloading the method so it worked nicely with the single versions
417
+ *
418
+ * @param Element target
419
+ * @param String optional position
420
+ * @return Selectable this
421
+ */
422
+ insertTo: function(target, where) {
423
+ Element.prototype.insertTo.call(
424
+ (this.isSingle ? this.container : this), target, where
425
+ );
426
+
427
+ return this;
428
+ },
429
+
430
+ // protected
431
+
432
+ // wrapping the events trigger to feed it with some more options
433
+ fire: function(name, item) {
434
+ if (item && item instanceof Element) {
435
+ this.$super(name, {item: item, index: this.items().indexOf(item)});
436
+ } else {
437
+ this.$super.apply(this, arguments);
438
+ }
439
+ return this;
440
+ },
441
+
442
+ // finds out the value for the item
443
+ itemValue: function(item) {
444
+ var value = item.get('id') || item.get('val');
445
+ return value ? this.options.parseIds ? value.match(/\d+/) : value : this.items().indexOf(item);
446
+ },
447
+
448
+ // returns the list of items
449
+ items: function() {
450
+ return this.find('li');
451
+ },
452
+
453
+ // returns matching items or all of them if there's no key
454
+ mapOrAll: function(keys) {
455
+ var items = this.items();
456
+
457
+ if (defined(keys)) {
458
+ if (!isArray(keys)) { keys = [keys]; }
459
+
460
+ items = R(keys).map(function(key) {
461
+ var index = (isString(key) && /^\d+$/.test(key)) ? parseInt(key,10) : key, item = key;
462
+
463
+ if (isNumber(index)) {
464
+ item = items[index];
465
+ } else if(isString(key)) {
466
+ item = items.first(function(i) {
467
+ return i.id == key || i.val == key;
468
+ });
469
+ }
470
+
471
+ return item;
472
+ }, this).compact();
473
+ }
474
+
475
+ return items;
476
+ },
477
+
478
+ // maps and filters only enabled items
479
+ mapEnabled: function(keys) {
480
+ return this.mapOrAll(keys).filter(function(item) {
481
+ return !item.hasClass('rui-selectable-disabled');
482
+ }, this);
483
+ },
484
+
485
+ // onmousedown callback
486
+ _mousedown: function(event) {
487
+ event.stop();
488
+ var item = event.target, items = this.items();
489
+
490
+ if (!this.disabled(item)) {
491
+ if (this.isSingle) { // single-selects are always select
492
+ this.select(item);
493
+ } else if (this.selected(item)) {
494
+ this.unselect(item);
495
+ this._massRemove = true; // mass-removing start
496
+ } else {
497
+ this.select(item);
498
+ this._massSelect = true; // mass-selection start
499
+ }
500
+
501
+ // mass-selection with a shift/meta key
502
+ if ((event.shiftKey || event.metaKey) && this._prevItem) {
503
+ var index1 = items.indexOf(this._prevItem);
504
+ var index2 = items.indexOf(item);
505
+
506
+ if (index1 != index2) {
507
+ if (index1 > index2) {
508
+ var t = index1;
509
+ index1 = index2;
510
+ index2 = index1;
511
+ }
512
+
513
+ for (var i=index1; i < index2; i++) {
514
+ this[this._prevItem.hasClass('rui-selectable-selected') ? 'select' : 'unselect'](items[i]);
515
+ }
516
+ }
517
+ }
518
+
519
+ this._prevItem = item;
520
+ }
521
+ },
522
+
523
+ // onmouseup callback
524
+ _mouseup: function(event) {
525
+ event.stop();
526
+ this._massRemove = this._massSelect = false; // mass-selection stop
527
+ },
528
+
529
+ // mouseover callback
530
+ _mouseover: function(event) {
531
+ var item = event.target;
532
+ this.fire('hover', item);
533
+
534
+ if (!this.isSingle) {
535
+ if (this._massSelect) {
536
+ this.select(item);
537
+ } else if (this._massRemove) {
538
+ this.unselect(item);
539
+ }
540
+ }
541
+ },
542
+
543
+ // mouseout callback
544
+ _mouseout: function(event) {
545
+ this.fire('leave', event.target);
546
+ },
547
+
548
+ // mouseclick callback
549
+ _click: function(event) {
550
+ event.stop();
551
+ },
552
+
553
+ // select/unselect listener fires the onchange events
554
+ _change: function() {
555
+ if (''+this.value != ''+this.getValue()) {
556
+ this.value = this.getValue();
557
+ this.fire('change');
558
+ }
559
+ },
560
+
561
+ // builds the widget programmatically
562
+ build: function() {
563
+ var options = this.options.options, items = R([]);
564
+
565
+ if (isArray(options)) {
566
+ options.each(function(option) {
567
+ items.push(isArray(option) ? option : [option, option]);
568
+ });
569
+ } else {
570
+ for (var key in options) {
571
+ items.push([options[key], key]);
572
+ }
573
+ }
574
+
575
+ items.each(function(option) {
576
+ this.insert($E('li', {val: option[1], html: option[0]}));
577
+ }, this);
578
+
579
+ return this;
580
+ },
581
+
582
+ // builds a container for a single-select
583
+ buildSingle: function() {
584
+ this.container = $E('div', {'class': 'rui-selectable-container'})
585
+ .insert([
586
+ this.trigger = $E('div', {'html': this.options.hCont, 'class': 'rui-selectable-handle'}),
587
+ this.display = $E('ul', {'class': 'rui-selectable-display'})
588
+ ])
589
+ .onClick(R(this.toggleList).bind(this));
590
+
591
+ if (this.parent()) {
592
+ this.container.insertTo(this, 'instead');
593
+ }
594
+
595
+ this.container.insert(this);
596
+
597
+ $(document).onClick(R(this.hideList).bind(this));
598
+
599
+ return this
600
+ .onSelect('showItem')
601
+ .onSelect('hideList')
602
+ .addClass('rui-dd-menu');
603
+ },
604
+
605
+ // toggles the single-selects list
606
+ toggleList: function(event) {
607
+ event.stop();
608
+ return this.visible() ? this.hideList() : this.showList(event);
609
+ },
610
+
611
+ // shows list for the single-selects
612
+ showList: function(event) {
613
+ event.stop();
614
+
615
+ $$('.rui-selectable-single').without(this).each('hide');
616
+
617
+ var dims = this.container.dimensions(), pos = this.container.position();
618
+
619
+ this.setStyle({
620
+ top: (dims.top + dims.height - pos.y - 1) + 'px',
621
+ left: (dims.left - pos.x) + 'px',
622
+ width: dims.width + 'px'
623
+ }).show(this.options.fxName, {
624
+ duration: this.options.fxDuration,
625
+ onFinish: this.fire.bind(this, 'show', this)
626
+ });
627
+
628
+ if (!this.options.fxName) {
629
+ this.fire('show', this);
630
+ }
631
+ },
632
+
633
+ // hides the list for the single-selects
634
+ hideList: function() {
635
+ if (this.isSingle && this.visible()) {
636
+ this.hide(this.options.fxName, {
637
+ duration: this.options.fxDuration,
638
+ onFinish: this.fire.bind(this, 'hide')
639
+ });
640
+
641
+ if (!this.options.fxName) {
642
+ this.fire('hide');
643
+ }
644
+ }
645
+ },
646
+
647
+ // shows the item in the main view of a single-selector
648
+ showItem: function() {
649
+ var item = this.items().first('hasClass', 'rui-selectable-selected') || this.items().first();
650
+ this.display.html('<li>'+(item ? item.html() : '&nbsp;')+'</li>');
651
+ },
652
+
653
+ // harvests options from a selectbox element
654
+ harvestOptions: function(selectbox) {
655
+ var options = {};
656
+
657
+ options.multiple = selectbox.has('multiple');
658
+ options.options = R([]);
659
+ options.selected = R([]);
660
+ options.disabled = R([]);
661
+
662
+ $A(selectbox._.getElementsByTagName('OPTION')).each(function(option, index) {
663
+ options.options.push([option.innerHTML, $(option).get('value') || option.innerHTML]);
664
+
665
+ if (option.selected) { options.selected.push(index); }
666
+ if (option.disabled) { options.disabled.push(index); }
667
+ });
668
+
669
+ if (options.selected.empty()) { options.selected = 0; }
670
+
671
+ return options;
672
+ }
673
+ });
674
+
675
+ /**
676
+ * The document on-load for Selectable
677
+ *
678
+ * Copyright (C) 2009-2010 Nikolay Nemshilov
679
+ */
680
+ $(document).onReady(function() {
681
+ Selectable.rescan();
682
+ });
683
+
684
+ document.write("<style type=\"text/css\"> *.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} *.rui-selectable, *.rui-selectable li, *.rui-selectable dt, *.rui-selectable dd, *.rui-selectable ul,div.rui-selectable-container ul.rui-selectable-display,div.rui-selectable-container ul.rui-selectable-display li{margin:0;padding:0;border:none;background:none;list-style:none} *.rui-selectable{border:1px solid #CCC;border-bottom:none;display:inline-block; *display:inline; *zoom:1;min-width:10em;-moz-border-radius:.2em;-webkit-border-radius:.2em;user-select:none;-moz-user-select:none;-webkit-user-select:none} *.rui-selectable li{padding:.3em 1em;cursor:pointer;border-bottom:1px solid #CCC} *.rui-selectable li:hover{background:#EEE} *.rui-selectable li.rui-selectable-selected{font-weight:bold;background:#DDD} *.rui-selectable li.rui-selectable-disabled, *.rui-selectable li.rui-selectable-disabled:hover{background:#CCC;color:#777;cursor:default}dl.rui-selectable dt{padding:.3em .5em;cursor:default;font-weight:bold;font-style:italic;color:#444;background:#EEE;border-bottom:1px solid #CCC}dl.rui-selectable dd li{padding-left:1.5em} *.rui-selectable-single{background:#FFF;display:none}div.rui-selectable-container{border:1px solid #CCC;-moz-border-radius:.2em;-webkit-border-radius:.2em;display:inline-block; *display:inline; *zoom:1; *width:10em;vertical-align:middle;min-width:10em;cursor:pointer;height:1.6em;position:relative}div.rui-selectable-container div.rui-selectable-handle{font-family:Arial;float:right;width:0.8em;background:#DDD;text-align:center;height:100%;line-height:0.8em;font-size:200%;color:#888;border-left:1px solid #CCC}div.rui-selectable-container:hover div.rui-selectable-handle{color:#666}div.rui-selectable-container ul.rui-selectable-display{display:block;width:auto;margin-right:2em;overflow:hidden}div.rui-selectable-container ul.rui-selectable-display li{line-height:1.6em;padding:0 .5em}select.rui-selectable{visibility:hidden}</style>");
685
+
686
+ return Selectable;
687
+ })(document, RightJS);