combodate-rails 1.0.1 → 1.0.7

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6807459d342dc5eb711df015ed49e5c1037cee65
4
+ data.tar.gz: 566df1d8b8454adae4b7229fbc77e1972e371d30
5
+ SHA512:
6
+ metadata.gz: '090eb19579f3d223c1438635921f64ec52b873bb238e86d2e93a4f01795f3684d4a575a986b393245bac26ff9ca1da85effae58f9d8d0d4b542be797a27c2c9e'
7
+ data.tar.gz: 2d4ebc7fb40fbc5f2800ab172e01bf7e9c494eda4321269ed5c9cebea33a6fa30e1cd516ff3476ab5ce657676f0446c3c99df58aae2ae00664a15dec02f2775b
data/README.md CHANGED
@@ -4,7 +4,7 @@ combodate-rails wraps the [combodate.js](http://http://vitalets.github.com/combo
4
4
  for simple use with the asset pipeline provided by rails 3.1. The gem includes the development (non-minified)
5
5
  source for ease of exploration. The asset pipeline will minify in production.
6
6
 
7
- combodate.js is a plugin that "...converts <input> into dropdown elements to pick day, month, year, hour, minutes
7
+ combodate.js is a plugin that "...converts \<input> into dropdown elements to pick day, month, year, hour, minutes
8
8
  and seconds." Please see the [documentation](http://vitalets.github.com/combodate/#docs) for details.
9
9
 
10
10
  ## Usage
@@ -24,8 +24,9 @@ If you want to include a localization file, also add the following directive:
24
24
  ## Versioning
25
25
 
26
26
  combodate-rails 1.0.1 == combodate.js 1.0.1
27
+ combodate-rails 1.0.7 == combodate.js 1.0.7
27
28
 
28
29
  Every attempt is made to mirror the currently shipping combodate.js version number wherever possible.
29
- The major, minor, and patch version numbers will always represent the Momentum.js version. Should a gem
30
+ The major, minor, and patch version numbers will always represent the combodate.js version. Should a gem
30
31
  bug be discovered, a 4th version identifier will be added and incremented.
31
32
 
@@ -1,10 +1,20 @@
1
1
  /**
2
- * Combodate - 1.0.1
2
+ * Combodate - 1.0.7
3
3
  * Dropdown date and time picker.
4
4
  * Converts text input into dropdowns to pick day, month, year, hour, minute and second.
5
5
  * Uses momentjs as datetime library http://momentjs.com.
6
6
  * For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang
7
7
  *
8
+ * Confusion at noon and midnight - see http://en.wikipedia.org/wiki/12-hour_clock#Confusion_at_noon_and_midnight
9
+ * In combodate:
10
+ * 12:00 pm --> 12:00 (24-h format, midday)
11
+ * 12:00 am --> 00:00 (24-h format, midnight, start of day)
12
+ *
13
+ * Differs from momentjs parse rules:
14
+ * 00:00 pm, 12:00 pm --> 12:00 (24-h format, day not change)
15
+ * 00:00 am, 12:00 am --> 00:00 (24-h format, day not change)
16
+ *
17
+ *
8
18
  * Author: Vitaliy Potapov
9
19
  * Project page: http://github.com/vitalets/combodate
10
20
  * Copyright (c) 2012 Vitaliy Potapov. Released under MIT License.
@@ -40,16 +50,22 @@
40
50
  this.initCombos();
41
51
 
42
52
  //update original input on change
43
- this.$widget.on('change', 'select', $.proxy(function(){
44
- this.$element.val(this.getValue());
53
+ this.$widget.on('change', 'select', $.proxy(function(e) {
54
+ this.$element.val(this.getValue()).change();
55
+ // update days count if month or year changes
56
+ if (this.options.smartDays) {
57
+ if ($(e.target).is('.month') || $(e.target).is('.year')) {
58
+ this.fillCombo('day');
59
+ }
60
+ }
45
61
  }, this));
46
62
 
47
63
  this.$widget.find('select').css('width', 'auto');
48
64
 
49
- //hide original input and insert widget
65
+ // hide original input and insert widget
50
66
  this.$element.hide().after(this.$widget);
51
67
 
52
- //set initial value
68
+ // set initial value
53
69
  this.setValue(this.$element.val() || this.options.value);
54
70
  },
55
71
 
@@ -58,6 +74,7 @@
58
74
  */
59
75
  getTemplate: function() {
60
76
  var tpl = this.options.template;
77
+ var customClass = this.options.customClass;
61
78
 
62
79
  //first pass
63
80
  $.each(this.map, function(k, v) {
@@ -76,7 +93,7 @@
76
93
  v = v[0];
77
94
  var token = v.length > 1 ? v.substring(1, 2) : v;
78
95
 
79
- tpl = tpl.replace('{'+token+'}', '<select class="'+k+'"></select>');
96
+ tpl = tpl.replace('{'+token+'}', '<select class="'+k+' '+customClass+'"></select>');
80
97
  });
81
98
 
82
99
  return tpl;
@@ -86,25 +103,48 @@
86
103
  Initialize combos that presents in template
87
104
  */
88
105
  initCombos: function() {
89
- var that = this;
90
- $.each(this.map, function(k, v) {
91
- var $c = that.$widget.find('.'+k), f, items;
92
- if($c.length) {
93
- that['$'+k] = $c; //set properties like this.$day, this.$month etc.
94
- f = 'fill' + k.charAt(0).toUpperCase() + k.slice(1); //define method name to fill items, e.g `fillDays`
95
- items = that[f]();
96
- that['$'+k].html(that.renderItems(items));
97
- }
98
- });
106
+ for (var k in this.map) {
107
+ var $c = this.$widget.find('.'+k);
108
+ // set properties like this.$day, this.$month etc.
109
+ this['$'+k] = $c.length ? $c : null;
110
+ // fill with items
111
+ this.fillCombo(k);
112
+ }
99
113
  },
100
-
114
+
115
+ /*
116
+ Fill combo with items
117
+ */
118
+ fillCombo: function(k) {
119
+ var $combo = this['$'+k];
120
+ if (!$combo) {
121
+ return;
122
+ }
123
+
124
+ // define method name to fill items, e.g `fillDays`
125
+ var f = 'fill' + k.charAt(0).toUpperCase() + k.slice(1);
126
+ var items = this[f]();
127
+ var value = $combo.val();
128
+
129
+ $combo.empty();
130
+ for(var i=0; i<items.length; i++) {
131
+ $combo.append('<option value="'+items[i][0]+'">'+items[i][1]+'</option>');
132
+ }
133
+
134
+ $combo.val(value);
135
+ },
136
+
101
137
  /*
102
138
  Initialize items of combos. Handles `firstItem` option
103
139
  */
104
- initItems: function(key) {
105
- var values = [];
140
+ fillCommon: function(key) {
141
+ var values = [],
142
+ relTime;
143
+
106
144
  if(this.options.firstItem === 'name') {
107
- var header = typeof moment.relativeTime[key] === 'function' ? moment.relativeTime[key](1, true, key, false) : moment.relativeTime[key];
145
+ //need both to support moment ver < 2 and >= 2
146
+ relTime = moment.relativeTime || moment.langData()._relativeTime;
147
+ var header = typeof relTime[key] === 'function' ? relTime[key](1, true, key, false) : relTime[key];
108
148
  //take last entry (see momentjs lang files structure)
109
149
  header = header.split(' ').reverse()[0];
110
150
  values.push(['', header]);
@@ -112,27 +152,29 @@
112
152
  values.push(['', '']);
113
153
  }
114
154
  return values;
115
- },
116
-
117
- /*
118
- render items to string of <option> tags
119
- */
120
- renderItems: function(items) {
121
- var str = [];
122
- for(var i=0; i<items.length; i++) {
123
- str.push('<option value="'+items[i][0]+'">'+items[i][1]+'</option>');
124
- }
125
- return str.join("\n");
126
- },
155
+ },
156
+
127
157
 
128
158
  /*
129
159
  fill day
130
160
  */
131
161
  fillDay: function() {
132
- var items = this.initItems('d'), name, i,
133
- twoDigit = this.options.template.indexOf('DD') !== -1;
134
-
135
- for(i=1; i<=31; i++) {
162
+ var items = this.fillCommon('d'), name, i,
163
+ twoDigit = this.options.template.indexOf('DD') !== -1,
164
+ daysCount = 31;
165
+
166
+ // detect days count (depends on month and year)
167
+ // originally https://github.com/vitalets/combodate/pull/7
168
+ if (this.options.smartDays && this.$month && this.$year) {
169
+ var month = parseInt(this.$month.val(), 10);
170
+ var year = parseInt(this.$year.val(), 10);
171
+
172
+ if (!isNaN(month) && !isNaN(year)) {
173
+ daysCount = moment([year, month]).daysInMonth();
174
+ }
175
+ }
176
+
177
+ for (i = 1; i <= daysCount; i++) {
136
178
  name = twoDigit ? this.leadZero(i) : i;
137
179
  items.push([i, name]);
138
180
  }
@@ -143,16 +185,17 @@
143
185
  fill month
144
186
  */
145
187
  fillMonth: function() {
146
- var items = this.initItems('M'), name, i,
188
+ var items = this.fillCommon('M'), name, i,
147
189
  longNames = this.options.template.indexOf('MMMM') !== -1,
148
190
  shortNames = this.options.template.indexOf('MMM') !== -1,
149
191
  twoDigit = this.options.template.indexOf('MM') !== -1;
150
192
 
151
193
  for(i=0; i<=11; i++) {
152
194
  if(longNames) {
153
- name = moment.months[i];
195
+ //see https://github.com/timrwood/momentjs.com/pull/36
196
+ name = moment().date(1).month(i).format('MMMM');
154
197
  } else if(shortNames) {
155
- name = moment.monthsShort[i];
198
+ name = moment().date(1).month(i).format('MMM');
156
199
  } else if(twoDigit) {
157
200
  name = this.leadZero(i+1);
158
201
  } else {
@@ -167,13 +210,16 @@
167
210
  fill year
168
211
  */
169
212
  fillYear: function() {
170
- var items = this.initItems('y'), name, i,
213
+ var items = [], name, i,
171
214
  longNames = this.options.template.indexOf('YYYY') !== -1;
172
-
215
+
173
216
  for(i=this.options.maxYear; i>=this.options.minYear; i--) {
174
217
  name = longNames ? i : (i+'').substring(2);
175
- items.push([i, name]);
176
- }
218
+ items[this.options.yearDescending ? 'push' : 'unshift']([i, name]);
219
+ }
220
+
221
+ items = this.fillCommon('y').concat(items);
222
+
177
223
  return items;
178
224
  },
179
225
 
@@ -181,13 +227,14 @@
181
227
  fill hour
182
228
  */
183
229
  fillHour: function() {
184
- var items = this.initItems('h'), name, i,
230
+ var items = this.fillCommon('h'), name, i,
185
231
  h12 = this.options.template.indexOf('h') !== -1,
186
232
  h24 = this.options.template.indexOf('H') !== -1,
187
233
  twoDigit = this.options.template.toLowerCase().indexOf('hh') !== -1,
234
+ min = h12 ? 1 : 0,
188
235
  max = h12 ? 12 : 23;
189
236
 
190
- for(i=0; i<=max; i++) {
237
+ for(i=min; i<=max; i++) {
191
238
  name = twoDigit ? this.leadZero(i) : i;
192
239
  items.push([i, name]);
193
240
  }
@@ -198,7 +245,7 @@
198
245
  fill minute
199
246
  */
200
247
  fillMinute: function() {
201
- var items = this.initItems('m'), name, i,
248
+ var items = this.fillCommon('m'), name, i,
202
249
  twoDigit = this.options.template.indexOf('mm') !== -1;
203
250
 
204
251
  for(i=0; i<=59; i+= this.options.minuteStep) {
@@ -212,7 +259,7 @@
212
259
  fill second
213
260
  */
214
261
  fillSecond: function() {
215
- var items = this.initItems('s'), name, i,
262
+ var items = this.fillCommon('s'), name, i,
216
263
  twoDigit = this.options.template.indexOf('ss') !== -1;
217
264
 
218
265
  for(i=0; i<=59; i+= this.options.secondStep) {
@@ -234,9 +281,9 @@
234
281
  ];
235
282
  return items;
236
283
  },
237
-
284
+
238
285
  /*
239
- Returns current date value.
286
+ Returns current date value from combos.
240
287
  If format not specified - `options.format` used.
241
288
  If format = `null` - Moment object returned.
242
289
  */
@@ -265,12 +312,14 @@
265
312
  return '';
266
313
  }
267
314
 
268
- //convert hours if 12h format
315
+ //convert hours 12h --> 24h
269
316
  if(this.$ampm) {
270
- values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
271
- if(values.hour === 24) {
272
- values.hour = 0;
273
- }
317
+ //12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day)
318
+ if(values.hour === 12) {
319
+ values.hour = this.$ampm.val() === 'am' ? 0 : 12;
320
+ } else {
321
+ values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12;
322
+ }
274
323
  }
275
324
 
276
325
  dt = moment([values.year, values.month, values.day, values.hour, values.minute, values.second]);
@@ -291,35 +340,73 @@
291
340
  return;
292
341
  }
293
342
 
294
- var dt = typeof value === 'string' ? moment(value, this.options.format) : moment(value),
343
+ // parse in strict mode (third param `true`)
344
+ var dt = typeof value === 'string' ? moment(value, this.options.format, true) : moment(value),
295
345
  that = this,
296
346
  values = {};
297
347
 
348
+ //function to find nearest value in select options
349
+ function getNearest($select, value) {
350
+ var delta = {};
351
+ $select.children('option').each(function(i, opt){
352
+ var optValue = $(opt).attr('value'),
353
+ distance;
354
+
355
+ if(optValue === '') return;
356
+ distance = Math.abs(optValue - value);
357
+ if(typeof delta.distance === 'undefined' || distance < delta.distance) {
358
+ delta = {value: optValue, distance: distance};
359
+ }
360
+ });
361
+ return delta.value;
362
+ }
363
+
298
364
  if(dt.isValid()) {
299
- //read values from date object
300
- $.each(this.map, function(k, v) {
301
- if(k === 'ampm') {
302
- return;
303
- }
304
- values[k] = dt[v[1]]();
305
- });
365
+ //read values from date object
366
+ $.each(this.map, function(k, v) {
367
+ if(k === 'ampm') {
368
+ return;
369
+ }
370
+ values[k] = dt[v[1]]();
371
+ });
306
372
 
307
- if(this.$ampm) {
308
- if(values.hour > 12) {
309
- values.hour -= 12;
310
- values.ampm = 'pm';
311
- } else {
312
- values.ampm = 'am';
313
- }
314
- }
373
+ if(this.$ampm) {
374
+ //12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day)
375
+ if(values.hour >= 12) {
376
+ values.ampm = 'pm';
377
+ if(values.hour > 12) {
378
+ values.hour -= 12;
379
+ }
380
+ } else {
381
+ values.ampm = 'am';
382
+ if(values.hour === 0) {
383
+ values.hour = 12;
384
+ }
385
+ }
386
+ }
315
387
 
316
- $.each(values, function(k, v) {
317
- if(that['$'+k]) {
318
- that['$'+k].val(v);
319
- }
320
- });
388
+ $.each(values, function(k, v) {
389
+ //call val() for each existing combo, e.g. this.$hour.val()
390
+ if(that['$'+k]) {
391
+
392
+ if(k === 'minute' && that.options.minuteStep > 1 && that.options.roundTime) {
393
+ v = getNearest(that['$'+k], v);
394
+ }
395
+
396
+ if(k === 'second' && that.options.secondStep > 1 && that.options.roundTime) {
397
+ v = getNearest(that['$'+k], v);
398
+ }
399
+
400
+ that['$'+k].val(v);
401
+ }
402
+ });
403
+
404
+ // update days count
405
+ if (this.options.smartDays) {
406
+ this.fillCombo('day');
407
+ }
321
408
 
322
- this.$element.val(dt.format(this.options.format));
409
+ this.$element.val(dt.format(this.options.format)).change();
323
410
  }
324
411
  },
325
412
 
@@ -389,10 +476,14 @@
389
476
  value: null,
390
477
  minYear: 1970,
391
478
  maxYear: 2015,
479
+ yearDescending: true,
392
480
  minuteStep: 5,
393
481
  secondStep: 1,
394
482
  firstItem: 'empty', //'name', 'empty', 'none'
395
- errorClass: null
483
+ errorClass: null,
484
+ customClass: '',
485
+ roundTime: true, // whether to round minutes and seconds if step > 1
486
+ smartDays: false // whether days in combo depend on selected month: 31, 30, 28
396
487
  };
397
488
 
398
489
  }(window.jQuery));
metadata CHANGED
@@ -1,49 +1,44 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: combodate-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
5
- prerelease:
4
+ version: 1.0.7
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ruurd Pels
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-01-16 00:00:00.000000000 Z
11
+ date: 2016-12-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: momentjs-rails
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: 1.7.2
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
26
  version: 1.7.2
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: railties
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ~>
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
33
  version: '3.1'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ~>
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
40
  version: '3.1'
46
- description: ! "\tCombodate is a javascript library for entering dates/times.\n\tIt
41
+ description: "\tCombodate is a javascript library for entering dates/times.\n\tIt
47
42
  depends on momentjs-rails that is included as a dependency.\n This gem allows
48
43
  for its easy inclusion into the rails asset pipeline.\n"
49
44
  email:
@@ -51,33 +46,32 @@ executables: []
51
46
  extensions: []
52
47
  extra_rdoc_files: []
53
48
  files:
54
- - lib/combodate-rails.rb
55
- - vendor/assets/javascripts/combodate.js
56
- - changelog.md
57
49
  - MIT-LICENSE
58
50
  - README.md
51
+ - changelog.md
52
+ - lib/combodate-rails.rb
53
+ - vendor/assets/javascripts/combodate.js
59
54
  homepage: https://github.com/ruurd/combodate-rails
60
55
  licenses: []
56
+ metadata: {}
61
57
  post_install_message:
62
58
  rdoc_options: []
63
59
  require_paths:
64
60
  - lib
65
61
  required_ruby_version: !ruby/object:Gem::Requirement
66
- none: false
67
62
  requirements:
68
- - - ! '>='
63
+ - - ">="
69
64
  - !ruby/object:Gem::Version
70
65
  version: '0'
71
66
  required_rubygems_version: !ruby/object:Gem::Requirement
72
- none: false
73
67
  requirements:
74
- - - ! '>='
68
+ - - ">="
75
69
  - !ruby/object:Gem::Version
76
70
  version: '0'
77
71
  requirements: []
78
72
  rubyforge_project:
79
- rubygems_version: 1.8.24
73
+ rubygems_version: 2.5.2
80
74
  signing_key:
81
- specification_version: 3
75
+ specification_version: 4
82
76
  summary: The Combodate JavaScript library ready to play with Rails.
83
77
  test_files: []