stuff_to_do_plugin 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYRIGHT.txt +18 -0
- data/CREDITS.txt +6 -0
- data/GPL.txt +339 -0
- data/README.rdoc +61 -0
- data/Rakefile +38 -0
- data/VERSION +1 -0
- data/app/controllers/stuff_to_do_controller.rb +161 -0
- data/app/helpers/stuff_to_do_helper.rb +88 -0
- data/app/models/stuff_to_do.rb +208 -0
- data/app/models/stuff_to_do_filter.rb +32 -0
- data/app/models/stuff_to_do_mailer.rb +16 -0
- data/app/views/settings/_stuff_to_do_settings.html.erb +27 -0
- data/app/views/stuff_to_do/_issue.html.erb +16 -0
- data/app/views/stuff_to_do/_item.html.erb +5 -0
- data/app/views/stuff_to_do/_left_panes.html.erb +51 -0
- data/app/views/stuff_to_do/_panes.html.erb +11 -0
- data/app/views/stuff_to_do/_project.html.erb +6 -0
- data/app/views/stuff_to_do/_right_panes.html.erb +25 -0
- data/app/views/stuff_to_do/_time_grid.html.erb +113 -0
- data/app/views/stuff_to_do/_time_grid_form.html.erb +32 -0
- data/app/views/stuff_to_do/index.html.erb +44 -0
- data/app/views/stuff_to_do_mailer/recommended_below_threshold.erb +3 -0
- data/app/views/stuff_to_do_mailer/recommended_below_threshold.text.html.rhtml +1 -0
- data/assets/images/b.png +0 -0
- data/assets/images/bl.png +0 -0
- data/assets/images/br.png +0 -0
- data/assets/images/closelabel.gif +0 -0
- data/assets/images/loading.gif +0 -0
- data/assets/images/tl.png +0 -0
- data/assets/images/tr.png +0 -0
- data/assets/javascripts/facebox.js +319 -0
- data/assets/javascripts/jquery-1.2.6.min.js +32 -0
- data/assets/javascripts/jquery-ui.js +2839 -0
- data/assets/javascripts/jquery.contextMenu.js +212 -0
- data/assets/javascripts/semantic.cache +15 -0
- data/assets/javascripts/stuff-to-do.js +270 -0
- data/assets/javascripts/ui/build.xml +24 -0
- data/assets/javascripts/ui/effects.blind.js +49 -0
- data/assets/javascripts/ui/effects.bounce.js +78 -0
- data/assets/javascripts/ui/effects.clip.js +54 -0
- data/assets/javascripts/ui/effects.core.js +510 -0
- data/assets/javascripts/ui/effects.drop.js +50 -0
- data/assets/javascripts/ui/effects.explode.js +79 -0
- data/assets/javascripts/ui/effects.fold.js +55 -0
- data/assets/javascripts/ui/effects.highlight.js +48 -0
- data/assets/javascripts/ui/effects.pulsate.js +55 -0
- data/assets/javascripts/ui/effects.scale.js +180 -0
- data/assets/javascripts/ui/effects.shake.js +57 -0
- data/assets/javascripts/ui/effects.slide.js +50 -0
- data/assets/javascripts/ui/effects.transfer.js +59 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ar.js +26 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-bg.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ca.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-cs.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-da.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-de.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-eo.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-es.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-fa.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-fi.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-fr.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-he.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-hr.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-hu.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-hy.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-id.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-is.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-it.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ja.js +26 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ko.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-lt.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-lv.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-nl.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-no.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-pl.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-pt-BR.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ro.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-ru.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-sk.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-sl.js +26 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-sq.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-sv.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-th.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-tr.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-uk.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-zh-CN.js +25 -0
- data/assets/javascripts/ui/i18n/ui.datepicker-zh-TW.js +25 -0
- data/assets/javascripts/ui/svn.log +11 -0
- data/assets/javascripts/ui/ui.accordion.js +400 -0
- data/assets/javascripts/ui/ui.core.js +533 -0
- data/assets/javascripts/ui/ui.datepicker.js +1754 -0
- data/assets/javascripts/ui/ui.dialog.js +630 -0
- data/assets/javascripts/ui/ui.draggable.js +696 -0
- data/assets/javascripts/ui/ui.droppable.js +314 -0
- data/assets/javascripts/ui/ui.progressbar.js +114 -0
- data/assets/javascripts/ui/ui.resizable.js +805 -0
- data/assets/javascripts/ui/ui.selectable.js +266 -0
- data/assets/javascripts/ui/ui.slider.js +552 -0
- data/assets/javascripts/ui/ui.sortable.js +1012 -0
- data/assets/javascripts/ui/ui.tabs.js +572 -0
- data/assets/stylesheets/stuff_to_do.css +216 -0
- data/config/locales/bg.yml +18 -0
- data/config/locales/ca-fr.yml +18 -0
- data/config/locales/cs.yml +16 -0
- data/config/locales/da.yml +16 -0
- data/config/locales/de.yml +18 -0
- data/config/locales/en.yml +24 -0
- data/config/locales/es.yml +19 -0
- data/config/locales/fr.yml +17 -0
- data/config/locales/hu.yml +16 -0
- data/config/locales/it.yml +16 -0
- data/config/locales/ja.yml +18 -0
- data/config/locales/ko.yml +18 -0
- data/config/locales/lt.yml +18 -0
- data/config/locales/nl.yml +20 -0
- data/config/locales/pt-BR.yml +18 -0
- data/config/locales/ru.yml +19 -0
- data/config/locales/sv.yml +19 -0
- data/config/locales/tr.yml +18 -0
- data/config/routes.rb +3 -0
- data/init.rb +54 -0
- data/lang/bg.yml +17 -0
- data/lang/ca-fr.yml +17 -0
- data/lang/cs.yml +15 -0
- data/lang/da.yml +15 -0
- data/lang/de.yml +17 -0
- data/lang/en.yml +21 -0
- data/lang/es.yml +18 -0
- data/lang/fr.yml +16 -0
- data/lang/hu.yml +15 -0
- data/lang/it.yml +15 -0
- data/lang/ja.yml +17 -0
- data/lang/ko.yml +17 -0
- data/lang/lt.yml +17 -0
- data/lang/pt-br.yml +17 -0
- data/lang/ru.yml +15 -0
- data/lang/sv.yml +18 -0
- data/lang/tr.yml +17 -0
- data/lib/redmine_stuff_to_do/stuff_to_do_compatibility.rb +15 -0
- data/lib/stuff_to_do_array_patch.rb +8 -0
- data/lib/stuff_to_do_issue_patch.rb +57 -0
- data/lib/stuff_to_do_project_patch.rb +31 -0
- data/lib/stuff_to_do_user_patch.rb +10 -0
- data/rails/init.rb +1 -0
- data/spec/controllers/stuff_to_do_controller_add_to_time_grid_spec.rb +58 -0
- data/spec/controllers/stuff_to_do_controller_index_spec.rb +155 -0
- data/spec/controllers/stuff_to_do_controller_remove_from_time_grid_spec.rb +56 -0
- data/spec/controllers/stuff_to_do_controller_reorder_spec.rb +179 -0
- data/spec/controllers/stuff_to_do_controller_save_time_entries_spec.rb +56 -0
- data/spec/controllers/stuff_to_do_private_methods_spec.rb +82 -0
- data/spec/lib/stuff_to_do_issue_patch_spec.rb +60 -0
- data/spec/lib/stuff_to_do_project_patch_spec.rb +50 -0
- data/spec/lib/stuff_to_do_user_patch_spec.rb +8 -0
- data/spec/models/stuff_to_do_filter_spec.rb +3 -0
- data/spec/models/stuff_to_do_mailer_spec.rb +42 -0
- data/spec/models/stuff_to_do_spec.rb +426 -0
- data/spec/sanity_spec.rb +7 -0
- data/spec/spec_helper.rb +130 -0
- metadata +211 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* jQuery UI Tabs @VERSION
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2008 AUTHORS.txt (http://ui.jquery.com/about)
|
|
5
|
+
* Dual licensed under the MIT (MIT-LICENSE.txt)
|
|
6
|
+
* and GPL (GPL-LICENSE.txt) licenses.
|
|
7
|
+
*
|
|
8
|
+
* http://docs.jquery.com/UI/Tabs
|
|
9
|
+
*
|
|
10
|
+
* Depends:
|
|
11
|
+
* ui.core.js
|
|
12
|
+
*/
|
|
13
|
+
(function($) {
|
|
14
|
+
|
|
15
|
+
$.widget("ui.tabs", {
|
|
16
|
+
|
|
17
|
+
_init: function() {
|
|
18
|
+
// create tabs
|
|
19
|
+
this._tabify(true);
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
destroy: function() {
|
|
23
|
+
var o = this.options;
|
|
24
|
+
this.element.unbind('.tabs')
|
|
25
|
+
.removeClass(o.navClass).removeData('tabs');
|
|
26
|
+
this.$tabs.each(function() {
|
|
27
|
+
var href = $.data(this, 'href.tabs');
|
|
28
|
+
if (href)
|
|
29
|
+
this.href = href;
|
|
30
|
+
var $this = $(this).unbind('.tabs');
|
|
31
|
+
$.each(['href', 'load', 'cache'], function(i, prefix) {
|
|
32
|
+
$this.removeData(prefix + '.tabs');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
this.$lis.add(this.$panels).each(function() {
|
|
36
|
+
if ($.data(this, 'destroy.tabs'))
|
|
37
|
+
$(this).remove();
|
|
38
|
+
else
|
|
39
|
+
$(this).removeClass([o.selectedClass, o.deselectableClass,
|
|
40
|
+
o.disabledClass, o.panelClass, o.hideClass].join(' '));
|
|
41
|
+
});
|
|
42
|
+
if (o.cookie)
|
|
43
|
+
this._cookie(null, o.cookie);
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
_setData: function(key, value) {
|
|
47
|
+
if ((/^selected/).test(key))
|
|
48
|
+
this.select(value);
|
|
49
|
+
else {
|
|
50
|
+
this.options[key] = value;
|
|
51
|
+
this._tabify();
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
length: function() {
|
|
56
|
+
return this.$tabs.length;
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
_tabId: function(a) {
|
|
60
|
+
return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
|
|
61
|
+
|| this.options.idPrefix + $.data(a);
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
_sanitizeSelector: function(hash) {
|
|
65
|
+
return hash.replace(/:/g, '\\:'); // we need this because an id may contain a ":"
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
_cookie: function() {
|
|
69
|
+
var cookie = this.cookie || (this.cookie = 'ui-tabs-' + $.data(this.element[0]));
|
|
70
|
+
return $.cookie.apply(null, [cookie].concat($.makeArray(arguments)));
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
_tabify: function(init) {
|
|
74
|
+
|
|
75
|
+
this.$lis = $('li:has(a[href])', this.element);
|
|
76
|
+
this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
|
|
77
|
+
this.$panels = $([]);
|
|
78
|
+
|
|
79
|
+
var self = this, o = this.options;
|
|
80
|
+
|
|
81
|
+
this.$tabs.each(function(i, a) {
|
|
82
|
+
// inline tab
|
|
83
|
+
if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
|
|
84
|
+
self.$panels = self.$panels.add(self._sanitizeSelector(a.hash));
|
|
85
|
+
// remote tab
|
|
86
|
+
else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
|
|
87
|
+
$.data(a, 'href.tabs', a.href); // required for restore on destroy
|
|
88
|
+
$.data(a, 'load.tabs', a.href); // mutable
|
|
89
|
+
var id = self._tabId(a);
|
|
90
|
+
a.href = '#' + id;
|
|
91
|
+
var $panel = $('#' + id);
|
|
92
|
+
if (!$panel.length) {
|
|
93
|
+
$panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
|
|
94
|
+
.insertAfter(self.$panels[i - 1] || self.element);
|
|
95
|
+
$panel.data('destroy.tabs', true);
|
|
96
|
+
}
|
|
97
|
+
self.$panels = self.$panels.add($panel);
|
|
98
|
+
}
|
|
99
|
+
// invalid tab href
|
|
100
|
+
else
|
|
101
|
+
o.disabled.push(i + 1);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// initialization from scratch
|
|
105
|
+
if (init) {
|
|
106
|
+
|
|
107
|
+
// attach necessary classes for styling if not present
|
|
108
|
+
this.element.addClass(o.navClass);
|
|
109
|
+
this.$panels.addClass(o.panelClass);
|
|
110
|
+
|
|
111
|
+
// Selected tab
|
|
112
|
+
// use "selected" option or try to retrieve:
|
|
113
|
+
// 1. from fragment identifier in url
|
|
114
|
+
// 2. from cookie
|
|
115
|
+
// 3. from selected class attribute on <li>
|
|
116
|
+
if (o.selected === undefined) {
|
|
117
|
+
if (location.hash) {
|
|
118
|
+
this.$tabs.each(function(i, a) {
|
|
119
|
+
if (a.hash == location.hash) {
|
|
120
|
+
o.selected = i;
|
|
121
|
+
return false; // break
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else if (o.cookie) {
|
|
126
|
+
var index = parseInt(self._cookie(), 10);
|
|
127
|
+
if (index && self.$tabs[index]) o.selected = index;
|
|
128
|
+
}
|
|
129
|
+
else if (self.$lis.filter('.' + o.selectedClass).length)
|
|
130
|
+
o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] );
|
|
131
|
+
}
|
|
132
|
+
o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default
|
|
133
|
+
|
|
134
|
+
// Take disabling tabs via class attribute from HTML
|
|
135
|
+
// into account and update option properly.
|
|
136
|
+
// A selected tab cannot become disabled.
|
|
137
|
+
o.disabled = $.unique(o.disabled.concat(
|
|
138
|
+
$.map(this.$lis.filter('.' + o.disabledClass),
|
|
139
|
+
function(n, i) { return self.$lis.index(n); } )
|
|
140
|
+
)).sort();
|
|
141
|
+
if ($.inArray(o.selected, o.disabled) != -1)
|
|
142
|
+
o.disabled.splice($.inArray(o.selected, o.disabled), 1);
|
|
143
|
+
|
|
144
|
+
// highlight selected tab
|
|
145
|
+
this.$panels.addClass(o.hideClass);
|
|
146
|
+
this.$lis.removeClass(o.selectedClass);
|
|
147
|
+
if (o.selected !== null) {
|
|
148
|
+
this.$panels.eq(o.selected).removeClass(o.hideClass);
|
|
149
|
+
var classes = [o.selectedClass];
|
|
150
|
+
if (o.deselectable) classes.push(o.deselectableClass);
|
|
151
|
+
this.$lis.eq(o.selected).addClass(classes.join(' '));
|
|
152
|
+
|
|
153
|
+
// seems to be expected behavior that the show callback is fired
|
|
154
|
+
var onShow = function() {
|
|
155
|
+
self._trigger('show', null,
|
|
156
|
+
self.ui(self.$tabs[o.selected], self.$panels[o.selected]));
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// load if remote tab
|
|
160
|
+
if ($.data(this.$tabs[o.selected], 'load.tabs'))
|
|
161
|
+
this.load(o.selected, onShow);
|
|
162
|
+
// just trigger show event
|
|
163
|
+
else onShow();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// clean up to avoid memory leaks in certain versions of IE 6
|
|
167
|
+
$(window).bind('unload', function() {
|
|
168
|
+
self.$tabs.unbind('.tabs');
|
|
169
|
+
self.$lis = self.$tabs = self.$panels = null;
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
}
|
|
173
|
+
// update selected after add/remove
|
|
174
|
+
else
|
|
175
|
+
o.selected = this.$lis.index( this.$lis.filter('.' + o.selectedClass)[0] );
|
|
176
|
+
|
|
177
|
+
// set or update cookie after init and add/remove respectively
|
|
178
|
+
if (o.cookie) this._cookie(o.selected, o.cookie);
|
|
179
|
+
|
|
180
|
+
// disable tabs
|
|
181
|
+
for (var i = 0, li; li = this.$lis[i]; i++)
|
|
182
|
+
$(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);
|
|
183
|
+
|
|
184
|
+
// reset cache if switching from cached to not cached
|
|
185
|
+
if (o.cache === false) this.$tabs.removeData('cache.tabs');
|
|
186
|
+
|
|
187
|
+
// set up animations
|
|
188
|
+
var hideFx, showFx;
|
|
189
|
+
if (o.fx) {
|
|
190
|
+
if (o.fx.constructor == Array) {
|
|
191
|
+
hideFx = o.fx[0];
|
|
192
|
+
showFx = o.fx[1];
|
|
193
|
+
}
|
|
194
|
+
else hideFx = showFx = o.fx;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Reset certain styles left over from animation
|
|
198
|
+
// and prevent IE's ClearType bug...
|
|
199
|
+
function resetStyle($el, fx) {
|
|
200
|
+
$el.css({ display: '' });
|
|
201
|
+
if ($.browser.msie && fx.opacity) $el[0].style.removeAttribute('filter');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Show a tab...
|
|
205
|
+
var showTab = showFx ?
|
|
206
|
+
function(clicked, $show) {
|
|
207
|
+
$show.animate(showFx, showFx.duration || 'normal', function() {
|
|
208
|
+
$show.removeClass(o.hideClass);
|
|
209
|
+
resetStyle($show, showFx);
|
|
210
|
+
self._trigger('show', null, self.ui(clicked, $show[0]));
|
|
211
|
+
});
|
|
212
|
+
} :
|
|
213
|
+
function(clicked, $show) {
|
|
214
|
+
$show.removeClass(o.hideClass);
|
|
215
|
+
self._trigger('show', null, self.ui(clicked, $show[0]));
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// Hide a tab, $show is optional...
|
|
219
|
+
var hideTab = hideFx ?
|
|
220
|
+
function(clicked, $hide, $show) {
|
|
221
|
+
$hide.animate(hideFx, hideFx.duration || 'normal', function() {
|
|
222
|
+
$hide.addClass(o.hideClass);
|
|
223
|
+
resetStyle($hide, hideFx);
|
|
224
|
+
if ($show) showTab(clicked, $show, $hide);
|
|
225
|
+
});
|
|
226
|
+
} :
|
|
227
|
+
function(clicked, $hide, $show) {
|
|
228
|
+
$hide.addClass(o.hideClass);
|
|
229
|
+
if ($show) showTab(clicked, $show);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Switch a tab...
|
|
233
|
+
function switchTab(clicked, $li, $hide, $show) {
|
|
234
|
+
var classes = [o.selectedClass];
|
|
235
|
+
if (o.deselectable) classes.push(o.deselectableClass);
|
|
236
|
+
$li.addClass(classes.join(' ')).siblings().removeClass(classes.join(' '));
|
|
237
|
+
hideTab(clicked, $hide, $show);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// attach tab event handler, unbind to avoid duplicates from former tabifying...
|
|
241
|
+
this.$tabs.unbind('.tabs').bind(o.event + '.tabs', function() {
|
|
242
|
+
|
|
243
|
+
//var trueClick = event.clientX; // add to history only if true click occured, not a triggered click
|
|
244
|
+
var $li = $(this).parents('li:eq(0)'),
|
|
245
|
+
$hide = self.$panels.filter(':visible'),
|
|
246
|
+
$show = $(self._sanitizeSelector(this.hash));
|
|
247
|
+
|
|
248
|
+
// If tab is already selected and not deselectable or tab disabled or
|
|
249
|
+
// or is already loading or click callback returns false stop here.
|
|
250
|
+
// Check if click handler returns false last so that it is not executed
|
|
251
|
+
// for a disabled or loading tab!
|
|
252
|
+
if (($li.hasClass(o.selectedClass) && !o.deselectable)
|
|
253
|
+
|| $li.hasClass(o.disabledClass)
|
|
254
|
+
|| $(this).hasClass(o.loadingClass)
|
|
255
|
+
|| self._trigger('select', null, self.ui(this, $show[0])) === false
|
|
256
|
+
) {
|
|
257
|
+
this.blur();
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
o.selected = self.$tabs.index(this);
|
|
262
|
+
|
|
263
|
+
// if tab may be closed
|
|
264
|
+
if (o.deselectable) {
|
|
265
|
+
if ($li.hasClass(o.selectedClass)) {
|
|
266
|
+
self.options.selected = null;
|
|
267
|
+
$li.removeClass([o.selectedClass, o.deselectableClass].join(' '));
|
|
268
|
+
self.$panels.stop();
|
|
269
|
+
hideTab(this, $hide);
|
|
270
|
+
this.blur();
|
|
271
|
+
return false;
|
|
272
|
+
} else if (!$hide.length) {
|
|
273
|
+
self.$panels.stop();
|
|
274
|
+
var a = this;
|
|
275
|
+
self.load(self.$tabs.index(this), function() {
|
|
276
|
+
$li.addClass([o.selectedClass, o.deselectableClass].join(' '));
|
|
277
|
+
showTab(a, $show);
|
|
278
|
+
});
|
|
279
|
+
this.blur();
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (o.cookie) self._cookie(o.selected, o.cookie);
|
|
285
|
+
|
|
286
|
+
// stop possibly running animations
|
|
287
|
+
self.$panels.stop();
|
|
288
|
+
|
|
289
|
+
// show new tab
|
|
290
|
+
if ($show.length) {
|
|
291
|
+
var a = this;
|
|
292
|
+
self.load(self.$tabs.index(this), $hide.length ?
|
|
293
|
+
function() {
|
|
294
|
+
switchTab(a, $li, $hide, $show);
|
|
295
|
+
} :
|
|
296
|
+
function() {
|
|
297
|
+
$li.addClass(o.selectedClass);
|
|
298
|
+
showTab(a, $show);
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
} else
|
|
302
|
+
throw 'jQuery UI Tabs: Mismatching fragment identifier.';
|
|
303
|
+
|
|
304
|
+
// Prevent IE from keeping other link focussed when using the back button
|
|
305
|
+
// and remove dotted border from clicked link. This is controlled via CSS
|
|
306
|
+
// in modern browsers; blur() removes focus from address bar in Firefox
|
|
307
|
+
// which can become a usability and annoying problem with tabs('rotate').
|
|
308
|
+
if ($.browser.msie) this.blur();
|
|
309
|
+
|
|
310
|
+
return false;
|
|
311
|
+
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// disable click if event is configured to something else
|
|
315
|
+
if (o.event != 'click') this.$tabs.bind('click.tabs', function(){return false;});
|
|
316
|
+
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
add: function(url, label, index) {
|
|
320
|
+
if (index == undefined)
|
|
321
|
+
index = this.$tabs.length; // append by default
|
|
322
|
+
|
|
323
|
+
var o = this.options;
|
|
324
|
+
var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label));
|
|
325
|
+
$li.data('destroy.tabs', true);
|
|
326
|
+
|
|
327
|
+
var id = url.indexOf('#') == 0 ? url.replace('#', '') : this._tabId( $('a:first-child', $li)[0] );
|
|
328
|
+
|
|
329
|
+
// try to find an existing element before creating a new one
|
|
330
|
+
var $panel = $('#' + id);
|
|
331
|
+
if (!$panel.length) {
|
|
332
|
+
$panel = $(o.panelTemplate).attr('id', id)
|
|
333
|
+
.addClass(o.hideClass)
|
|
334
|
+
.data('destroy.tabs', true);
|
|
335
|
+
}
|
|
336
|
+
$panel.addClass(o.panelClass);
|
|
337
|
+
if (index >= this.$lis.length) {
|
|
338
|
+
$li.appendTo(this.element);
|
|
339
|
+
$panel.appendTo(this.element[0].parentNode);
|
|
340
|
+
} else {
|
|
341
|
+
$li.insertBefore(this.$lis[index]);
|
|
342
|
+
$panel.insertBefore(this.$panels[index]);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
o.disabled = $.map(o.disabled,
|
|
346
|
+
function(n, i) { return n >= index ? ++n : n });
|
|
347
|
+
|
|
348
|
+
this._tabify();
|
|
349
|
+
|
|
350
|
+
if (this.$tabs.length == 1) {
|
|
351
|
+
$li.addClass(o.selectedClass);
|
|
352
|
+
$panel.removeClass(o.hideClass);
|
|
353
|
+
var href = $.data(this.$tabs[0], 'load.tabs');
|
|
354
|
+
if (href)
|
|
355
|
+
this.load(index, href);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// callback
|
|
359
|
+
this._trigger('add', null, this.ui(this.$tabs[index], this.$panels[index]));
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
remove: function(index) {
|
|
363
|
+
var o = this.options, $li = this.$lis.eq(index).remove(),
|
|
364
|
+
$panel = this.$panels.eq(index).remove();
|
|
365
|
+
|
|
366
|
+
// If selected tab was removed focus tab to the right or
|
|
367
|
+
// in case the last tab was removed the tab to the left.
|
|
368
|
+
if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
|
|
369
|
+
this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));
|
|
370
|
+
|
|
371
|
+
o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
|
|
372
|
+
function(n, i) { return n >= index ? --n : n });
|
|
373
|
+
|
|
374
|
+
this._tabify();
|
|
375
|
+
|
|
376
|
+
// callback
|
|
377
|
+
this._trigger('remove', null, this.ui($li.find('a')[0], $panel[0]));
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
enable: function(index) {
|
|
381
|
+
var o = this.options;
|
|
382
|
+
if ($.inArray(index, o.disabled) == -1)
|
|
383
|
+
return;
|
|
384
|
+
|
|
385
|
+
var $li = this.$lis.eq(index).removeClass(o.disabledClass);
|
|
386
|
+
if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
|
|
387
|
+
$li.css('display', 'inline-block');
|
|
388
|
+
setTimeout(function() {
|
|
389
|
+
$li.css('display', 'block');
|
|
390
|
+
}, 0);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
|
|
394
|
+
|
|
395
|
+
// callback
|
|
396
|
+
this._trigger('enable', null, this.ui(this.$tabs[index], this.$panels[index]));
|
|
397
|
+
},
|
|
398
|
+
|
|
399
|
+
disable: function(index) {
|
|
400
|
+
var self = this, o = this.options;
|
|
401
|
+
if (index != o.selected) { // cannot disable already selected tab
|
|
402
|
+
this.$lis.eq(index).addClass(o.disabledClass);
|
|
403
|
+
|
|
404
|
+
o.disabled.push(index);
|
|
405
|
+
o.disabled.sort();
|
|
406
|
+
|
|
407
|
+
// callback
|
|
408
|
+
this._trigger('disable', null, this.ui(this.$tabs[index], this.$panels[index]));
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
|
|
412
|
+
select: function(index) {
|
|
413
|
+
// TODO make null as argument work
|
|
414
|
+
if (typeof index == 'string')
|
|
415
|
+
index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] );
|
|
416
|
+
this.$tabs.eq(index).trigger(this.options.event + '.tabs');
|
|
417
|
+
},
|
|
418
|
+
|
|
419
|
+
load: function(index, callback) { // callback is for internal usage only
|
|
420
|
+
|
|
421
|
+
var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
|
|
422
|
+
bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');
|
|
423
|
+
|
|
424
|
+
callback = callback || function() {};
|
|
425
|
+
|
|
426
|
+
// no remote or from cache - just finish with callback
|
|
427
|
+
if (!url || !bypassCache && $.data(a, 'cache.tabs')) {
|
|
428
|
+
callback();
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// load remote from here on
|
|
433
|
+
|
|
434
|
+
var inner = function(parent) {
|
|
435
|
+
var $parent = $(parent), $inner = $parent.find('*:last');
|
|
436
|
+
return $inner.length && $inner.is(':not(img)') && $inner || $parent;
|
|
437
|
+
};
|
|
438
|
+
var cleanup = function() {
|
|
439
|
+
self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass)
|
|
440
|
+
.each(function() {
|
|
441
|
+
if (o.spinner)
|
|
442
|
+
inner(this).parent().html(inner(this).data('label.tabs'));
|
|
443
|
+
});
|
|
444
|
+
self.xhr = null;
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
if (o.spinner) {
|
|
448
|
+
var label = inner(a).html();
|
|
449
|
+
inner(a).wrapInner('<em></em>')
|
|
450
|
+
.find('em').data('label.tabs', label).html(o.spinner);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
var ajaxOptions = $.extend({}, o.ajaxOptions, {
|
|
454
|
+
url: url,
|
|
455
|
+
success: function(r, s) {
|
|
456
|
+
$(self._sanitizeSelector(a.hash)).html(r);
|
|
457
|
+
cleanup();
|
|
458
|
+
|
|
459
|
+
if (o.cache)
|
|
460
|
+
$.data(a, 'cache.tabs', true); // if loaded once do not load them again
|
|
461
|
+
|
|
462
|
+
// callbacks
|
|
463
|
+
self._trigger('load', null, self.ui(self.$tabs[index], self.$panels[index]));
|
|
464
|
+
try {
|
|
465
|
+
o.ajaxOptions.success(r, s);
|
|
466
|
+
}
|
|
467
|
+
catch (event) {}
|
|
468
|
+
|
|
469
|
+
// This callback is required because the switch has to take
|
|
470
|
+
// place after loading has completed. Call last in order to
|
|
471
|
+
// fire load before show callback...
|
|
472
|
+
callback();
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
if (this.xhr) {
|
|
476
|
+
// terminate pending requests from other tabs and restore tab label
|
|
477
|
+
this.xhr.abort();
|
|
478
|
+
cleanup();
|
|
479
|
+
}
|
|
480
|
+
$a.addClass(o.loadingClass);
|
|
481
|
+
self.xhr = $.ajax(ajaxOptions);
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
url: function(index, url) {
|
|
485
|
+
this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
|
|
486
|
+
},
|
|
487
|
+
|
|
488
|
+
ui: function(tab, panel) {
|
|
489
|
+
return {
|
|
490
|
+
options: this.options,
|
|
491
|
+
tab: tab,
|
|
492
|
+
panel: panel,
|
|
493
|
+
index: this.$tabs.index(tab)
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
$.extend($.ui.tabs, {
|
|
500
|
+
version: '@VERSION',
|
|
501
|
+
getter: 'length',
|
|
502
|
+
defaults: {
|
|
503
|
+
ajaxOptions: null,
|
|
504
|
+
cache: false,
|
|
505
|
+
cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
|
|
506
|
+
deselectable: false,
|
|
507
|
+
deselectableClass: 'ui-tabs-deselectable',
|
|
508
|
+
disabled: [],
|
|
509
|
+
disabledClass: 'ui-tabs-disabled',
|
|
510
|
+
event: 'click',
|
|
511
|
+
fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
|
|
512
|
+
hideClass: 'ui-tabs-hide',
|
|
513
|
+
idPrefix: 'ui-tabs-',
|
|
514
|
+
loadingClass: 'ui-tabs-loading',
|
|
515
|
+
navClass: 'ui-tabs-nav',
|
|
516
|
+
panelClass: 'ui-tabs-panel',
|
|
517
|
+
panelTemplate: '<div></div>',
|
|
518
|
+
selectedClass: 'ui-tabs-selected',
|
|
519
|
+
spinner: 'Loading…',
|
|
520
|
+
tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>'
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
/*
|
|
525
|
+
* Tabs Extensions
|
|
526
|
+
*/
|
|
527
|
+
|
|
528
|
+
/*
|
|
529
|
+
* Rotate
|
|
530
|
+
*/
|
|
531
|
+
$.extend($.ui.tabs.prototype, {
|
|
532
|
+
rotation: null,
|
|
533
|
+
rotate: function(ms, continuing) {
|
|
534
|
+
|
|
535
|
+
continuing = continuing || false;
|
|
536
|
+
|
|
537
|
+
var self = this, t = this.options.selected;
|
|
538
|
+
|
|
539
|
+
function start() {
|
|
540
|
+
self.rotation = setInterval(function() {
|
|
541
|
+
t = ++t < self.$tabs.length ? t : 0;
|
|
542
|
+
self.select(t);
|
|
543
|
+
}, ms);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function stop(event) {
|
|
547
|
+
if (!event || event.clientX) { // only in case of a true click
|
|
548
|
+
clearInterval(self.rotation);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// start interval
|
|
553
|
+
if (ms) {
|
|
554
|
+
start();
|
|
555
|
+
if (!continuing)
|
|
556
|
+
this.$tabs.bind(this.options.event + '.tabs', stop);
|
|
557
|
+
else
|
|
558
|
+
this.$tabs.bind(this.options.event + '.tabs', function() {
|
|
559
|
+
stop();
|
|
560
|
+
t = self.options.selected;
|
|
561
|
+
start();
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
// stop interval
|
|
565
|
+
else {
|
|
566
|
+
stop();
|
|
567
|
+
this.$tabs.unbind(this.options.event + '.tabs', stop);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
})(jQuery);
|