materialize-rails 0.97.5.custom1

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.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +63 -0
  6. data/Rakefile +1 -0
  7. data/lib/materialize-rails.rb +25 -0
  8. data/lib/materialize-rails/engine.rb +14 -0
  9. data/lib/materialize-rails/version.rb +3 -0
  10. data/materialize-rails.gemspec +25 -0
  11. data/vendor/assets/fonts/materialize/material-design-icons/LICENSE.txt +428 -0
  12. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.eot +0 -0
  13. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.svg +769 -0
  14. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.ttf +0 -0
  15. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.woff +0 -0
  16. data/vendor/assets/fonts/materialize/material-design-icons/Material-Design-Icons.woff2 +0 -0
  17. data/vendor/assets/fonts/materialize/roboto/Roboto-Bold.eot +0 -0
  18. data/vendor/assets/fonts/materialize/roboto/Roboto-Bold.ttf +0 -0
  19. data/vendor/assets/fonts/materialize/roboto/Roboto-Bold.woff +0 -0
  20. data/vendor/assets/fonts/materialize/roboto/Roboto-Bold.woff2 +0 -0
  21. data/vendor/assets/fonts/materialize/roboto/Roboto-Light.eot +0 -0
  22. data/vendor/assets/fonts/materialize/roboto/Roboto-Light.ttf +0 -0
  23. data/vendor/assets/fonts/materialize/roboto/Roboto-Light.woff +0 -0
  24. data/vendor/assets/fonts/materialize/roboto/Roboto-Light.woff2 +0 -0
  25. data/vendor/assets/fonts/materialize/roboto/Roboto-Medium.eot +0 -0
  26. data/vendor/assets/fonts/materialize/roboto/Roboto-Medium.ttf +0 -0
  27. data/vendor/assets/fonts/materialize/roboto/Roboto-Medium.woff +0 -0
  28. data/vendor/assets/fonts/materialize/roboto/Roboto-Medium.woff2 +0 -0
  29. data/vendor/assets/fonts/materialize/roboto/Roboto-Regular.eot +0 -0
  30. data/vendor/assets/fonts/materialize/roboto/Roboto-Regular.ttf +0 -0
  31. data/vendor/assets/fonts/materialize/roboto/Roboto-Regular.woff +0 -0
  32. data/vendor/assets/fonts/materialize/roboto/Roboto-Regular.woff2 +0 -0
  33. data/vendor/assets/fonts/materialize/roboto/Roboto-Thin.eot +0 -0
  34. data/vendor/assets/fonts/materialize/roboto/Roboto-Thin.ttf +0 -0
  35. data/vendor/assets/fonts/materialize/roboto/Roboto-Thin.woff +0 -0
  36. data/vendor/assets/fonts/materialize/roboto/Roboto-Thin.woff2 +0 -0
  37. data/vendor/assets/javascripts/materialize.js +30 -0
  38. data/vendor/assets/javascripts/materialize/animation.js +9 -0
  39. data/vendor/assets/javascripts/materialize/buttons.js +91 -0
  40. data/vendor/assets/javascripts/materialize/cards.js +29 -0
  41. data/vendor/assets/javascripts/materialize/carousel.js +350 -0
  42. data/vendor/assets/javascripts/materialize/character_counter.js +59 -0
  43. data/vendor/assets/javascripts/materialize/chips.js +9 -0
  44. data/vendor/assets/javascripts/materialize/collapsible.js +137 -0
  45. data/vendor/assets/javascripts/materialize/date_picker/picker.date.js +1430 -0
  46. data/vendor/assets/javascripts/materialize/date_picker/picker.js +1123 -0
  47. data/vendor/assets/javascripts/materialize/dropdown.js +228 -0
  48. data/vendor/assets/javascripts/materialize/forms.js +581 -0
  49. data/vendor/assets/javascripts/materialize/global.js +45 -0
  50. data/vendor/assets/javascripts/materialize/hammer.min.js +1 -0
  51. data/vendor/assets/javascripts/materialize/initial.js +11 -0
  52. data/vendor/assets/javascripts/materialize/jquery.easing.1.3.js +205 -0
  53. data/vendor/assets/javascripts/materialize/jquery.hammer.js +33 -0
  54. data/vendor/assets/javascripts/materialize/leanModal.js +178 -0
  55. data/vendor/assets/javascripts/materialize/materialbox.js +269 -0
  56. data/vendor/assets/javascripts/materialize/parallax.js +58 -0
  57. data/vendor/assets/javascripts/materialize/pushpin.js +62 -0
  58. data/vendor/assets/javascripts/materialize/scrollFire.js +44 -0
  59. data/vendor/assets/javascripts/materialize/scrollspy.js +285 -0
  60. data/vendor/assets/javascripts/materialize/sideNav.js +315 -0
  61. data/vendor/assets/javascripts/materialize/slider.js +321 -0
  62. data/vendor/assets/javascripts/materialize/tabs.js +129 -0
  63. data/vendor/assets/javascripts/materialize/toasts.js +136 -0
  64. data/vendor/assets/javascripts/materialize/tooltip.js +203 -0
  65. data/vendor/assets/javascripts/materialize/transitions.js +154 -0
  66. data/vendor/assets/javascripts/materialize/velocity.min.js +5 -0
  67. data/vendor/assets/javascripts/materialize/waves.js +338 -0
  68. data/vendor/assets/stylesheets/components/_buttons.scss +181 -0
  69. data/vendor/assets/stylesheets/components/_cards.scss +134 -0
  70. data/vendor/assets/stylesheets/components/_carousel.scss +34 -0
  71. data/vendor/assets/stylesheets/components/_chips.scss +27 -0
  72. data/vendor/assets/stylesheets/components/_collapsible.scss +85 -0
  73. data/vendor/assets/stylesheets/components/_color.scss +412 -0
  74. data/vendor/assets/stylesheets/components/_dropdown.scss +57 -0
  75. data/vendor/assets/stylesheets/components/_form.scss +918 -0
  76. data/vendor/assets/stylesheets/components/_global.scss +766 -0
  77. data/vendor/assets/stylesheets/components/_grid.scss +146 -0
  78. data/vendor/assets/stylesheets/components/_icons-material-design.scss +3263 -0
  79. data/vendor/assets/stylesheets/components/_materialbox.scss +42 -0
  80. data/vendor/assets/stylesheets/components/_mixins.scss +5 -0
  81. data/vendor/assets/stylesheets/components/_modal.scss +90 -0
  82. data/vendor/assets/stylesheets/components/_navbar.scss +171 -0
  83. data/vendor/assets/stylesheets/components/_normalize.scss +427 -0
  84. data/vendor/assets/stylesheets/components/_prefixer.scss +384 -0
  85. data/vendor/assets/stylesheets/components/_preloader.scss +334 -0
  86. data/vendor/assets/stylesheets/components/_roboto.scss +49 -0
  87. data/vendor/assets/stylesheets/components/_sideNav.scss +112 -0
  88. data/vendor/assets/stylesheets/components/_slider.scss +92 -0
  89. data/vendor/assets/stylesheets/components/_table_of_contents.scss +33 -0
  90. data/vendor/assets/stylesheets/components/_tabs.scss +56 -0
  91. data/vendor/assets/stylesheets/components/_toast.scss +65 -0
  92. data/vendor/assets/stylesheets/components/_tooltip.scss +33 -0
  93. data/vendor/assets/stylesheets/components/_typography.scss +61 -0
  94. data/vendor/assets/stylesheets/components/_variables.scss +161 -0
  95. data/vendor/assets/stylesheets/components/_waves.scss +173 -0
  96. data/vendor/assets/stylesheets/components/date_picker/_default.date.scss +435 -0
  97. data/vendor/assets/stylesheets/components/date_picker/_default.scss +201 -0
  98. data/vendor/assets/stylesheets/components/date_picker/_default.time.scss +125 -0
  99. data/vendor/assets/stylesheets/materialize.scss +40 -0
  100. metadata +199 -0
@@ -0,0 +1,59 @@
1
+ (function ($) {
2
+
3
+ $.fn.characterCounter = function(){
4
+ return this.each(function(){
5
+
6
+ var itHasLengthAttribute = $(this).attr('length') !== undefined;
7
+
8
+ if(itHasLengthAttribute){
9
+ $(this).on('input', updateCounter);
10
+ $(this).on('focus', updateCounter);
11
+ $(this).on('blur', removeCounterElement);
12
+
13
+ addCounterElement($(this));
14
+ }
15
+
16
+ });
17
+ };
18
+
19
+ function updateCounter(){
20
+ var maxLength = +$(this).attr('length'),
21
+ actualLength = +$(this).val().length,
22
+ isValidLength = actualLength <= maxLength;
23
+
24
+ $(this).parent().find('span[class="character-counter"]')
25
+ .html( actualLength + '/' + maxLength);
26
+
27
+ addInputStyle(isValidLength, $(this));
28
+ }
29
+
30
+ function addCounterElement($input){
31
+ var $counterElement = $('<span/>')
32
+ .addClass('character-counter')
33
+ .css('float','right')
34
+ .css('font-size','12px')
35
+ .css('height', 1);
36
+
37
+ $input.parent().append($counterElement);
38
+ }
39
+
40
+ function removeCounterElement(){
41
+ $(this).parent().find('span[class="character-counter"]').html('');
42
+ }
43
+
44
+ function addInputStyle(isValidLength, $input){
45
+ var inputHasInvalidClass = $input.hasClass('invalid');
46
+ if (isValidLength && inputHasInvalidClass) {
47
+ $input.removeClass('invalid');
48
+ }
49
+ else if(!isValidLength && !inputHasInvalidClass){
50
+ $input.removeClass('valid');
51
+ $input.addClass('invalid');
52
+ }
53
+ }
54
+
55
+ $(document).ready(function(){
56
+ $('input, textarea').characterCounter();
57
+ });
58
+
59
+ }( jQuery ));
@@ -0,0 +1,9 @@
1
+ (function ($) {
2
+ $(document).ready(function() {
3
+
4
+ $(document).on('click.chip', '.chip .material-icons', function (e) {
5
+ $(this).parent().remove();
6
+ });
7
+
8
+ });
9
+ }( jQuery ));
@@ -0,0 +1,137 @@
1
+ (function ($) {
2
+ $.fn.collapsible = function(options) {
3
+ var defaults = {
4
+ accordion: undefined
5
+ };
6
+
7
+ options = $.extend(defaults, options);
8
+
9
+
10
+ return this.each(function() {
11
+
12
+ var $this = $(this);
13
+
14
+ var $panel_headers = $(this).find('> li > .collapsible-header');
15
+
16
+ var collapsible_type = $this.data("collapsible");
17
+
18
+ // Turn off any existing event handlers
19
+ $this.off('click.collapse', '> li > .collapsible-header');
20
+ $panel_headers.off('click.collapse');
21
+
22
+
23
+ /****************
24
+ Helper Functions
25
+ ****************/
26
+
27
+ // Accordion Open
28
+ function accordionOpen(object) {
29
+ $panel_headers = $this.find('> li > .collapsible-header');
30
+ if (object.hasClass('active')) {
31
+ object.parent().addClass('active');
32
+ }
33
+ else {
34
+ object.parent().removeClass('active');
35
+ }
36
+ if (object.parent().hasClass('active')){
37
+ object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
38
+ }
39
+ else{
40
+ object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
41
+ }
42
+
43
+ $panel_headers.not(object).removeClass('active').parent().removeClass('active');
44
+ $panel_headers.not(object).parent().children('.collapsible-body').stop(true,false).slideUp(
45
+ {
46
+ duration: 350,
47
+ easing: "easeOutQuart",
48
+ queue: false,
49
+ complete:
50
+ function() {
51
+ $(this).css('height', '');
52
+ }
53
+ });
54
+ }
55
+
56
+ // Expandable Open
57
+ function expandableOpen(object) {
58
+ if (object.hasClass('active')) {
59
+ object.parent().addClass('active');
60
+ }
61
+ else {
62
+ object.parent().removeClass('active');
63
+ }
64
+ if (object.parent().hasClass('active')){
65
+ object.siblings('.collapsible-body').stop(true,false).slideDown({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
66
+ }
67
+ else{
68
+ object.siblings('.collapsible-body').stop(true,false).slideUp({ duration: 350, easing: "easeOutQuart", queue: false, complete: function() {$(this).css('height', '');}});
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Check if object is children of panel header
74
+ * @param {Object} object Jquery object
75
+ * @return {Boolean} true if it is children
76
+ */
77
+ function isChildrenOfPanelHeader(object) {
78
+
79
+ var panelHeader = getPanelHeader(object);
80
+
81
+ return panelHeader.length > 0;
82
+ }
83
+
84
+ /**
85
+ * Get panel header from a children element
86
+ * @param {Object} object Jquery object
87
+ * @return {Object} panel header object
88
+ */
89
+ function getPanelHeader(object) {
90
+
91
+ return object.closest('li > .collapsible-header');
92
+ }
93
+
94
+ /***** End Helper Functions *****/
95
+
96
+
97
+
98
+ // Add click handler to only direct collapsible header children
99
+ $this.on('click.collapse', '> li > .collapsible-header', function(e) {
100
+ var $header = $(this),
101
+ element = $(e.target);
102
+
103
+ if (isChildrenOfPanelHeader(element)) {
104
+ element = getPanelHeader(element);
105
+ }
106
+
107
+ element.toggleClass('active');
108
+
109
+ if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion
110
+ accordionOpen(element);
111
+ } else { // Handle Expandables
112
+ expandableOpen(element);
113
+
114
+ if ($header.hasClass('active')) {
115
+ expandableOpen($header);
116
+ }
117
+ }
118
+ });
119
+
120
+ // Open first active
121
+ var $panel_headers = $this.find('> li > .collapsible-header');
122
+ if (options.accordion || collapsible_type === "accordion" || collapsible_type === undefined) { // Handle Accordion
123
+ accordionOpen($panel_headers.filter('.active').first());
124
+ }
125
+ else { // Handle Expandables
126
+ $panel_headers.filter('.active').each(function() {
127
+ expandableOpen($(this));
128
+ });
129
+ }
130
+
131
+ });
132
+ };
133
+
134
+ $(document).ready(function(){
135
+ $('.collapsible').collapsible();
136
+ });
137
+ }( jQuery ));
@@ -0,0 +1,1430 @@
1
+ /*!
2
+ * Date picker for pickadate.js v3.5.0
3
+ * http://amsul.github.io/pickadate.js/date.htm
4
+ */
5
+
6
+ (function ( factory ) {
7
+
8
+ // AMD.
9
+ if ( typeof define == 'function' && define.amd )
10
+ define( ['picker', 'jquery'], factory )
11
+
12
+ // Node.js/browserify.
13
+ else if ( typeof exports == 'object' )
14
+ module.exports = factory( require('./picker.js'), require('jquery') )
15
+
16
+ // Browser globals.
17
+ else factory( Picker, jQuery )
18
+
19
+ }(function( Picker, $ ) {
20
+
21
+
22
+ /**
23
+ * Globals and constants
24
+ */
25
+ var DAYS_IN_WEEK = 7,
26
+ WEEKS_IN_CALENDAR = 6,
27
+ _ = Picker._
28
+
29
+
30
+
31
+ /**
32
+ * The date picker constructor
33
+ */
34
+ function DatePicker( picker, settings ) {
35
+
36
+ var calendar = this,
37
+ element = picker.$node[ 0 ],
38
+ elementValue = element.value,
39
+ elementDataValue = picker.$node.data( 'value' ),
40
+ valueString = elementDataValue || elementValue,
41
+ formatString = elementDataValue ? settings.formatSubmit : settings.format,
42
+ isRTL = function() {
43
+
44
+ return element.currentStyle ?
45
+
46
+ // For IE.
47
+ element.currentStyle.direction == 'rtl' :
48
+
49
+ // For normal browsers.
50
+ getComputedStyle( picker.$root[0] ).direction == 'rtl'
51
+ }
52
+
53
+ calendar.settings = settings
54
+ calendar.$node = picker.$node
55
+
56
+ // The queue of methods that will be used to build item objects.
57
+ calendar.queue = {
58
+ min: 'measure create',
59
+ max: 'measure create',
60
+ now: 'now create',
61
+ select: 'parse create validate',
62
+ highlight: 'parse navigate create validate',
63
+ view: 'parse create validate viewset',
64
+ disable: 'deactivate',
65
+ enable: 'activate'
66
+ }
67
+
68
+ // The component's item object.
69
+ calendar.item = {}
70
+
71
+ calendar.item.clear = null
72
+ calendar.item.disable = ( settings.disable || [] ).slice( 0 )
73
+ calendar.item.enable = -(function( collectionDisabled ) {
74
+ return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1
75
+ })( calendar.item.disable )
76
+
77
+ calendar.
78
+ set( 'min', settings.min ).
79
+ set( 'max', settings.max ).
80
+ set( 'now' )
81
+
82
+ // When there’s a value, set the `select`, which in turn
83
+ // also sets the `highlight` and `view`.
84
+ if ( valueString ) {
85
+ calendar.set( 'select', valueString, { format: formatString })
86
+ }
87
+
88
+ // If there’s no value, default to highlighting “today”.
89
+ else {
90
+ calendar.
91
+ set( 'select', null ).
92
+ set( 'highlight', calendar.item.now )
93
+ }
94
+
95
+
96
+ // The keycode to movement mapping.
97
+ calendar.key = {
98
+ 40: 7, // Down
99
+ 38: -7, // Up
100
+ 39: function() { return isRTL() ? -1 : 1 }, // Right
101
+ 37: function() { return isRTL() ? 1 : -1 }, // Left
102
+ go: function( timeChange ) {
103
+ var highlightedObject = calendar.item.highlight,
104
+ targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange )
105
+ calendar.set(
106
+ 'highlight',
107
+ targetDate,
108
+ { interval: timeChange }
109
+ )
110
+ this.render()
111
+ }
112
+ }
113
+
114
+
115
+ // Bind some picker events.
116
+ picker.
117
+ on( 'render', function() {
118
+ picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() {
119
+ var value = this.value
120
+ if ( value ) {
121
+ picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] )
122
+ picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' )
123
+ }
124
+ })
125
+ picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() {
126
+ var value = this.value
127
+ if ( value ) {
128
+ picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] )
129
+ picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' )
130
+ }
131
+ })
132
+ }, 1 ).
133
+ on( 'open', function() {
134
+ var includeToday = ''
135
+ if ( calendar.disabled( calendar.get('now') ) ) {
136
+ includeToday = ':not(.' + settings.klass.buttonToday + ')'
137
+ }
138
+ picker.$root.find( 'button' + includeToday + ', select' ).attr( 'disabled', false )
139
+ }, 1 ).
140
+ on( 'close', function() {
141
+ picker.$root.find( 'button, select' ).attr( 'disabled', true )
142
+ }, 1 )
143
+
144
+ } //DatePicker
145
+
146
+
147
+ /**
148
+ * Set a datepicker item object.
149
+ */
150
+ DatePicker.prototype.set = function( type, value, options ) {
151
+
152
+ var calendar = this,
153
+ calendarItem = calendar.item
154
+
155
+ // If the value is `null` just set it immediately.
156
+ if ( value === null ) {
157
+ if ( type == 'clear' ) type = 'select'
158
+ calendarItem[ type ] = value
159
+ return calendar
160
+ }
161
+
162
+ // Otherwise go through the queue of methods, and invoke the functions.
163
+ // Update this as the time unit, and set the final value as this item.
164
+ // * In the case of `enable`, keep the queue but set `disable` instead.
165
+ // And in the case of `flip`, keep the queue but set `enable` instead.
166
+ calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) {
167
+ value = calendar[ method ]( type, value, options )
168
+ return value
169
+ }).pop()
170
+
171
+ // Check if we need to cascade through more updates.
172
+ if ( type == 'select' ) {
173
+ calendar.set( 'highlight', calendarItem.select, options )
174
+ }
175
+ else if ( type == 'highlight' ) {
176
+ calendar.set( 'view', calendarItem.highlight, options )
177
+ }
178
+ else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) {
179
+ if ( calendarItem.select && calendar.disabled( calendarItem.select ) ) {
180
+ calendar.set( 'select', calendarItem.select, options )
181
+ }
182
+ if ( calendarItem.highlight && calendar.disabled( calendarItem.highlight ) ) {
183
+ calendar.set( 'highlight', calendarItem.highlight, options )
184
+ }
185
+ }
186
+
187
+ return calendar
188
+ } //DatePicker.prototype.set
189
+
190
+
191
+ /**
192
+ * Get a datepicker item object.
193
+ */
194
+ DatePicker.prototype.get = function( type ) {
195
+ return this.item[ type ]
196
+ } //DatePicker.prototype.get
197
+
198
+
199
+ /**
200
+ * Create a picker date object.
201
+ */
202
+ DatePicker.prototype.create = function( type, value, options ) {
203
+
204
+ var isInfiniteValue,
205
+ calendar = this
206
+
207
+ // If there’s no value, use the type as the value.
208
+ value = value === undefined ? type : value
209
+
210
+
211
+ // If it’s infinity, update the value.
212
+ if ( value == -Infinity || value == Infinity ) {
213
+ isInfiniteValue = value
214
+ }
215
+
216
+ // If it’s an object, use the native date object.
217
+ else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) {
218
+ value = value.obj
219
+ }
220
+
221
+ // If it’s an array, convert it into a date and make sure
222
+ // that it’s a valid date – otherwise default to today.
223
+ else if ( $.isArray( value ) ) {
224
+ value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] )
225
+ value = _.isDate( value ) ? value : calendar.create().obj
226
+ }
227
+
228
+ // If it’s a number or date object, make a normalized date.
229
+ else if ( _.isInteger( value ) || _.isDate( value ) ) {
230
+ value = calendar.normalize( new Date( value ), options )
231
+ }
232
+
233
+ // If it’s a literal true or any other case, set it to now.
234
+ else /*if ( value === true )*/ {
235
+ value = calendar.now( type, value, options )
236
+ }
237
+
238
+ // Return the compiled object.
239
+ return {
240
+ year: isInfiniteValue || value.getFullYear(),
241
+ month: isInfiniteValue || value.getMonth(),
242
+ date: isInfiniteValue || value.getDate(),
243
+ day: isInfiniteValue || value.getDay(),
244
+ obj: isInfiniteValue || value,
245
+ pick: isInfiniteValue || value.getTime()
246
+ }
247
+ } //DatePicker.prototype.create
248
+
249
+
250
+ /**
251
+ * Create a range limit object using an array, date object,
252
+ * literal “true”, or integer relative to another time.
253
+ */
254
+ DatePicker.prototype.createRange = function( from, to ) {
255
+
256
+ var calendar = this,
257
+ createDate = function( date ) {
258
+ if ( date === true || $.isArray( date ) || _.isDate( date ) ) {
259
+ return calendar.create( date )
260
+ }
261
+ return date
262
+ }
263
+
264
+ // Create objects if possible.
265
+ if ( !_.isInteger( from ) ) {
266
+ from = createDate( from )
267
+ }
268
+ if ( !_.isInteger( to ) ) {
269
+ to = createDate( to )
270
+ }
271
+
272
+ // Create relative dates.
273
+ if ( _.isInteger( from ) && $.isPlainObject( to ) ) {
274
+ from = [ to.year, to.month, to.date + from ];
275
+ }
276
+ else if ( _.isInteger( to ) && $.isPlainObject( from ) ) {
277
+ to = [ from.year, from.month, from.date + to ];
278
+ }
279
+
280
+ return {
281
+ from: createDate( from ),
282
+ to: createDate( to )
283
+ }
284
+ } //DatePicker.prototype.createRange
285
+
286
+
287
+ /**
288
+ * Check if a date unit falls within a date range object.
289
+ */
290
+ DatePicker.prototype.withinRange = function( range, dateUnit ) {
291
+ range = this.createRange(range.from, range.to)
292
+ return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick
293
+ }
294
+
295
+
296
+ /**
297
+ * Check if two date range objects overlap.
298
+ */
299
+ DatePicker.prototype.overlapRanges = function( one, two ) {
300
+
301
+ var calendar = this
302
+
303
+ // Convert the ranges into comparable dates.
304
+ one = calendar.createRange( one.from, one.to )
305
+ two = calendar.createRange( two.from, two.to )
306
+
307
+ return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) ||
308
+ calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to )
309
+ }
310
+
311
+
312
+ /**
313
+ * Get the date today.
314
+ */
315
+ DatePicker.prototype.now = function( type, value, options ) {
316
+ value = new Date()
317
+ if ( options && options.rel ) {
318
+ value.setDate( value.getDate() + options.rel )
319
+ }
320
+ return this.normalize( value, options )
321
+ }
322
+
323
+
324
+ /**
325
+ * Navigate to next/prev month.
326
+ */
327
+ DatePicker.prototype.navigate = function( type, value, options ) {
328
+
329
+ var targetDateObject,
330
+ targetYear,
331
+ targetMonth,
332
+ targetDate,
333
+ isTargetArray = $.isArray( value ),
334
+ isTargetObject = $.isPlainObject( value ),
335
+ viewsetObject = this.item.view/*,
336
+ safety = 100*/
337
+
338
+
339
+ if ( isTargetArray || isTargetObject ) {
340
+
341
+ if ( isTargetObject ) {
342
+ targetYear = value.year
343
+ targetMonth = value.month
344
+ targetDate = value.date
345
+ }
346
+ else {
347
+ targetYear = +value[0]
348
+ targetMonth = +value[1]
349
+ targetDate = +value[2]
350
+ }
351
+
352
+ // If we’re navigating months but the view is in a different
353
+ // month, navigate to the view’s year and month.
354
+ if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) {
355
+ targetYear = viewsetObject.year
356
+ targetMonth = viewsetObject.month
357
+ }
358
+
359
+ // Figure out the expected target year and month.
360
+ targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 )
361
+ targetYear = targetDateObject.getFullYear()
362
+ targetMonth = targetDateObject.getMonth()
363
+
364
+ // If the month we’re going to doesn’t have enough days,
365
+ // keep decreasing the date until we reach the month’s last date.
366
+ while ( /*safety &&*/ new Date( targetYear, targetMonth, targetDate ).getMonth() !== targetMonth ) {
367
+ targetDate -= 1
368
+ /*safety -= 1
369
+ if ( !safety ) {
370
+ throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.'
371
+ }*/
372
+ }
373
+
374
+ value = [ targetYear, targetMonth, targetDate ]
375
+ }
376
+
377
+ return value
378
+ } //DatePicker.prototype.navigate
379
+
380
+
381
+ /**
382
+ * Normalize a date by setting the hours to midnight.
383
+ */
384
+ DatePicker.prototype.normalize = function( value/*, options*/ ) {
385
+ value.setHours( 0, 0, 0, 0 )
386
+ return value
387
+ }
388
+
389
+
390
+ /**
391
+ * Measure the range of dates.
392
+ */
393
+ DatePicker.prototype.measure = function( type, value/*, options*/ ) {
394
+
395
+ var calendar = this
396
+
397
+ // If it’s anything false-y, remove the limits.
398
+ if ( !value ) {
399
+ value = type == 'min' ? -Infinity : Infinity
400
+ }
401
+
402
+ // If it’s a string, parse it.
403
+ else if ( typeof value == 'string' ) {
404
+ value = calendar.parse( type, value )
405
+ }
406
+
407
+ // If it's an integer, get a date relative to today.
408
+ else if ( _.isInteger( value ) ) {
409
+ value = calendar.now( type, value, { rel: value } )
410
+ }
411
+
412
+ return value
413
+ } ///DatePicker.prototype.measure
414
+
415
+
416
+ /**
417
+ * Create a viewset object based on navigation.
418
+ */
419
+ DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) {
420
+ return this.create([ dateObject.year, dateObject.month, 1 ])
421
+ }
422
+
423
+
424
+ /**
425
+ * Validate a date as enabled and shift if needed.
426
+ */
427
+ DatePicker.prototype.validate = function( type, dateObject, options ) {
428
+
429
+ var calendar = this,
430
+
431
+ // Keep a reference to the original date.
432
+ originalDateObject = dateObject,
433
+
434
+ // Make sure we have an interval.
435
+ interval = options && options.interval ? options.interval : 1,
436
+
437
+ // Check if the calendar enabled dates are inverted.
438
+ isFlippedBase = calendar.item.enable === -1,
439
+
440
+ // Check if we have any enabled dates after/before now.
441
+ hasEnabledBeforeTarget, hasEnabledAfterTarget,
442
+
443
+ // The min & max limits.
444
+ minLimitObject = calendar.item.min,
445
+ maxLimitObject = calendar.item.max,
446
+
447
+ // Check if we’ve reached the limit during shifting.
448
+ reachedMin, reachedMax,
449
+
450
+ // Check if the calendar is inverted and at least one weekday is enabled.
451
+ hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter( function( value ) {
452
+
453
+ // If there’s a date, check where it is relative to the target.
454
+ if ( $.isArray( value ) ) {
455
+ var dateTime = calendar.create( value ).pick
456
+ if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true
457
+ else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true
458
+ }
459
+
460
+ // Return only integers for enabled weekdays.
461
+ return _.isInteger( value )
462
+ }).length/*,
463
+
464
+ safety = 100*/
465
+
466
+
467
+
468
+ // Cases to validate for:
469
+ // [1] Not inverted and date disabled.
470
+ // [2] Inverted and some dates enabled.
471
+ // [3] Not inverted and out of range.
472
+ //
473
+ // Cases to **not** validate for:
474
+ // • Navigating months.
475
+ // • Not inverted and date enabled.
476
+ // • Inverted and all dates disabled.
477
+ // • ..and anything else.
478
+ if ( !options || !options.nav ) if (
479
+ /* 1 */ ( !isFlippedBase && calendar.disabled( dateObject ) ) ||
480
+ /* 2 */ ( isFlippedBase && calendar.disabled( dateObject ) && ( hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget ) ) ||
481
+ /* 3 */ ( !isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick) )
482
+ ) {
483
+
484
+
485
+ // When inverted, flip the direction if there aren’t any enabled weekdays
486
+ // and there are no enabled dates in the direction of the interval.
487
+ if ( isFlippedBase && !hasEnabledWeekdays && ( ( !hasEnabledAfterTarget && interval > 0 ) || ( !hasEnabledBeforeTarget && interval < 0 ) ) ) {
488
+ interval *= -1
489
+ }
490
+
491
+
492
+ // Keep looping until we reach an enabled date.
493
+ while ( /*safety &&*/ calendar.disabled( dateObject ) ) {
494
+
495
+ /*safety -= 1
496
+ if ( !safety ) {
497
+ throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.'
498
+ }*/
499
+
500
+
501
+ // If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval.
502
+ if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) {
503
+ dateObject = originalDateObject
504
+ interval = interval > 0 ? 1 : -1
505
+ }
506
+
507
+
508
+ // If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit.
509
+ if ( dateObject.pick <= minLimitObject.pick ) {
510
+ reachedMin = true
511
+ interval = 1
512
+ dateObject = calendar.create([
513
+ minLimitObject.year,
514
+ minLimitObject.month,
515
+ minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1)
516
+ ])
517
+ }
518
+ else if ( dateObject.pick >= maxLimitObject.pick ) {
519
+ reachedMax = true
520
+ interval = -1
521
+ dateObject = calendar.create([
522
+ maxLimitObject.year,
523
+ maxLimitObject.month,
524
+ maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1)
525
+ ])
526
+ }
527
+
528
+
529
+ // If we’ve reached both limits, just break out of the loop.
530
+ if ( reachedMin && reachedMax ) {
531
+ break
532
+ }
533
+
534
+
535
+ // Finally, create the shifted date using the interval and keep looping.
536
+ dateObject = calendar.create([ dateObject.year, dateObject.month, dateObject.date + interval ])
537
+ }
538
+
539
+ } //endif
540
+
541
+
542
+ // Return the date object settled on.
543
+ return dateObject
544
+ } //DatePicker.prototype.validate
545
+
546
+
547
+ /**
548
+ * Check if a date is disabled.
549
+ */
550
+ DatePicker.prototype.disabled = function( dateToVerify ) {
551
+
552
+ var
553
+ calendar = this,
554
+
555
+ // Filter through the disabled dates to check if this is one.
556
+ isDisabledMatch = calendar.item.disable.filter( function( dateToDisable ) {
557
+
558
+ // If the date is a number, match the weekday with 0index and `firstDay` check.
559
+ if ( _.isInteger( dateToDisable ) ) {
560
+ return dateToVerify.day === ( calendar.settings.firstDay ? dateToDisable : dateToDisable - 1 ) % 7
561
+ }
562
+
563
+ // If it’s an array or a native JS date, create and match the exact date.
564
+ if ( $.isArray( dateToDisable ) || _.isDate( dateToDisable ) ) {
565
+ return dateToVerify.pick === calendar.create( dateToDisable ).pick
566
+ }
567
+
568
+ // If it’s an object, match a date within the “from” and “to” range.
569
+ if ( $.isPlainObject( dateToDisable ) ) {
570
+ return calendar.withinRange( dateToDisable, dateToVerify )
571
+ }
572
+ })
573
+
574
+ // If this date matches a disabled date, confirm it’s not inverted.
575
+ isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) {
576
+ return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' ||
577
+ $.isPlainObject( dateToDisable ) && dateToDisable.inverted
578
+ }).length
579
+
580
+ // Check the calendar “enabled” flag and respectively flip the
581
+ // disabled state. Then also check if it’s beyond the min/max limits.
582
+ return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch ||
583
+ dateToVerify.pick < calendar.item.min.pick ||
584
+ dateToVerify.pick > calendar.item.max.pick
585
+
586
+ } //DatePicker.prototype.disabled
587
+
588
+
589
+ /**
590
+ * Parse a string into a usable type.
591
+ */
592
+ DatePicker.prototype.parse = function( type, value, options ) {
593
+
594
+ var calendar = this,
595
+ parsingObject = {}
596
+
597
+ // If it’s already parsed, we’re good.
598
+ if ( !value || typeof value != 'string' ) {
599
+ return value
600
+ }
601
+
602
+ // We need a `.format` to parse the value with.
603
+ if ( !( options && options.format ) ) {
604
+ options = options || {}
605
+ options.format = calendar.settings.format
606
+ }
607
+
608
+ // Convert the format into an array and then map through it.
609
+ calendar.formats.toArray( options.format ).map( function( label ) {
610
+
611
+ var
612
+ // Grab the formatting label.
613
+ formattingLabel = calendar.formats[ label ],
614
+
615
+ // The format length is from the formatting label function or the
616
+ // label length without the escaping exclamation (!) mark.
617
+ formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length
618
+
619
+ // If there's a format label, split the value up to the format length.
620
+ // Then add it to the parsing object with appropriate label.
621
+ if ( formattingLabel ) {
622
+ parsingObject[ label ] = value.substr( 0, formatLength )
623
+ }
624
+
625
+ // Update the value as the substring from format length to end.
626
+ value = value.substr( formatLength )
627
+ })
628
+
629
+ // Compensate for month 0index.
630
+ return [
631
+ parsingObject.yyyy || parsingObject.yy,
632
+ +( parsingObject.mm || parsingObject.m ) - 1,
633
+ parsingObject.dd || parsingObject.d
634
+ ]
635
+ } //DatePicker.prototype.parse
636
+
637
+
638
+ /**
639
+ * Various formats to display the object in.
640
+ */
641
+ DatePicker.prototype.formats = (function() {
642
+
643
+ // Return the length of the first word in a collection.
644
+ function getWordLengthFromCollection( string, collection, dateObject ) {
645
+
646
+ // Grab the first word from the string.
647
+ var word = string.match( /\w+/ )[ 0 ]
648
+
649
+ // If there's no month index, add it to the date object
650
+ if ( !dateObject.mm && !dateObject.m ) {
651
+ dateObject.m = collection.indexOf( word ) + 1
652
+ }
653
+
654
+ // Return the length of the word.
655
+ return word.length
656
+ }
657
+
658
+ // Get the length of the first word in a string.
659
+ function getFirstWordLength( string ) {
660
+ return string.match( /\w+/ )[ 0 ].length
661
+ }
662
+
663
+ return {
664
+
665
+ d: function( string, dateObject ) {
666
+
667
+ // If there's string, then get the digits length.
668
+ // Otherwise return the selected date.
669
+ return string ? _.digits( string ) : dateObject.date
670
+ },
671
+ dd: function( string, dateObject ) {
672
+
673
+ // If there's a string, then the length is always 2.
674
+ // Otherwise return the selected date with a leading zero.
675
+ return string ? 2 : _.lead( dateObject.date )
676
+ },
677
+ ddd: function( string, dateObject ) {
678
+
679
+ // If there's a string, then get the length of the first word.
680
+ // Otherwise return the short selected weekday.
681
+ return string ? getFirstWordLength( string ) : this.settings.weekdaysShort[ dateObject.day ]
682
+ },
683
+ dddd: function( string, dateObject ) {
684
+
685
+ // If there's a string, then get the length of the first word.
686
+ // Otherwise return the full selected weekday.
687
+ return string ? getFirstWordLength( string ) : this.settings.weekdaysFull[ dateObject.day ]
688
+ },
689
+ m: function( string, dateObject ) {
690
+
691
+ // If there's a string, then get the length of the digits
692
+ // Otherwise return the selected month with 0index compensation.
693
+ return string ? _.digits( string ) : dateObject.month + 1
694
+ },
695
+ mm: function( string, dateObject ) {
696
+
697
+ // If there's a string, then the length is always 2.
698
+ // Otherwise return the selected month with 0index and leading zero.
699
+ return string ? 2 : _.lead( dateObject.month + 1 )
700
+ },
701
+ mmm: function( string, dateObject ) {
702
+
703
+ var collection = this.settings.monthsShort
704
+
705
+ // If there's a string, get length of the relevant month from the short
706
+ // months collection. Otherwise return the selected month from that collection.
707
+ return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ]
708
+ },
709
+ mmmm: function( string, dateObject ) {
710
+
711
+ var collection = this.settings.monthsFull
712
+
713
+ // If there's a string, get length of the relevant month from the full
714
+ // months collection. Otherwise return the selected month from that collection.
715
+ return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ]
716
+ },
717
+ yy: function( string, dateObject ) {
718
+
719
+ // If there's a string, then the length is always 2.
720
+ // Otherwise return the selected year by slicing out the first 2 digits.
721
+ return string ? 2 : ( '' + dateObject.year ).slice( 2 )
722
+ },
723
+ yyyy: function( string, dateObject ) {
724
+
725
+ // If there's a string, then the length is always 4.
726
+ // Otherwise return the selected year.
727
+ return string ? 4 : dateObject.year
728
+ },
729
+
730
+ // Create an array by splitting the formatting string passed.
731
+ toArray: function( formatString ) { return formatString.split( /(d{1,4}|m{1,4}|y{4}|yy|!.)/g ) },
732
+
733
+ // Format an object into a string using the formatting options.
734
+ toString: function ( formatString, itemObject ) {
735
+ var calendar = this
736
+ return calendar.formats.toArray( formatString ).map( function( label ) {
737
+ return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' )
738
+ }).join( '' )
739
+ }
740
+ }
741
+ })() //DatePicker.prototype.formats
742
+
743
+
744
+
745
+
746
+ /**
747
+ * Check if two date units are the exact.
748
+ */
749
+ DatePicker.prototype.isDateExact = function( one, two ) {
750
+
751
+ var calendar = this
752
+
753
+ // When we’re working with weekdays, do a direct comparison.
754
+ if (
755
+ ( _.isInteger( one ) && _.isInteger( two ) ) ||
756
+ ( typeof one == 'boolean' && typeof two == 'boolean' )
757
+ ) {
758
+ return one === two
759
+ }
760
+
761
+ // When we’re working with date representations, compare the “pick” value.
762
+ if (
763
+ ( _.isDate( one ) || $.isArray( one ) ) &&
764
+ ( _.isDate( two ) || $.isArray( two ) )
765
+ ) {
766
+ return calendar.create( one ).pick === calendar.create( two ).pick
767
+ }
768
+
769
+ // When we’re working with range objects, compare the “from” and “to”.
770
+ if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) {
771
+ return calendar.isDateExact( one.from, two.from ) && calendar.isDateExact( one.to, two.to )
772
+ }
773
+
774
+ return false
775
+ }
776
+
777
+
778
+ /**
779
+ * Check if two date units overlap.
780
+ */
781
+ DatePicker.prototype.isDateOverlap = function( one, two ) {
782
+
783
+ var calendar = this,
784
+ firstDay = calendar.settings.firstDay ? 1 : 0
785
+
786
+ // When we’re working with a weekday index, compare the days.
787
+ if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) {
788
+ one = one % 7 + firstDay
789
+ return one === calendar.create( two ).day + 1
790
+ }
791
+ if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) {
792
+ two = two % 7 + firstDay
793
+ return two === calendar.create( one ).day + 1
794
+ }
795
+
796
+ // When we’re working with range objects, check if the ranges overlap.
797
+ if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) {
798
+ return calendar.overlapRanges( one, two )
799
+ }
800
+
801
+ return false
802
+ }
803
+
804
+
805
+ /**
806
+ * Flip the “enabled” state.
807
+ */
808
+ DatePicker.prototype.flipEnable = function(val) {
809
+ var itemObject = this.item
810
+ itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1)
811
+ }
812
+
813
+
814
+ /**
815
+ * Mark a collection of dates as “disabled”.
816
+ */
817
+ DatePicker.prototype.deactivate = function( type, datesToDisable ) {
818
+
819
+ var calendar = this,
820
+ disabledItems = calendar.item.disable.slice(0)
821
+
822
+
823
+ // If we’re flipping, that’s all we need to do.
824
+ if ( datesToDisable == 'flip' ) {
825
+ calendar.flipEnable()
826
+ }
827
+
828
+ else if ( datesToDisable === false ) {
829
+ calendar.flipEnable(1)
830
+ disabledItems = []
831
+ }
832
+
833
+ else if ( datesToDisable === true ) {
834
+ calendar.flipEnable(-1)
835
+ disabledItems = []
836
+ }
837
+
838
+ // Otherwise go through the dates to disable.
839
+ else {
840
+
841
+ datesToDisable.map(function( unitToDisable ) {
842
+
843
+ var matchFound
844
+
845
+ // When we have disabled items, check for matches.
846
+ // If something is matched, immediately break out.
847
+ for ( var index = 0; index < disabledItems.length; index += 1 ) {
848
+ if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) {
849
+ matchFound = true
850
+ break
851
+ }
852
+ }
853
+
854
+ // If nothing was found, add the validated unit to the collection.
855
+ if ( !matchFound ) {
856
+ if (
857
+ _.isInteger( unitToDisable ) ||
858
+ _.isDate( unitToDisable ) ||
859
+ $.isArray( unitToDisable ) ||
860
+ ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to )
861
+ ) {
862
+ disabledItems.push( unitToDisable )
863
+ }
864
+ }
865
+ })
866
+ }
867
+
868
+ // Return the updated collection.
869
+ return disabledItems
870
+ } //DatePicker.prototype.deactivate
871
+
872
+
873
+ /**
874
+ * Mark a collection of dates as “enabled”.
875
+ */
876
+ DatePicker.prototype.activate = function( type, datesToEnable ) {
877
+
878
+ var calendar = this,
879
+ disabledItems = calendar.item.disable,
880
+ disabledItemsCount = disabledItems.length
881
+
882
+ // If we’re flipping, that’s all we need to do.
883
+ if ( datesToEnable == 'flip' ) {
884
+ calendar.flipEnable()
885
+ }
886
+
887
+ else if ( datesToEnable === true ) {
888
+ calendar.flipEnable(1)
889
+ disabledItems = []
890
+ }
891
+
892
+ else if ( datesToEnable === false ) {
893
+ calendar.flipEnable(-1)
894
+ disabledItems = []
895
+ }
896
+
897
+ // Otherwise go through the disabled dates.
898
+ else {
899
+
900
+ datesToEnable.map(function( unitToEnable ) {
901
+
902
+ var matchFound,
903
+ disabledUnit,
904
+ index,
905
+ isExactRange
906
+
907
+ // Go through the disabled items and try to find a match.
908
+ for ( index = 0; index < disabledItemsCount; index += 1 ) {
909
+
910
+ disabledUnit = disabledItems[index]
911
+
912
+ // When an exact match is found, remove it from the collection.
913
+ if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) {
914
+ matchFound = disabledItems[index] = null
915
+ isExactRange = true
916
+ break
917
+ }
918
+
919
+ // When an overlapped match is found, add the “inverted” state to it.
920
+ else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) {
921
+ if ( $.isPlainObject( unitToEnable ) ) {
922
+ unitToEnable.inverted = true
923
+ matchFound = unitToEnable
924
+ }
925
+ else if ( $.isArray( unitToEnable ) ) {
926
+ matchFound = unitToEnable
927
+ if ( !matchFound[3] ) matchFound.push( 'inverted' )
928
+ }
929
+ else if ( _.isDate( unitToEnable ) ) {
930
+ matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ]
931
+ }
932
+ break
933
+ }
934
+ }
935
+
936
+ // If a match was found, remove a previous duplicate entry.
937
+ if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) {
938
+ if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) {
939
+ disabledItems[index] = null
940
+ break
941
+ }
942
+ }
943
+
944
+ // In the event that we’re dealing with an exact range of dates,
945
+ // make sure there are no “inverted” dates because of it.
946
+ if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) {
947
+ if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) {
948
+ disabledItems[index] = null
949
+ break
950
+ }
951
+ }
952
+
953
+ // If something is still matched, add it into the collection.
954
+ if ( matchFound ) {
955
+ disabledItems.push( matchFound )
956
+ }
957
+ })
958
+ }
959
+
960
+ // Return the updated collection.
961
+ return disabledItems.filter(function( val ) { return val != null })
962
+ } //DatePicker.prototype.activate
963
+
964
+
965
+ /**
966
+ * Create a string for the nodes in the picker.
967
+ */
968
+ DatePicker.prototype.nodes = function( isOpen ) {
969
+
970
+ var
971
+ calendar = this,
972
+ settings = calendar.settings,
973
+ calendarItem = calendar.item,
974
+ nowObject = calendarItem.now,
975
+ selectedObject = calendarItem.select,
976
+ highlightedObject = calendarItem.highlight,
977
+ viewsetObject = calendarItem.view,
978
+ disabledCollection = calendarItem.disable,
979
+ minLimitObject = calendarItem.min,
980
+ maxLimitObject = calendarItem.max,
981
+
982
+
983
+ // Create the calendar table head using a copy of weekday labels collection.
984
+ // * We do a copy so we don't mutate the original array.
985
+ tableHead = (function( collection, fullCollection ) {
986
+
987
+ // If the first day should be Monday, move Sunday to the end.
988
+ if ( settings.firstDay ) {
989
+ collection.push( collection.shift() )
990
+ fullCollection.push( fullCollection.shift() )
991
+ }
992
+
993
+ // Create and return the table head group.
994
+ return _.node(
995
+ 'thead',
996
+ _.node(
997
+ 'tr',
998
+ _.group({
999
+ min: 0,
1000
+ max: DAYS_IN_WEEK - 1,
1001
+ i: 1,
1002
+ node: 'th',
1003
+ item: function( counter ) {
1004
+ return [
1005
+ collection[ counter ],
1006
+ settings.klass.weekdays,
1007
+ 'scope=col title="' + fullCollection[ counter ] + '"'
1008
+ ]
1009
+ }
1010
+ })
1011
+ )
1012
+ ) //endreturn
1013
+
1014
+ // Materialize modified
1015
+ })( ( settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysLetter ).slice( 0 ), settings.weekdaysFull.slice( 0 ) ), //tableHead
1016
+
1017
+
1018
+ // Create the nav for next/prev month.
1019
+ createMonthNav = function( next ) {
1020
+
1021
+ // Otherwise, return the created month tag.
1022
+ return _.node(
1023
+ 'div',
1024
+ ' ',
1025
+ settings.klass[ 'nav' + ( next ? 'Next' : 'Prev' ) ] + (
1026
+
1027
+ // If the focused month is outside the range, disabled the button.
1028
+ ( next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month ) ||
1029
+ ( !next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month ) ?
1030
+ ' ' + settings.klass.navDisabled : ''
1031
+ ),
1032
+ 'data-nav=' + ( next || -1 ) + ' ' +
1033
+ _.ariaAttr({
1034
+ role: 'button',
1035
+ controls: calendar.$node[0].id + '_table'
1036
+ }) + ' ' +
1037
+ 'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev ) + '"'
1038
+ ) //endreturn
1039
+ }, //createMonthNav
1040
+
1041
+
1042
+ // Create the month label.
1043
+ //Materialize modified
1044
+ createMonthLabel = function(override) {
1045
+
1046
+ var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull
1047
+
1048
+ // Materialize modified
1049
+ if (override == "short_months") {
1050
+ monthsCollection = settings.monthsShort;
1051
+ }
1052
+
1053
+ // If there are months to select, add a dropdown menu.
1054
+ if ( settings.selectMonths && override == undefined) {
1055
+
1056
+ return _.node( 'select',
1057
+ _.group({
1058
+ min: 0,
1059
+ max: 11,
1060
+ i: 1,
1061
+ node: 'option',
1062
+ item: function( loopedMonth ) {
1063
+
1064
+ return [
1065
+
1066
+ // The looped month and no classes.
1067
+ monthsCollection[ loopedMonth ], 0,
1068
+
1069
+ // Set the value and selected index.
1070
+ 'value=' + loopedMonth +
1071
+ ( viewsetObject.month == loopedMonth ? ' selected' : '' ) +
1072
+ (
1073
+ (
1074
+ ( viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month ) ||
1075
+ ( viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month )
1076
+ ) ?
1077
+ ' disabled' : ''
1078
+ )
1079
+ ]
1080
+ }
1081
+ }),
1082
+ settings.klass.selectMonth + ' browser-default',
1083
+ ( isOpen ? '' : 'disabled' ) + ' ' +
1084
+ _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' +
1085
+ 'title="' + settings.labelMonthSelect + '"'
1086
+ )
1087
+ }
1088
+
1089
+ // Materialize modified
1090
+ if (override == "short_months")
1091
+ if (selectedObject != null)
1092
+ return _.node( 'div', monthsCollection[ selectedObject.month ] );
1093
+ else return _.node( 'div', monthsCollection[ viewsetObject.month ] );
1094
+
1095
+ // If there's a need for a month selector
1096
+ return _.node( 'div', monthsCollection[ viewsetObject.month ], settings.klass.month )
1097
+ }, //createMonthLabel
1098
+
1099
+
1100
+ // Create the year label.
1101
+ // Materialize modified
1102
+ createYearLabel = function(override) {
1103
+
1104
+ var focusedYear = viewsetObject.year,
1105
+
1106
+ // If years selector is set to a literal "true", set it to 5. Otherwise
1107
+ // divide in half to get half before and half after focused year.
1108
+ numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 )
1109
+
1110
+ // If there are years to select, add a dropdown menu.
1111
+ if ( numberYears ) {
1112
+
1113
+ var
1114
+ minYear = minLimitObject.year,
1115
+ maxYear = maxLimitObject.year,
1116
+ lowestYear = focusedYear - numberYears,
1117
+ highestYear = focusedYear + numberYears
1118
+
1119
+ // If the min year is greater than the lowest year, increase the highest year
1120
+ // by the difference and set the lowest year to the min year.
1121
+ if ( minYear > lowestYear ) {
1122
+ highestYear += minYear - lowestYear
1123
+ lowestYear = minYear
1124
+ }
1125
+
1126
+ // If the max year is less than the highest year, decrease the lowest year
1127
+ // by the lower of the two: available and needed years. Then set the
1128
+ // highest year to the max year.
1129
+ if ( maxYear < highestYear ) {
1130
+
1131
+ var availableYears = lowestYear - minYear,
1132
+ neededYears = highestYear - maxYear
1133
+
1134
+ lowestYear -= availableYears > neededYears ? neededYears : availableYears
1135
+ highestYear = maxYear
1136
+ }
1137
+
1138
+ if ( settings.selectYears && override == undefined ) {
1139
+ return _.node( 'select',
1140
+ _.group({
1141
+ min: lowestYear,
1142
+ max: highestYear,
1143
+ i: 1,
1144
+ node: 'option',
1145
+ item: function( loopedYear ) {
1146
+ return [
1147
+
1148
+ // The looped year and no classes.
1149
+ loopedYear, 0,
1150
+
1151
+ // Set the value and selected index.
1152
+ 'value=' + loopedYear + ( focusedYear == loopedYear ? ' selected' : '' )
1153
+ ]
1154
+ }
1155
+ }),
1156
+ settings.klass.selectYear + ' browser-default',
1157
+ ( isOpen ? '' : 'disabled' ) + ' ' + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' +
1158
+ 'title="' + settings.labelYearSelect + '"'
1159
+ )
1160
+ }
1161
+ }
1162
+
1163
+ // Materialize modified
1164
+ if (override == "raw")
1165
+ return _.node( 'div', focusedYear )
1166
+
1167
+ // Otherwise just return the year focused
1168
+ return _.node( 'div', focusedYear, settings.klass.year )
1169
+ } //createYearLabel
1170
+
1171
+
1172
+ // Materialize modified
1173
+ createDayLabel = function() {
1174
+ if (selectedObject != null)
1175
+ return _.node( 'div', selectedObject.date)
1176
+ else return _.node( 'div', nowObject.date)
1177
+ }
1178
+ createWeekdayLabel = function() {
1179
+ var display_day;
1180
+
1181
+ if (selectedObject != null)
1182
+ display_day = selectedObject.day;
1183
+ else
1184
+ display_day = nowObject.day;
1185
+ var weekday = settings.weekdaysFull[ display_day ]
1186
+ return weekday
1187
+ }
1188
+
1189
+
1190
+ // Create and return the entire calendar.
1191
+ return _.node(
1192
+ // Date presentation View
1193
+ 'div',
1194
+ _.node(
1195
+ 'div',
1196
+ createWeekdayLabel(),
1197
+ "picker__weekday-display"
1198
+ )+
1199
+ _.node(
1200
+ // Div for short Month
1201
+ 'div',
1202
+ createMonthLabel("short_months"),
1203
+ settings.klass.month_display
1204
+ )+
1205
+ _.node(
1206
+ // Div for Day
1207
+ 'div',
1208
+ createDayLabel() ,
1209
+ settings.klass.day_display
1210
+ )+
1211
+ _.node(
1212
+ // Div for Year
1213
+ 'div',
1214
+ createYearLabel("raw") ,
1215
+ settings.klass.year_display
1216
+ ),
1217
+ settings.klass.date_display
1218
+ )+
1219
+ // Calendar container
1220
+ _.node('div',
1221
+ _.node('div',
1222
+ ( settings.selectYears ? createMonthLabel() + createYearLabel() : createMonthLabel() + createYearLabel() ) +
1223
+ createMonthNav() + createMonthNav( 1 ),
1224
+ settings.klass.header
1225
+ ) + _.node(
1226
+ 'table',
1227
+ tableHead +
1228
+ _.node(
1229
+ 'tbody',
1230
+ _.group({
1231
+ min: 0,
1232
+ max: WEEKS_IN_CALENDAR - 1,
1233
+ i: 1,
1234
+ node: 'tr',
1235
+ item: function( rowCounter ) {
1236
+
1237
+ // If Monday is the first day and the month starts on Sunday, shift the date back a week.
1238
+ var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0
1239
+
1240
+ return [
1241
+ _.group({
1242
+ min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index
1243
+ max: function() {
1244
+ return this.min + DAYS_IN_WEEK - 1
1245
+ },
1246
+ i: 1,
1247
+ node: 'td',
1248
+ item: function( targetDate ) {
1249
+
1250
+ // Convert the time date from a relative date to a target date.
1251
+ targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ])
1252
+
1253
+ var isSelected = selectedObject && selectedObject.pick == targetDate.pick,
1254
+ isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick,
1255
+ isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick,
1256
+ formattedDate = _.trigger( calendar.formats.toString, calendar, [ settings.format, targetDate ] )
1257
+
1258
+ return [
1259
+ _.node(
1260
+ 'div',
1261
+ targetDate.date,
1262
+ (function( klasses ) {
1263
+
1264
+ // Add the `infocus` or `outfocus` classes based on month in view.
1265
+ klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus )
1266
+
1267
+ // Add the `today` class if needed.
1268
+ if ( nowObject.pick == targetDate.pick ) {
1269
+ klasses.push( settings.klass.now )
1270
+ }
1271
+
1272
+ // Add the `selected` class if something's selected and the time matches.
1273
+ if ( isSelected ) {
1274
+ klasses.push( settings.klass.selected )
1275
+ }
1276
+
1277
+ // Add the `highlighted` class if something's highlighted and the time matches.
1278
+ if ( isHighlighted ) {
1279
+ klasses.push( settings.klass.highlighted )
1280
+ }
1281
+
1282
+ // Add the `disabled` class if something's disabled and the object matches.
1283
+ if ( isDisabled ) {
1284
+ klasses.push( settings.klass.disabled )
1285
+ }
1286
+
1287
+ return klasses.join( ' ' )
1288
+ })([ settings.klass.day ]),
1289
+ 'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({
1290
+ role: 'gridcell',
1291
+ label: formattedDate,
1292
+ selected: isSelected && calendar.$node.val() === formattedDate ? true : null,
1293
+ activedescendant: isHighlighted ? true : null,
1294
+ disabled: isDisabled ? true : null
1295
+ })
1296
+ ),
1297
+ '',
1298
+ _.ariaAttr({ role: 'presentation' })
1299
+ ] //endreturn
1300
+ }
1301
+ })
1302
+ ] //endreturn
1303
+ }
1304
+ })
1305
+ ),
1306
+ settings.klass.table,
1307
+ 'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({
1308
+ role: 'grid',
1309
+ controls: calendar.$node[0].id,
1310
+ readonly: true
1311
+ })
1312
+ )
1313
+ , settings.klass.calendar_container) // end calendar
1314
+
1315
+ +
1316
+
1317
+ // * For Firefox forms to submit, make sure to set the buttons’ `type` attributes as “button”.
1318
+ _.node(
1319
+ 'div',
1320
+ _.node( 'button', settings.today, "btn-flat picker__today",
1321
+ 'type=button data-pick=' + nowObject.pick +
1322
+ ( isOpen && !calendar.disabled(nowObject) ? '' : ' disabled' ) + ' ' +
1323
+ _.ariaAttr({ controls: calendar.$node[0].id }) ) +
1324
+ _.node( 'button', settings.clear, "btn-flat picker__clear",
1325
+ 'type=button data-clear=1' +
1326
+ ( isOpen ? '' : ' disabled' ) + ' ' +
1327
+ _.ariaAttr({ controls: calendar.$node[0].id }) ) +
1328
+ _.node('button', settings.close, "btn-flat picker__close",
1329
+ 'type=button data-close=true ' +
1330
+ ( isOpen ? '' : ' disabled' ) + ' ' +
1331
+ _.ariaAttr({ controls: calendar.$node[0].id }) ),
1332
+ settings.klass.footer
1333
+ ) //endreturn
1334
+ } //DatePicker.prototype.nodes
1335
+
1336
+
1337
+
1338
+
1339
+ /**
1340
+ * The date picker defaults.
1341
+ */
1342
+ DatePicker.defaults = (function( prefix ) {
1343
+
1344
+ return {
1345
+
1346
+ // The title label to use for the month nav buttons
1347
+ labelMonthNext: 'Next month',
1348
+ labelMonthPrev: 'Previous month',
1349
+
1350
+ // The title label to use for the dropdown selectors
1351
+ labelMonthSelect: 'Select a month',
1352
+ labelYearSelect: 'Select a year',
1353
+
1354
+ // Months and weekdays
1355
+ monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ],
1356
+ monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ],
1357
+ weekdaysFull: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ],
1358
+ weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ],
1359
+
1360
+ // Materialize modified
1361
+ weekdaysLetter: [ 'S', 'M', 'T', 'W', 'T', 'F', 'S' ],
1362
+
1363
+ // Today and clear
1364
+ today: 'Today',
1365
+ clear: 'Clear',
1366
+ close: 'Close',
1367
+
1368
+ // The format to show on the `input` element
1369
+ format: 'd mmmm, yyyy',
1370
+
1371
+ // Classes
1372
+ klass: {
1373
+
1374
+ table: prefix + 'table',
1375
+
1376
+ header: prefix + 'header',
1377
+
1378
+
1379
+ // Materialize Added klasses
1380
+ date_display: prefix + 'date-display',
1381
+ day_display: prefix + 'day-display',
1382
+ month_display: prefix + 'month-display',
1383
+ year_display: prefix + 'year-display',
1384
+ calendar_container: prefix + 'calendar-container',
1385
+ // end
1386
+
1387
+
1388
+
1389
+ navPrev: prefix + 'nav--prev',
1390
+ navNext: prefix + 'nav--next',
1391
+ navDisabled: prefix + 'nav--disabled',
1392
+
1393
+ month: prefix + 'month',
1394
+ year: prefix + 'year',
1395
+
1396
+ selectMonth: prefix + 'select--month',
1397
+ selectYear: prefix + 'select--year',
1398
+
1399
+ weekdays: prefix + 'weekday',
1400
+
1401
+ day: prefix + 'day',
1402
+ disabled: prefix + 'day--disabled',
1403
+ selected: prefix + 'day--selected',
1404
+ highlighted: prefix + 'day--highlighted',
1405
+ now: prefix + 'day--today',
1406
+ infocus: prefix + 'day--infocus',
1407
+ outfocus: prefix + 'day--outfocus',
1408
+
1409
+ footer: prefix + 'footer',
1410
+
1411
+ buttonClear: prefix + 'button--clear',
1412
+ buttonToday: prefix + 'button--today',
1413
+ buttonClose: prefix + 'button--close'
1414
+ }
1415
+ }
1416
+ })( Picker.klasses().picker + '__' )
1417
+
1418
+
1419
+
1420
+
1421
+
1422
+ /**
1423
+ * Extend the picker to add the date picker.
1424
+ */
1425
+ Picker.extend( 'pickadate', DatePicker )
1426
+
1427
+
1428
+ }));
1429
+
1430
+