will_pickdate 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/Gemfile.lock ADDED
@@ -0,0 +1,85 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ will_pickdate (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ actionpack (3.2.13)
10
+ activemodel (= 3.2.13)
11
+ activesupport (= 3.2.13)
12
+ builder (~> 3.0.0)
13
+ erubis (~> 2.7.0)
14
+ journey (~> 1.0.4)
15
+ rack (~> 1.4.5)
16
+ rack-cache (~> 1.2)
17
+ rack-test (~> 0.6.1)
18
+ sprockets (~> 2.2.1)
19
+ activemodel (3.2.13)
20
+ activesupport (= 3.2.13)
21
+ builder (~> 3.0.0)
22
+ activesupport (3.2.13)
23
+ i18n (= 0.6.1)
24
+ multi_json (~> 1.0)
25
+ builder (3.0.4)
26
+ diff-lcs (1.2.1)
27
+ erubis (2.7.0)
28
+ hike (1.2.1)
29
+ i18n (0.6.1)
30
+ journey (1.0.4)
31
+ jquery-rails (2.2.1)
32
+ railties (>= 3.0, < 5.0)
33
+ thor (>= 0.14, < 2.0)
34
+ json (1.7.7)
35
+ multi_json (1.7.1)
36
+ rack (1.4.5)
37
+ rack-cache (1.2)
38
+ rack (>= 0.4)
39
+ rack-ssl (1.3.3)
40
+ rack
41
+ rack-test (0.6.2)
42
+ rack (>= 1.0)
43
+ railties (3.2.13)
44
+ actionpack (= 3.2.13)
45
+ activesupport (= 3.2.13)
46
+ rack-ssl (~> 1.3.2)
47
+ rake (>= 0.8.7)
48
+ rdoc (~> 3.4)
49
+ thor (>= 0.14.6, < 2.0)
50
+ rake (10.0.3)
51
+ rdoc (3.12.2)
52
+ json (~> 1.4)
53
+ rspec (2.13.0)
54
+ rspec-core (~> 2.13.0)
55
+ rspec-expectations (~> 2.13.0)
56
+ rspec-mocks (~> 2.13.0)
57
+ rspec-core (2.13.1)
58
+ rspec-expectations (2.13.0)
59
+ diff-lcs (>= 1.1.3, < 2.0)
60
+ rspec-mocks (2.13.0)
61
+ simplecov (0.7.1)
62
+ multi_json (~> 1.0)
63
+ simplecov-html (~> 0.7.1)
64
+ simplecov-html (0.7.1)
65
+ sprockets (2.2.2)
66
+ hike (~> 1.2)
67
+ multi_json (~> 1.0)
68
+ rack (~> 1.0)
69
+ tilt (~> 1.1, != 1.3.0)
70
+ test-unit (2.5.4)
71
+ thor (0.17.0)
72
+ tilt (1.3.6)
73
+
74
+ PLATFORMS
75
+ ruby
76
+
77
+ DEPENDENCIES
78
+ actionpack
79
+ activesupport
80
+ jquery-rails
81
+ rake
82
+ rspec
83
+ simplecov
84
+ test-unit
85
+ will_pickdate!
@@ -1,3 +1,3 @@
1
1
  module WillPickdate
2
- VERSION = "0.1.3"
2
+ VERSION = "0.1.4"
3
3
  end
@@ -0,0 +1,84 @@
1
+ /*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
2
+ * Licensed under the MIT License (LICENSE.txt).
3
+ *
4
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
5
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
6
+ * Thanks to: Seamus Leahy for adding deltaX and deltaY
7
+ *
8
+ * Version: 3.0.6
9
+ *
10
+ * Requires: 1.2.2+
11
+ */
12
+
13
+ (function($) {
14
+
15
+ var types = ['DOMMouseScroll', 'mousewheel'];
16
+
17
+ if ($.event.fixHooks) {
18
+ for ( var i=types.length; i; ) {
19
+ $.event.fixHooks[ types[--i] ] = $.event.mouseHooks;
20
+ }
21
+ }
22
+
23
+ $.event.special.mousewheel = {
24
+ setup: function() {
25
+ if ( this.addEventListener ) {
26
+ for ( var i=types.length; i; ) {
27
+ this.addEventListener( types[--i], handler, false );
28
+ }
29
+ } else {
30
+ this.onmousewheel = handler;
31
+ }
32
+ },
33
+
34
+ teardown: function() {
35
+ if ( this.removeEventListener ) {
36
+ for ( var i=types.length; i; ) {
37
+ this.removeEventListener( types[--i], handler, false );
38
+ }
39
+ } else {
40
+ this.onmousewheel = null;
41
+ }
42
+ }
43
+ };
44
+
45
+ $.fn.extend({
46
+ mousewheel: function(fn) {
47
+ return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
48
+ },
49
+
50
+ unmousewheel: function(fn) {
51
+ return this.unbind("mousewheel", fn);
52
+ }
53
+ });
54
+
55
+
56
+ function handler(event) {
57
+ var orgEvent = event || window.event, args = [].slice.call( arguments, 1 ), delta = 0, returnValue = true, deltaX = 0, deltaY = 0;
58
+ event = $.event.fix(orgEvent);
59
+ event.type = "mousewheel";
60
+
61
+ // Old school scrollwheel delta
62
+ if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta/120; }
63
+ if ( orgEvent.detail ) { delta = -orgEvent.detail/3; }
64
+
65
+ // New school multidimensional scroll (touchpads) deltas
66
+ deltaY = delta;
67
+
68
+ // Gecko
69
+ if ( orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
70
+ deltaY = 0;
71
+ deltaX = -1*delta;
72
+ }
73
+
74
+ // Webkit
75
+ if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY/120; }
76
+ if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = -1*orgEvent.wheelDeltaX/120; }
77
+
78
+ // Add event and delta to the front of the arguments
79
+ args.unshift(event, delta, deltaX, deltaY);
80
+
81
+ return ($.event.dispatch || $.event.handle).apply(this, args);
82
+ }
83
+
84
+ })(jQuery);
@@ -0,0 +1,828 @@
1
+ //= require jquery.mousewheel
2
+
3
+ (function($) {
4
+ $.fn.will_pickdate = function(opts) {
5
+ return this.each(function(index) {
6
+ if(!$.data(this, 'will_pickdate')) {
7
+ new will_pickdate(this, index, opts);
8
+ }
9
+ });
10
+ };
11
+
12
+ function will_pickdate(element, index, options) {
13
+ var init_clone_val;
14
+
15
+ this.element = $(element);
16
+
17
+ this.options = $.extend({
18
+ pickerClass: 'wpd',
19
+ days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
20
+ months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October',
21
+ 'November', 'December'],
22
+ dayShort: 2,
23
+ monthShort: 3,
24
+ startDay: 0, // Sunday (0) through Saturday (6) - be aware that this may affect your layout, since the days on
25
+ // the right might have a different margin
26
+ timePicker: true,
27
+ timePickerOnly: false,
28
+ yearPicker: true,
29
+ militaryTime: false,
30
+ yearsPerPage: 20,
31
+ format: 'F d, Y @ h:ia',
32
+ allowEmpty: false,
33
+ inputOutputFormat: 'S', // default to unix timestamp
34
+ animationDuration: 400,
35
+ useFadeInOut: !$.browser.msie, // dont animate fade-in/fade-out for IE
36
+ startView: 'month', // allowed values: {time, month, year, decades}
37
+ positionOffset: { x: 0, y: 0 },
38
+ minDate: null, // { date: '[date-string]', format: '[date-string-interpretation-format]' }
39
+ maxDate: null, // same as minDate
40
+ debug: false,
41
+ toggleElements: null,
42
+ initializeDate: null,
43
+
44
+ // and some event hooks:
45
+ onShow: $.noop, // triggered when will_pickdate pops up
46
+ onClose: $.noop, // triggered after will_pickdate is closed (destroyed)
47
+ onSelect: $.noop // triggered when a date is selected
48
+ }, options);
49
+
50
+ if(!this.options.initializeDate) {
51
+ this.options.initializeDate = new Date();
52
+ }
53
+
54
+ if(this.options.toggleElements != null && this.options.toggleElements.jquery) {
55
+ this.toggler = this.options.toggleElements.eq(index);
56
+
57
+ document.keydown($.proxy(function(event) {
58
+ if(event.which == 9) this.close(null, true);
59
+ }, this));
60
+ }
61
+
62
+ this.formatMinMaxDates();
63
+ $(document).mousedown($.proxy(this.close, this));
64
+
65
+ if (this.options.timePickerOnly) {
66
+ this.options.timePicker = true;
67
+ this.options.startView = 'time';
68
+ }
69
+
70
+ if(init_clone_val = this.element.val()) {
71
+ init_clone_val = this.format(new Date(this.unformat(init_clone_val, this.options.inputOutputFormat)),
72
+ this.options.format);
73
+ }
74
+ else if(!this.options.allowEmpty) {
75
+ init_clone_val = this.format(this.options.initializeDate, this.options.format);
76
+ this.element.val(this.format(this.options.initializeDate, this.options.inputOutputFormat));
77
+ }
78
+ else {
79
+ init_clone_val = '';
80
+ }
81
+
82
+ this.display = this.element.css('display');
83
+ this.clone = this.element
84
+ .css('display', this.options.debug ? this.display : 'none')
85
+ .data('will_pickdate', true)
86
+ .clone(true)
87
+ .data('will_pickdate', true)
88
+ .removeAttr('name')
89
+ .attr('id', this.element.attr('id') + '_display')
90
+ .css('display', this.display)
91
+ .val(init_clone_val);
92
+
93
+ this.element.before(this.clone);
94
+
95
+ if(this.toggler) {
96
+ this.toggler.css('cursor', 'pointer').click($.proxy(function(event) {
97
+ this.onFocus(this.element, this.clone);
98
+ }, this));
99
+
100
+ this.clone.blur($.proxy(function() {
101
+ this.element.val(this.clone.val());
102
+ }, this));
103
+ }
104
+ else {
105
+ this.clone.bind({
106
+ 'keydown': $.proxy(function(e) {
107
+ if(this.options.allowEmpty && (e.which == 46 || e.which == 8)) { // delete or backspace
108
+ this.element.val('');
109
+ $(e.target).val('');
110
+ this.close(null, true);
111
+ }
112
+ else if(e.which == 9 || e.which == 27) { // tab or esc
113
+ this.close(null, true);
114
+ }
115
+ else {
116
+ e.preventDefault();
117
+ }
118
+ }, this),
119
+ 'focus': $.proxy(function(e) {
120
+ this.onFocus(this.element, this.clone);
121
+ }, this)
122
+ });
123
+ }
124
+ }
125
+
126
+ will_pickdate.prototype = {
127
+ onFocus: function(original, visual_input) {
128
+ var init_visual_date;
129
+
130
+ if(init_visual_date = original.val()) {
131
+ init_visual_date = this.unformat(init_visual_date, this.options.inputOutputFormat).valueOf();
132
+ }
133
+ else {
134
+ init_visual_date = this.options.initializeDate;
135
+ if(this.options.maxDate && init_visual_date.valueOf() > this.options.maxDate.valueOf()) {
136
+ init_visual_date = new Date(this.options.maxDate.valueOf());
137
+ }
138
+ if(this.options.minDate && init_visual_date.valueOf() < this.options.minDate.valueOf()) {
139
+ init_visual_date = new Date(this.options.minDate.valueOf());
140
+ }
141
+ }
142
+
143
+ this.input = original, this.visual = visual_input;
144
+ this.show(init_visual_date);
145
+ },
146
+
147
+ dateToObject: function(d) {
148
+ return {
149
+ year: d.getFullYear(),
150
+ month: d.getMonth(),
151
+ day: d.getDate(),
152
+ hours: d.getHours(),
153
+ minutes: d.getMinutes(),
154
+ seconds: d.getSeconds()
155
+ }
156
+ },
157
+
158
+ dateFromObject: function(values) {
159
+ var d = this.options.initializeDate, v;
160
+ d.setDate(1);
161
+ $.each(['year', 'month', 'day', 'hours', 'minutes', 'seconds'], $.proxy(function(index, value) {
162
+ v = values[value];
163
+ if(!(v || v === 0)) return;
164
+ switch(value) {
165
+ case 'day': d.setDate(v); break;
166
+ case 'month': d.setMonth(v); break;
167
+ case 'year': d.setFullYear(v); break;
168
+ case 'hours': d.setHours(v); break;
169
+ case 'minutes': d.setMinutes(v); break;
170
+ case 'seconds': d.setSeconds(v); break;
171
+ }
172
+ }, this));
173
+
174
+ return d;
175
+ },
176
+
177
+ // Calculate position for picker. Returns object for use with css.
178
+ pickerPosition: function() {
179
+ // base position is top left corner of visual input plus offset specified by user options
180
+ var position = { left: this.visual.offset().left + this.options.positionOffset.x,
181
+ top: this.visual.offset().top + this.options.positionOffset.y },
182
+ docHeight = $(window).height(),
183
+ scrollTop = $(window).scrollTop(),
184
+ pickerHeight = this.picker.outerHeight(),
185
+ lowerDifference = Math.abs(docHeight - position.top + this.visual.outerHeight()),
186
+ upperDifference = position.top + scrollTop,
187
+ displayBelow = lowerDifference > pickerHeight,
188
+ displayAbove = upperDifference > pickerHeight;
189
+
190
+ if (!displayAbove && !displayBelow) {
191
+ // display at midpoint of available screen realestate
192
+ position.top = docHeight / 2 - pickerHeight / 2;
193
+ if (docHeight + scrollTop < pickerHeight) {
194
+ console.warn("will_pickdate: Not enough room to display date picker.")
195
+ }
196
+
197
+ } else if (displayBelow) {
198
+ // display below takes priority over display above
199
+ position.top += this.visual.outerHeight();
200
+ } else {
201
+ // display at offset above visual element
202
+ position.top -= pickerHeight;
203
+ }
204
+ return position;
205
+ },
206
+
207
+ show: function(timestamp) {
208
+ this.formatMinMaxDates();
209
+ if(timestamp) {
210
+ this.working_date = new Date(timestamp);
211
+ }
212
+ else {
213
+ this.working_date = this.options.initializeDate;
214
+ }
215
+ this.today = this.options.initializeDate;
216
+ this.choice = this.dateToObject(this.working_date);
217
+ this.mode = (this.options.startView == 'time' && !this.options.timePicker) ? 'month' : this.options.startView;
218
+
219
+ this.render();
220
+
221
+ this.picker.css(this.pickerPosition());
222
+
223
+ if($.isFunction(this.options.onShow))
224
+ this.options.onShow();
225
+ },
226
+
227
+ render: function(use_fx) {
228
+ if(!this.picker) {
229
+ this.constructPicker();
230
+ }
231
+ else {
232
+ var o = this.oldContents;
233
+ this.oldContents = this.newContents;
234
+ this.newContents = o;
235
+ this.newContents.empty();
236
+ }
237
+
238
+ var startDate = new Date(this.working_date.getTime());
239
+ this.limit = { right: false, left: false };
240
+
241
+ switch(this.mode) {
242
+ case 'decades': this.renderDecades(); break;
243
+ case 'year': this.renderYear(); break;
244
+ case 'time': this.renderTime(); this.limit = { right: true, left: true }; break;
245
+ default: this.renderMonth();
246
+ }
247
+
248
+ this.picker.find('.previous').toggleClass('disabled',this.limit.left);
249
+ this.picker.find('.next').toggleClass('disabled',this.limit.right);
250
+ this.picker.find('.title').css('cursor', this.allowZoomOut() ? 'pointer' : 'default');
251
+
252
+ this.working_date = startDate;
253
+
254
+ if(this.options.useFadeInOut) {
255
+ this.picker.fadeIn(this.options.animationDuration);
256
+ }
257
+
258
+ if(use_fx) this.fx(use_fx);
259
+ },
260
+
261
+ fx: function(effects) {
262
+ if(effects == 'right') {
263
+ this.oldContents.css('left',0).show();
264
+ this.newContents.css('left',this.bodyWidth).show();
265
+ this.slider.css('left',0).animate({'left':-this.bodyWidth});
266
+ }
267
+ else if(effects == 'left') {
268
+ this.oldContents.css('left',this.bodyWidth).show();
269
+ this.newContents.css('left',0).show();
270
+ this.slider.css('left',-this.bodyWidth).animate({'left':0});
271
+ }
272
+ else if(effects == 'fade') {
273
+ this.slider.css('left',0);
274
+ this.oldContents.css('left',0).fadeOut(this.options.animationDuration>>1);
275
+ this.newContents.css('left',0).hide().fadeIn(this.options.animationDuration);
276
+ }
277
+ },
278
+
279
+ constructPicker: function() {
280
+ $(document.body).append(this.picker = $('<div class="' + this.options.pickerClass + '" />'));
281
+ if(this.options.useFadeInOut) {
282
+ this.picker.hide();
283
+ }
284
+
285
+ var h, title_cont, b;
286
+
287
+ this.picker.append(h = $('<div class="header"/>'));
288
+ h.append(title_cont = $('<div class="title"/>').click($.proxy(this.zoomOut, this)));
289
+
290
+ h.append($('<div class="previous">&larr;</div>').click($.proxy(this.previous, this)));
291
+ h.append($('<div class="next">&rarr;</div>').click($.proxy(this.next, this)));
292
+ h.append($('<div class="closeButton">x</div>').click($.proxy(this.close, this)));
293
+ title_cont.append($('<span class="titleText"/>'));
294
+
295
+ this.picker.append(b = $('<div class="body"/>'));
296
+ this.bodyHeight = b.outerHeight();
297
+ this.bodyWidth = b.outerWidth();
298
+ b.append(this.slider = $('<div style="position:absolute;top:0;left:0;width:' + 2 * this.bodyWidth +
299
+ 'px;height:' + 2 * this.bodyHeight + 'px" />'));
300
+
301
+ this.slider.append(this.oldContents = $('<div style="position:absolute;top:0;left:' + this.bodyWidth +
302
+ 'px;width:' + this.bodyWidth + 'px;height:' + this.bodyHeight + 'px" />'));
303
+
304
+ this.slider.append(this.newContents = $('<div style="position:absolute;top:0;left:0;width:' +
305
+ this.bodyWidth + 'px;height:' + this.bodyHeight + 'px" />'));
306
+ },
307
+
308
+ renderDecades: function() {
309
+ while(this.working_date.getFullYear() % this.options.yearsPerPage > 0) {
310
+ this.working_date.setFullYear(this.working_date.getFullYear() - 1);
311
+ }
312
+
313
+ this.renderTitle(this.working_date.getFullYear() + '-' +
314
+ (this.working_date.getFullYear() + this.options.yearsPerPage - 1));
315
+
316
+ var i, y, e, available = false, container;
317
+
318
+ this.newContents.append(container = $('<div class="years"/>'));
319
+
320
+ if(this.options.minDate && this.working_date.getFullYear() <= this.options.minDate.getFullYear()) {
321
+ this.limit.left = true;
322
+ }
323
+
324
+ for(i = 0; i < this.options.yearsPerPage; i++) {
325
+ y = this.working_date.getFullYear();
326
+ container.append(e = $('<div class="year year' + i + (y == this.today.getFullYear() ? ' today' : '') +
327
+ (y == this.choice.year ? ' selected' : '') + '">' + y + '</>'));
328
+
329
+ if(this.limited('year')) {
330
+ e.addClass('unavailable');
331
+ if(available) {
332
+ this.limit.right = true;
333
+ }
334
+ else {
335
+ this.limit.left = true
336
+ }
337
+ }
338
+ else {
339
+ available = true;
340
+ e.click({year: y}, $.proxy(function(event) {
341
+ this.working_date.setFullYear(event.data.year);
342
+ this.mode = 'year';
343
+ this.render('fade');
344
+ }, this));
345
+ }
346
+ this.working_date.setFullYear(this.working_date.getFullYear() + 1);
347
+ }
348
+
349
+ if(!available ||
350
+ (this.options.maxDate && this.working_date.getFullYear() >= this.options.maxDate.getFullYear())) {
351
+ this.limit.right = true;
352
+ }
353
+ },
354
+
355
+ renderYear: function() {
356
+ var month = this.today.getMonth(),
357
+ this_year = this.working_date.getFullYear() == this.today.getFullYear(),
358
+ selected_year = this.working_date.getFullYear() == this.choice.year,
359
+ available = false,
360
+ container,
361
+ i,e;
362
+
363
+ this.renderTitle(this.working_date.getFullYear());
364
+ this.working_date.setMonth(0);
365
+
366
+ this.newContents.append(container = $('<div class="months"/>'));
367
+
368
+ for(i = 0; i<= 11; i++) {
369
+ container.append(e = $('<div class="month month' + (i+1) + (i==month && this_year ? ' today' : '') +
370
+ (i==this.choice.month && selected_year ? ' selected' : '') + '">' +
371
+ (this.options.monthShort ? this.options.months[i].substring(0, this.options.monthShort) :
372
+ this.options.months[i]) + '</div>'));
373
+
374
+ if(this.limited('month')) {
375
+ e.addClass('unavailable');
376
+ if(available) {
377
+ this.limit.right = true;
378
+ }
379
+ else {
380
+ this.limit.left = true;
381
+ }
382
+ }
383
+ else {
384
+ available = true;
385
+ e.click({month:i}, $.proxy(function(event) {
386
+ this.working_date.setDate(1);
387
+ this.working_date.setMonth(event.data.month);
388
+ this.mode = 'month';
389
+ this.render('fade');
390
+ }, this));
391
+ }
392
+ this.working_date.setMonth(i);
393
+ }
394
+ if(!available) this.limit.right = true;
395
+ },
396
+
397
+ hourShifter: function(event, d, dx, dy) {
398
+ event.preventDefault();
399
+ event.stopPropagation();
400
+
401
+ var i = $(event.target), v = parseInt(i.val(), 10);
402
+ i.focus();
403
+
404
+ if(this.options.militaryTime) {
405
+ if(dy > 0) {
406
+ v = (v < 23) ? v + 1 : 0;
407
+ }
408
+ else if(dy < 0) {
409
+ v = (v > 0) ? v - 1 : 23;
410
+ }
411
+ }
412
+ else {
413
+ var ampm = this.picker.find('.ampm');
414
+ if(dy > 0) {
415
+ if(v == 11) {
416
+ v = 12;
417
+ ampm.val(ampm.val() == 'AM' ? 'PM' : 'AM');
418
+ }
419
+ else if(v < 12) {
420
+ v++;
421
+ }
422
+ else {
423
+ v = 1;
424
+ }
425
+ }
426
+ else if (dy < 0) {
427
+ if(v == 12) {
428
+ v = 11;
429
+ ampm.val(ampm.val() == 'AM' ? 'PM' : 'AM');
430
+ }
431
+ else if(v > 1) {
432
+ v--;
433
+ }
434
+ else {
435
+ v = 12;
436
+ }
437
+ }
438
+ }
439
+
440
+ i.val(this.leadZero(v));
441
+ },
442
+
443
+ minuteShifter: function(event, d, dx, dy) {
444
+ event.preventDefault();
445
+ event.stopPropagation();
446
+
447
+ var i = $(event.target), v = parseInt(i.val(), 10);
448
+ i.focus();
449
+ if(dy > 0) {
450
+ v = (v < 59) ? v + 1 : 0;
451
+ }
452
+ else if(dy < 0) {
453
+ v = (v > 0) ? v - 1 : 59;
454
+ }
455
+
456
+ i.val(this.leadZero(v));
457
+ },
458
+
459
+ ampmShifter: function(event, d, dx, dy) {
460
+ event.preventDefault();
461
+ event.stopPropagation();
462
+
463
+ var i = $(event.target);
464
+ i.focus();
465
+
466
+ if(dy > 0 || dy < 0) {
467
+ i.val(i.val() == "AM" ? "PM" : "AM");
468
+ }
469
+ },
470
+
471
+ keyWrapper: function(f, event) {
472
+ dy = 0;
473
+ if(event.which == 38) {
474
+ dy = 1;
475
+ } else if (event.which = 40) {
476
+ dy = -1;
477
+ }
478
+ $.proxy(f, this)(event, null, null, dy);
479
+ },
480
+
481
+ renderTime: function() {
482
+ var container;
483
+
484
+ this.newContents.append(container = $('<div class="time"/>'));
485
+
486
+ if(this.options.timePickerOnly) {
487
+ this.renderTitle('Select a time');
488
+ }
489
+ else {
490
+ this.renderTitle(this.format(this.working_date, 'j M, Y'));
491
+ }
492
+
493
+ container.append($('<input type="text" class="hour"' + (this.options.militaryTime ? ' style="left:30px"' : '') +
494
+ ' maxlength="2" value="' +
495
+ this.leadZero(this.options.militaryTime ?
496
+ this.working_date.getHours() :
497
+ (this.working_date.getHours() > 12 ? this.working_date.getHours() - 12 :
498
+ this.working_date.getHours())) + '"/>')
499
+ .on('keydown', $.proxy(this.keyWrapper, this, this.hourShifter))
500
+ .mousewheel($.proxy(this.hourShifter, this)));
501
+
502
+ container.append($('<input type="text" class="minutes"' + (this.options.militaryTime ? ' style="left:110px"' : '') + ' maxlength="2" value="' +
503
+ this.leadZero(this.working_date.getMinutes()) + '"/>')
504
+ .on('keydown', $.proxy(this.keyWrapper, this, this.minuteShifter))
505
+ .mousewheel($.proxy(this.minuteShifter, this)));
506
+
507
+ container.append($('<div class="separator"' + (this.options.militaryTime ? ' style="left:91px"' : '') + '>:</div>'));
508
+
509
+ if(!this.options.militaryTime) {
510
+ container.append($('<input type="text" class="ampm" maxlength="2" value="' +
511
+ (this.working_date.getHours() >= 12 ? "PM" : "AM") + '"/>')
512
+ .on('keydown', $.proxy(this.keyWrapper, this, this.ampmShifter))
513
+ .mousewheel($.proxy(this.ampmShifter)));
514
+ }
515
+
516
+ container.append($('<input type="submit" value="OK" class="ok"/>').click($.proxy(function(event) {
517
+ event.stopPropagation();
518
+
519
+ var parsedHours = parseInt(this.picker.find('.hour').val(), 10);
520
+ if(!this.options.militaryTime){
521
+ parsedHours = parsedHours === 12 ? 0 : parsedHours;
522
+ }
523
+
524
+ this.select($.extend(this.dateToObject(this.working_date),
525
+ {
526
+ hours: parsedHours + (!this.options.militaryTime && this.picker.find('.ampm').val() == "PM" ? 12 : 0),
527
+ minutes: parseInt(this.picker.find('.minutes').val(), 10)
528
+ }));
529
+ }, this)));
530
+ },
531
+
532
+ renderMonth: function() {
533
+ var month = this.working_date.getMonth(),
534
+ container = $('<div class="days"/>'),
535
+ titles = $('<div class="titles"/>'),
536
+ available = false,
537
+ t = this.today.toDateString(),
538
+ currentChoice = this.dateFromObject(this.choice).toDateString(),
539
+ d, i, classes, e, weekContainer;
540
+ this.renderTitle(this.options.months[month] + ' ' + this.working_date.getFullYear());
541
+
542
+ this.working_date.setDate(1);
543
+ while(this.working_date.getDay() != this.options.startDay) {
544
+ this.working_date.setDate(this.working_date.getDate() - 1);
545
+ }
546
+
547
+ this.newContents.append(container.append(titles));
548
+
549
+ for(d = this.options.startDay; d < (this.options.startDay + 7); d++) {
550
+ titles.append($('<div class="title day day' + (d % 7) + '">' +
551
+ this.options.days[(d % 7)].substring(0,this.options.dayShort) + '</div>'));
552
+ }
553
+
554
+ for(i=0;i<42;i++) {
555
+ classes = ['day', 'day' + this.working_date.getDay()];
556
+ if(this.working_date.toDateString() == t) classes.push('today');
557
+ if(this.working_date.toDateString() == currentChoice) classes.push('selected');
558
+ if(this.working_date.getMonth() != month) classes.push('otherMonth');
559
+
560
+ if(i%7 == 0) {
561
+ container.append(weekContainer = $('<div class="week week' + Math.floor(i/7) + '"/>'));
562
+ }
563
+
564
+ weekContainer.append(e = $('<div class="' + classes.join(' ') + '">' + this.working_date.getDate() + '</div>'));
565
+ if(this.limited('date')) {
566
+ e.addClass('unavailable');
567
+ if(available) {
568
+ this.limit.right = true;
569
+ }
570
+ else if(this.working_date.getMonth() == month) {
571
+ this.limit.left = true;
572
+ }
573
+ }
574
+ else {
575
+ available = true;
576
+ e.click({day: this.working_date.getDate(), month: this.working_date.getMonth(),
577
+ year: this.working_date.getFullYear()},
578
+ $.proxy(function(event) {
579
+ if(this.options.timePicker) {
580
+ this.working_date.setDate(event.data.day);
581
+ this.working_date.setMonth(event.data.month);
582
+ this.mode = 'time';
583
+ this.render('fade');
584
+ }
585
+ else {
586
+ this.select(event.data);
587
+ }
588
+ }, this));
589
+ }
590
+ this.working_date.setDate(this.working_date.getDate() + 1);
591
+ }
592
+
593
+ if(!available) this.limit.right = true;
594
+ },
595
+
596
+ renderTitle: function(text){
597
+ if(this.allowZoomOut()){
598
+ this.picker.find('.title').removeClass('disabled');
599
+ }else{
600
+ this.picker.find('.title').addClass('disabled');
601
+ }
602
+ this.picker.find('.titleText').text(text);
603
+ },
604
+
605
+ limited: function(type) {
606
+ var cs = !!this.options.minDate,
607
+ ce = !!this.options.maxDate;
608
+
609
+ if(!(cs || ce)) return false;
610
+
611
+ switch(type) {
612
+ case 'year':
613
+ return (cs && this.working_date.getFullYear() < this.options.minDate.getFullYear()) ||
614
+ (ce && this.working_date.getFullYear() > this.options.maxDate.getFullYear());
615
+
616
+ case 'month':
617
+ var ms = parseInt('' + this.working_date.getFullYear() + this.leadZero(this.working_date.getMonth()), 10);
618
+ return cs && ms < parseInt('' + this.options.minDate.getFullYear() +
619
+ this.leadZero(this.options.minDate.getMonth()), 10) || ce && ms >
620
+ parseInt('' + this.options.maxDate.getFullYear() + this.leadZero(this.options.maxDate.getMonth()), 10);
621
+
622
+ case 'date':
623
+ return (cs && this.working_date < this.options.minDate) || (ce && this.working_date > this.options.maxDate);
624
+ }
625
+ },
626
+
627
+ allowZoomOut: function() {
628
+ if (this.mode == 'time' && this.options.timePickerOnly) return false;
629
+ if (this.mode == 'decades') return false;
630
+ return !(this.mode == 'year' && !this.options.yearPicker);
631
+ },
632
+
633
+ zoomOut: function() {
634
+ if(!this.allowZoomOut()) return;
635
+ switch(this.mode) {
636
+ case 'year': this.mode = 'decades'; break;
637
+ case 'time': this.mode = 'month'; break;
638
+ default: this.mode = 'year';
639
+ }
640
+ this.render('fade');
641
+ },
642
+
643
+ previous: function() {
644
+ switch(this.mode) {
645
+ case 'decades':
646
+ this.working_date.setFullYear(this.working_date.getFullYear() - this.options.yearsPerPage); break;
647
+ case 'year':
648
+ this.working_date.setFullYear(this.working_date.getFullYear() - 1); break;
649
+ case 'month':
650
+ this.working_date.setMonth(this.working_date.getMonth() - 1);
651
+ }
652
+ if(this.mode != 'time'){
653
+ this.render('left');
654
+ }
655
+
656
+ },
657
+
658
+ next: function() {
659
+ switch(this.mode) {
660
+ case 'decades':
661
+ this.working_date.setFullYear(this.working_date.getFullYear() + this.options.yearsPerPage); break;
662
+ case 'year':
663
+ this.working_date.setFullYear(this.working_date.getFullYear() + 1); break;
664
+ case 'month':
665
+ this.working_date.setMonth(this.working_date.getMonth() + 1);
666
+ }
667
+ if (this.mode !='time'){
668
+ this.render('right');
669
+ }
670
+ },
671
+
672
+ close: function(e, force) {
673
+ if(!this.picker || this.closing) return;
674
+
675
+ if(force || (e && e.target != this.picker && this.picker.has(e.target).size() == 0 &&
676
+ e.target != this.visual)) {
677
+
678
+ this.element.blur();
679
+ if(this.options.useFadeInOut) {
680
+ this.closing = true;
681
+ this.picker.fadeOut(this.options.animationDuration >> 1, $.proxy(this.destroy, this));
682
+ }
683
+ else {
684
+ this.destroy();
685
+ }
686
+ }
687
+ },
688
+
689
+ destroy: function() {
690
+ this.picker.remove();
691
+ this.picker = null;
692
+ this.closing = false;
693
+ if($.isFunction(this.options.onClose)) this.options.onClose();
694
+ },
695
+
696
+ select: function(values) {
697
+ this.working_date = this.dateFromObject($.extend(this.choice, values));
698
+ this.input.val(this.format(this.working_date, this.options.inputOutputFormat)).change();
699
+ this.visual.val(this.format(this.working_date, this.options.format));
700
+ if($.isFunction(this.options.onSelect)) this.options.onSelect(this.working_date);
701
+ this.close(null, true);
702
+ },
703
+
704
+ formatMinMaxDates: function() {
705
+ if (this.options.minDate && this.options.minDate.format) {
706
+ this.options.minDate = this.unformat(this.options.minDate.date, this.options.minDate.format);
707
+ }
708
+ if (this.options.maxDate && this.options.maxDate.format) {
709
+ this.options.maxDate = this.unformat(this.options.maxDate.date, this.options.maxDate.format);
710
+ this.options.maxDate.setHours(23);
711
+ this.options.maxDate.setMinutes(59);
712
+ this.options.maxDate.setSeconds(59);
713
+ }
714
+ },
715
+
716
+ leadZero: function(v) {
717
+ return v < 10 ? '0'+v : v;
718
+ },
719
+
720
+ format: function(t, format) {
721
+ var f = '',
722
+ h = t.getHours(),
723
+ m = t.getMonth();
724
+
725
+ for (var i = 0; i < format.length; i++) {
726
+ switch(format.charAt(i)) {
727
+ case '\\': i++; f+= format.charAt(i); break;
728
+ case 'y': f += (100 + t.getYear() + '').substring(1); break;
729
+ case 'Y': f += t.getFullYear(); break;
730
+ case 'm': f += this.leadZero(m + 1); break;
731
+ case 'n': f += (m + 1); break;
732
+ case 'M': f += this.options.months[m].substring(0,this.options.monthShort); break;
733
+ case 'F': f += this.options.months[m]; break;
734
+ case 'd': f += this.leadZero(t.getDate()); break;
735
+ case 'j': f += t.getDate(); break;
736
+ case 'D': f += this.options.days[t.getDay()].substring(0,this.options.dayShort); break;
737
+ case 'l': f += this.options.days[t.getDay()]; break;
738
+ case 'G': f += h; break;
739
+ case 'H': f += this.leadZero(h); break;
740
+ case 'g': f += (h % 12 ? h % 12 : 12); break;
741
+ case 'h': f += this.leadZero(h % 12 ? h % 12 : 12); break;
742
+ case 'a': f += (h > 11 ? 'pm' : 'am'); break;
743
+ case 'A': f += (h > 11 ? 'PM' : 'AM'); break;
744
+ case 'i': f += this.leadZero(t.getMinutes()); break;
745
+ case 's': f += this.leadZero(t.getSeconds()); break;
746
+ case 'U': f += Math.floor(t.valueOf() / 1000); break;
747
+ case 'S': f += t.toISOString(); break;
748
+ default: f += format.charAt(i);
749
+ }
750
+ }
751
+ return f;
752
+ },
753
+
754
+ unformat: function(t, format) {
755
+ var d = this.options.initializeDate,
756
+ a = {},
757
+ c,m,v;
758
+ t = t.toString();
759
+
760
+ for (var i = 0; i < format.length; i++) {
761
+ c = format.charAt(i);
762
+ switch(c) {
763
+ case '\\': r = null; i++; break;
764
+ case 'y': r = /^[0-9]{2}/; break;
765
+ case 'Y': r = /^[0-9]{4}/; break;
766
+ case 'm': r = /^0[1-9]|1[012]/; break;
767
+ case 'n': r = /^[1-9]|1[012]/; break;
768
+ case 'M': r = '^[A-Za-z]{'+this.options.monthShort+'}'; break;
769
+ case 'F': r = /[A-Za-z]+/; break;
770
+ case 'd': r = /^0[1-9]|[12][0-9]|3[01]/; break;
771
+ case 'j': r = /^[1-9]|[12][0-9]|3[01]/; break;
772
+ case 'D': r = '^[A-Za-z]{'+this.options.dayShort+'}'; break;
773
+ case 'l': r = /^[A-Za-z]+/; break;
774
+ case 'G':
775
+ case 'H':
776
+ case 'g':
777
+ case 'h': r = /^[0-9]{1,2}/; break;
778
+ case 'a': r = /^(am|pm)/; break;
779
+ case 'A': r = /^(AM|PM)/; break;
780
+ case 'i':
781
+ case 's': r = /^[012345][0-9]/; break;
782
+ case 'U': r = /^-?[0-9]+$/; break;
783
+ case 'S': r = /^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/; break;
784
+ default: r = null;
785
+ }
786
+
787
+ if (r) {
788
+ m = t.match(r);
789
+ if (m) {
790
+ a[c] = m[0];
791
+ t = t.substring(a[c].length);
792
+ } else {
793
+ if (this.options.debug) alert("Fatal Error in will_pickdate\n\nUnexpected format at: '"+t+"' expected format character '"+c+"' (pattern '"+r+"')");
794
+ return d;
795
+ }
796
+ } else {
797
+ t = t.substring(1);
798
+ }
799
+ }
800
+
801
+ for (c in a) {
802
+ v = a[c];
803
+ switch(c) {
804
+ case 'y': d.setFullYear(v < 30 ? 2000 + parseInt(v, 10) : 1900 + parseInt(v, 10)); break; // assume between 1930 - 2029
805
+ case 'Y': d.setFullYear(v); break;
806
+ case 'm':
807
+ case 'n': d.setMonth(v - 1); break;
808
+ // FALL THROUGH NOTICE! "M" has no break, because "v" now is the full month (eg. 'February'), which will work with the next format "F":
809
+ case 'M': v = this.options.months.filter(function(index) { return this.substring(0,this.options.monthShort) == v })[0];
810
+ case 'F': d.setMonth(options.months.indexOf(v)); break;
811
+ case 'd':
812
+ case 'j': d.setDate(v); break;
813
+ case 'G':
814
+ case 'H': d.setHours(v); break;
815
+ case 'g':
816
+ case 'h': if (a['a'] == 'pm' || a['A'] == 'PM') { d.setHours(v == 12 ? 0 : parseInt(v, 10) + 12); } else { d.setHours(v); } break;
817
+ case 'i': d.setMinutes(v); break;
818
+ case 's': d.setSeconds(v); break;
819
+ case 'U': d = new Date(parseInt(v, 10) * 1000); break;
820
+ case 'S': d = new Date(v);
821
+ }
822
+ }
823
+
824
+ return d;
825
+ }
826
+ };
827
+
828
+ })(jQuery);
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "will_pickdate/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "will_pickdate"
7
+ s.version = WillPickdate::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Fabio Batista"]
10
+ s.email = ["fbatista@webreakstuff.com"]
11
+ s.homepage = "http://github.com/fbatista/ruby_will_pickdate"
12
+ s.summary = "Gem wrapping of will_pickdate javascript widget"
13
+ s.description = "Ruby gem wrapping will_pickdate javascript widget giving support for rails datetime_select to render it instead of the usuall set of select boxes."
14
+
15
+ s.rubyforge_project = "will_pickdate"
16
+
17
+ s.add_development_dependency "rake"
18
+ s.add_development_dependency "test-unit"
19
+ s.add_development_dependency "activesupport"
20
+ s.add_development_dependency "actionpack"
21
+ s.add_development_dependency 'jquery-rails'
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.require_path = "lib"
25
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: will_pickdate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -99,13 +99,18 @@ executables: []
99
99
  extensions: []
100
100
  extra_rdoc_files: []
101
101
  files:
102
- - lib/will_pickdate/pickdate_builder.rb
103
- - lib/will_pickdate/version.rb
104
- - lib/will_pickdate.rb
102
+ - .gitignore
105
103
  - Gemfile
104
+ - Gemfile.lock
106
105
  - MIT-LICENSE
107
- - Rakefile
108
106
  - README.md
107
+ - Rakefile
108
+ - lib/will_pickdate.rb
109
+ - lib/will_pickdate/pickdate_builder.rb
110
+ - lib/will_pickdate/version.rb
111
+ - vendor/assets/javascripts/jquery.mousewheel.js
112
+ - vendor/assets/javascripts/will_pickdate.js
113
+ - will_pickdate.gemspec
109
114
  homepage: http://github.com/fbatista/ruby_will_pickdate
110
115
  licenses: []
111
116
  post_install_message: