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
@@ -1,937 +0,0 @@
1
- /**
2
- * Unified tabs engine for RightJS (http://rightjs.org/ui/tabs)
3
- *
4
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
5
- */
6
- if (!RightJS) throw "Gimme RightJS";/**
7
- * The basic tabs handling engine
8
- *
9
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
10
- */
11
- var Tabs = new Class(Observer, {
12
- extend: {
13
- EVENTS: $w('show hide click load disable enable add remove move'),
14
-
15
- Options: {
16
- idPrefix: '', // the tab-body elements id prefix
17
- tabsElement: null, // the tabs list element reference, in case it situated somewhere else
18
-
19
- resizeFx: 'both', // 'slide', 'fade', 'both' or null for no fx
20
- resizeDuration: 400, // the tab panels resize fx duration
21
-
22
- scrollTabs: false, // use the tabs list scrolling
23
- scrollDuration: 400, // the tabs scrolling fx duration
24
-
25
- selected: null, // the index of the currently opened tab, by default will check url, cookies or set 0
26
- disabled: [], // list of disabled tab indexes
27
-
28
- closable: false, // set true if you want a close icon on your tabs
29
-
30
- loop: false, // put a delay in ms to make it autostart the slideshow loop
31
- loopPause: true, // make the loop get paused when user hovers the tabs with mouse
32
-
33
- url: false, // a common remote tabs url template, should have the %{id} placeholder
34
- cache: false, // marker if the remote tabs should be cached
35
-
36
- Xhr: null, // the xhr addtional options
37
- Cookie: null // set the cookie options if you'd like to keep the last selected tab index in cookies
38
- },
39
-
40
- // scans and automatically intializes the tabs
41
- rescan: function(scope) {
42
- ($(scope) || document).select('*.right-tabs').each(function(element) {
43
- if (!element._tabs) {
44
- new Tabs(element);
45
- }
46
- });
47
- }
48
- },
49
-
50
- /**
51
- * The basic constructor
52
- *
53
- * @param element or id
54
- * @param Object options
55
- */
56
- initialize: function(element, options) {
57
- this.element = $(element);
58
- this.$super(options || eval('('+this.element.get('data-tabs-options')+')'));
59
-
60
- this.element._tabs = this.init();
61
- },
62
-
63
- /**
64
- * destructor
65
- *
66
- * @return Tabs this
67
- */
68
- destroy: function() {
69
- delete(this.element._tabs);
70
- },
71
-
72
- /**
73
- * Shows the given tab
74
- *
75
- * @param integer tab index or a Tabs.Tab instance
76
- * @return Tabs this
77
- */
78
- show: function(tab) {
79
- return this.callTab(tab, 'show');
80
- },
81
-
82
- /**
83
- * Disables the given tab
84
- *
85
- * @param integer tab index or a Tabs.Tab instance or a list of them
86
- * @return Tabs this
87
- */
88
- disable: function(tab) {
89
- return this.callTab(tab, 'disable');
90
- },
91
-
92
- /**
93
- * Enables the given tab
94
- *
95
- * @param integer tab index or a Tabs.Tab instance or a list of them
96
- * @return Tabs this
97
- */
98
- enable: function(tab) {
99
- return this.callTab(tab, 'enable');
100
- },
101
-
102
- // protected
103
-
104
- // calls the tab (or tabs) method
105
- callTab: function(tab, method) {
106
- if (isArray(tab)) tab.each(this[method], this);
107
- else if (tab = isNumber(tab) ? this.tabs[tab] : tab) tab[method]();
108
- return this;
109
- },
110
-
111
- // initializes the tabs unit
112
- init: function() {
113
- this.isHarmonica = this.element.tagName == 'DL';
114
- this.isCarousel = this.element.hasClass('right-tabs-carousel');
115
- this.isSimple = !this.isHarmonica && !this.isCarousel;
116
-
117
- this.findTabs();
118
-
119
- this.element.addClass('right-tabs');
120
- if (this.isSimple)
121
- this.element.addClass('right-tabs-simple');
122
-
123
- return this.disable(this.options.disabled);
124
- },
125
-
126
- // finds and interconnects the tabs
127
- findTabs: function() {
128
- this.tabsList = this.isHarmonica ? this.element :
129
- $(this.options.tabsElement) || this.element.first('.right-tabs-list') ||
130
- this.element.first('UL').addClass('right-tabs-list');
131
-
132
- this.tabs = this.tabsList.subNodes(this.isHarmonica ? 'dt' : null).map(function(node) {
133
- return new Tabs.Tab(node, this);
134
- }, this);
135
- },
136
-
137
- // searches/builds a panel for the tab
138
- findPanel: function(tab) {
139
- var panel_id = this.options.idPrefix + tab.id, panel;
140
-
141
- if (this.isHarmonica) {
142
- var next = tab.element.next();
143
- panel = (next && next.tagName == 'DD') ? next : $E('DD').insertTo(tab.element, 'after');
144
- } else {
145
- panel = $(panel_id) || $E(this.element.tagName == 'UL' ? 'LI' : 'DIV').insertTo(this.element);
146
- }
147
-
148
- return panel.set('id', panel_id);
149
- }
150
- });
151
-
152
- /**
153
- * A single tab handling object
154
- *
155
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
156
- */
157
- Tabs.Tab = new Class({
158
- extend: {
159
- autoId: 0
160
- },
161
-
162
- initialize: function(element, controller) {
163
- this.element = element.addClass('right-tabs-tab');
164
- this.controller = controller;
165
-
166
- this.element.onMousedown(this.click.bind(this)).onClick('stopEvent');
167
-
168
- this.findLink();
169
-
170
- this.panel = new Tabs.Panel(controller.findPanel(this), this);
171
-
172
- // adding the 'close' icon onto the tab
173
- if (controller.options.closable) {
174
- this.link.insert($E('div', {
175
- 'class': 'right-tabs-tab-close-icon', 'html': '×'
176
- }).onMousedown(this.remove.bind(this)).onClick('stopEvent'));
177
- }
178
- },
179
-
180
- click: function(event) {
181
- event.stop();
182
- return this.fire('click').show();
183
- },
184
-
185
- show: function() {
186
- if (this.enabled()) {
187
- var prev_tab = this.controller.tabs.first('current');
188
- if (prev_tab) prev_tab.fire('hide');
189
-
190
- this.element.radioClass('right-tabs-current');
191
- this.controller.scrollToTab(this);
192
- this.panel.show();
193
-
194
- this.fire('show');
195
- }
196
-
197
- return this;
198
- },
199
-
200
- disable: function() {
201
- this.element.addClass('right-tabs-disabled');
202
- return this.fire('disable');
203
- },
204
-
205
- enable: function() {
206
- this.element.removeClass('right-tabs-disabled');
207
- return this.fire('enable');
208
- },
209
-
210
- disabled: function() {
211
- return !this.enabled();
212
- },
213
-
214
- enabled: function() {
215
- return !this.element.hasClass('right-tabs-disabled');
216
- },
217
-
218
- current: function() {
219
- return this.element.hasClass('right-tabs-current');
220
- },
221
-
222
- remove: function(event) {
223
- if (event) event.stop();
224
-
225
- // switching to the next available sibling
226
- if (this.current()) {
227
- var enabled = this.controller.tabs.filter('enabled');
228
- var sibling = enabled[enabled.indexOf(this) + 1] || enabled[enabled.indexOf(this)-1];
229
-
230
- if (sibling) {
231
- sibling.show();
232
- }
233
- }
234
-
235
- // removing the tab out of the list
236
- this.controller.tabs.splice(this.controller.tabs.indexOf(this), 1);
237
- this.element.remove();
238
- this.panel.remove();
239
-
240
- return this;
241
- },
242
-
243
- // protected
244
- // returns the tab width, used for the scrolling calculations
245
- width: function() {
246
- return this.element.offsetWidth + this.element.getStyle('marginRight').toInt();
247
- },
248
-
249
- // the events firing wrapper
250
- fire: function(event) {
251
- this.controller.fire(event, this);
252
- return this;
253
- },
254
-
255
- // generates the automaticall id for the tab
256
- findLink: function() {
257
- this.link = this.element.first('a');
258
- this.id = this.link.href.split('#')[1] || (this.controller.options.idPrefix + (Tabs.Tab.autoId++));
259
- }
260
- });
261
-
262
- /**
263
- * The tab panels behavior logic
264
- *
265
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
266
- */
267
- Tabs.Panel = new Class(Observer, {
268
-
269
- initialize: function(element, tab) {
270
- this.tab = tab;
271
- this.id = element.id;
272
- this.element = element.addClass('right-tabs-panel');
273
- },
274
-
275
- // shows the panel
276
- show: function() {
277
- return this.resizing(function() {
278
- this.tab.controller.tabs.each(function(tab) {
279
- var element = tab.panel.element;
280
- element[element == this.element ?
281
- 'addClass' : 'removeClass']('right-tabs-panel-current');
282
- }, this);
283
- });
284
- },
285
-
286
- // updates the panel content
287
- update: function(content) {
288
- // don't use resize if it's some other hidden tab was loaded asynch
289
- if (this.tab.current()) {
290
- this.resizing(function() {
291
- this.element.update(content||'');
292
- });
293
- } else {
294
- this.element.update(content||'');
295
- }
296
-
297
- return this;
298
- },
299
-
300
- // removes the pannel
301
- remove: function() {
302
- this.element.remove();
303
- return this;
304
- },
305
-
306
- // locks the panel with a spinner locker
307
- lock: function() {
308
- this.element.insert(this.locker(), 'top');
309
- },
310
-
311
- // protected
312
-
313
- resizing: function(callback) {
314
- var controller = this.tab.controller;
315
-
316
- if (controller.__working) return this.resizing.bind(this, callback).delay(100);
317
-
318
- var options = controller.options;
319
- var prev_panel = controller.element.first('.right-tabs-panel-current');
320
- var this_panel = this.element;
321
- var swapping = prev_panel != this_panel;
322
- var loading = this.element.first('div.right-tabs-panel-locker');
323
-
324
- // sometimes it looses the parent on remote tabs
325
- if (this_panel.parentNode.hasClass('right-tabs-resizer')) this_panel.insertTo(prev_panel.parentNode);
326
-
327
- if (options.resizeFx && self.Fx && prev_panel && (swapping || loading)) {
328
- controller.__working = true;
329
- var unlock = function() { controller.__working = false; };
330
-
331
- // calculating the visual effects durations
332
- var fx_name = (options.resizeFx == 'both' && loading) ? 'slide' : options.resizeFx;
333
- var duration = options.resizeDuration; duration = Fx.Durations[duration] || duration;
334
- var resize_duration = fx_name == 'fade' ? 0 : fx_name == 'slide' ? duration : duration / 2;
335
- var fade_duration = duration - resize_duration;
336
-
337
- if (fx_name != 'slide')
338
- this_panel.setStyle({opacity: 0});
339
-
340
- // saving the previous sizes
341
- var prev_panel_height = (controller.isHarmonica && swapping) ? 0 : prev_panel.offsetHeight;
342
-
343
- // applying the changes
344
- callback.call(this);
345
-
346
- // getting the new size
347
- var new_panel_height = this_panel.offsetHeight;
348
- var fx_wrapper = null;
349
-
350
- if (fx_name != 'fade' && prev_panel_height != new_panel_height) {
351
- // preserving the whole element size so it didn't jump when we are tossing the tabs around
352
- controller.element.style.height = controller.element.offsetHeight + 'px';
353
-
354
- // wrapping the element with an overflowed element to visualize the resize
355
- fx_wrapper = $E('div', {
356
- 'class': 'right-tabs-resizer',
357
- 'style': 'height: '+ prev_panel_height + 'px'
358
- });
359
-
360
- // in case of harmonica nicely hidding the previous panel
361
- if (controller.isHarmonica && swapping) {
362
- prev_panel.addClass('right-tabs-panel-current');
363
- var hide_wrapper = $E('div', {'class': 'right-tabs-resizer'});
364
- hide_wrapper.style.height = prev_panel.offsetHeight + 'px';
365
- var prev_back = function() {
366
- hide_wrapper.replace(prev_panel.removeClass('right-tabs-panel-current'));
367
- };
368
- prev_panel.wrap(hide_wrapper);
369
-
370
- fx_wrapper.style.height = '0px';
371
- }
372
-
373
- this_panel.wrap(fx_wrapper);
374
-
375
- // getting back the auto-size so we could resize it
376
- controller.element.style.height = 'auto';
377
-
378
- } else {
379
- // removing the resize duration out of the equasion
380
- rezise_duration = 0;
381
- duration = fade_duration;
382
- }
383
-
384
- var counter = 0;
385
- var set_back = function() {
386
- if (fx_wrapper) {
387
- if (fx_name == 'both' && !counter)
388
- return counter ++;
389
-
390
- fx_wrapper.replace(this_panel);
391
- }
392
-
393
- unlock();
394
- };
395
-
396
- if (hide_wrapper)
397
- hide_wrapper.morph({height: '0px'},
398
- {duration: resize_duration, onFinish: prev_back});
399
-
400
- if (fx_wrapper)
401
- fx_wrapper.morph({height: new_panel_height + 'px'},
402
- {duration: resize_duration, onFinish: set_back});
403
-
404
- if (fx_name != 'slide')
405
- this_panel.morph.bind(this_panel, {opacity: 1},
406
- {duration: fade_duration, onFinish: set_back}
407
- ).delay(resize_duration);
408
-
409
- if (!fx_wrapper && fx_name == 'slide')
410
- set_back();
411
-
412
- } else {
413
- callback.call(this);
414
- }
415
-
416
- return this;
417
- },
418
-
419
- // builds the locker element
420
- locker: function() {
421
- if (!this._locker) {
422
- var locker = $E('div', {'class': 'right-tabs-panel-locker'});
423
- var spinner = $E('div', {'class': 'right-tabs-panel-locker-spinner'}).insertTo(locker);
424
- var dots = '1234'.split('').map(function(i) {
425
- return $E('div', {'class': i == 1 ? 'glow':null}).insertTo(spinner);
426
- });
427
-
428
- (function() {
429
- spinner.insert(dots.last(), 'top');
430
- dots.unshift(dots.pop());
431
- }).periodical(400);
432
-
433
- this._locker = locker;
434
- }
435
- return this._locker;
436
- }
437
-
438
- });
439
-
440
- /**
441
- * Contains the tabs scrolling functionality
442
- *
443
- * NOTE: different types of tabs have different scrolling behavior
444
- * simple tabs just scroll the tabs line without actually picking
445
- * any tab. But the carousel tabs scrolls to the next/previous
446
- * tabs on the list.
447
- *
448
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
449
- */
450
- Tabs.include((function() {
451
- var old_init = Tabs.prototype.init;
452
-
453
- return {
454
-
455
- /**
456
- * Shows the next tab
457
- *
458
- * @return Tabs this
459
- */
460
- next: function() {
461
- return this.pickTab(+1);
462
- },
463
-
464
- /**
465
- * Shows the preveious tab
466
- *
467
- * @return Tabs this
468
- */
469
- prev: function() {
470
- return this.pickTab(-1);
471
- },
472
-
473
- /**
474
- * Scrolls the tabs to the left
475
- *
476
- * @return Tabs this
477
- */
478
- scrollLeft: function() {
479
- return this[this.isCarousel ? 'prev' : 'justScroll'](+0.6);
480
- },
481
-
482
- /**
483
- * Scrolls the tabs to the right
484
- *
485
- * @return Tabs this
486
- */
487
- scrollRight: function() {
488
- return this[this.isCarousel ? 'next' : 'justScroll'](-0.6);
489
- },
490
-
491
- // protected
492
-
493
- // overloading the init script to add the scrollbar support
494
- init: function() {
495
- old_init.call(this);
496
-
497
- if (this.scrollable = (this.options.scrollTabs || this.isCarousel)) {
498
- this.buildScroller();
499
- }
500
-
501
- return this;
502
- },
503
-
504
- // builds the tabs scroller block
505
- buildScroller: function() {
506
- if (this.element.first('.right-tabs-scroller')) {
507
- this.prevButton = this.element.first('.right-tabs-scroll-left');
508
- this.nextButton = this.element.first('.right-tabs-scroll-right');
509
- } else {
510
- this.prevButton = $E('div', {'class': 'right-tabs-scroll-left', 'html': '«'});
511
- this.nextButton = $E('div', {'class': 'right-tabs-scroll-right', 'html': '»'});
512
-
513
- this.element.insert($E('div', {'class': 'right-tabs-scroller'}).insert([
514
- this.prevButton, this.nextButton, $E('div', {'class': 'right-tabs-scroll-body'}).insert(this.tabsList)
515
- ]), 'top');
516
- }
517
-
518
- this.prevButton.onClick(this.scrollLeft.bind(this));
519
- this.nextButton.onClick(this.scrollRight.bind(this));
520
- },
521
-
522
- // picks the next/prev non-disabled available tab
523
- pickTab: function(pos) {
524
- var current = this.tabs.first('current');
525
- if (current && current.enabled()) {
526
- var enabled_tabs = this.tabs.filter('enabled');
527
- var tab = enabled_tabs[enabled_tabs.indexOf(current) + pos];
528
- if (tab) tab.show();
529
- }
530
- },
531
-
532
- // scrolls the tabs line to make the tab visible
533
- scrollToTab: function(tab) {
534
- if (this.scrollable) {
535
- // calculating the previous tabs widths
536
- var tabs_width = 0;
537
- for (var i=0; i < this.tabs.length; i++) {
538
- tabs_width += this.tabs[i].width();
539
- if (this.tabs[i] == tab) break;
540
- }
541
-
542
- // calculating the scroll (the carousel tabs should be centralized)
543
- var available_width = this.tabsList.parentNode.offsetWidth;
544
- var scroll = (this.isCarousel ? (available_width/2 + tab.width()/2) : available_width) - tabs_width;
545
-
546
- // check if the tab doesn't need to be scrolled
547
- if (!this.isCarousel) {
548
- var current_scroll = this.tabsList.getStyle('left').toInt() || 0;
549
-
550
- if (scroll >= current_scroll && scroll < (current_scroll + available_width - tab.width()))
551
- scroll = current_scroll;
552
- else if (current_scroll > -tabs_width && current_scroll <= (tab.width() - tabs_width))
553
- scroll = tab.width() - tabs_width;
554
- }
555
-
556
- this.scrollTo(scroll);
557
- }
558
- },
559
-
560
- // just scrolls the scrollable area onto the given number of scrollable area widths
561
- justScroll: function(size) {
562
- var current_scroll = this.tabsList.getStyle('left').toInt() || 0;
563
- var available_width = this.tabsList.parentNode.offsetWidth;
564
-
565
- this.scrollTo(current_scroll + available_width * size);
566
- },
567
-
568
- // scrolls the tabs list to the position
569
- scrollTo: function(scroll) {
570
- // checking the constraints
571
- var current_scroll = this.tabsList.getStyle('left').toInt() || 0;
572
- var available_width = this.tabsList.parentNode.offsetWidth;
573
- var overall_width = 0;
574
- for (var i=0; i < this.tabs.length; i++) {
575
- overall_width += this.tabs[i].width();
576
- }
577
-
578
- if (scroll < (available_width - overall_width))
579
- scroll = available_width - overall_width;
580
- if (scroll > 0) scroll = 0;
581
-
582
- // applying the scroll
583
- var style = {left: scroll + 'px'};
584
-
585
- if (this.options.scrollDuration && self.Fx && current_scroll != scroll) {
586
- this.tabsList.morph(style, {duration: this.options.scrollDuration});
587
- } else {
588
- this.tabsList.setStyle(style);
589
- }
590
-
591
- this.checkScrollButtons(overall_width, available_width, scroll);
592
- },
593
-
594
- // checks the scroll buttons
595
- checkScrollButtons: function(overall_width, available_width, scroll) {
596
- var has_prev = has_next = false;
597
-
598
- if (this.isCarousel) {
599
- var enabled = this.tabs.filter('enabled');
600
- var current = enabled.first('current');
601
-
602
- if (current) {
603
- var index = enabled.indexOf(current);
604
-
605
- has_prev = index > 0;
606
- has_next = index < enabled.length - 1;
607
- }
608
- } else {
609
- has_prev = scroll != 0;
610
- has_next = scroll > (available_width - overall_width);
611
- }
612
-
613
- this.prevButton[has_prev ? 'removeClass' : 'addClass']('right-tabs-scroll-disabled');
614
- this.nextButton[has_next ? 'removeClass' : 'addClass']('right-tabs-scroll-disabled');
615
- }
616
-
617
- }})());
618
-
619
- /**
620
- * This module handles the current tab state saving/restoring processes
621
- *
622
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
623
- */
624
- Tabs.include((function() {
625
- var old_initialize = Tabs.prototype.initialize;
626
-
627
- var get_cookie_indexes = function() {
628
- return self.Cookie ? (Cookie.get('right-tabs-indexes') || '').split(',') : [];
629
- };
630
-
631
- var save_tab_in_cookies = function(options, tabs, tab) {
632
- if (self.Cookie) {
633
- var indexes = get_cookie_indexes();
634
- indexes = indexes.without.apply(indexes, tabs.map('id'));
635
- indexes.push(tab.id);
636
- Cookie.set('right-tabs-indexes', indexes.uniq().join(','), options);
637
- }
638
- };
639
-
640
- return {
641
-
642
- // overloading the constructor to catch up the current tab properly
643
- initialize: function() {
644
- old_initialize.apply(this, arguments);
645
-
646
- this.findCurrent();
647
-
648
- // initializing the cookies storage if set
649
- if (this.options.Cookie)
650
- this.onShow(save_tab_in_cookies.curry(this.options.Cookie, this.tabs));
651
- },
652
-
653
-
654
- // protected
655
-
656
- // searches and activates the current tab
657
- findCurrent: function() {
658
- var current;
659
- if (this.options.selected !== null)
660
- current = this.options.selected;
661
- else {
662
- var enabled = this.tabs.filter('enabled');
663
- current = enabled[this.urlIndex()] || enabled[this.cookieIndex()] || enabled.first('current') || enabled[0];
664
- }
665
- if (current) current.show();
666
- },
667
-
668
- // tries to find the current tab index in the url hash
669
- urlIndex: function() {
670
- var index = -1, id = document.location.href.split('#')[1];
671
-
672
- if (id) {
673
- for (var i=0; i < this.tabs.length; i++) {
674
- if (this.tabs[i].id == id) {
675
- index = i;
676
- break;
677
- }
678
- }
679
- }
680
-
681
- return index;
682
- },
683
-
684
- // tries to find the current tab index in the cookies storage
685
- cookieIndex: function() {
686
- var index = -1;
687
-
688
- if (this.options.Cookie) {
689
- var indexes = get_cookie_indexes();
690
- for (var i=0; i < this.tabs.length; i++) {
691
- if (indexes.include(this.tabs[i].id)) {
692
- index = i;
693
- break;
694
- }
695
- }
696
- }
697
-
698
- return index;
699
- }
700
-
701
- }})());
702
-
703
- /**
704
- * This module handles the tabs cration and removing processes
705
- *
706
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
707
- */
708
- Tabs.include({
709
- /**
710
- * Creates a new tab
711
- *
712
- * USAGE:
713
- * With the #add method you have to specify the tab title
714
- * optional content (possibly empty or null) and some options
715
- * The options might have the following keys
716
- *
717
- * * id - the tab/panel id (will use the idPrefix option for the panels)
718
- * * url - a remote tab content address
719
- * * position - an integer position of the tab in the stack
720
- *
721
- * @param String title
722
- * @param mixed content
723
- * @param Object options
724
- * @return Tabs this
725
- */
726
- add: function(title, content, options) {
727
- var options = options || {};
728
-
729
- // creating the new tab element
730
- var element = $E(this.isHarmonica ? 'dt' : 'li').insert(
731
- $E('a', {html: title, href: options.url || '#'+(options.id||'')}
732
- )).insertTo(this.tabsList);
733
-
734
- // creating the actual tab instance
735
- var tab = new Tabs.Tab(element, this);
736
- tab.panel.element.update(content||'');
737
- this.tabs.push(tab);
738
-
739
- // moving the tab in place if asked
740
- if (defined(options.position)) this.move(tab, options.position);
741
-
742
- return this.fire('add', tab);
743
- },
744
-
745
- /**
746
- * Moves the given tab to the given position
747
- *
748
- * NOTE if the position is not within the tabs range then it will do nothing
749
- *
750
- * @param mixed tab index or a tab instance
751
- * @param Integer position
752
- * @return Tabs this
753
- */
754
- move: function(tab, position) {
755
- var tab = this.tabs[tab] || tab;
756
-
757
- if (this.tabs[position] && this.tabs[position] !== tab) {
758
- // moving the tab element
759
- this.tabs[position].element.insert(tab.element, (position == this.tabs.length-1) ? 'after' : 'before');
760
- if (this.isHarmonica) tab.element.insert(tab.panel.element, 'after');
761
-
762
- // moving the tab in the registry
763
- this.tabs.splice(this.tabs.indexOf(tab), 1);
764
- this.tabs.splice(position, 0, tab);
765
-
766
- this.fire('move', tab, position);
767
- }
768
-
769
- return this;
770
- },
771
-
772
- /**
773
- * Removes the given tab
774
- *
775
- * @param integer tab index or a Tabs.Tab instance or a list of them
776
- * @return Tabs this
777
- */
778
- remove: function(tab) {
779
- return this.callTab(tab, 'remove');
780
- }
781
-
782
- });
783
-
784
- /**
785
- * This module contains the remote tabs loading logic
786
- *
787
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
788
- */
789
- Tabs.Tab.include((function() {
790
- var old_show = Tabs.Tab.prototype.show;
791
-
792
- return {
793
-
794
- // wrapping the show mehtod, to catch the remote requests
795
- show: function() {
796
- if (this.dogPiling(arguments)) return this;
797
-
798
- var result = old_show.apply(this, arguments);
799
- var url = this.link.href;
800
- var options = this.controller.options;
801
-
802
- // building the url
803
- if (url.includes('#'))
804
- url = options.url ? options.url.replace('%{id}', url.split('#')[1]) : null;
805
-
806
- // if there is an actual url and no ongoing request or a cache, starting the request
807
- if (url && !this.request && !(options.cache || this.cache)) {
808
- this.panel.lock();
809
-
810
- try { // basically that's for the development tests, so the IE browsers didn't get screwed on the test page
811
-
812
- this.request = new Xhr(url, Object.merge({method: 'get'}, options.Xhr))
813
- .onComplete(function(response) {
814
- if (this.controller.__working)
815
- return arguments.callee.bind(this, response).delay(100);
816
-
817
- this.panel.update(response.text);
818
-
819
- this.request = null; // removing the request marker so it could be rerun
820
- if (options.cache) this.cache = true;
821
-
822
- this.fire('load');
823
- }.bind(this)
824
- ).send();
825
-
826
- } catch(e) { if (!Browser.OLD) throw(e) }
827
- }
828
-
829
- return result;
830
- },
831
-
832
- // protected
833
-
834
- dogPiling: function(args) {
835
- if (this.controller.__working) {
836
- if (this.controller.__timeout)
837
- this.controller.__timeout.cancel();
838
-
839
- this.controller.__timeout = (function(args) {
840
- this.show.apply(this, args);
841
- }).bind(this, args).delay(100);
842
-
843
- return true;
844
- }
845
-
846
- return this.controller.__timeout = null;
847
- }
848
-
849
- }})());
850
-
851
- /**
852
- * This module handles the slide-show loop feature for the Tabs
853
- *
854
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
855
- */
856
- Tabs.include((function() {
857
- var old_initialize = Tabs.prototype.initialize;
858
-
859
- return {
860
- /**
861
- * Overloading the constructor to start the slideshow loop automatically
862
- *
863
- */
864
- initialize: function() {
865
- old_initialize.apply(this, arguments);
866
-
867
- if (this.options.loop) {
868
- this.startLoop();
869
- }
870
- },
871
-
872
- /**
873
- * Starts the slideshow loop
874
- *
875
- * @param Number optional delay in ms
876
- * @return Tabs this
877
- */
878
- startLoop: function(delay) {
879
- if (!delay && !this.options.loop) return this;
880
-
881
- // attaching the loop pause feature
882
- if (this.options.loopPause) {
883
- this._stopLoop = this._stopLoop || this.stopLoop.bind(this, true);
884
- this._startLoop = this._startLoop || this.startLoop.bind(this, delay);
885
-
886
- this.forgetHovers().on({
887
- mouseover: this._stopLoop,
888
- mouseout: this._startLoop
889
- });
890
- }
891
-
892
- if (this.timer) this.timer.stop();
893
-
894
- this.timer = function() {
895
- var enabled = this.tabs.filter('enabled');
896
- var current = this.tabs.first('current');
897
- var next = enabled[enabled.indexOf(current)+1];
898
-
899
- this.show(next || enabled.first());
900
-
901
- }.bind(this).periodical(this.options.loop || delay);
902
-
903
- return this;
904
- },
905
-
906
- /**
907
- * Stops the slideshow loop
908
- *
909
- * @return Tabs this
910
- */
911
- stopLoop: function(event, pause) {
912
- if (this.timer) {
913
- this.timer.stop();
914
- this.timer = null;
915
- }
916
- if (!pause && this._startLoop)
917
- this.forgetHovers();
918
- },
919
-
920
- // private
921
- forgetHovers: function() {
922
- return this.element
923
- .stopObserving('mouseover', this._stopLoop)
924
- .stopObserving('mouseout', this._startLoop);
925
- }
926
-
927
-
928
- }})());
929
-
930
- /**
931
- * The document level hooks for the tabs-egnine
932
- *
933
- * Copyright (C) 2009-2010 Nikolay V. Nemshilov
934
- */
935
- document.onReady(function() {
936
- Tabs.rescan();
937
- });document.write("<style type=\"text/css\">.right-tabs,.right-tabs-list,.right-tabs-tab,.right-tabs-panel,.right-tabs-scroll-left,.right-tabs-scroll-right,.right-tabs-scroll-body,.right-tabs-panel-locker,.right-tabs-resizer{margin:0;padding:0;background:none;border:none;list-style:none;display:block;width:auto;height:auto}.right-tabs{border-bottom:1px solid #CCC}.right-tabs-resizer{overflow:hidden}.right-tabs-tab,.right-tabs-tab a{display:block;float:left}.right-tabs-tab a{position:relative;cursor:pointer;text-decoration:none;border:1px solid #CCC;background:#DDD;color:#444;-moz-border-radius:.3em;-webkit-border-radius:.3em}.right-tabs-tab a:hover{border-color:#CCC;background:#EEE}.right-tabs-tab.right-tabs-current a{font-weight:bold;color:#000;background:#FFF}.right-tabs-tab a img{border:none;opacity:.6;filter:alpha(opacity=60)}.right-tabs-tab a:hover img,.right-tabs-tab.right-tabs-current a img{opacity:1;filter:alpha(opacity=100)}.right-tabs-disabled a,.right-tabs-disabled a:hover{background:#EEE;border-color:#DDD;color:#AAA;cursor:default}.right-tabs-disabled a img,.right-tabs-disabled a:hover img{opacity:.5;filter:alpha(opacity=50)}.right-tabs-tab-close-icon{display:inline-block;*display:inline;*zoom:1;margin-right:-0.5em;margin-left:0.5em;cursor:pointer;opacity:0.5;filter:alpha(opacity=50)}.right-tabs-tab-close-icon:hover{opacity:1;filter:alpha(opacity=100);color:#B00;text-shadow:#888 .15em .15em .2em}.right-tabs-panel{display:none;position:relative;min-height:4em;padding:.5em 0}.right-tabs-panel-current{display:block}.right-tabs-panel-locker{position:absolute;top:0px;left:0px;opacity:0.5;filter:alpha(opacity=50);background:#CCC;width:100%;height:100%;text-align:center;line-height:100%}.right-tabs-panel-locker-spinner{position:absolute;left:44%;top:44%}.right-tabs-panel-locker-spinner div{float:left;background:#777;width:.5em;height:1em;margin-right:.1em;-moz-border-radius:.1em;-webkit-border-radius:.1em}.right-tabs-panel-locker-spinner div.glow{background:#444;height:1.2em;margin-top:-0.1em}.right-tabs-scroller{padding:0 1.4em;position:relative;margin-bottom:.5em}.right-tabs-scroll-left,.right-tabs-scroll-right{width:1.1em;text-align:center;background:#EEE;color:#666;cursor:pointer;border:1px solid #CCC;-moz-border-radius:.2em;-webkit-border-radius:.2em;position:absolute;top:0px;left:0px;z-index:100}div.right-tabs-scroll-left:hover,div.right-tabs-scroll-right:hover{color:#000;background:#DDD;border-color:#AAA}.right-tabs-scroll-right{left:auto;right:0px}.right-tabs .right-tabs-scroller .right-tabs-scroll-disabled,.right-tabs .right-tabs-scroller .right-tabs-scroll-disabled:hover{cursor:default;background:#DDD;border-color:#DDD;color:#AAA}.right-tabs-scroll-body{width:100%;overflow:hidden;position:relative;z-index:50}.right-tabs-scroller .right-tabs-list{position:relative;width:999em;margin:0}.right-tabs-simple .right-tabs-list{height:2em;padding:0 1em;border-bottom:1px solid #CCC}.right-tabs-simple .right-tabs-tab{margin-top:-1px;margin-right:1px}.right-tabs-simple .right-tabs-tab a{line-height:1.8em;margin-top:.2em;padding:0 1em;border-bottom:none;-moz-border-radius-bottomleft:0;-moz-border-radius-bottomright:0;-webkit-border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0}.right-tabs-simple .right-tabs-tab.right-tabs-current a{line-height:2em;margin-top:1px}.right-tabs-simple .right-tabs-scroller{border-bottom:1px solid #CCC}.right-tabs-simple .right-tabs-scroll-left,.right-tabs-simple .right-tabs-scroll-right{line-height:1.8em;top:.2em;-moz-border-radius-bottomleft:0;-moz-border-radius-bottomright:0;-webkit-border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0}.right-tabs-simple .right-tabs-scroll-body{position:relative;top:1px}.right-tabs-simple .right-tabs-list{padding:0}.right-tabs-carousel .right-tabs-list,.right-tabs-carousel .right-tabs-tab a,.right-tabs-carousel .right-tabs-scroller .right-tabs-scroll-left,.right-tabs-carousel .right-tabs-scroller .right-tabs-scroll-right{height:6em;line-height:6em}.right-tabs-carousel .right-tabs-tab{margin-right:2px}.right-tabs-carousel .right-tabs-tab a img{border:1px solid #CCC;margin:.4em;padding:0}dl.right-tabs{overflow:none;border:none}dt.right-tabs-tab,dt.right-tabs-tab a{display:block;float:none}dt.right-tabs-tab a{padding:.2em 1em}dl.right-tabs dt.right-tabs-current a{background:#EEE;-moz-border-radius-bottomleft:0;-moz-border-radius-bottomright:0;-webkit-border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0}</style>");