puffer 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/VERSION +1 -1
  2. data/app/helpers/puffer_helper.rb +8 -0
  3. data/app/views/layouts/puffer.html.erb +5 -11
  4. data/lib/generators/puffer/install/install_generator.rb +2 -2
  5. data/lib/generators/puffer/install/templates/puffer.rb +12 -0
  6. data/lib/generators/puffer/install/templates/puffer/javascripts/{application.js → puffer.js} +0 -0
  7. data/lib/generators/puffer/install/templates/puffer/javascripts/{rails-src.js → rails.js} +0 -0
  8. data/lib/puffer.rb +14 -0
  9. data/lib/puffer/controller/mutate.rb +8 -2
  10. data/lib/puffer/extensions/mapper.rb +2 -2
  11. data/lib/puffer/inputs.rb +1 -1
  12. data/lib/puffer/path_set.rb +14 -7
  13. data/lib/puffer/resource.rb +1 -1
  14. data/puffer.gemspec +8 -44
  15. data/spec/dummy/config/initializers/puffer.rb +12 -0
  16. data/spec/dummy/public/puffer/javascripts/{application.js → puffer.js} +0 -0
  17. data/spec/dummy/public/puffer/javascripts/{rails-src.js → rails.js} +0 -0
  18. metadata +10 -46
  19. data/lib/generators/puffer/install/templates/puffer/javascripts/right-autocompleter-src.js +0 -621
  20. data/lib/generators/puffer/install/templates/puffer/javascripts/right-autocompleter.js.gz +0 -0
  21. data/lib/generators/puffer/install/templates/puffer/javascripts/right-calendar-src.js +0 -1461
  22. data/lib/generators/puffer/install/templates/puffer/javascripts/right-calendar.js.gz +0 -0
  23. data/lib/generators/puffer/install/templates/puffer/javascripts/right-in-edit-src.js +0 -369
  24. data/lib/generators/puffer/install/templates/puffer/javascripts/right-in-edit.js +0 -13
  25. data/lib/generators/puffer/install/templates/puffer/javascripts/right-in-edit.js.gz +0 -0
  26. data/lib/generators/puffer/install/templates/puffer/javascripts/right-lightbox-src.js +0 -905
  27. data/lib/generators/puffer/install/templates/puffer/javascripts/right-lightbox.js +0 -24
  28. data/lib/generators/puffer/install/templates/puffer/javascripts/right-lightbox.js.gz +0 -0
  29. data/lib/generators/puffer/install/templates/puffer/javascripts/right-sortable-src.js +0 -428
  30. data/lib/generators/puffer/install/templates/puffer/javascripts/right-sortable.js +0 -17
  31. data/lib/generators/puffer/install/templates/puffer/javascripts/right-sortable.js.gz +0 -0
  32. data/lib/generators/puffer/install/templates/puffer/javascripts/right-src.js +0 -5892
  33. data/lib/generators/puffer/install/templates/puffer/javascripts/right-tabs-src.js +0 -1145
  34. data/lib/generators/puffer/install/templates/puffer/javascripts/right-tabs.js +0 -29
  35. data/lib/generators/puffer/install/templates/puffer/javascripts/right-tabs.js.gz +0 -0
  36. data/lib/generators/puffer/install/templates/puffer/javascripts/right.js.gz +0 -0
  37. data/spec/dummy/config/puffer.rb +0 -0
  38. data/spec/dummy/public/puffer/javascripts/right-autocompleter-src.js +0 -621
  39. data/spec/dummy/public/puffer/javascripts/right-autocompleter.js.gz +0 -0
  40. data/spec/dummy/public/puffer/javascripts/right-calendar-src.js +0 -1461
  41. data/spec/dummy/public/puffer/javascripts/right-calendar.js.gz +0 -0
  42. data/spec/dummy/public/puffer/javascripts/right-in-edit-src.js +0 -369
  43. data/spec/dummy/public/puffer/javascripts/right-in-edit.js +0 -13
  44. data/spec/dummy/public/puffer/javascripts/right-in-edit.js.gz +0 -0
  45. data/spec/dummy/public/puffer/javascripts/right-lightbox-src.js +0 -905
  46. data/spec/dummy/public/puffer/javascripts/right-lightbox.js +0 -24
  47. data/spec/dummy/public/puffer/javascripts/right-lightbox.js.gz +0 -0
  48. data/spec/dummy/public/puffer/javascripts/right-sortable-src.js +0 -428
  49. data/spec/dummy/public/puffer/javascripts/right-sortable.js +0 -17
  50. data/spec/dummy/public/puffer/javascripts/right-sortable.js.gz +0 -0
  51. data/spec/dummy/public/puffer/javascripts/right-src.js +0 -5892
  52. data/spec/dummy/public/puffer/javascripts/right-tabs-src.js +0 -1145
  53. data/spec/dummy/public/puffer/javascripts/right-tabs.js +0 -29
  54. data/spec/dummy/public/puffer/javascripts/right-tabs.js.gz +0 -0
  55. data/spec/dummy/public/puffer/javascripts/right.js.gz +0 -0
@@ -1,1145 +0,0 @@
1
- /**
2
- * Tabs widget for RightJS (http://rightjs.org/ui/tabs)
3
- *
4
- * Copyright (C) 2009-2010 Nikolay Nemshilov
5
- */
6
- var Tabs = RightJS.Tabs = (function(document, parseInt, RightJS) {
7
- /**
8
- * This module defines the basic widgets constructor
9
- * it creates an abstract proxy with the common functionality
10
- * which then we reuse and override in the actual widgets
11
- *
12
- * Copyright (C) 2010-2011 Nikolay Nemshilov
13
- */
14
-
15
- /**
16
- * The tabs init-script
17
- *
18
- * Copyright (C) 2010-2011 Nikolay Nemshilov
19
- */
20
- var R = RightJS,
21
- $ = RightJS.$,
22
- $$ = RightJS.$$,
23
- $w = RightJS.$w,
24
- $E = RightJS.$E,
25
- Fx = RightJS.Fx,
26
- Object = RightJS.Object,
27
- Browser = RightJS.Browser,
28
- isArray = RightJS.isArray,
29
- isNumber = RightJS.isNumber,
30
- Class = RightJS.Class,
31
- Element = RightJS.Element,
32
- Cookie = RightJS.Cookie;
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
- /**
41
- * The widget units constructor
42
- *
43
- * @param String tag-name or Object methods
44
- * @param Object methods
45
- * @return Widget wrapper
46
- */
47
- function Widget(tag_name, methods) {
48
- if (!methods) {
49
- methods = tag_name;
50
- tag_name = 'DIV';
51
- }
52
-
53
- /**
54
- * An Abstract Widget Unit
55
- *
56
- * Copyright (C) 2010 Nikolay Nemshilov
57
- */
58
- var AbstractWidget = new RightJS.Class(RightJS.Element.Wrappers[tag_name] || RightJS.Element, {
59
- /**
60
- * The common constructor
61
- *
62
- * @param Object options
63
- * @param String optional tag name
64
- * @return void
65
- */
66
- initialize: function(key, options) {
67
- this.key = key;
68
- var args = [{'class': 'rui-' + key}];
69
-
70
- // those two have different constructors
71
- if (!(this instanceof RightJS.Input || this instanceof RightJS.Form)) {
72
- args.unshift(tag_name);
73
- }
74
- this.$super.apply(this, args);
75
-
76
- if (RightJS.isString(options)) {
77
- options = RightJS.$(options);
78
- }
79
-
80
- // if the options is another element then
81
- // try to dynamically rewrap it with our widget
82
- if (options instanceof RightJS.Element) {
83
- this._ = options._;
84
- if ('$listeners' in options) {
85
- options.$listeners = options.$listeners;
86
- }
87
- options = {};
88
- }
89
- this.setOptions(options, this);
90
-
91
- return (RightJS.Wrapper.Cache[RightJS.$uid(this._)] = this);
92
- },
93
-
94
- // protected
95
-
96
- /**
97
- * Catches the options
98
- *
99
- * @param Object user-options
100
- * @param Element element with contextual options
101
- * @return void
102
- */
103
- setOptions: function(options, element) {
104
- element = element || this;
105
- RightJS.Options.setOptions.call(this,
106
- RightJS.Object.merge(options, eval("("+(
107
- element.get('data-'+ this.key) || '{}'
108
- )+")"))
109
- );
110
- return this;
111
- }
112
- });
113
-
114
- /**
115
- * Creating the actual widget class
116
- *
117
- */
118
- var Klass = new RightJS.Class(AbstractWidget, methods);
119
-
120
- // creating the widget related shortcuts
121
- RightJS.Observer.createShortcuts(Klass.prototype, Klass.EVENTS || []);
122
-
123
- return Klass;
124
- }
125
-
126
-
127
- /**
128
- * A shared module to create textual spinners
129
- *
130
- * Copyright (C) 2010-2011 Nikolay Nemshilov
131
- */
132
- var Spinner = new RightJS.Class(RightJS.Element, {
133
- /**
134
- * Constructor
135
- *
136
- * @param Number optional spinner size (4 by default)
137
- * @return void
138
- */
139
- initialize: function(size) {
140
- this.$super('div', {'class': 'rui-spinner'});
141
- this.dots = [];
142
-
143
- for (var i=0; i < (size || 4); i++) {
144
- this.dots.push(new RightJS.Element('div'));
145
- }
146
-
147
- this.dots[0].addClass('glowing');
148
- this.insert(this.dots);
149
- RightJS(this.shift).bind(this).periodical(300);
150
- },
151
-
152
- /**
153
- * Shifts the spinner elements
154
- *
155
- * @return void
156
- */
157
- shift: function() {
158
- if (this.visible()) {
159
- var dot = this.dots.pop();
160
- this.dots.unshift(dot);
161
- this.insert(dot, 'top');
162
- }
163
- }
164
- });
165
-
166
-
167
- /**
168
- * The basic tabs handling engine
169
- *
170
- * Copyright (C) 2009-2011 Nikolay Nemshilov
171
- */
172
- var Tabs = new Widget('UL', {
173
- extend: {
174
- version: '2.2.0',
175
-
176
- EVENTS: $w('select hide load disable enable add remove move'),
177
-
178
- Options: {
179
- idPrefix: '', // the tab-body elements id prefix
180
- tabsElement: null, // the tabs list element reference, in case it's situated somewhere else
181
-
182
- resizeFx: 'both', // 'slide', 'fade', 'both' or null for no fx
183
- resizeDuration: 400, // the tab panels resize fx duration
184
-
185
- scrollTabs: false, // use the tabs list scrolling
186
- scrollDuration: 400, // the tabs scrolling fx duration
187
-
188
- selected: null, // the index of the currently opened tab, by default will check url, cookies or set 0
189
- disabled: null, // list of disabled tab indexes
190
-
191
- closable: false, // set true if you want a close icon on your tabs
192
-
193
- loop: false, // put a delay in ms to make it autostart the slideshow loop
194
- loopPause: true, // make the loop get paused when user hovers the tabs with mouse
195
-
196
- url: false, // a common remote tabs url template, should have the %{id} placeholder
197
- cache: false, // marker if the remote tabs should be cached
198
-
199
- Xhr: null, // the xhr addtional options
200
- Cookie: null // set the cookie options if you'd like to keep the last selected tab index in cookies
201
- },
202
-
203
- // scans and automatically intializes the tabs
204
- rescan: function(scope) {
205
- $(scope || document).find('.rui-tabs,*[data-tabs]').each(function(element) {
206
- element = element instanceof Tabs ? element : new Tabs(element);
207
- });
208
- }
209
- },
210
-
211
- /**
212
- * The basic constructor
213
- *
214
- * @param element or id
215
- * @param Object options
216
- */
217
- initialize: function(element, options) {
218
- this
219
- .$super('tabs', element)
220
- .setOptions(options)
221
- .addClass('rui-tabs');
222
-
223
- this.isHarmonica = this._.tagName === 'DL';
224
- this.isCarousel = this.hasClass('rui-tabs-carousel');
225
- this.isSimple = !this.isHarmonica && !this.isCarousel;
226
-
227
- this
228
- .findTabs()
229
- .initScrolls()
230
- .findCurrent()
231
- .setStyle('visibility:visible');
232
-
233
- if (this.options.disabled) {
234
- this.disable(this.options.disabled);
235
- }
236
-
237
- if (this.options.loop) {
238
- this.startLoop();
239
- }
240
- },
241
-
242
- /**
243
- * Shows the given tab
244
- *
245
- * @param integer tab index or a Tabs.Tab instance
246
- * @return Tabs this
247
- */
248
- select: function(tab) {
249
- return this.callTab(tab, 'select');
250
- },
251
-
252
- /**
253
- * Disables the given tab
254
- *
255
- * @param integer tab index or a Tabs.Tab instance or a list of them
256
- * @return Tabs this
257
- */
258
- disable: function(tab) {
259
- return this.callTab(tab, 'disable');
260
- },
261
-
262
- /**
263
- * Enables the given tab
264
- *
265
- * @param integer tab index or a Tabs.Tab instance or a list of them
266
- * @return Tabs this
267
- */
268
- enable: function(tab) {
269
- return this.callTab(tab, 'enable');
270
- },
271
-
272
- /**
273
- * Returns the reference to the currently opened tab
274
- *
275
- * @return Tab tab or undefined
276
- */
277
- current: function() {
278
- return this.tabs.first('current');
279
- },
280
-
281
- /**
282
- * Returns the list of enabled tabs
283
- *
284
- * @return Array of enabled tabs
285
- */
286
- enabled: function() {
287
- return this.tabs.filter('enabled');
288
- },
289
-
290
- // protected
291
-
292
- // calls the tab (or tabs) method
293
- callTab: function(tabs, method) {
294
- R(isArray(tabs) ? tabs : [tabs]).each(function(tab) {
295
- if (isNumber(tab)) { tab = this.tabs[tab]; }
296
- if (tab && tab instanceof Tab) {
297
- tab[method]();
298
- }
299
- }, this);
300
-
301
- return this;
302
- },
303
-
304
- // finds and interconnects the tabs
305
- findTabs: function() {
306
- this.tabsList = this.isHarmonica ? this :
307
- $(this.options.tabsElement) || this.first('.rui-tabs-list') ||
308
- (this.first('UL') || $E('UL').insertTo(this)).addClass('rui-tabs-list');
309
-
310
- this.tabs = R([]);
311
-
312
- this.tabsList.children(this.isHarmonica ? 'dt' : null).map(function(node) {
313
- this.tabs.push(new Tab(node, this));
314
- }, this);
315
-
316
- // removing the whitespaces so the didn't screw with the margins
317
- for (var i=0, list = this.tabsList.get('childNodes'); i < list.length; i++) {
318
- if (list[i].nodeType == 3) { this.tabsList._.removeChild(list[i]); }
319
- }
320
-
321
- return this;
322
- }
323
- });
324
-
325
-
326
- /**
327
- * A single tab handling object
328
- *
329
- * Copyright (C) 2009-2011 Nikolay Nemshilov
330
- */
331
- var Tab = Tabs.Tab = new Class(Element, {
332
- extend: {
333
- autoId: 0
334
- },
335
-
336
- /**
337
- * Constructor
338
- *
339
- * @param Element the tab's element
340
- * @param Tabs the main element
341
- * @return void
342
- */
343
- initialize: function(element, main) {
344
- this.$super(element._);
345
- this.addClass('rui-tabs-tab');
346
-
347
- this.main = main;
348
- this.link = this.first('a');
349
- this.id = this.link.get('href').split('#')[1] || Tab.autoId++;
350
- this.panel = new Panel(this.findPanel(), this);
351
-
352
- if (this.current()) {
353
- this.select();
354
- }
355
-
356
- // adding the 'close' icon onto the tab if needed
357
- if (main.options.closable) {
358
- this.link.insert($E('div', {
359
- 'class': 'rui-tabs-tab-close-icon', 'html': '&times;'
360
- }).onClick(R(this.remove).bind(this)));
361
- }
362
-
363
- this.onClick(this._clicked);
364
- },
365
-
366
- select: function() {
367
- if (this.enabled()) {
368
- var prev_tab = this.main.current();
369
- if (prev_tab) {
370
- prev_tab.removeClass('rui-tabs-current').fire('hide');
371
- }
372
-
373
- this.addClass('rui-tabs-current');
374
- this.main.scrollToTab(this);
375
- this.panel.show();
376
- }
377
-
378
- return this.fire('select');
379
- },
380
-
381
- disable: function() {
382
- return this.addClass('rui-tabs-disabled').fire('disable');
383
- },
384
-
385
- enable: function() {
386
- return this.removeClass('rui-tabs-disabled').fire('enable');
387
- },
388
-
389
- disabled: function() {
390
- return !this.enabled();
391
- },
392
-
393
- enabled: function() {
394
- return !this.hasClass('rui-tabs-disabled');
395
- },
396
-
397
- current: function() {
398
- return this.hasClass('rui-tabs-current');
399
- },
400
-
401
- remove: function(event) {
402
- if (event) { event.stop(); }
403
-
404
- // switching to the next available sibling
405
- if (this.current()) {
406
- var enabled = this.main.enabled();
407
- var sibling = enabled[enabled.indexOf(this) + 1] || enabled[enabled.indexOf(this)-1];
408
-
409
- if (sibling) {
410
- sibling.select();
411
- }
412
- }
413
-
414
- // removing the tab out of the list
415
- this.main.tabs.splice(this.main.tabs.indexOf(this), 1);
416
- this.panel.remove();
417
-
418
- return this.$super().fire('remove');
419
- },
420
-
421
- // protected
422
-
423
- // handles the clicks on the tabs
424
- _clicked: function(event) {
425
- event.stop();
426
- return this.select();
427
- },
428
-
429
- // searches for a panel for the tab
430
- findPanel: function() {
431
- var main = this.main, panel_id = main.options.idPrefix + this.id, panel;
432
-
433
- if (main.isHarmonica) {
434
- var next = this.next();
435
- panel = (next && next._.tagName === 'DD') ? next : $E('DD').insertTo(this, 'after');
436
- } else {
437
- panel = $(panel_id) || $E(main._.tagName === 'UL' ? 'LI' : 'DIV').insertTo(main);
438
- }
439
-
440
- return panel.set('id', panel_id);
441
- },
442
-
443
- // returns the tab width, used for the scrolling calculations
444
- width: function() {
445
- var next = this.next();
446
-
447
- if (next) {
448
- return next.position().x - this.position().x;
449
- } else {
450
- return this.size().x + 1;
451
- }
452
- }
453
-
454
- });
455
-
456
-
457
- /**
458
- * The tab panels behavior logic
459
- *
460
- * Copyright (C) 2009-2011 Nikolay Nemshilov
461
- */
462
- var Panel = Tabs.Panel = new Class(Element, {
463
-
464
- /**
465
- * Basic constructor
466
- *
467
- * @param Element panel-element
468
- * @param Tab the tab object
469
- * @return void
470
- */
471
- initialize: function(element, tab) {
472
- this.$super(element._);
473
- this.addClass('rui-tabs-panel');
474
-
475
- this.tab = tab;
476
- this.id = this.get('id');
477
- },
478
-
479
- // shows the panel
480
- show: function() {
481
- return this.resizing(function() {
482
- this.tab.main.find('.rui-tabs-panel').each(function(panel) {
483
- panel[panel === this ? 'addClass' : 'removeClass']('rui-tabs-current');
484
- }, this);
485
- });
486
- },
487
-
488
- // updates the panel content
489
- update: function(content) {
490
- // don't use resize if it's some other hidden tab was loaded asynch
491
- if (this.tab.current()) {
492
- this.resizing(function() {
493
- Element.prototype.update.call(this, content||'');
494
- });
495
- } else {
496
- this.$super(content||'');
497
- }
498
-
499
- return this;
500
- },
501
-
502
- // locks the panel with a spinner locker
503
- lock: function() {
504
- this.insert(this.locker(), 'top');
505
- },
506
-
507
- // protected
508
-
509
- resizing: function(callback) {
510
- var controller = this.tab.main;
511
-
512
- if (controller.__working) { return this.resizing.bind(this, callback).delay(100); }
513
-
514
- var options = controller.options;
515
- var prev_panel = controller.first('.rui-tabs-panel.rui-tabs-current');
516
- var this_panel = this;
517
- var swapping = prev_panel !== this_panel;
518
- var loading = this.first('div.rui-tabs-panel-locker');
519
-
520
- // sometimes it looses the parent on remote tabs
521
- if (this_panel.parent().hasClass('rui-tabs-resizer')) {
522
- this_panel.insertTo(prev_panel.parent());
523
- }
524
-
525
- if (options.resizeFx && RightJS.Fx && prev_panel && (swapping || loading)) {
526
- controller.__working = true;
527
- var unlock = function() { controller.__working = false; };
528
-
529
- // calculating the visual effects durations
530
- var fx_name = (options.resizeFx === 'both' && loading) ? 'slide' : options.resizeFx;
531
- var duration = options.resizeDuration; duration = Fx.Durations[duration] || duration;
532
- var resize_duration = fx_name === 'fade' ? 0 : fx_name === 'slide' ? duration : duration / 2;
533
- var fade_duration = duration - resize_duration;
534
-
535
- if (fx_name !== 'slide') {
536
- this_panel.setStyle({opacity: 0});
537
- }
538
-
539
- // saving the previous sizes
540
- var prev_panel_height = (controller.isHarmonica && swapping) ? 0 : prev_panel.size().y;
541
-
542
- // applying the changes
543
- callback.call(this);
544
-
545
- // getting the new size
546
- var new_panel_height = this_panel.size().y;
547
- var fx_wrapper = null;
548
- var hide_wrapper = null;
549
- var prev_back = null;
550
-
551
- if (fx_name !== 'fade' && prev_panel_height !== new_panel_height) {
552
- // preserving the whole element size so it didn't jump when we are tossing the tabs around
553
- controller._.style.height = controller.size().y + 'px';
554
-
555
- // wrapping the element with an overflowed element to visualize the resize
556
- fx_wrapper = $E('div', {
557
- 'class': 'rui-tabs-resizer',
558
- 'style': 'height: '+ prev_panel_height + 'px'
559
- });
560
-
561
- // in case of harmonica nicely hidding the previous panel
562
- if (controller.isHarmonica && swapping) {
563
- prev_panel.addClass('rui-tabs-current');
564
- hide_wrapper = $E('div', {'class': 'rui-tabs-resizer'});
565
- hide_wrapper._.style.height = prev_panel.size().y + 'px';
566
- prev_back = function() {
567
- hide_wrapper.replace(prev_panel.removeClass('rui-tabs-current'));
568
- };
569
- prev_panel.wrap(hide_wrapper);
570
-
571
- fx_wrapper._.style.height = '0px';
572
- }
573
-
574
- this_panel.wrap(fx_wrapper);
575
-
576
- // getting back the auto-size so we could resize it
577
- controller._.style.height = 'auto';
578
-
579
- } else {
580
- // removing the resize duration out of the equasion
581
- rezise_duration = 0;
582
- duration = fade_duration;
583
- }
584
-
585
- var counter = 0;
586
- var set_back = function() {
587
- if (fx_wrapper) {
588
- if (fx_name == 'both' && !counter) {
589
- return counter ++;
590
- }
591
-
592
- fx_wrapper.replace(this_panel);
593
- }
594
-
595
- unlock();
596
- };
597
-
598
- if (hide_wrapper) {
599
- hide_wrapper.morph({height: '0px'},
600
- {duration: resize_duration, onFinish: prev_back});
601
- }
602
-
603
- if (fx_wrapper) {
604
- fx_wrapper.morph({height: new_panel_height + 'px'},
605
- {duration: resize_duration, onFinish: set_back});
606
- }
607
-
608
- if (fx_name !== 'slide') {
609
- this_panel.morph.bind(this_panel, {opacity: 1},
610
- {duration: fade_duration, onFinish: set_back}
611
- ).delay(resize_duration);
612
- }
613
-
614
- if (!fx_wrapper && fx_name === 'slide') {
615
- set_back();
616
- }
617
-
618
- } else {
619
- callback.call(this);
620
- }
621
-
622
- return this;
623
- },
624
-
625
- // builds the locker element
626
- locker: function() {
627
- return this._locker || (this._locker =
628
- $E('div', {'class': 'rui-tabs-panel-locker'}).insert(new Spinner(5))
629
- );
630
- }
631
- });
632
-
633
-
634
- /**
635
- * Contains the tabs scrolling functionality
636
- *
637
- * NOTE: different types of tabs have different scrolling behavior
638
- * simple tabs just scroll the tabs line without actually picking
639
- * any tab. But the carousel tabs scrolls to the next/previous
640
- * tabs on the list.
641
- *
642
- * Copyright (C) 2009-2010 Nikolay Nemshilov
643
- */
644
- Tabs.include({
645
- /**
646
- * Shows the next tab
647
- *
648
- * @return Tabs this
649
- */
650
- next: function() {
651
- return this.pickTab(+1);
652
- },
653
-
654
- /**
655
- * Shows the preveious tab
656
- *
657
- * @return Tabs this
658
- */
659
- prev: function() {
660
- return this.pickTab(-1);
661
- },
662
-
663
- /**
664
- * Scrolls the tabs to the left
665
- *
666
- * @return Tabs this
667
- */
668
- scrollLeft: function() {
669
- if (!this.prevButton.hasClass('rui-tabs-scroller-disabled')) {
670
- this[this.isCarousel ? 'prev' : 'justScroll'](+0.6);
671
- }
672
- return this;
673
- },
674
-
675
- /**
676
- * Scrolls the tabs to the right
677
- *
678
- * @return Tabs this
679
- */
680
- scrollRight: function() {
681
- if (!this.nextButton.hasClass('rui-tabs-scroller-disabled')) {
682
- this[this.isCarousel ? 'next' : 'justScroll'](-0.6);
683
- }
684
- return this;
685
- },
686
-
687
- // protected
688
-
689
- // overloading the init script to add the scrollbar support
690
- initScrolls: function() {
691
- if ((this.scrollable = (this.options.scrollTabs || this.isCarousel))) {
692
- this.buildScroller();
693
- }
694
-
695
- return this;
696
- },
697
-
698
- // builds the tabs scroller block
699
- buildScroller: function() {
700
- if (!(
701
- (this.prevButton = this.first('.rui-tabs-scroller-prev')) &&
702
- (this.nextButton = this.first('.rui-tabs-scroller-next'))
703
- )) {
704
- this.prevButton = $E('div', {'class': 'rui-tabs-scroller-prev', 'html': '&laquo;'});
705
- this.nextButton = $E('div', {'class': 'rui-tabs-scroller-next', 'html': '&raquo;'});
706
-
707
- // using a dummy element to insert the scroller in place of the tabs list
708
- $E('div').insertTo(this.tabsList, 'before')
709
- .replace(
710
- $E('div', {'class': 'rui-tabs-scroller'}).insert([
711
- this.prevButton, this.nextButton, this.scroller = $E('div', {
712
- 'class': 'rui-tabs-scroller-body'
713
- }).insert(this.tabsList)
714
- ])
715
- ).remove();
716
- }
717
-
718
- this.prevButton.onClick(R(this.scrollLeft).bind(this));
719
- this.nextButton.onClick(R(this.scrollRight).bind(this));
720
- },
721
-
722
- // picks the next/prev non-disabled available tab
723
- pickTab: function(pos) {
724
- var current = this.current();
725
- if (current && current.enabled()) {
726
- var enabled_tabs = this.enabled();
727
- var tab = enabled_tabs[enabled_tabs.indexOf(current) + pos];
728
- if (tab) { tab.select(); }
729
- }
730
- },
731
-
732
- // scrolls the tabs line to make the tab visible
733
- scrollToTab: function(tab) {
734
- if (this.scroller) {
735
- // calculating the previous tabs widths
736
- var tabs_width = 0;
737
- for (var i=0; i < this.tabs.length; i++) {
738
- tabs_width += this.tabs[i].width();
739
- if (this.tabs[i] === tab) { break; }
740
- }
741
-
742
- // calculating the scroll (the carousel tabs should be centralized)
743
- var available_width = this.scroller.size().x;
744
- var scroll = (this.isCarousel ? (available_width/2 + tab.width()/2) : available_width) - tabs_width;
745
-
746
- // check if the tab doesn't need to be scrolled
747
- if (!this.isCarousel) {
748
- var current_scroll = parseInt(this.tabsList.getStyle('left') || 0, 10);
749
-
750
- if (scroll >= current_scroll && scroll < (current_scroll + available_width - tab.width())) {
751
- scroll = current_scroll;
752
- } else if (current_scroll > -tabs_width && current_scroll <= (tab.width() - tabs_width)) {
753
- scroll = tab.width() - tabs_width;
754
- }
755
- }
756
-
757
- this.scrollTo(scroll);
758
- }
759
- },
760
-
761
- // just scrolls the scrollable area onto the given number of scrollable area widths
762
- justScroll: function(size) {
763
- if (!this.scroller) { return this; }
764
- var current_scroll = parseInt(this.tabsList.getStyle('left') || 0, 10);
765
- var available_width = this.scroller.size().x;
766
-
767
- this.scrollTo(current_scroll + available_width * size);
768
- },
769
-
770
- // scrolls the tabs list to the position
771
- scrollTo: function(scroll) {
772
- // checking the constraints
773
- var available_width = this.scroller.size().x;
774
- var overall_width = this.tabs.map('width').sum();
775
-
776
- if (scroll < (available_width - overall_width)) {
777
- scroll = available_width - overall_width;
778
- }
779
- if (scroll > 0) { scroll = 0; }
780
-
781
- // applying the scroll
782
- this.tabsList.morph({left: scroll+'px'}, {duration: this.options.scrollDuration});
783
-
784
- this.checkScrollButtons(overall_width, available_width, scroll);
785
- },
786
-
787
- // checks the scroll buttons
788
- checkScrollButtons: function(overall_width, available_width, scroll) {
789
- var has_prev = false, has_next = false;
790
-
791
- if (this.isCarousel) {
792
- var enabled = this.enabled();
793
- var current = enabled.first('current');
794
-
795
- if (current) {
796
- var index = enabled.indexOf(current);
797
-
798
- has_prev = index > 0;
799
- has_next = index < enabled.length - 1;
800
- }
801
- } else {
802
- has_prev = scroll !== 0;
803
- has_next = scroll > (available_width - overall_width);
804
- }
805
-
806
- this.prevButton[has_prev ? 'removeClass' : 'addClass']('rui-tabs-scroller-disabled');
807
- this.nextButton[has_next ? 'removeClass' : 'addClass']('rui-tabs-scroller-disabled');
808
- }
809
-
810
- });
811
-
812
-
813
- /**
814
- * This module handles the current tab state saving/restoring processes
815
- *
816
- * Copyright (C) 2009-2010 Nikolay Nemshilov
817
- */
818
- function get_cookie_indexes() {
819
- return R(RightJS.Cookie ? (Cookie.get('right-tabs-indexes') || '').split(',') : []);
820
- }
821
-
822
- function save_tab_in_cookies(options, tabs, event) {
823
- if (RightJS.Cookie) {
824
- var indexes = get_cookie_indexes();
825
- indexes = indexes.without.apply(indexes, tabs.map('id'));
826
- indexes.push(event.target.id);
827
- Cookie.set('right-tabs-indexes', indexes.uniq().join(','), options);
828
- }
829
- }
830
-
831
- Tabs.include({
832
-
833
- // protected
834
-
835
- // searches and activates the current tab
836
- findCurrent: function() {
837
- var enabled = this.enabled(), current = (
838
- this.tabs[this.options.selected] ||
839
- this.tabs[this.urlIndex()] ||
840
- this.tabs[this.cookieIndex()] ||
841
- enabled.first('current') ||
842
- enabled[0]
843
- );
844
-
845
- if (current) {
846
- current.select();
847
- }
848
-
849
- // initializing the cookies storage if set
850
- if (this.options.Cookie) {
851
- this.onSelect(R(save_tab_in_cookies).curry(this.options.Cookie, this.tabs));
852
- }
853
-
854
- return this;
855
- },
856
-
857
- // tries to find the current tab index in the url hash
858
- urlIndex: function() {
859
- var index = -1, id = document.location.href.split('#')[1];
860
-
861
- if (id) {
862
- for (var i=0; i < this.tabs.length; i++) {
863
- if (this.tabs[i].id == id) {
864
- index = i;
865
- break;
866
- }
867
- }
868
- }
869
-
870
- return index;
871
- },
872
-
873
- // tries to find the current tab index in the cookies storage
874
- cookieIndex: function() {
875
- var index = -1;
876
-
877
- if (this.options.Cookie) {
878
- var indexes = get_cookie_indexes();
879
- for (var i=0; i < this.tabs.length; i++) {
880
- if (indexes.include(this.tabs[i].id)) {
881
- index = i;
882
- break;
883
- }
884
- }
885
- }
886
-
887
- return index;
888
- }
889
-
890
- });
891
-
892
-
893
- /**
894
- * This module handles the tabs cration and removing processes
895
- *
896
- * Copyright (C) 2009-2010 Nikolay Nemshilov
897
- */
898
- Tabs.include({
899
- /**
900
- * Creates a new tab
901
- *
902
- * USAGE:
903
- * With the #add method you have to specify the tab title
904
- * optional content (possibly empty or null) and some options
905
- * The options might have the following keys
906
- *
907
- * * id - the tab/panel id (will use the idPrefix option for the panels)
908
- * * url - a remote tab content address
909
- * * position - an integer position of the tab in the stack
910
- *
911
- * @param String title
912
- * @param mixed content
913
- * @param Object options
914
- * @return Tabs this
915
- */
916
- add: function(title, content, options) {
917
- options = options || {};
918
-
919
- // creating the new tab element
920
- var element = $E(this.isHarmonica ? 'dt' : 'li').insert(
921
- $E('a', {html: title, href: options.url || '#'+(options.id||'')}
922
- )).insertTo(this.tabsList);
923
-
924
- // creating the actual tab instance
925
- var tab = new Tab(element, this);
926
- tab.panel.update(content||'');
927
- this.tabs.push(tab);
928
- tab.fire('add');
929
-
930
- // moving the tab in place if asked
931
- if ('position' in options) {
932
- this.move(tab, options.position);
933
- }
934
-
935
- return this;
936
- },
937
-
938
- /**
939
- * Moves the given tab to the given position
940
- *
941
- * NOTE if the position is not within the tabs range then it will do nothing
942
- *
943
- * @param mixed tab index or a tab instance
944
- * @param Integer position
945
- * @return Tabs this
946
- */
947
- move: function(tab, position) {
948
- tab = this.tabs[tab] || tab;
949
-
950
- if (this.tabs[position] && this.tabs[position] !== tab) {
951
- // moving the tab element
952
- this.tabs[position].insert(tab, (position === this.tabs.length-1) ? 'after' : 'before');
953
-
954
- // inserting the panel after the tab if it's a harmonica
955
- if (this.isHarmonica) {
956
- tab.insert(tab.panel, 'after');
957
- }
958
-
959
- // moving the tab in the registry
960
- this.tabs.splice(this.tabs.indexOf(tab), 1);
961
- this.tabs.splice(position, 0, tab);
962
-
963
- tab.fire('move', {index: position});
964
- }
965
-
966
- return this;
967
- },
968
-
969
- /**
970
- * Removes the given tab
971
- *
972
- * @param integer tab index or a Tabs.Tab instance or a list of them
973
- * @return Tabs this
974
- */
975
- remove: function(tab) {
976
- return this.callTab(tab, 'remove');
977
- }
978
-
979
- });
980
-
981
-
982
- /**
983
- * This module contains the remote tabs loading logic
984
- *
985
- * Copyright (C) 2009-2010 Nikolay Nemshilov
986
- */
987
- var old_select = Tab.prototype.select;
988
-
989
- Tab.include({
990
-
991
- // wrapping the original mehtod, to catch the remote requests
992
- select: function() {
993
- if (this.dogPiling(arguments)) { return this; }
994
-
995
- var result = old_select.apply(this, arguments);
996
- var url = R(this.link.get('href'));
997
- var options = this.main.options;
998
-
999
- // building the url
1000
- if (url.includes('#')) {
1001
- url = options.url ? options.url.replace('%{id}', url.split('#')[1]) : null;
1002
- }
1003
-
1004
- // if there is an actual url and no ongoing request or a cache, starting the request
1005
- if (url && !this.request && !(options.cache || this.cache)) {
1006
- this.panel.lock();
1007
-
1008
- try { // basically that's for the development tests, so the IE browsers didn't get screwed on the test page
1009
-
1010
- this.request = new RightJS.Xhr(url, Object.merge({method: 'get'}, options.Xhr))
1011
- .onComplete(R(function(response) {
1012
- if (this.main.__working) {
1013
- return arguments.callee.bind(this, response).delay(100);
1014
- }
1015
-
1016
- this.panel.update(response.text);
1017
-
1018
- this.request = null; // removing the request marker so it could be rerun
1019
- if (options.cache) {
1020
- this.cache = true;
1021
- }
1022
-
1023
- this.fire('load');
1024
- }).bind(this)
1025
- ).send();
1026
-
1027
- } catch(e) { if (!Browser.OLD) { throw(e); } }
1028
- }
1029
-
1030
- return result;
1031
- },
1032
-
1033
- // protected
1034
-
1035
- dogPiling: function(args) {
1036
- if (this.main.__working) {
1037
- if (this.main.__timeout) {
1038
- this.main.__timeout.cancel();
1039
- }
1040
-
1041
- this.main.__timeout = R(function(args) {
1042
- this.select.apply(this, args);
1043
- }).bind(this, args).delay(100);
1044
-
1045
- return true;
1046
- }
1047
-
1048
- return (this.main.__timeout = null);
1049
- }
1050
-
1051
- });
1052
-
1053
-
1054
- /**
1055
- * This module handles the slide-show loop feature for the Tabs
1056
- *
1057
- * Copyright (C) 2009-2010 Nikolay Nemshilov
1058
- */
1059
- Tabs.include({
1060
-
1061
- /**
1062
- * Starts the slideshow loop
1063
- *
1064
- * @param Number optional delay in ms
1065
- * @return Tabs this
1066
- */
1067
- startLoop: function(delay) {
1068
- if (!delay && !this.options.loop) { return this; }
1069
-
1070
- // attaching the loop pause feature
1071
- if (this.options.loopPause) {
1072
- this._stopLoop = this._stopLoop || R(this.stopLoop).bind(this, true);
1073
- this._startLoop = this._startLoop || R(this.startLoop).bind(this, delay);
1074
-
1075
- this.forgetHovers().on({
1076
- mouseover: this._stopLoop,
1077
- mouseout: this._startLoop
1078
- });
1079
- }
1080
-
1081
- if (this.timer) { this.timer.stop(); }
1082
-
1083
- this.timer = R(function() {
1084
- var enabled = this.enabled();
1085
- var current = this.current();
1086
- var next = enabled[enabled.indexOf(current)+1];
1087
-
1088
- this.select(next || enabled.first());
1089
-
1090
- }).bind(this).periodical(this.options.loop || delay);
1091
-
1092
- return this;
1093
- },
1094
-
1095
- /**
1096
- * Stops the slideshow loop
1097
- *
1098
- * @return Tabs this
1099
- */
1100
- stopLoop: function(event, pause) {
1101
- if (this.timer) {
1102
- this.timer.stop();
1103
- this.timer = null;
1104
- }
1105
- if (!pause && this._startLoop) {
1106
- this.forgetHovers();
1107
- }
1108
- },
1109
-
1110
- // private
1111
- forgetHovers: function() {
1112
- return this
1113
- .stopObserving('mouseover', this._stopLoop)
1114
- .stopObserving('mouseout', this._startLoop);
1115
- }
1116
-
1117
-
1118
- });
1119
-
1120
-
1121
- /**
1122
- * The document level hooks for the tabs-egnine
1123
- *
1124
- * Copyright (C) 2009-2010 Nikolay Nemshilov
1125
- */
1126
- $(document).onReady(function() {
1127
- Tabs.rescan();
1128
- });
1129
- (function() {
1130
- var style = document.createElement('style'),
1131
- rules = document.createTextNode("div.rui-spinner,div.rui-spinner div{margin:0;padding:0;border:none;background:none;list-style:none;font-weight:normal;float:none;display:inline-block; *display:inline; *zoom:1;border-radius:.12em;-moz-border-radius:.12em;-webkit-border-radius:.12em}div.rui-spinner{text-align:center;white-space:nowrap;background:#EEE;border:1px solid #DDD;height:1.2em;padding:0 .2em}div.rui-spinner div{width:.4em;height:70%;background:#BBB;margin-left:1px}div.rui-spinner div:first-child{margin-left:0}div.rui-spinner div.glowing{background:#777}.rui-tabs,.rui-tabs-list,.rui-tabs-tab,.rui-tabs-panel,.rui-tabs-scroll-left,.rui-tabs-scroll-right,.rui-tabs-scroll-body,.rui-tabs-panel-locker,.rui-tabs-resizer{margin:0;padding:0;background:none;border:none;list-style:none;display:block;width:auto;height:auto}.rui-tabs{display:block;visibility:hidden;border-bottom:1px solid #CCC}.rui-tabs-resizer{overflow:hidden}.rui-tabs-list{display:block;position:relative;padding:0 .5em;border-bottom:1px solid #CCC;white-space:nowrap}.rui-tabs-list .rui-tabs-tab,.rui-tabs-tab *,.rui-tabs-tab *:hover{display:inline-block; *display:inline; *zoom:1;cursor:pointer;text-decoration:none;vertical-align:center}.rui-tabs-list .rui-tabs-tab{vertical-align:bottom;margin-right:.1em}.rui-tabs-tab a{outline:none;position:relative;border:1px solid #CCC;background:#DDD;color:#444;padding:.3em 1em;border-radius:.3em;-moz-border-radius:.3em;-webkit-border-radius:.3em;border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomleft:0;-moz-border-radius-bottomright:0;-webkit-border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0}.rui-tabs-tab a:hover{border-color:#CCC;background:#EEE}.rui-tabs-list .rui-tabs-current a,.rui-tabs-list .rui-tabs-current a:hover{font-weight:bold;color:#000;background:#FFF;border-bottom:1px solid #FFF;border-top-width:2px;padding-top:.34em;padding-bottom:.34em;top:1px}.rui-tabs-tab a img{border:none;opacity:.6;filter:alpha(opacity=60)}.rui-tabs-tab a:hover img,.rui-tabs-list .rui-tabs-current a img{opacity:1;filter:alpha(opacity=100)}.rui-tabs-disabled a,.rui-tabs-disabled a:hover{background:#EEE;border-color:#DDD;color:#AAA;cursor:default}.rui-tabs-disabled a img,.rui-tabs-disabled a:hover img{opacity:.5;filter:alpha(opacity=50)}.rui-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)}.rui-tabs-tab-close-icon:hover{opacity:1;filter:alpha(opacity=100);color:#B00;text-shadow:#888 .15em .15em .2em}.rui-tabs-panel{display:none;position:relative;min-height:4em;padding:.5em 0}.rui-tabs-current{display:block}.rui-tabs-scroller{position:relative;padding:0 1.4em}.rui-tabs-scroller-prev,.rui-tabs-scroller-next{width:1.1em;text-align:center;background:#EEE;color:#666;cursor:pointer;border:1px solid #CCC;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;position:absolute;bottom:0px;left:0px;padding:0.3em 0;user-select:none;-moz-user-select:none;-webkit-user-select:none}.rui-tabs-scroller-prev:hover,.rui-tabs-scroller-next:hover{color:#000;background:#DDD;border-color:#AAA}.rui-tabs-scroller-prev:active,.rui-tabs-scroller-next:active{background:#eee;border-color:#ccc}.rui-tabs-scroller-next{left:auto;right:0px}.rui-tabs-scroller-disabled,.rui-tabs-scroller-disabled:hover{cursor:default;background:#DDD;border-color:#DDD;color:#AAA}.rui-tabs-scroller-body{overflow:hidden;width:100%;position:relative}.rui-tabs-scroller .rui-tabs-list{padding-left:0;padding-right:0;width:9999em;z-index:10}.rui-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}.rui-tabs-panel-locker .rui-spinner{position:absolute;left:44%;top:44%;background:none;border:none;height:2em}.rui-tabs-panel-locker .rui-spinner div{background:#666;width:.65em;margin-left:.15em}.rui-tabs-panel-locker .rui-spinner div.glowing{background:#000}.rui-tabs-carousel .rui-tabs-list{border:none}.rui-tabs-carousel .rui-tabs-tab a,.rui-tabs-carousel .rui-tabs-scroller .rui-tabs-scroller-prev,.rui-tabs-carousel .rui-tabs-scroller .rui-tabs-scroller-next{height:6em;line-height:6em;padding:0;border-bottom:1px solid #ccc;border-radius:.25em;-moz-border-radius:.25em;-webkit-border-radius:.25em}.rui-tabs-carousel .rui-tabs-tab{margin-right:3px}.rui-tabs-carousel .rui-tabs-tab a img{border:1px solid #CCC;vertical-align:middle;margin:.4em;padding:0;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0}.rui-tabs-carousel .rui-tabs-list .rui-tabs-current a{border-width:1px;border-color:#AAA;padding:0;top:auto}.rui-tabs-carousel .rui-tabs-list .rui-tabs-current a img{border-color:#bbb}.rui-tabs-carousel .rui-tabs-panel{text-align:center}dl.rui-tabs{border:none}dt.rui-tabs-tab,dt.rui-tabs-tab a,dt.rui-tabs-tab a:hover{display:block;float:none}dt.rui-tabs-tab a,dt.rui-tabs-tab a:hover{padding:.2em 1em;border:1px solid #ccc;border-radius:.25em;-moz-border-radius:.3em;-webkit-border-radius:.3em}dl.rui-tabs dt.rui-tabs-current a{background:#EEE;border-bottom-left-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomleft:0;-moz-border-radius-bottomright:0;-webkit-border-bottom-left-radius:0;-webkit-border-bottom-right-radius:0}dl.rui-tabs dd.rui-tabs-current+dt.rui-tabs-tab a{border-top-left-radius:0;border-top-right-radius:0;-moz-border-radius-topleft:0;-moz-border-radius-topright:0;-webkit-border-top-left-radius:0;-webkit-border-top-right-radius:0}");
1132
-
1133
- style.type = 'text/css';
1134
-
1135
- if(style.styleSheet) {
1136
- style.styleSheet.cssText = rules.nodeValue;
1137
- } else {
1138
- style.appendChild(rules);
1139
- }
1140
-
1141
- document.getElementsByTagName('head')[0].appendChild(style);
1142
- })();
1143
-
1144
- return Tabs;
1145
- })(document, parseInt, RightJS);