kalendae_assets 0.2.1 → 0.4.1

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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Zjk4ODFiYmI5ZjVkZTc2ZjRlNDk5ZGU4OTI1ZDFiMGJmNmEzNWNlYQ==
5
+ data.tar.gz: !binary |-
6
+ ZDRhNGVkYWNlYjZmMWNjMmIxMzU3NTM4MjRiNjZlNTQyY2I5ZmMwZQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YzUxODcyOWM4MDdmYjI5OTdjNzA5YTRiODZmOWNlYTJkNWM0ZTQzN2QyNDUy
10
+ OTRmNWMxMjU0NDY2ZjVhOWE1NDA5NTFlNDUzNDM5ZjZkODdlOTczZDlkYTNi
11
+ N2MwZTk0ZTc3ZDY1MGM4M2FhYmRjZGQ0ODhjNWEzNzk1Y2ZhMzg=
12
+ data.tar.gz: !binary |-
13
+ NGU5YjBlY2U0YzQwZDNmMmYyOTIyZjI2ODFiM2M4NWM5Mjk0MjA1ZGIyZDkz
14
+ MzBlMDRkYWJjZTIzOWNiZmQwYTQxYjNhYmQ5NDg0ZGU1NjhhMzkyM2MyMDc3
15
+ NjA0MjJhOTkyODcwZmRlNDY0MGEzYjZjZTViNGZiNjQwZDhjYmM=
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  .config
5
5
  .yardoc
6
6
  Gemfile.lock
7
+ gemfiles/*.lock
7
8
  InstalledFiles
8
9
  _yardoc
9
10
  coverage
@@ -2,3 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
4
  - rbx-19mode
5
+ gemfile:
6
+ - gemfiles/rails_3.gemfile
7
+ - gemfiles/rails_4.0.gemfile
8
+ - gemfiles/rails_4.1.gemfile
@@ -0,0 +1,11 @@
1
+ appraise 'rails-3' do
2
+ gem 'rails', '~> 3.1'
3
+ end
4
+
5
+ appraise 'rails-4.0' do
6
+ gem 'rails', '~> 4.0.0'
7
+ end
8
+
9
+ appraise 'rails-4.1' do
10
+ gem 'rails', '~> 4.1.0'
11
+ end
data/README.md CHANGED
@@ -5,7 +5,11 @@
5
5
 
6
6
  **Step 1**
7
7
 
8
- Load `kalendae_assets` in your `Gemfile` as part of the `assets` group
8
+ Load `kalendae_assets` in your `Gemfile`. In Rails 4, don't put it in a group:
9
+
10
+ gem 'kalendae_assets'
11
+
12
+ In Rails 3, place it in the `assets` group:
9
13
 
10
14
  group :assets do
11
15
  gem 'kalendae_assets'
@@ -19,6 +23,12 @@ Run 'bundle install'
19
23
 
20
24
  Require `kalendae.js` in your Javascript manifest (e.g. `application.js`)
21
25
 
26
+ //= require kalendae.standalone
27
+
28
+ The standalone version bundles a copy of of moment.js. If you already have
29
+ moment.js in your app, you can use the non-standalone version to keep your
30
+ assets smaller:
31
+
22
32
  //= require kalendae
23
33
 
24
34
  **Step 4**
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 3.1"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.0.0"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 4.1.0"
6
+
7
+ gemspec :path => "../"
@@ -14,7 +14,8 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "kalendae_assets"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = KalendaeAssets::VERSION
17
- gem.add_dependency 'rails', '~> 3.1'
17
+ gem.add_dependency 'rails', '>= 3.1'
18
+ gem.add_development_dependency 'appraisal'
18
19
  gem.add_development_dependency 'sqlite3'
19
20
  gem.add_development_dependency 'minitest'
20
21
  gem.add_development_dependency 'capybara'
@@ -1,3 +1,3 @@
1
1
  module KalendaeAssets
2
- VERSION = "0.2.1"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -30,8 +30,10 @@ Dummy::Application.configure do
30
30
  config.action_mailer.delivery_method = :test
31
31
 
32
32
  # Raise exception on mass assignment protection for Active Record models
33
- config.active_record.mass_assignment_sanitizer = :strict
33
+ config.active_record.mass_assignment_sanitizer = :strict if Rails::VERSION::MAJOR < 4
34
34
 
35
35
  # Print deprecation notices to the stderr
36
36
  config.active_support.deprecation = :stderr
37
+
38
+ config.eager_load = true
37
39
  end
@@ -12,5 +12,9 @@ class IntegrationTest < MiniTest::Spec
12
12
  register_spec_type(/integration$/, self)
13
13
  end
14
14
 
15
- Turn.config.format = :pretty
16
- Turn.config.natural = true
15
+ unless Rails.version.to_f > 4
16
+ require 'turn'
17
+
18
+ Turn.config.format = :pretty
19
+ Turn.config.natural = true
20
+ end
@@ -1,17 +1,26 @@
1
1
  /********************************************************************
2
2
  * Kalendae, a framework agnostic javascript date picker *
3
- * Copyright(c) 2012 Jarvis Badgley (chipersoft@gmail.com) *
3
+ * Copyright(c) 2013 Jarvis Badgley (chipersoft@gmail.com) *
4
4
  * http://github.com/ChiperSoft/Kalendae *
5
- * Version 0.2 *
5
+ * Version 0.4.1 *
6
6
  ********************************************************************/
7
7
 
8
8
  (function (undefined) {
9
9
 
10
- var today;
10
+ var today, moment;
11
11
 
12
12
  var Kalendae = function (targetElement, options) {
13
+ if (typeof document.addEventListener !== 'function' && !util.isIE8()) return;
14
+
13
15
  //if the first argument isn't an element and isn't a string, assume that it is the options object
14
- if (!(targetElement instanceof Element || typeof targetElement === 'string')) options = targetElement;
16
+ var is_element = false;
17
+ try {
18
+ is_element = targetElement instanceof Element;
19
+ }
20
+ catch (err) {
21
+ is_element = !!targetElement && is_element.nodeType === 1;
22
+ }
23
+ if (!(is_element || typeof(targetElement) === 'string')) options = targetElement;
15
24
 
16
25
  var self = this,
17
26
  classes = self.classes,
@@ -35,7 +44,7 @@ var Kalendae = function (targetElement, options) {
35
44
  //generate the column headers (Su, Mo, Tu, etc)
36
45
  i = 7;
37
46
  while (i--) {
38
- columnHeaders.push( startDay.format('ddd').substr(0,opts.columnHeaderLength) );
47
+ columnHeaders.push( startDay.format(opts.columnHeaderFormat) );
39
48
  startDay.add('days',1);
40
49
  }
41
50
 
@@ -62,11 +71,11 @@ var Kalendae = function (targetElement, options) {
62
71
  self.viewStartDate = vsd.date(1);
63
72
 
64
73
  var viewDelta = ({
65
- 'past' : opts.months-1,
66
- 'today-past' : opts.months-1,
67
- 'any' : opts.months>2?Math.floor(opts.months/2):0,
68
- 'today-future' : 0,
69
- 'future' : 0
74
+ 'past' : opts.months-1,
75
+ 'today-past' : opts.months-1,
76
+ 'any' : opts.months>2?Math.floor(opts.months/2):0,
77
+ 'today-future' : 0,
78
+ 'future' : 0
70
79
  })[this.settings.direction];
71
80
 
72
81
 
@@ -78,16 +87,16 @@ var Kalendae = function (targetElement, options) {
78
87
  if (typeof opts.blackout === 'function') {
79
88
  self.blackout = opts.blackout;
80
89
  } else if (!!opts.blackout) {
81
- var bdates = parseDates(opts.blackout, opts.parseSplitDelimiter);
90
+ var bdates = parseDates(opts.blackout, opts.parseSplitDelimiter, opts.format);
82
91
  self.blackout = function (input) {
83
92
  input = moment(input).yearDay();
84
- if (input < 1 || !self._sel || self._sel.length < 1) return false;
93
+ if (input < 1 || !self._sel) return false;
85
94
  var i = bdates.length;
86
95
  while (i--) if (bdates[i].yearDay() === input) return true;
87
96
  return false;
88
- }
97
+ };
89
98
  } else {
90
- self.blackout = function () {return false;}
99
+ self.blackout = function () {return false;};
91
100
  }
92
101
 
93
102
 
@@ -108,11 +117,14 @@ var Kalendae = function (targetElement, options) {
108
117
 
109
118
  //title bar
110
119
  $title = util.make('div', {'class':classes.title}, $cal);
111
- util.make('a', {'class':classes.previousYear}, $title); //previous button
112
- util.make('a', {'class':classes.previousMonth}, $title); //previous button
113
- util.make('a', {'class':classes.nextYear}, $title); //next button
114
- util.make('a', {'class':classes.nextMonth}, $title); //next button
115
- $caption = util.make('span', {'class':classes.caption}, $title); //title caption
120
+ if(!opts.useYearNav){
121
+ util.addClassName($title, classes.disableYearNav);
122
+ }
123
+ util.make('a', {'class':classes.previousYear}, $title); //previous button
124
+ util.make('a', {'class':classes.previousMonth}, $title); //previous button
125
+ util.make('a', {'class':classes.nextYear}, $title); //next button
126
+ util.make('a', {'class':classes.nextMonth}, $title); //next button
127
+ $caption = util.make('span', {'class':classes.caption}, $title); //title caption
116
128
 
117
129
  //column headers
118
130
  $header = util.make('div', {'class':classes.header}, $cal);
@@ -120,7 +132,7 @@ var Kalendae = function (targetElement, options) {
120
132
  do {
121
133
  $span = util.make('span', {}, $header);
122
134
  $span.innerHTML = columnHeaders[i];
123
- } while (++i < 7)
135
+ } while (++i < 7);
124
136
 
125
137
  //individual day cells
126
138
  $days = util.make('div', {'class':classes.days}, $cal);
@@ -212,52 +224,56 @@ var Kalendae = function (targetElement, options) {
212
224
 
213
225
  Kalendae.prototype = {
214
226
  defaults : {
215
- attachTo: null, /* the element to attach the root container to. can be string or DOMElement */
216
- months: 1, /* total number of months to display side by side */
217
- weekStart: 0, /* day to use for the start of the week. 0 is Sunday */
218
- direction: 'any', /* past, today-past, any, today-future, future */
219
- directionScrolling: true, /* if a direction other than any is defined, prevent scrolling out of range */
220
- viewStartDate: null, /* date in the month to display. When multiple months, this is the left most */
221
- blackout: null, /* array of dates, or function to be passed a date */
222
- selected: null, /* dates already selected. can be string, date, or array of strings or dates. */
223
- mode: 'single', /* single, multiple, range */
224
- format: null, /* string used for parsing dates. */
225
- subscribe: null, /* object containing events to subscribe to */
226
-
227
- columnHeaderLength: 2, /* number of characters to show in the column headers */
228
- titleFormat: 'MMMM, YYYY', /* format mask for month titles. See momentjs.com for rules */
229
- dayNumberFormat: 'D', /* format mask for individual days */
230
- dayAttributeFormat: 'YYYY-MM-DD', /* format mask for the data-date attribute set on every span */
231
- parseSplitDelimiter: /,\s*|\s+-\s+/, /* regex to use for splitting multiple dates from a passed string */
232
- rangeDelimiter: ' - ', /* string to use between dates when outputting in range mode */
233
- multipleDelimiter: ', ', /* string to use between dates when outputting in multiple mode */
234
-
235
- dateClassMap: {}
227
+ attachTo :null, /* the element to attach the root container to. can be string or DOMElement */
228
+ months :1, /* total number of months to display side by side */
229
+ weekStart :0, /* day to use for the start of the week. 0 is Sunday */
230
+ direction :'any', /* past, today-past, any, today-future, future */
231
+ directionScrolling :true, /* if a direction other than any is defined, prevent scrolling out of range */
232
+ viewStartDate :null, /* date in the month to display. When multiple months, this is the left most */
233
+ blackout :null, /* array of dates, or function to be passed a date */
234
+ selected :null, /* dates already selected. can be string, date, or array of strings or dates. */
235
+ mode :'single', /* single, multiple, range */
236
+ dayOutOfMonthClickable:false,
237
+ format :null, /* string used for parsing dates. */
238
+ subscribe :null, /* object containing events to subscribe to */
239
+
240
+ columnHeaderFormat :'dd', /* number of characters to show in the column headers */
241
+ titleFormat :'MMMM, YYYY', /* format mask for month titles. See momentjs.com for rules */
242
+ dayNumberFormat :'D', /* format mask for individual days */
243
+ dayAttributeFormat :'YYYY-MM-DD', /* format mask for the data-date attribute set on every span */
244
+ parseSplitDelimiter : /,\s*|\s+-\s+/, /* regex to use for splitting multiple dates from a passed string */
245
+ rangeDelimiter :' - ', /* string to use between dates when outputting in range mode */
246
+ multipleDelimiter :', ', /* string to use between dates when outputting in multiple mode */
247
+ useYearNav :true,
248
+
249
+ dateClassMap :{}
236
250
  },
237
251
  classes : {
238
- container :'kalendae',
239
- calendar :'k-calendar',
240
- monthFirst :'k-first-month',
241
- monthMiddle :'k-middle-month',
242
- monthLast :'k-last-month',
243
- title :'k-title',
244
- previousMonth :'k-btn-previous-month',
245
- nextMonth :'k-btn-next-month',
246
- previousYear :'k-btn-previous-year',
247
- nextYear :'k-btn-next-year',
248
- caption :'k-caption',
249
- header :'k-header',
250
- days :'k-days',
251
- dayOutOfMonth :'k-out-of-month',
252
- dayActive :'k-active',
253
- daySelected :'k-selected',
254
- dayInRange :'k-range',
255
- dayToday :'k-today',
256
- monthSeparator :'k-separator',
257
- disablePreviousMonth :'k-disable-previous-month-btn',
258
- disableNextMonth :'k-disable-next-month-btn',
259
- disablePreviousYear :'k-disable-previous-year-btn',
260
- disableNextYear :'k-disable-next-year-btn'
252
+ container :'kalendae',
253
+ calendar :'k-calendar',
254
+ monthFirst :'k-first-month',
255
+ monthMiddle :'k-middle-month',
256
+ monthLast :'k-last-month',
257
+ title :'k-title',
258
+ previousMonth :'k-btn-previous-month',
259
+ nextMonth :'k-btn-next-month',
260
+ previousYear :'k-btn-previous-year',
261
+ nextYear :'k-btn-next-year',
262
+ caption :'k-caption',
263
+ header :'k-header',
264
+ days :'k-days',
265
+ dayOutOfMonth :'k-out-of-month',
266
+ dayInMonth :'k-in-month',
267
+ dayActive :'k-active',
268
+ daySelected :'k-selected',
269
+ dayInRange :'k-range',
270
+ dayToday :'k-today',
271
+ monthSeparator :'k-separator',
272
+ disablePreviousMonth :'k-disable-previous-month-btn',
273
+ disableNextMonth :'k-disable-next-month-btn',
274
+ disablePreviousYear :'k-disable-previous-year-btn',
275
+ disableNextYear :'k-disable-next-year-btn',
276
+ disableYearNav :'k-disable-year-nav'
261
277
  },
262
278
 
263
279
  disablePreviousMonth: false,
@@ -266,11 +282,11 @@ Kalendae.prototype = {
266
282
  disableNextYear: false,
267
283
 
268
284
  directions: {
269
- 'past' :function (date) {return moment(date).yearDay() >= today.yearDay();},
270
- 'today-past' :function (date) {return moment(date).yearDay() > today.yearDay();},
271
- 'any' :function (date) {return false;},
272
- 'today-future' :function (date) {return moment(date).yearDay() < today.yearDay();},
273
- 'future' :function (date) {return moment(date).yearDay() <= today.yearDay();}
285
+ 'past' :function (date) {return moment(date).yearDay() >= today.yearDay();},
286
+ 'today-past' :function (date) {return moment(date).yearDay() > today.yearDay();},
287
+ 'any' :function (date) {return false;},
288
+ 'today-future' :function (date) {return moment(date).yearDay() < today.yearDay();},
289
+ 'future' :function (date) {return moment(date).yearDay() <= today.yearDay();}
274
290
  },
275
291
 
276
292
  getSelectedAsDates : function () {
@@ -286,7 +302,7 @@ Kalendae.prototype = {
286
302
  var out = [];
287
303
  var i=0, c = this._sel.length;
288
304
  for (;i<c;i++) {
289
- out.push(this._sel[i].format(format || this.settings.format || 'YYYY-MM-DD'))
305
+ out.push(this._sel[i].format(format || this.settings.format || 'YYYY-MM-DD'));
290
306
  }
291
307
  return out;
292
308
  },
@@ -295,7 +311,7 @@ Kalendae.prototype = {
295
311
  var out = [];
296
312
  var i=0, c = this._sel.length;
297
313
  for (;i<c;i++) {
298
- out.push(moment(this._sel[i]))
314
+ out.push(moment(this._sel[i]));
299
315
  }
300
316
  return out;
301
317
  },
@@ -352,14 +368,24 @@ Kalendae.prototype = {
352
368
  },
353
369
 
354
370
  setSelected : function (input, draw) {
355
- this._sel = parseDates(input, this.settings.parseSplitDelimiter, this.settings.format);
356
- this._sel.sort(function (a,b) {return a.yearDay() - b.yearDay();});
371
+ var i,
372
+ new_dates = parseDates(input, this.settings.parseSplitDelimiter, this.settings.format),
373
+ old_dates = parseDates(this.getSelected(), this.settings.parseSplitDelimiter, this.settings.format);
374
+
375
+ i = old_dates.length;
376
+ while(i--) { this.removeSelected(old_dates[i], draw); }
377
+
378
+ i = new_dates.length;
379
+ while(i--) { this.addSelected(new_dates[i], draw); }
357
380
 
358
381
  if (draw !== false) this.draw();
359
382
  },
360
383
 
361
384
  addSelected : function (date, draw) {
362
- date = moment(date).hours(12);
385
+ date = moment(date, this.settings.format).hours(12);
386
+
387
+ if(this.settings.dayOutOfMonthClickable && this.settings.mode !== 'range'){ this.makeSelectedDateVisible(date); }
388
+
363
389
  switch (this.settings.mode) {
364
390
  case 'multiple':
365
391
  if (!this.isSelected(date)) this._sel.push(date);
@@ -380,18 +406,29 @@ Kalendae.prototype = {
380
406
  break;
381
407
  }
382
408
  this._sel.sort(function (a,b) {return a.yearDay() - b.yearDay();});
383
- this.publish('change', this);
409
+ this.publish('change', this, [date]);
384
410
  if (draw !== false) this.draw();
385
411
  return true;
386
412
  },
387
413
 
414
+ makeSelectedDateVisible: function (date) {
415
+ outOfViewMonth = moment(date).date('1').diff(this.viewStartDate,'months');
416
+
417
+ if(outOfViewMonth < 0){
418
+ this.viewStartDate.subtract('months',1);
419
+ }
420
+ else if(outOfViewMonth > 0 && outOfViewMonth >= this.settings.months){
421
+ this.viewStartDate.add('months',1);
422
+ }
423
+ },
424
+
388
425
  removeSelected : function (date, draw) {
389
- date = moment(date).yearDay();
426
+ date = moment(date, this.settings.format).hours(12);
390
427
  var i = this._sel.length;
391
428
  while (i--) {
392
- if (this._sel[i].yearDay() === date) {
429
+ if (this._sel[i].yearDay() === date.yearDay()) {
393
430
  this._sel.splice(i,1);
394
- this.publish('change', this);
431
+ this.publish('change', this, [date]);
395
432
  if (draw !== false) this.draw();
396
433
  return true;
397
434
  }
@@ -411,7 +448,8 @@ Kalendae.prototype = {
411
448
  j=0, k,
412
449
  s,
413
450
  dateString,
414
- opts = this.settings;
451
+ opts = this.settings,
452
+ diff;
415
453
 
416
454
  c = this.calendars.length;
417
455
 
@@ -433,7 +471,9 @@ Kalendae.prototype = {
433
471
  if (s) klass.push(({'-1':classes.dayInRange,'1':classes.daySelected, 'true':classes.daySelected})[s]);
434
472
 
435
473
  if (day.month() != month.month()) klass.push(classes.dayOutOfMonth);
436
- else if (!(this.blackout(day) || this.direction(day)) || s>0) klass.push(classes.dayActive);
474
+ else klass.push(classes.dayInMonth);
475
+
476
+ if (!(this.blackout(day) || this.direction(day) || (day.month() != month.month() && opts.dayOutOfMonthClickable === false)) || s>0) klass.push(classes.dayActive);
437
477
 
438
478
  if (day.yearDay() === today.yearDay()) klass.push(classes.dayToday);
439
479
 
@@ -451,9 +491,8 @@ Kalendae.prototype = {
451
491
  } while (++i < c);
452
492
 
453
493
  if (opts.directionScrolling) {
454
- var diff = -(moment().diff(month, 'months'));
455
494
  if (opts.direction==='today-past' || opts.direction==='past') {
456
-
495
+ diff = month.add({m:1}).diff(moment(), 'months', true);
457
496
  if (diff <= 0) {
458
497
  this.disableNextMonth = false;
459
498
  util.removeClassName(this.container, classes.disableNextMonth);
@@ -463,7 +502,7 @@ Kalendae.prototype = {
463
502
  }
464
503
 
465
504
  } else if (opts.direction==='today-future' || opts.direction==='future') {
466
-
505
+ diff = month.subtract({m:1}).diff(moment(), 'months', true);
467
506
  if (diff > opts.months) {
468
507
  this.disablePreviousMonth = false;
469
508
  util.removeClassName(this.container, classes.disablePreviousMonth);
@@ -476,7 +515,8 @@ Kalendae.prototype = {
476
515
 
477
516
 
478
517
  if (opts.direction==='today-past' || opts.direction==='past') {
479
- if (month.add({Y:1}).diff(moment(), 'years') < 0) {
518
+ diff = month.add({m:12}).diff(moment(), 'months', true);
519
+ if (diff <= -11) {
480
520
  this.disableNextYear = false;
481
521
  util.removeClassName(this.container, classes.disableNextYear);
482
522
  } else {
@@ -485,7 +525,8 @@ Kalendae.prototype = {
485
525
  }
486
526
 
487
527
  } else if (opts.direction==='today-future' || opts.direction==='future') {
488
- if (month.subtract({Y:1}).diff(moment(), 'years') > 0) {
528
+ diff = month.subtract({m:12}).diff(moment(), 'months', true);
529
+ if (diff > (11 + opts.months)) {
489
530
  this.disablePreviousYear = false;
490
531
  util.removeClassName(this.container, classes.disablePreviousYear);
491
532
  } else {
@@ -497,7 +538,7 @@ Kalendae.prototype = {
497
538
 
498
539
  }
499
540
  }
500
- }
541
+ };
501
542
 
502
543
  var parseDates = function (input, delimiter, format) {
503
544
  var output = [];
@@ -508,14 +549,15 @@ var parseDates = function (input, delimiter, format) {
508
549
  input = [input];
509
550
  }
510
551
 
511
- var c = input.length;
512
- i = 0;
552
+ var c = input.length,
553
+ i = 0;
554
+
513
555
  do {
514
556
  if (input[i]) output.push( moment(input[i], format).hours(12) );
515
557
  } while (++i < c);
516
558
 
517
559
  return output;
518
- }
560
+ };
519
561
 
520
562
 
521
563
 
@@ -524,7 +566,7 @@ window.Kalendae = Kalendae;
524
566
  var util = Kalendae.util = {
525
567
 
526
568
  isIE8: function() {
527
- return !!( (/msie 8./i).test(navigator.appVersion) && !(/opera/i).test(navigator.userAgent) && window.ActiveXObject && XDomainRequest && !window.msPerformance );
569
+ return !!( (/msie 8./i).test(navigator.appVersion) && !(/opera/i).test(navigator.userAgent) && window.ActiveXObject && XDomainRequest && !window.msPerformance );
528
570
  },
529
571
 
530
572
  // ELEMENT FUNCTIONS
@@ -620,6 +662,14 @@ var util = Kalendae.util = {
620
662
  return false;
621
663
  },
622
664
 
665
+ scrollContainer: function (elem) {
666
+ do {
667
+ var overflow = util.getStyle(elem, 'overflow');
668
+ if (overflow === 'auto' || overflow === 'scroll') return elem;
669
+ } while ((elem = elem.parentNode) && elem != window.document.body);
670
+ return null;
671
+ },
672
+
623
673
  getPosition: function (elem, isInner) {
624
674
  var x = elem.offsetLeft,
625
675
  y = elem.offsetTop,
@@ -673,7 +723,7 @@ var util = Kalendae.util = {
673
723
  else a[k] = b[k];
674
724
  }
675
725
  return a;
676
- }
726
+ };
677
727
 
678
728
  for (; i < arguments.length; i++) {
679
729
  _c(d, arguments[i]);
@@ -682,45 +732,45 @@ var util = Kalendae.util = {
682
732
  },
683
733
 
684
734
  isArray: function (array) {
685
- return !(
686
- !array ||
687
- (!array.length || array.length === 0) ||
688
- typeof array !== 'object' ||
689
- !array.constructor ||
690
- array.nodeType ||
691
- array.item
692
- );
735
+ return Object.prototype.toString.call(array) == "[object Array]"
693
736
  }
694
737
  };
695
738
 
696
739
 
697
740
  //auto-initializaiton code
698
- Kalendae.util.domReady(function () {
741
+ if (typeof document.addEventListener === 'function') Kalendae.util.domReady(function () {
699
742
  var els = util.$$('.auto-kal'),
700
743
  i = els.length,
701
- e;
744
+ e,
745
+ options,
746
+ optionsRaw;
702
747
 
703
748
  while (i--) {
704
749
  e = els[i];
750
+ optionsRaw = e.getAttribute('data-kal');
751
+ options = (optionsRaw == null || optionsRaw == "") ? {} : (new Function('return {' + optionsRaw + '};'))();
752
+
705
753
  if (e.tagName === 'INPUT') {
706
754
  //if element is an input, bind a popup calendar to the input.
707
- new Kalendae.Input(e);
755
+ new Kalendae.Input(e, options);
708
756
  } else {
709
757
  //otherwise, insert a flat calendar into the element.
710
- new Kalendae({attachTo:e});
758
+ new Kalendae(util.merge(options, {attachTo:e}));
711
759
  }
712
760
 
713
761
  }
714
762
  });
715
-
716
763
  Kalendae.Input = function (targetElement, options) {
764
+ if (typeof document.addEventListener !== 'function' && !util.isIE8()) return;
765
+
717
766
  var $input = this.input = util.$(targetElement),
718
- overwriteInput;
767
+ overwriteInput,
768
+ $closeButton;
719
769
 
720
770
  if (!$input || $input.tagName !== 'INPUT') throw "First argument for Kalendae.Input must be an <input> element or a valid element id.";
721
771
 
722
772
  var self = this,
723
- classes = self.classes
773
+ classes = self.classes,
724
774
  opts = self.settings = util.merge(self.defaults, options);
725
775
 
726
776
  //force attachment to the body
@@ -735,7 +785,7 @@ Kalendae.Input = function (targetElement, options) {
735
785
 
736
786
  //create the close button
737
787
  if (opts.closeButton) {
738
- var $closeButton = util.make('a', {'class':classes.closeButton}, self.container)
788
+ $closeButton = util.make('a', {'class':classes.closeButton}, self.container);
739
789
  util.addEvent($closeButton, 'click', function () {
740
790
  $input.blur();
741
791
  });
@@ -762,7 +812,7 @@ Kalendae.Input = function (targetElement, options) {
762
812
  });
763
813
 
764
814
  util.addEvent($input, 'blur', function () {
765
- if (noclose) {
815
+ if (noclose && util.isIE8()) {
766
816
  noclose = false;
767
817
  $input.focus();
768
818
  }
@@ -772,6 +822,16 @@ Kalendae.Input = function (targetElement, options) {
772
822
  self.setSelected(this.value);
773
823
  });
774
824
 
825
+ var $scrollContainer = util.scrollContainer($input);
826
+
827
+ if( $scrollContainer ) {
828
+
829
+ // Hide calendar when $scrollContainer is scrolled
830
+ util.addEvent($scrollContainer, 'scroll', function (event) {
831
+ $input.blur();
832
+ });
833
+ }
834
+
775
835
  self.subscribe('change', function () {
776
836
  $input.value = self.getSelected();
777
837
  });
@@ -795,36 +855,41 @@ Kalendae.Input.prototype = util.merge(Kalendae.prototype, {
795
855
  var $container = this.container,
796
856
  style = $container.style,
797
857
  $input = this.input,
798
- pos = util.getPosition($input);
858
+ pos = util.getPosition($input),
859
+ $scrollContainer = util.scrollContainer($input),
860
+ scrollTop = $scrollContainer ? $scrollContainer.scrollTop : 0,
861
+ opts = this.settings;
799
862
 
800
863
  style.display = '';
801
864
  switch (opts.side) {
802
865
  case 'left':
803
- style.left = (pos.left - util.getWidth($container) + this.settings.offsetLeft) + 'px';
804
- style.top = (pos.top + this.settings.offsetTop) + 'px';
866
+ style.left = (pos.left - util.getWidth($container) + opts.offsetLeft) + 'px';
867
+ style.top = (pos.top + opts.offsetTop - scrollTop) + 'px';
805
868
  break;
806
869
  case 'right':
807
870
  style.left = (pos.left + util.getWidth($input)) + 'px';
808
- style.top = (pos.top + this.settings.offsetTop) + 'px';
871
+ style.top = (pos.top + opts.offsetTop - scrollTop) + 'px';
809
872
  break;
810
873
  case 'top':
811
- style.left = (pos.left + this.settings.offsetLeft) + 'px';
812
- style.top = (pos.top - util.getHeight($container) + this.settings.offsetTop) + 'px';
874
+ style.left = (pos.left + opts.offsetLeft) + 'px';
875
+ style.top = (pos.top - util.getHeight($container) + opts.offsetTop - scrollTop) + 'px';
813
876
  break;
814
877
  case 'bottom':
815
878
  /* falls through */
816
879
  default:
817
- style.left = (pos.left + this.settings.offsetLeft) + 'px';
818
- style.top = (pos.top + util.getHeight($input) + this.settings.offsetTop) + 'px';
880
+ style.left = (pos.left + opts.offsetLeft) + 'px';
881
+ style.top = (pos.top + util.getHeight($input) + opts.offsetTop - scrollTop) + 'px';
819
882
  break;
820
883
  }
821
884
 
822
885
  style.position = util.isFixed($input) ? 'fixed' : 'absolute';
823
886
 
887
+ this.publish('show', this);
824
888
  },
825
889
 
826
890
  hide : function () {
827
891
  this.container.style.display = 'none';
892
+ this.publish('hide', this);
828
893
  }
829
894
 
830
895
  });
@@ -916,736 +981,22 @@ var MinPubSub = function(d){
916
981
  }
917
982
  };
918
983
 
919
- };// moment.js
920
- // Altered slightly for use in Kalendae.js
921
- // version : 1.5.0
922
- // author : Tim Wood
923
- // license : MIT
924
- // momentjs.com
925
-
926
- var moment = Kalendae.moment = (function (Date, undefined) {
927
-
928
- var moment,
929
- round = Math.round,
930
- languages = {},
931
- hasModule = (typeof module !== 'undefined'),
932
- paramsToParse = 'months|monthsShort|monthsParse|weekdays|weekdaysShort|longDateFormat|calendar|relativeTime|ordinal|meridiem'.split('|'),
933
- i,
934
- jsonRegex = /^\/?Date\((\-?\d+)/i,
935
- charactersToReplace = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|dddd?|do?|w[o|w]?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|zz?|ZZ?|LT|LL?L?L?)/g,
936
- nonuppercaseLetters = /[^A-Z]/g,
937
- timezoneRegex = /\([A-Za-z ]+\)|:[0-9]{2} [A-Z]{3} /g,
938
- tokenCharacters = /(\\)?(MM?M?M?|dd?d?d|DD?D?D?|YYYY|YY|a|A|hh?|HH?|mm?|ss?|ZZ?|T)/g,
939
- inputCharacters = /(\\)?([0-9]+|([a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+|([\+\-]\d\d:?\d\d))/gi,
940
- isoRegex = /\d{4}.\d\d.\d\d(T(\d\d(.\d\d(.\d\d)?)?)?([\+\-]\d\d:?\d\d)?)?/,
941
- isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
942
- isoTimes = [
943
- ['HH:mm:ss', /T\d\d:\d\d:\d\d/],
944
- ['HH:mm', /T\d\d:\d\d/],
945
- ['HH', /T\d\d/]
946
- ],
947
- timezoneParseRegex = /([\+\-]|\d\d)/gi,
948
- VERSION = "1.5.0",
949
- shortcuts = 'Month|Date|Hours|Minutes|Seconds|Milliseconds'.split('|');
950
-
951
- // Moment prototype object
952
- function Moment(date, isUTC) {
953
- this._d = date;
954
- this._isUTC = !!isUTC;
955
- }
956
-
957
- // left zero fill a number
958
- // see http://jsperf.com/left-zero-filling for performance comparison
959
- function leftZeroFill(number, targetLength) {
960
- var output = number + '';
961
- while (output.length < targetLength) {
962
- output = '0' + output;
963
- }
964
- return output;
965
- }
966
-
967
- // helper function for _.addTime and _.subtractTime
968
- function dateAddRemove(date, _input, adding, val) {
969
- var isString = (typeof _input === 'string'),
970
- input = isString ? {} : _input,
971
- ms, d, M, currentDate;
972
- if (isString && val) {
973
- input[_input] = +val;
974
- }
975
- ms = (input.ms || input.milliseconds || 0) +
976
- (input.s || input.seconds || 0) * 1e3 + // 1000
977
- (input.m || input.minutes || 0) * 6e4 + // 1000 * 60
978
- (input.h || input.hours || 0) * 36e5; // 1000 * 60 * 60
979
- d = (input.d || input.days || 0) +
980
- (input.w || input.weeks || 0) * 7;
981
- M = (input.M || input.months || 0) +
982
- (input.y || input.years || 0) * 12;
983
- if (ms) {
984
- date.setTime(+date + ms * adding);
985
- }
986
- if (d) {
987
- date.setDate(date.getDate() + d * adding);
988
- }
989
- if (M) {
990
- currentDate = date.getDate();
991
- date.setDate(1);
992
- date.setMonth(date.getMonth() + M * adding);
993
- date.setDate(Math.min(new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(), currentDate));
994
- }
995
- return date;
996
- }
997
-
998
- // check if is an array
999
- function isArray(input) {
1000
- return Object.prototype.toString.call(input) === '[object Array]';
1001
- }
1002
-
1003
- // convert an array to a date.
1004
- // the array should mirror the parameters below
1005
- // note: all values past the year are optional and will default to the lowest possible value.
1006
- // [year, month, day , hour, minute, second, millisecond]
1007
- function dateFromArray(input) {
1008
- return new Date(input[0], input[1] || 0, input[2] || 1, input[3] || 0, input[4] || 0, input[5] || 0, input[6] || 0);
1009
- }
1010
-
1011
- // format date using native date object
1012
- function formatMoment(m, inputString) {
1013
- var currentMonth = m.month(),
1014
- currentDate = m.date(),
1015
- currentYear = m.year(),
1016
- currentDay = m.day(),
1017
- currentHours = m.hours(),
1018
- currentMinutes = m.minutes(),
1019
- currentSeconds = m.seconds(),
1020
- currentZone = -m.zone(),
1021
- ordinal = moment.ordinal,
1022
- meridiem = moment.meridiem;
1023
- // check if the character is a format
1024
- // return formatted string or non string.
1025
- //
1026
- // uses switch/case instead of an object of named functions (like http://phpjs.org/functions/date:380)
1027
- // for minification and performance
1028
- // see http://jsperf.com/object-of-functions-vs-switch for performance comparison
1029
- function replaceFunction(input) {
1030
- // create a couple variables to be used later inside one of the cases.
1031
- var a, b;
1032
- switch (input) {
1033
- // MONTH
1034
- case 'M' :
1035
- return currentMonth + 1;
1036
- case 'Mo' :
1037
- return (currentMonth + 1) + ordinal(currentMonth + 1);
1038
- case 'MM' :
1039
- return leftZeroFill(currentMonth + 1, 2);
1040
- case 'MMM' :
1041
- return moment.monthsShort[currentMonth];
1042
- case 'MMMM' :
1043
- return moment.months[currentMonth];
1044
- // DAY OF MONTH
1045
- case 'D' :
1046
- return currentDate;
1047
- case 'Do' :
1048
- return currentDate + ordinal(currentDate);
1049
- case 'DD' :
1050
- return leftZeroFill(currentDate, 2);
1051
- // DAY OF YEAR
1052
- case 'DDD' :
1053
- a = new Date(currentYear, currentMonth, currentDate);
1054
- b = new Date(currentYear, 0, 1);
1055
- return ~~ (((a - b) / 864e5) + 1.5);
1056
- case 'DDDo' :
1057
- a = replaceFunction('DDD');
1058
- return a + ordinal(a);
1059
- case 'DDDD' :
1060
- return leftZeroFill(replaceFunction('DDD'), 3);
1061
- // WEEKDAY
1062
- case 'd' :
1063
- return currentDay;
1064
- case 'do' :
1065
- return currentDay + ordinal(currentDay);
1066
- case 'ddd' :
1067
- return moment.weekdaysShort[currentDay];
1068
- case 'dddd' :
1069
- return moment.weekdays[currentDay];
1070
- // WEEK OF YEAR
1071
- case 'w' :
1072
- a = new Date(currentYear, currentMonth, currentDate - currentDay + 5);
1073
- b = new Date(a.getFullYear(), 0, 4);
1074
- return ~~ ((a - b) / 864e5 / 7 + 1.5);
1075
- case 'wo' :
1076
- a = replaceFunction('w');
1077
- return a + ordinal(a);
1078
- case 'ww' :
1079
- return leftZeroFill(replaceFunction('w'), 2);
1080
- // YEAR
1081
- case 'YY' :
1082
- return leftZeroFill(currentYear % 100, 2);
1083
- case 'YYYY' :
1084
- return currentYear;
1085
- // AM / PM
1086
- case 'a' :
1087
- return currentHours > 11 ? meridiem.pm : meridiem.am;
1088
- case 'A' :
1089
- return currentHours > 11 ? meridiem.PM : meridiem.AM;
1090
- // 24 HOUR
1091
- case 'H' :
1092
- return currentHours;
1093
- case 'HH' :
1094
- return leftZeroFill(currentHours, 2);
1095
- // 12 HOUR
1096
- case 'h' :
1097
- return currentHours % 12 || 12;
1098
- case 'hh' :
1099
- return leftZeroFill(currentHours % 12 || 12, 2);
1100
- // MINUTE
1101
- case 'm' :
1102
- return currentMinutes;
1103
- case 'mm' :
1104
- return leftZeroFill(currentMinutes, 2);
1105
- // SECOND
1106
- case 's' :
1107
- return currentSeconds;
1108
- case 'ss' :
1109
- return leftZeroFill(currentSeconds, 2);
1110
- // TIMEZONE
1111
- case 'zz' :
1112
- // depreciating 'zz' fall through to 'z'
1113
- case 'z' :
1114
- return (m._d.toString().match(timezoneRegex) || [''])[0].replace(nonuppercaseLetters, '');
1115
- case 'Z' :
1116
- return (currentZone < 0 ? '-' : '+') + leftZeroFill(~~(Math.abs(currentZone) / 60), 2) + ':' + leftZeroFill(~~(Math.abs(currentZone) % 60), 2);
1117
- case 'ZZ' :
1118
- return (currentZone < 0 ? '-' : '+') + leftZeroFill(~~(10 * Math.abs(currentZone) / 6), 4);
1119
- // LONG DATES
1120
- case 'L' :
1121
- case 'LL' :
1122
- case 'LLL' :
1123
- case 'LLLL' :
1124
- case 'LT' :
1125
- return formatMoment(m, moment.longDateFormat[input]);
1126
- // DEFAULT
1127
- default :
1128
- return input.replace(/(^\[)|(\\)|\]$/g, "");
1129
- }
1130
- }
1131
- return inputString.replace(charactersToReplace, replaceFunction);
1132
- }
1133
-
1134
- // date from string and format string
1135
- function makeDateFromStringAndFormat(string, format) {
1136
- var inArray = [0, 0, 1, 0, 0, 0, 0],
1137
- timezoneHours = 0,
1138
- timezoneMinutes = 0,
1139
- isUsingUTC = false,
1140
- inputParts = string.match(inputCharacters),
1141
- formatParts = format.match(tokenCharacters),
1142
- len = Math.min(inputParts.length, formatParts.length),
1143
- i,
1144
- isPm;
1145
-
1146
- // function to convert string input to date
1147
- function addTime(format, input) {
1148
- var a;
1149
- switch (format) {
1150
- // MONTH
1151
- case 'M' :
1152
- // fall through to MM
1153
- case 'MM' :
1154
- inArray[1] = ~~input - 1;
1155
- break;
1156
- case 'MMM' :
1157
- // fall through to MMMM
1158
- case 'MMMM' :
1159
- for (a = 0; a < 12; a++) {
1160
- if (moment.monthsParse[a].test(input)) {
1161
- inArray[1] = a;
1162
- break;
1163
- }
1164
- }
1165
- break;
1166
- // DAY OF MONTH
1167
- case 'D' :
1168
- // fall through to DDDD
1169
- case 'DD' :
1170
- // fall through to DDDD
1171
- case 'DDD' :
1172
- // fall through to DDDD
1173
- case 'DDDD' :
1174
- inArray[2] = ~~input;
1175
- break;
1176
- // YEAR
1177
- case 'YY' :
1178
- input = ~~input;
1179
- inArray[0] = input + (input > 70 ? 1900 : 2000);
1180
- break;
1181
- case 'YYYY' :
1182
- inArray[0] = ~~Math.abs(input);
1183
- break;
1184
- // AM / PM
1185
- case 'a' :
1186
- // fall through to A
1187
- case 'A' :
1188
- isPm = (input.toLowerCase() === 'pm');
1189
- break;
1190
- // 24 HOUR
1191
- case 'H' :
1192
- // fall through to hh
1193
- case 'HH' :
1194
- // fall through to hh
1195
- case 'h' :
1196
- // fall through to hh
1197
- case 'hh' :
1198
- inArray[3] = ~~input;
1199
- break;
1200
- // MINUTE
1201
- case 'm' :
1202
- // fall through to mm
1203
- case 'mm' :
1204
- inArray[4] = ~~input;
1205
- break;
1206
- // SECOND
1207
- case 's' :
1208
- // fall through to ss
1209
- case 'ss' :
1210
- inArray[5] = ~~input;
1211
- break;
1212
- // TIMEZONE
1213
- case 'Z' :
1214
- // fall through to ZZ
1215
- case 'ZZ' :
1216
- isUsingUTC = true;
1217
- a = (input || '').match(timezoneParseRegex);
1218
- if (a && a[1]) {
1219
- timezoneHours = ~~a[1];
1220
- }
1221
- if (a && a[2]) {
1222
- timezoneMinutes = ~~a[2];
1223
- }
1224
- // reverse offsets
1225
- if (a && a[0] === '+') {
1226
- timezoneHours = -timezoneHours;
1227
- timezoneMinutes = -timezoneMinutes;
1228
- }
1229
- break;
1230
- }
1231
- }
1232
- for (i = 0; i < len; i++) {
1233
- addTime(formatParts[i], inputParts[i]);
1234
- }
1235
- // handle am pm
1236
- if (isPm && inArray[3] < 12) {
1237
- inArray[3] += 12;
1238
- }
1239
- // if is 12 am, change hours to 0
1240
- if (isPm === false && inArray[3] === 12) {
1241
- inArray[3] = 0;
1242
- }
1243
- // handle timezone
1244
- inArray[3] += timezoneHours;
1245
- inArray[4] += timezoneMinutes;
1246
- // return
1247
- return isUsingUTC ? new Date(Date.UTC.apply({}, inArray)) : dateFromArray(inArray);
1248
- }
1249
-
1250
- // compare two arrays, return the number of differences
1251
- function compareArrays(array1, array2) {
1252
- var len = Math.min(array1.length, array2.length),
1253
- lengthDiff = Math.abs(array1.length - array2.length),
1254
- diffs = 0,
1255
- i;
1256
- for (i = 0; i < len; i++) {
1257
- if (~~array1[i] !== ~~array2[i]) {
1258
- diffs++;
1259
- }
1260
- }
1261
- return diffs + lengthDiff;
1262
- }
1263
-
1264
- // date from string and array of format strings
1265
- function makeDateFromStringAndArray(string, formats) {
1266
- var output,
1267
- inputParts = string.match(inputCharacters),
1268
- scores = [],
1269
- scoreToBeat = 99,
1270
- i,
1271
- curDate,
1272
- curScore;
1273
- for (i = 0; i < formats.length; i++) {
1274
- curDate = makeDateFromStringAndFormat(string, formats[i]);
1275
- curScore = compareArrays(inputParts, formatMoment(new Moment(curDate), formats[i]).match(inputCharacters));
1276
- if (curScore < scoreToBeat) {
1277
- scoreToBeat = curScore;
1278
- output = curDate;
1279
- }
1280
- }
1281
- return output;
1282
- }
1283
-
1284
- // date from iso format
1285
- function makeDateFromString(string) {
1286
- var format = 'YYYY-MM-DDT',
1287
- i;
1288
- if (isoRegex.exec(string)) {
1289
- for (i = 0; i < 3; i++) {
1290
- if (isoTimes[i][1].exec(string)) {
1291
- format += isoTimes[i][0];
1292
- break;
1293
- }
1294
- }
1295
- return makeDateFromStringAndFormat(string, format + 'Z');
1296
- }
1297
- return new Date(string);
1298
- }
1299
-
1300
- // helper function for _date.from() and _date.fromNow()
1301
- function substituteTimeAgo(string, number, withoutSuffix) {
1302
- var rt = moment.relativeTime[string];
1303
- return (typeof rt === 'function') ?
1304
- rt(number || 1, !!withoutSuffix, string) :
1305
- rt.replace(/%d/i, number || 1);
1306
- }
1307
-
1308
- function relativeTime(milliseconds, withoutSuffix) {
1309
- var seconds = round(Math.abs(milliseconds) / 1000),
1310
- minutes = round(seconds / 60),
1311
- hours = round(minutes / 60),
1312
- days = round(hours / 24),
1313
- years = round(days / 365),
1314
- args = seconds < 45 && ['s', seconds] ||
1315
- minutes === 1 && ['m'] ||
1316
- minutes < 45 && ['mm', minutes] ||
1317
- hours === 1 && ['h'] ||
1318
- hours < 22 && ['hh', hours] ||
1319
- days === 1 && ['d'] ||
1320
- days <= 25 && ['dd', days] ||
1321
- days <= 45 && ['M'] ||
1322
- days < 345 && ['MM', round(days / 30)] ||
1323
- years === 1 && ['y'] || ['yy', years];
1324
- args[2] = withoutSuffix;
1325
- return substituteTimeAgo.apply({}, args);
1326
- }
1327
-
1328
- moment = function (input, format) {
1329
- if (input === null || input === '') {
1330
- return null;
1331
- }
1332
- var date,
1333
- matched;
1334
- // parse Moment object
1335
- if (input && input._d instanceof Date) {
1336
- date = new Date(+input._d);
1337
- // parse string and format
1338
- } else if (format) {
1339
- if (isArray(format)) {
1340
- date = makeDateFromStringAndArray(input, format);
1341
- } else {
1342
- date = makeDateFromStringAndFormat(input, format);
1343
- }
1344
- // evaluate it as a JSON-encoded date
1345
- } else {
1346
- matched = jsonRegex.exec(input);
1347
- date = input === undefined ? new Date() :
1348
- matched ? new Date(+matched[1]) :
1349
- input instanceof Date ? input :
1350
- isArray(input) ? dateFromArray(input) :
1351
- typeof input === 'string' ? makeDateFromString(input) :
1352
- new Date(input);
1353
- }
1354
- return new Moment(date);
1355
- };
1356
-
1357
- // creating with utc
1358
- moment.utc = function (input, format) {
1359
- if (isArray(input)) {
1360
- return new Moment(new Date(Date.UTC.apply({}, input)), true);
1361
- }
1362
- return (format && input) ? moment(input + ' 0', format + ' Z').utc() : moment(input).utc();
1363
- };
1364
-
1365
- // humanizeDuration
1366
- moment.humanizeDuration = function (num, type, withSuffix) {
1367
- var difference = +num,
1368
- rel = moment.relativeTime,
1369
- output;
1370
- switch (type) {
1371
- case "seconds" :
1372
- difference *= 1000; // 1000
1373
- break;
1374
- case "minutes" :
1375
- difference *= 60000; // 60 * 1000
1376
- break;
1377
- case "hours" :
1378
- difference *= 3600000; // 60 * 60 * 1000
1379
- break;
1380
- case "days" :
1381
- difference *= 86400000; // 24 * 60 * 60 * 1000
1382
- break;
1383
- case "weeks" :
1384
- difference *= 604800000; // 7 * 24 * 60 * 60 * 1000
1385
- break;
1386
- case "months" :
1387
- difference *= 2592000000; // 30 * 24 * 60 * 60 * 1000
1388
- break;
1389
- case "years" :
1390
- difference *= 31536000000; // 365 * 24 * 60 * 60 * 1000
1391
- break;
1392
- default :
1393
- withSuffix = !!type;
1394
- break;
1395
- }
1396
- output = relativeTime(difference, !withSuffix);
1397
- return withSuffix ? (difference <= 0 ? rel.past : rel.future).replace(/%s/i, output) : output;
1398
- };
1399
-
1400
- // version number
1401
- moment.version = VERSION;
1402
-
1403
- // default format
1404
- moment.defaultFormat = isoFormat;
1405
-
1406
- // language switching and caching
1407
- moment.lang = function (key, values) {
1408
- var i,
1409
- param,
1410
- req,
1411
- parse = [];
1412
- if (values) {
1413
- for (i = 0; i < 12; i++) {
1414
- parse[i] = new RegExp('^' + values.months[i] + '|^' + values.monthsShort[i].replace('.', ''), 'i');
1415
- }
1416
- values.monthsParse = values.monthsParse || parse;
1417
- languages[key] = values;
1418
- }
1419
- if (languages[key]) {
1420
- for (i = 0; i < paramsToParse.length; i++) {
1421
- param = paramsToParse[i];
1422
- moment[param] = languages[key][param] || moment[param];
1423
- }
1424
- } else {
1425
- if (hasModule) {
1426
- req = require('./lang/' + key);
1427
- moment.lang(key, req);
1428
- }
1429
- }
1430
- };
1431
-
1432
- // set default language
1433
- moment.lang('en', {
1434
- months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
1435
- monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
1436
- weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
1437
- weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
1438
- longDateFormat : {
1439
- LT : "h:mm A",
1440
- L : "MM/DD/YYYY",
1441
- LL : "MMMM D YYYY",
1442
- LLL : "MMMM D YYYY LT",
1443
- LLLL : "dddd, MMMM D YYYY LT"
1444
- },
1445
- meridiem : {
1446
- AM : 'AM',
1447
- am : 'am',
1448
- PM : 'PM',
1449
- pm : 'pm'
1450
- },
1451
- calendar : {
1452
- sameDay : '[Today at] LT',
1453
- nextDay : '[Tomorrow at] LT',
1454
- nextWeek : 'dddd [at] LT',
1455
- lastDay : '[Yesterday at] LT',
1456
- lastWeek : '[last] dddd [at] LT',
1457
- sameElse : 'L'
1458
- },
1459
- relativeTime : {
1460
- future : "in %s",
1461
- past : "%s ago",
1462
- s : "a few seconds",
1463
- m : "a minute",
1464
- mm : "%d minutes",
1465
- h : "an hour",
1466
- hh : "%d hours",
1467
- d : "a day",
1468
- dd : "%d days",
1469
- M : "a month",
1470
- MM : "%d months",
1471
- y : "a year",
1472
- yy : "%d years"
1473
- },
1474
- ordinal : function (number) {
1475
- var b = number % 10;
1476
- return (~~ (number % 100 / 10) === 1) ? 'th' :
1477
- (b === 1) ? 'st' :
1478
- (b === 2) ? 'nd' :
1479
- (b === 3) ? 'rd' : 'th';
1480
- }
1481
- });
1482
-
1483
- // compare moment object
1484
- moment.isMoment = function (obj) {
1485
- return obj instanceof Moment;
1486
- };
1487
-
1488
- // shortcut for prototype
1489
- moment.fn = Moment.prototype = {
1490
-
1491
- clone : function () {
1492
- return moment(this);
1493
- },
1494
-
1495
- valueOf : function () {
1496
- return +this._d;
1497
- },
1498
-
1499
- 'native' : function () {
1500
- return this._d;
1501
- },
1502
-
1503
- toString : function () {
1504
- return this._d.toString();
1505
- },
1506
-
1507
- toDate : function () {
1508
- return this._d;
1509
- },
1510
-
1511
- utc : function () {
1512
- this._isUTC = true;
1513
- return this;
1514
- },
1515
-
1516
- local : function () {
1517
- this._isUTC = false;
1518
- return this;
1519
- },
1520
-
1521
- format : function (inputString) {
1522
- return formatMoment(this, inputString ? inputString : moment.defaultFormat);
1523
- },
1524
-
1525
- add : function (input, val) {
1526
- this._d = dateAddRemove(this._d, input, 1, val);
1527
- return this;
1528
- },
1529
-
1530
- subtract : function (input, val) {
1531
- this._d = dateAddRemove(this._d, input, -1, val);
1532
- return this;
1533
- },
1534
-
1535
- diff : function (input, val, asFloat) {
1536
- var inputMoment = moment(input),
1537
- zoneDiff = (this.zone() - inputMoment.zone()) * 6e4,
1538
- diff = this._d - inputMoment._d - zoneDiff,
1539
- year = this.year() - inputMoment.year(),
1540
- month = this.month() - inputMoment.month(),
1541
- date = this.date() - inputMoment.date(),
1542
- output;
1543
- if (val === 'months') {
1544
- output = year * 12 + month + date / 30;
1545
- } else if (val === 'years') {
1546
- output = year + month / 12;
1547
- } else {
1548
- output = val === 'seconds' ? diff / 1e3 : // 1000
1549
- val === 'minutes' ? diff / 6e4 : // 1000 * 60
1550
- val === 'hours' ? diff / 36e5 : // 1000 * 60 * 60
1551
- val === 'days' ? diff / 864e5 : // 1000 * 60 * 60 * 24
1552
- val === 'weeks' ? diff / 6048e5 : // 1000 * 60 * 60 * 24 * 7
1553
- diff;
1554
- }
1555
- return asFloat ? output : round(output);
1556
- },
1557
-
1558
- from : function (time, withoutSuffix) {
1559
- return moment.humanizeDuration(this.diff(time), !withoutSuffix);
1560
- },
1561
-
1562
- fromNow : function (withoutSuffix) {
1563
- return this.from(moment(), withoutSuffix);
1564
- },
1565
-
1566
- calendar : function () {
1567
- var diff = this.diff(moment().sod(), 'days', true),
1568
- calendar = moment.calendar,
1569
- allElse = calendar.sameElse,
1570
- format = diff < -6 ? allElse :
1571
- diff < -1 ? calendar.lastWeek :
1572
- diff < 0 ? calendar.lastDay :
1573
- diff < 1 ? calendar.sameDay :
1574
- diff < 2 ? calendar.nextDay :
1575
- diff < 7 ? calendar.nextWeek : allElse;
1576
- return this.format(typeof format === 'function' ? format.apply(this) : format);
1577
- },
1578
-
1579
- isLeapYear : function () {
1580
- var year = this.year();
1581
- return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
1582
- },
1583
-
1584
- isDST : function () {
1585
- return (this.zone() < moment([this.year()]).zone() ||
1586
- this.zone() < moment([this.year(), 5]).zone());
1587
- },
1588
-
1589
- day : function (input) {
1590
- var day = this._d.getDay();
1591
- return (typeof input === 'undefined') ? day :
1592
- this.add({ d : input - day });
1593
- },
1594
-
1595
- sod: function () {
1596
- return this.clone()
1597
- .hours(0)
1598
- .minutes(0)
1599
- .seconds(0)
1600
- .milliseconds(0);
1601
- },
1602
-
1603
- eod: function () {
1604
- // end of day = start of day plus 1 day, minus 1 millisecond
1605
- return this.sod().add({
1606
- d : 1,
1607
- ms : -1
1608
- });
1609
- },
1610
-
1611
- zone : function () {
1612
- return this._isUTC ? 0 : this._d.getTimezoneOffset();
1613
- },
1614
-
1615
- daysInMonth : function () {
1616
- return this.clone().month(this.month() + 1).date(0).date();
1617
- }
1618
- };
1619
-
1620
- // helper for adding shortcuts
1621
- function makeShortcut(name, key) {
1622
- moment.fn[name] = function (input) {
1623
- var utc = this._isUTC ? 'UTC' : '';
1624
- if (typeof input !== 'undefined') {
1625
- this._d['set' + utc + key](input);
1626
- return this;
1627
- } else {
1628
- return this._d['get' + utc + key]();
1629
- }
1630
- };
1631
- }
1632
-
1633
- // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
1634
- for (i = 0; i < shortcuts.length; i ++) {
1635
- makeShortcut(shortcuts[i].toLowerCase(), shortcuts[i]);
1636
- }
1637
-
1638
- // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
1639
- makeShortcut('year', 'FullYear');
1640
-
1641
- return moment;
1642
- })(Date);
984
+ };
985
+ if (!Kalendae.moment) {
986
+ if (window.moment) {
987
+ Kalendae.moment = window.moment;
988
+ } else {
989
+ throw "Kalendae requires moment.js. You must use kalendae.standalone.js if moment is not available on the page.";
990
+ }
991
+ }
992
+
993
+ moment = Kalendae.moment;
1643
994
 
1644
995
  //function to reset the date object to 00:00 GMT
1645
996
  moment.fn.stripTime = function () {
1646
997
  this._d = new Date(Math.floor(this._d.valueOf() / 86400000) * 86400000);
1647
998
  return this;
1648
- }
999
+ };
1649
1000
 
1650
1001
 
1651
1002
  //function to get the total number of days since the epoch.
@@ -1653,11 +1004,11 @@ moment.fn.yearDay = function (input) {
1653
1004
  var yearday = Math.floor(this._d / 86400000);
1654
1005
  return (typeof input === 'undefined') ? yearday :
1655
1006
  this.add({ d : input - yearday });
1656
- }
1007
+ };
1657
1008
 
1658
- today = moment().stripTime();
1009
+ today = Kalendae.moment().stripTime();
1659
1010
 
1660
- if (typeof jQuery !== 'undefined') {
1011
+ if (typeof jQuery !== 'undefined' && (typeof document.addEventListener === 'function' || util.isIE8())) {
1661
1012
  jQuery.fn.kalendae = function (options) {
1662
1013
  this.each(function (i, e) {
1663
1014
  if (e.tagName === 'INPUT') {
@@ -1669,7 +1020,7 @@ if (typeof jQuery !== 'undefined') {
1669
1020
  }
1670
1021
  });
1671
1022
  return this;
1672
- }
1023
+ };
1673
1024
  }
1674
1025
 
1675
1026