fuelux-rails 2.4.2 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -32,7 +32,6 @@
32
32
  },
33
33
 
34
34
  itemclicked: function(e) {
35
-
36
35
  var $li = $(e.currentTarget);
37
36
  var data = $.extend({
38
37
  text : $li.html()
@@ -45,45 +44,56 @@
45
44
  },
46
45
 
47
46
  itemCount: function() {
48
-
49
47
  return this.$element.find('li').length;
50
48
  },
51
49
 
52
50
  addItem: function(text, value) {
53
-
54
- value = value || text;
55
-
56
- //<li data-value="foo">Item One</li>
57
-
51
+ value = value || text;
58
52
  var $li = $('<li data-value="' + value + '">' + text + '</li>');
59
53
 
60
- this.$element.find('ul').append($li);
54
+ if( this.$element.find('ul').length > 0 ) {
55
+ this.$element.find('ul').append($li);
56
+ } else {
57
+ this.$element.append($li);
58
+ }
59
+
60
+ this.$element.trigger( 'added', { text: text, value: value } );
61
61
 
62
62
  return $li;
63
63
  },
64
64
 
65
- removeBySelector: function(selector) {
65
+ removeBySelector: function(selector, trigger) {
66
+ if( typeof trigger === "undefined" ) {
67
+ trigger = true;
68
+ }
66
69
 
67
70
  this.$element.find('ul').find(selector).remove();
71
+
72
+ if( !!trigger ) {
73
+ this._removePillTrigger( { method: 'removeBySelector', removedSelector: selector } );
74
+ }
68
75
  },
69
76
 
70
77
  removeByValue: function(value) {
71
-
72
78
  var selector = 'li[data-value="' + value + '"]';
73
79
 
74
- this.removeBySelector(selector);
80
+ this.removeBySelector( selector, false );
81
+ this._removePillTrigger( { method: 'removeByValue', removedValue: value } );
75
82
  },
76
83
 
77
84
  removeByText: function(text) {
78
-
79
85
  var selector = 'li:contains("' + text + '")';
80
86
 
81
- this.removeBySelector(selector);
87
+ this.removeBySelector( selector, false );
88
+ this._removePillTrigger( { method: 'removeByText', removedText: text } );
82
89
  },
83
90
 
84
91
  clear: function() {
85
-
86
92
  this.$element.find('ul').empty();
93
+ },
94
+
95
+ _removePillTrigger: function( removedBy ) {
96
+ this.$element.trigger( 'removed', removedBy );
87
97
  }
88
98
  };
89
99
 
@@ -0,0 +1,512 @@
1
+ /*
2
+ * Fuel UX Scheduler
3
+ * https://github.com/ExactTarget/fuelux
4
+ *
5
+ * Copyright (c) 2012 ExactTarget
6
+ * Licensed under the MIT license.
7
+ */
8
+
9
+ !function ($) {
10
+
11
+ var old = $.fn.scheduler;
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+ // SCHEDULER CONSTRUCTOR AND PROTOTYPE
20
+
21
+ var Scheduler = function (element, options) {
22
+ var self = this;
23
+
24
+ this.$element = $(element);
25
+ this.options = $.extend({}, $.fn.scheduler.defaults, options);
26
+
27
+ // cache elements
28
+ this.$startDate = this.$element.find('.scheduler-start .datepicker');
29
+ this.$startTime = this.$element.find('.scheduler-start .combobox');
30
+
31
+ this.$timeZone = this.$element.find('.scheduler-timezone .select');
32
+
33
+ this.$repeatIntervalPanel = this.$element.find('.repeat-interval-panel');
34
+ this.$repeatIntervalSelect = this.$element.find('.repeat-interval .select');
35
+ this.$repeatIntervalSpinner = this.$element.find('.repeat-interval-panel .spinner');
36
+ this.$repeatIntervalTxt = this.$element.find('.repeat-interval-text');
37
+
38
+ this.$end = this.$element.find('.scheduler-end');
39
+ this.$endAfter = this.$end.find('.spinner');
40
+ this.$endSelect= this.$end.find('.select');
41
+ this.$endDate = this.$end.find('.datepicker');
42
+
43
+ // panels
44
+ this.$recurrencePanels = this.$element.find('.recurrence-panel');
45
+
46
+ // bind events
47
+ this.$element.find('.scheduler-weekly .btn-group .btn').on('click', function(e, data){ self.changed(e, data, true); });
48
+ this.$element.find('.combobox').on('changed', $.proxy(this.changed, this));
49
+ this.$element.find('.datepicker').on('changed', $.proxy(this.changed, this));
50
+ this.$element.find('.select').on('changed', $.proxy(this.changed, this));
51
+ this.$element.find('.spinner').on('changed', $.proxy(this.changed, this));
52
+ this.$element.find('.scheduler-monthly label.radio, .scheduler-yearly label.radio').on('mouseup', $.proxy(this.changed, this));
53
+
54
+ this.$repeatIntervalSelect.on('changed', $.proxy(this.repeatIntervalSelectChanged, this));
55
+ this.$endSelect.on('changed', $.proxy(this.endSelectChanged, this));
56
+
57
+ //initialize sub-controls
58
+ this.$startDate.datepicker();
59
+ this.$startTime.combobox();
60
+ if(this.$startTime.find('input').val()===''){
61
+ this.$startTime.combobox('selectByIndex', 0);
62
+ }
63
+ this.$repeatIntervalSpinner.spinner();
64
+ this.$endAfter.spinner();
65
+ this.$endDate.datepicker();
66
+ };
67
+
68
+ Scheduler.prototype = {
69
+ constructor: Scheduler,
70
+
71
+ changed: function(e, data, propagate){
72
+ if(!propagate){
73
+ e.stopPropagation();
74
+ }
75
+ this.$element.trigger('changed', {
76
+ data: (data!==undefined) ? data : $(e.currentTarget).data(),
77
+ originalEvent: e,
78
+ value: this.getValue()
79
+ });
80
+ },
81
+
82
+ disable: function(){
83
+ this.toggleState('disable');
84
+ },
85
+
86
+ enable: function(){
87
+ this.toggleState('enable');
88
+ },
89
+
90
+ // called when the end range changes
91
+ // (Never, After, On date)
92
+ endSelectChanged: function(e, data) {
93
+ var selectedItem, val;
94
+
95
+ if(!data){
96
+ selectedItem = this.$endSelect.select('selectedItem');
97
+ val = selectedItem.value;
98
+ }else{
99
+ val = data.value;
100
+ }
101
+
102
+ // hide all panels
103
+ this.$endAfter.hide();
104
+ this.$endDate.hide();
105
+
106
+ if(val==='after'){
107
+ this.$endAfter.show();
108
+ }else if(val==='date'){
109
+ this.$endDate.show();
110
+ }
111
+ },
112
+
113
+ getValue: function(){
114
+ // FREQ = frequency (hourly, daily, monthly...)
115
+ // BYDAY = when picking days (MO,TU,WE,etc)
116
+ // BYMONTH = when picking months (Jan,Feb,March) - note the values should be 1,2,3...
117
+ // BYMONTHDAY = when picking days of the month (1,2,3...)
118
+ // BYSETPOS = when picking First,Second,Third,Fourth,Last (1,2,3,4,-1)
119
+
120
+ var interval = this.$repeatIntervalSpinner.spinner('value');
121
+ var pattern = '';
122
+ var repeat = this.$repeatIntervalSelect.select('selectedItem').value;
123
+ var startTime = this.$startTime.combobox('selectedItem').text.toLowerCase();
124
+ var timeZone = this.$timeZone.select('selectedItem');
125
+ var getFormattedDate = function(dateObj, dash){
126
+ var fdate = '';
127
+ var item;
128
+
129
+ fdate += dateObj.getFullYear();
130
+ fdate += dash;
131
+ item = dateObj.getMonth() + 1; //because 0 indexing makes sense when dealing with months /sarcasm
132
+ fdate += (item<10) ? '0' + item : item;
133
+ fdate += dash;
134
+ item = dateObj.getDate();
135
+ fdate += (item<10) ? '0' + item : item;
136
+
137
+ return fdate;
138
+ };
139
+ var day, days, hasAm, hasPm, month, pos, startDateTime, type;
140
+
141
+ startDateTime = '' + getFormattedDate(this.$startDate.datepicker('getDate'), '-');
142
+
143
+ startDateTime += 'T';
144
+ hasAm = (startTime.search('am')>=0);
145
+ hasPm = (startTime.search('pm')>=0);
146
+ startTime = $.trim(startTime.replace(/am/g, '').replace(/pm/g, '')).split(':');
147
+ startTime[0] = parseInt(startTime[0], 10);
148
+ startTime[1] = parseInt(startTime[1], 10);
149
+ if(hasAm && startTime[0]>11){
150
+ startTime[0] = 0;
151
+ }else if(hasPm && startTime[0]<12){
152
+ startTime[0] += 12;
153
+ }
154
+ startDateTime += (startTime[0]<10) ? '0' + startTime[0] : startTime[0];
155
+ startDateTime += ':';
156
+ startDateTime += (startTime[1]<10) ? '0' + startTime[1] : startTime[1];
157
+
158
+ startDateTime += (timeZone.offset==='+00:00') ? 'Z' : timeZone.offset;
159
+
160
+ if(repeat === 'none') {
161
+ pattern = 'FREQ=DAILY;INTERVAL=1;COUNT=1;';
162
+ }
163
+ else if(repeat === 'hourly') {
164
+ pattern = 'FREQ=HOURLY;';
165
+ pattern += 'INTERVAL=' + interval + ';';
166
+ }
167
+ else if(repeat === 'daily') {
168
+ pattern += 'FREQ=DAILY;';
169
+ pattern += 'INTERVAL=' + interval + ';';
170
+ }
171
+ else if(repeat === 'weekdays') {
172
+ pattern += 'FREQ=DAILY;';
173
+ pattern += 'BYDAY=MO,TU,WE,TH,FR;';
174
+ pattern += 'INTERVAL=1;';
175
+ }
176
+ else if(repeat === 'weekly') {
177
+ days = [];
178
+ this.$element.find('.scheduler-weekly .btn-group button.active').each(function() {
179
+ days.push($(this).data().value);
180
+ });
181
+
182
+ pattern += 'FREQ=WEEKLY;';
183
+ pattern += 'BYDAY=' + days.join(',') + ';';
184
+ pattern += 'INTERVAL=' + interval + ';';
185
+ }
186
+ else if(repeat === 'monthly') {
187
+ pattern += 'FREQ=MONTHLY;';
188
+ pattern += 'INTERVAL=' + interval + ';';
189
+
190
+ type = parseInt(this.$element.find('input[name=scheduler-month]:checked').val(), 10);
191
+ if(type === 1) {
192
+ day = parseInt(this.$element.find('.scheduler-monthly-date .select').select('selectedItem').text, 10);
193
+ pattern += 'BYMONTHDAY=' + day + ';';
194
+ }
195
+ else if(type === 2) {
196
+ days = this.$element.find('.month-days').select('selectedItem').value;
197
+ pos = this.$element.find('.month-day-pos').select('selectedItem').value;
198
+
199
+ pattern += 'BYDAY=' + days + ';';
200
+ pattern += 'BYSETPOS=' + pos + ';';
201
+ }
202
+ }
203
+ else if(repeat === 'yearly') {
204
+ pattern += 'FREQ=YEARLY;';
205
+
206
+ type = parseInt(this.$element.find('input[name=scheduler-year]:checked').val(), 10);
207
+ if(type === 1) {
208
+ month = this.$element.find('.scheduler-yearly-date .year-month').select('selectedItem').value;
209
+ day = this.$element.find('.year-month-day').select('selectedItem').text;
210
+
211
+ pattern += 'BYMONTH=' + month + ';';
212
+ pattern += 'BYMONTHDAY=' + day + ';';
213
+ }
214
+ else if(type === 2) {
215
+ days = this.$element.find('.year-month-days').select('selectedItem').value;
216
+ pos = this.$element.find('.year-month-day-pos').select('selectedItem').value;
217
+ month = this.$element.find('.scheduler-yearly-day .year-month').select('selectedItem').value;
218
+
219
+ pattern += 'BYDAY=' + days + ';';
220
+ pattern += 'BYSETPOS=' + pos + ';';
221
+ pattern += 'BYMONTH=' + month + ';';
222
+ }
223
+ }
224
+
225
+ var end = this.$endSelect.select('selectedItem').value;
226
+ var duration = '';
227
+
228
+ // if both UNTIL and COUNT are not specified, the recurrence will repeat forever
229
+ // http://tools.ietf.org/html/rfc2445#section-4.3.10
230
+ if(repeat !=='none'){
231
+ if(end === 'after') {
232
+ duration = 'COUNT=' + this.$endAfter.spinner('value') + ';';
233
+ }
234
+ else if(end === 'date') {
235
+ duration = 'UNTIL=' + getFormattedDate(this.$endDate.datepicker('getDate'), '') + ';';
236
+ }
237
+ }
238
+
239
+ pattern += duration;
240
+
241
+ var data = {
242
+ startDateTime: startDateTime,
243
+ timeZone: {
244
+ name: timeZone.name,
245
+ offset: timeZone.offset
246
+ },
247
+ recurrencePattern: pattern
248
+ };
249
+
250
+ return data;
251
+ },
252
+
253
+ // called when the repeat interval changes
254
+ // (None, Hourly, Daily, Weekdays, Weekly, Monthly, Yearly
255
+ repeatIntervalSelectChanged: function(e, data) {
256
+ var selectedItem, val, txt;
257
+
258
+ if(!data){
259
+ selectedItem = this.$repeatIntervalSelect.select('selectedItem');
260
+ val = selectedItem.value;
261
+ txt = selectedItem.text;
262
+ }else{
263
+ val = data.value;
264
+ txt = data.text;
265
+ }
266
+
267
+ // set the text
268
+ this.$repeatIntervalTxt.text(txt);
269
+
270
+ switch(val.toLowerCase()) {
271
+ case 'hourly':
272
+ case 'daily':
273
+ case 'weekly':
274
+ case 'monthly':
275
+ this.$repeatIntervalPanel.show();
276
+ break;
277
+ default:
278
+ this.$repeatIntervalPanel.hide();
279
+ break;
280
+ }
281
+
282
+ // hide all panels
283
+ this.$recurrencePanels.hide();
284
+
285
+ // show panel for current selection
286
+ this.$element.find('.scheduler-' + val).show();
287
+
288
+ // the end selection should only be shown when
289
+ // the repeat interval is not "None (run once)"
290
+ if(val === 'none') {
291
+ this.$end.hide();
292
+ }
293
+ else {
294
+ this.$end.show();
295
+ }
296
+ },
297
+
298
+ setValue: function(options){
299
+ var hours, i, item, l, minutes, period, recur, temp;
300
+
301
+ if(options.startDateTime){
302
+ temp = options.startDateTime.split('T');
303
+ this.$startDate.datepicker('setDate', temp[0]);
304
+
305
+ if(temp[1]){
306
+ temp[1] = temp[1].split(':');
307
+ hours = parseInt(temp[1][0], 10);
308
+ minutes = (temp[1][1]) ? parseInt(temp[1][1].split('+')[0].split('-')[0].split('Z')[0], 10) : 0;
309
+ period = (hours<12) ? 'AM' : 'PM';
310
+
311
+ if(hours===0){
312
+ hours = 12;
313
+ }else if(hours>12){
314
+ hours -= 12;
315
+ }
316
+ minutes = (minutes<10) ? '0' + minutes : minutes;
317
+
318
+ temp = hours + ':' + minutes + ' ' + period;
319
+ this.$startTime.find('input').val(temp);
320
+ this.$startTime.combobox('selectByText', temp);
321
+ }
322
+ }
323
+
324
+ item = 'li[data';
325
+ if(options.timeZone){
326
+ if(typeof(options.timeZone)==='string'){
327
+ item += '-name="' + options.timeZone;
328
+ }else{
329
+ if(options.timeZone.name){
330
+ item += '-name="' + options.timeZone.name;
331
+ }else{
332
+ item += '-offset="' + options.timeZone.offset;
333
+ }
334
+ }
335
+ item += '"]';
336
+ this.$timeZone.select('selectBySelector', item);
337
+ }else if(options.startDateTime){
338
+ temp = options.startDateTime.split('T')[1];
339
+ if(temp){
340
+ if(temp.search(/\+/)>-1){
341
+ temp = '+' + $.trim(temp.split('+')[1]);
342
+ }else if(temp.search(/\-/)>-1){
343
+ temp = '-' + $.trim(temp.split('-')[1]);
344
+ }else{
345
+ temp = '+00:00';
346
+ }
347
+ }else{
348
+ temp = '+00:00';
349
+ }
350
+ item += '-offset="' + temp + '"]';
351
+ this.$timeZone.select('selectBySelector', item);
352
+ }
353
+
354
+ if(options.recurrencePattern){
355
+ recur = {};
356
+ temp = options.recurrencePattern.toUpperCase().split(';');
357
+ for(i=0, l=temp.length; i<l; i++){
358
+ if(temp[i]!==''){
359
+ item = temp[i].split('=');
360
+ recur[item[0]] = item[1];
361
+ }
362
+ }
363
+
364
+ if(recur.FREQ==='DAILY'){
365
+ if(recur.BYDAY==='MO,TU,WE,TH,FR'){
366
+ item = 'weekdays';
367
+ }else{
368
+ if(recur.INTERVAL==='1' && recur.COUNT==='1'){
369
+ item = 'none';
370
+ }else{
371
+ item = 'daily';
372
+ }
373
+ }
374
+ }else if(recur.FREQ==='HOURLY'){
375
+ item = 'hourly';
376
+ }else if(recur.FREQ==='WEEKLY'){
377
+ if(recur.BYDAY){
378
+ item = this.$element.find('.scheduler-weekly .btn-group');
379
+ item.find('button').removeClass('active');
380
+ temp = recur.BYDAY.split(',');
381
+ for(i=0,l=temp.length; i<l; i++){
382
+ item.find('button[data-value="' + temp[i] + '"]').addClass('active');
383
+ }
384
+ }
385
+ item = 'weekly';
386
+ }else if(recur.FREQ==='MONTHLY'){
387
+ this.$element.find('.scheduler-monthly input').removeClass('checked');
388
+ if(recur.BYMONTHDAY){
389
+ temp = this.$element.find('.scheduler-monthly-date');
390
+ temp.find('input').addClass('checked');
391
+ temp.find('.select').select('selectByValue', recur.BYMONTHDAY);
392
+ }else if(recur.BYDAY){
393
+ temp = this.$element.find('.scheduler-monthly-day');
394
+ temp.find('input').addClass('checked');
395
+ if(recur.BYSETPOS){
396
+ temp.find('.month-day-pos').select('selectByValue', recur.BYSETPOS);
397
+ }
398
+ temp.find('.month-days').select('selectByValue', recur.BYDAY);
399
+ }
400
+ item = 'monthly';
401
+ }else if(recur.FREQ==='YEARLY'){
402
+ this.$element.find('.scheduler-yearly input').removeClass('checked');
403
+ if(recur.BYMONTHDAY){
404
+ temp = this.$element.find('.scheduler-yearly-date');
405
+ temp.find('input').addClass('checked');
406
+ if(recur.BYMONTH){
407
+ temp.find('.year-month').select('selectByValue', recur.BYMONTH);
408
+ }
409
+ temp.find('.year-month-day').select('selectByValue', recur.BYMONTHDAY);
410
+ }else if(recur.BYSETPOS){
411
+ temp = this.$element.find('.scheduler-yearly-day');
412
+ temp.find('input').addClass('checked');
413
+ temp.find('.year-month-day-pos').select('selectByValue', recur.BYSETPOS);
414
+ if(recur.BYDAY){
415
+ temp.find('.year-month-days').select('selectByValue', recur.BYDAY);
416
+ }
417
+ if(recur.BYMONTH){
418
+ temp.find('.year-month').select('selectByValue', recur.BYMONTH);
419
+ }
420
+ }
421
+ item = 'yearly';
422
+ }else{
423
+ item = 'none';
424
+ }
425
+
426
+ if(recur.COUNT){
427
+ this.$endAfter.spinner('value', parseInt(recur.COUNT, 10));
428
+ this.$endSelect.select('selectByValue', 'after');
429
+ }else if(recur.UNTIL){
430
+ temp = recur.UNTIL;
431
+ if(temp.length===8){
432
+ temp = temp.split('');
433
+ temp.splice(4, 0, '-');
434
+ temp.splice(7, 0, '-');
435
+ temp = temp.join('');
436
+ }
437
+ this.$endDate.datepicker('setDate', temp);
438
+ this.$endSelect.select('selectByValue', 'date');
439
+ }
440
+ this.endSelectChanged();
441
+
442
+ if(recur.INTERVAL){
443
+ this.$repeatIntervalSpinner.spinner('value', parseInt(recur.INTERVAL, 10));
444
+ }
445
+ this.$repeatIntervalSelect.select('selectByValue', item);
446
+ this.repeatIntervalSelectChanged();
447
+ }
448
+ },
449
+
450
+ toggleState: function(action){
451
+ this.$element.find('.combobox').combobox(action);
452
+ this.$element.find('.datepicker').datepicker(action);
453
+ this.$element.find('.select').select(action);
454
+ this.$element.find('.spinner').spinner(action);
455
+ this.$element.find('.radio').radio(action);
456
+
457
+ if(action==='disable'){
458
+ action = 'addClass';
459
+ }else{
460
+ action = 'removeClass';
461
+ }
462
+ this.$element.find('.scheduler-weekly .btn-group')[action]('disabled');
463
+ },
464
+
465
+ value: function(options) {
466
+ if(options){
467
+ return this.setValue(options);
468
+ }else{
469
+ return this.getValue();
470
+ }
471
+ }
472
+ };
473
+
474
+
475
+ // SCHEDULER PLUGIN DEFINITION
476
+
477
+ $.fn.scheduler = function (option) {
478
+ var args = Array.prototype.slice.call( arguments, 1 );
479
+ var methodReturn;
480
+
481
+ var $set = this.each(function () {
482
+ var $this = $(this);
483
+ var data = $this.data('scheduler');
484
+ var options = typeof option === 'object' && option;
485
+
486
+ if (!data) $this.data('scheduler', (data = new Scheduler(this, options)));
487
+ if( typeof option === 'string' ) methodReturn = data[ option ].apply( data, args );
488
+ });
489
+
490
+ return ( methodReturn === undefined ) ? $set : methodReturn;
491
+ };
492
+
493
+ $.fn.scheduler.defaults = {};
494
+
495
+ $.fn.scheduler.Constructor = Scheduler;
496
+
497
+ $.fn.scheduler.noConflict = function () {
498
+ $.fn.scheduler = old;
499
+ return this;
500
+ };
501
+
502
+ // SCHEDULER DATA-API
503
+
504
+ $(function () {
505
+ $('body').on('mousedown.scheduler.data-api', '.scheduler', function () {
506
+ var $this = $(this);
507
+ if ($this.data('scheduler')) return;
508
+ $this.scheduler($this.data());
509
+ });
510
+ });
511
+
512
+ }(window.jQuery);