contour 1.1.3 → 1.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/CHANGELOG.rdoc +18 -9
  2. data/README.rdoc +4 -4
  3. data/app/assets/images/twitter-bootstrap/{v2.2.2 → v2.3.0}/glyphicons-halflings-white.png +0 -0
  4. data/app/assets/images/twitter-bootstrap/{v2.2.2 → v2.3.0}/glyphicons-halflings.png +0 -0
  5. data/app/assets/javascripts/contour.js +2 -2
  6. data/app/assets/javascripts/contour/global.js.coffee +14 -8
  7. data/app/assets/javascripts/external/bootstrap-datepicker.js +983 -0
  8. data/app/assets/javascripts/external/bootstrap-timepicker.js +837 -0
  9. data/app/assets/javascripts/external/jquery-ui-1.10.0.custom.min.js +6 -0
  10. data/app/assets/javascripts/twitter-bootstrap/{v2.2.2 → v2.3.0}/bootstrap.js +189 -80
  11. data/app/assets/stylesheets/bootstrap-base-overrides.css +6 -14
  12. data/app/assets/stylesheets/contour.css +5 -3
  13. data/app/assets/stylesheets/datepicker.css +301 -0
  14. data/app/assets/stylesheets/jquery-ui-1.10.0.custom.css +86 -0
  15. data/app/assets/stylesheets/timepicker.css +82 -0
  16. data/app/assets/stylesheets/twitter-bootstrap/{v2.2.2 → v2.3.0}/bootstrap-responsive.css +24 -7
  17. data/app/assets/stylesheets/twitter-bootstrap/{v2.2.2 → v2.3.0}/bootstrap.css +238 -119
  18. data/app/controllers/contour/authentications_controller.rb +1 -2
  19. data/app/views/contour/authentications/_login_table.html.erb +1 -1
  20. data/app/views/contour/layouts/_menu.html.erb +5 -0
  21. data/contour.gemspec +3 -3
  22. data/lib/contour.rb +10 -0
  23. data/lib/contour/version.rb +3 -3
  24. data/lib/generators/contour/install/templates/contour.rb +9 -0
  25. data/lib/generators/contour/scaffold/templates/_paginate.html.erb +1 -1
  26. data/lib/generators/contour/scaffold/templates/index.html.erb +1 -1
  27. data/test/dummy/app/models/user.rb +0 -1
  28. data/test/dummy/db/development.sqlite3 +0 -0
  29. data/test/dummy/db/test.sqlite3 +0 -0
  30. data/test/dummy/log/development.log +129 -0
  31. data/test/dummy/log/test.log +2059 -47940
  32. metadata +26 -18
  33. data/app/assets/javascripts/external/jquery-ui-1.8.22.custom.min.js +0 -93
  34. data/app/assets/stylesheets/jquery-ui-1.8.22.custom.css +0 -381
@@ -1,14 +1,23 @@
1
- == 1.1.3 (February 11, 2013)
1
+ == 1.2.0
2
2
 
3
3
  * Enhancements
4
- * Tooltip base line-height is now fixed at 20px
5
- * Update Gem Dependencies
6
- * rails 3.2.11
7
- * Removed tooltips from alternate login providers to save iPhones and iPads from clicking the authentication button twice
8
- * Added a <tt>.center</tt> CSS class to use instead of the deprecated <tt>&lt;center&gt;</tt> tag
9
-
10
- * Bug Fix
11
- * apply_omniauth(omniauth) updated to account for PostgreSQL error, see {README}[https://github.com/remomueller/contour/blob/master/README]
4
+ * Updated Twitter Bootstrap to 2.3.0
5
+ * Updated Gem Dependencies
6
+ * devise 2.2.3, jquery-rails 2.2.1
7
+ * Updated jQuery UI to 1.10.0, the following modules are included:
8
+ * UI Core: Core, Widget, Mouse
9
+ * Interactions: Draggable, Droppable, Sortable
10
+ * Effects: Effects Core, Fade, Highlight
11
+ * Added bootstrap-datepicker and bootstrap-timepicker
12
+ * Contour can now be configured to have a search bar in the navigation menu
13
+ * For example:
14
+ config.search_bar = {
15
+ display: 'always',
16
+ id: 'global-search',
17
+ path: 'search_path',
18
+ placeholder: 'Search',
19
+ position: 'left'
20
+ }
12
21
 
13
22
  == 1.1.2 (January 3, 2013)
14
23
 
@@ -1,4 +1,4 @@
1
- = Contour {<img src="https://secure.travis-ci.org/remomueller/contour.png"/>}[http://travis-ci.org/remomueller/contour] {<img src="https://gemnasium.com/remomueller/contour.png" alt="Dependency Status" />}[https://gemnasium.com/remomueller/contour] {<img src="https://codeclimate.com/github/remomueller/contour.png" />}[https://codeclimate.com/github/remomueller/contour]
1
+ = Contour {<img src="https://secure.travis-ci.org/remomueller/contour.png"/>}[http://travis-ci.org/remomueller/contour] {<img src="https://gemnasium.com/remomueller/contour.png" alt="Dependency Status" />}[https://gemnasium.com/remomueller/contour] {<img src="https://codeclimate.com/badge.png" />}[https://codeclimate.com/github/remomueller/contour]
2
2
 
3
3
  Basic Rails framework files and assets for layout and authentication
4
4
 
@@ -14,7 +14,7 @@ Or update your <tt>Gemfile</tt> to include
14
14
 
15
15
  == Getting started
16
16
 
17
- Make sure you have Rails 3.2.11
17
+ Make sure you have Rails 3.2.10
18
18
 
19
19
  rails -v
20
20
 
@@ -24,7 +24,7 @@ Make sure you have Rails 3.2.11
24
24
 
25
25
  Modify <tt>Gemfile</tt> and add
26
26
 
27
- gem 'contour', '~> 1.1.3'
27
+ gem 'contour', '~> 1.2.0'
28
28
 
29
29
  Run Bundle install
30
30
 
@@ -87,7 +87,6 @@ Add the following to your <tt>app/models/user.rb</tt>
87
87
  unless omniauth['info'].blank?
88
88
  self.email = omniauth['info']['email'] if email.blank?
89
89
  end
90
- self.password = Devise.friendly_token[0,20] if self.password.blank?
91
90
  authentications.build( provider: omniauth['provider'], uid: omniauth['uid'] )
92
91
  end
93
92
 
@@ -193,3 +192,4 @@ For those interested in having better control on modifying the Twitter Bootstrap
193
192
  == Copyright {<img style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/3.0/80x15.png"/>}[http://creativecommons.org/licenses/by-nc-sa/3.0/]
194
193
 
195
194
  Copyright (c) 2013 Remo Mueller. See {LICENSE}[https://github.com/remomueller/contour/blob/master/LICENSE] for further details.
195
+
@@ -4,10 +4,10 @@
4
4
  //= require jquery
5
5
  //= require jquery_ujs
6
6
  //
7
- //= require external/jquery-ui-1.8.22.custom.min.js
7
+ //= require external/jquery-ui-1.10.0.custom.min.js
8
8
  //= require external/jquery.qtip.min.js
9
9
  //
10
- //= require twitter-bootstrap/v2.2.2/bootstrap
10
+ //= require twitter-bootstrap/v2.3.0/bootstrap
11
11
  //
12
12
  //= require twitter-bootstrap/bootstrap-scroll-modal
13
13
  //= require twitter-bootstrap/bootstrap
@@ -2,7 +2,7 @@
2
2
  @showWaiting = (element_id, text, centered) ->
3
3
  element = $(element_id)
4
4
  if element && centered
5
- element.html('<br /><div class=\"center\"><img width=\"13\" height=\"13\" src=\"' + root_url + 'assets/contour/ajax-loader.gif\" align=\"absmiddle\" alt=\"...\" />' + text + '</div><br />')
5
+ element.html('<br /><center><img width=\"13\" height=\"13\" src=\"' + root_url + 'assets/contour/ajax-loader.gif\" align=\"absmiddle\" alt=\"...\" />' + text + '</center><br />')
6
6
  else if element
7
7
  element.html('<img width=\"13\" height=\"13\" src=\"' + root_url + 'assets/contour/ajax-loader.gif\" align=\"absmiddle\" alt=\"...\" />' + text)
8
8
 
@@ -18,13 +18,19 @@
18
18
  event.which > 1 or event.metaKey or event.ctrlKey or event.shiftKey or event.altKey
19
19
 
20
20
  jQuery ->
21
- $(".datepicker").datepicker
22
- showOtherMonths: true
23
- selectOtherMonths: true
24
- changeMonth: true
25
- changeYear: true
26
-
27
- $("#ui-datepicker-div").hide()
21
+ $(".timepicker").timepicker
22
+ showMeridian: false
23
+ showSeconds: true
24
+ defaultTime: false
25
+ $(".datepicker").datepicker('remove')
26
+ $(".datepicker").datepicker( autoclose: true )
27
+
28
+ $(document).on('change', '.datepicker', () ->
29
+ try
30
+ $(this).val($.datepicker.formatDate('mm/dd/yy', $.datepicker.parseDate('mm/dd/yy', $(this).val())))
31
+ catch error
32
+ # Nothing
33
+ )
28
34
 
29
35
  $(document).on('click', ".pagination a, .page a, .next a, .prev a", () ->
30
36
  return false if $(this).parent().is('.active, .disabled, .per_page')
@@ -0,0 +1,983 @@
1
+ /* =========================================================
2
+ * bootstrap-datepicker.js
3
+ * http://www.eyecon.ro/bootstrap-datepicker
4
+ * =========================================================
5
+ * Copyright 2012 Stefan Petre
6
+ * Improvements by Andrew Rowls
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ * ========================================================= */
20
+
21
+ !function( $ ) {
22
+
23
+ function UTCDate(){
24
+ return new Date(Date.UTC.apply(Date, arguments));
25
+ }
26
+ function UTCToday(){
27
+ var today = new Date();
28
+ return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
29
+ }
30
+
31
+ // Picker object
32
+
33
+ var Datepicker = function(element, options) {
34
+ var that = this;
35
+
36
+ this.element = $(element);
37
+ this.language = options.language||this.element.data('date-language')||"en";
38
+ this.language = this.language in dates ? this.language : this.language.split('-')[0]; //Check if "de-DE" style date is available, if not language should fallback to 2 letter code eg "de"
39
+ this.language = this.language in dates ? this.language : "en";
40
+ this.isRTL = dates[this.language].rtl||false;
41
+ this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||dates[this.language].format||'mm/dd/yyyy');
42
+ this.isInline = false;
43
+ this.isInput = this.element.is('input');
44
+ this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
45
+ this.hasInput = this.component && this.element.find('input').length;
46
+ if(this.component && this.component.length === 0)
47
+ this.component = false;
48
+
49
+ this._attachEvents();
50
+
51
+ this.forceParse = true;
52
+ if ('forceParse' in options) {
53
+ this.forceParse = options.forceParse;
54
+ } else if ('dateForceParse' in this.element.data()) {
55
+ this.forceParse = this.element.data('date-force-parse');
56
+ }
57
+
58
+
59
+ this.picker = $(DPGlobal.template)
60
+ .appendTo(this.isInline ? this.element : 'body')
61
+ .on({
62
+ click: $.proxy(this.click, this),
63
+ mousedown: $.proxy(this.mousedown, this)
64
+ });
65
+
66
+ if(this.isInline) {
67
+ this.picker.addClass('datepicker-inline');
68
+ } else {
69
+ this.picker.addClass('datepicker-dropdown dropdown-menu');
70
+ }
71
+ if (this.isRTL){
72
+ this.picker.addClass('datepicker-rtl');
73
+ this.picker.find('.prev i, .next i')
74
+ .toggleClass('icon-arrow-left icon-arrow-right');
75
+ }
76
+ $(document).on('mousedown', function (e) {
77
+ // Clicked outside the datepicker, hide it
78
+ if ($(e.target).closest('.datepicker.datepicker-inline, .datepicker.datepicker-dropdown').length === 0) {
79
+ that.hide();
80
+ }
81
+ });
82
+
83
+ this.autoclose = false;
84
+ if ('autoclose' in options) {
85
+ this.autoclose = options.autoclose;
86
+ } else if ('dateAutoclose' in this.element.data()) {
87
+ this.autoclose = this.element.data('date-autoclose');
88
+ }
89
+
90
+ this.keyboardNavigation = true;
91
+ if ('keyboardNavigation' in options) {
92
+ this.keyboardNavigation = options.keyboardNavigation;
93
+ } else if ('dateKeyboardNavigation' in this.element.data()) {
94
+ this.keyboardNavigation = this.element.data('date-keyboard-navigation');
95
+ }
96
+
97
+ this.viewMode = this.startViewMode = 0;
98
+ switch(options.startView || this.element.data('date-start-view')){
99
+ case 2:
100
+ case 'decade':
101
+ this.viewMode = this.startViewMode = 2;
102
+ break;
103
+ case 1:
104
+ case 'year':
105
+ this.viewMode = this.startViewMode = 1;
106
+ break;
107
+ }
108
+
109
+ this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false);
110
+ this.todayHighlight = (options.todayHighlight||this.element.data('date-today-highlight')||false);
111
+
112
+ this.calendarWeeks = false;
113
+ if ('calendarWeeks' in options) {
114
+ this.calendarWeeks = options.calendarWeeks;
115
+ } else if ('dateCalendarWeeks' in this.element.data()) {
116
+ this.calendarWeeks = this.element.data('date-calendar-weeks');
117
+ }
118
+ if (this.calendarWeeks)
119
+ this.picker.find('tfoot th.today')
120
+ .attr('colspan', function(i, val){
121
+ return parseInt(val) + 1;
122
+ });
123
+
124
+ this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7);
125
+ this.weekEnd = ((this.weekStart + 6) % 7);
126
+ this.startDate = -Infinity;
127
+ this.endDate = Infinity;
128
+ this.daysOfWeekDisabled = [];
129
+ this.setStartDate(options.startDate||this.element.data('date-startdate'));
130
+ this.setEndDate(options.endDate||this.element.data('date-enddate'));
131
+ this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled'));
132
+ this.fillDow();
133
+ this.fillMonths();
134
+ this.update();
135
+ this.showMode();
136
+
137
+ if(this.isInline) {
138
+ this.show();
139
+ }
140
+ };
141
+
142
+ Datepicker.prototype = {
143
+ constructor: Datepicker,
144
+
145
+ _events: [],
146
+ _attachEvents: function(){
147
+ this._detachEvents();
148
+ if (this.isInput) { // single input
149
+ this._events = [
150
+ [this.element, {
151
+ focus: $.proxy(this.show, this),
152
+ keyup: $.proxy(this.update, this),
153
+ keydown: $.proxy(this.keydown, this)
154
+ }]
155
+ ];
156
+ }
157
+ else if (this.component && this.hasInput){ // component: input + button
158
+ this._events = [
159
+ // For components that are not readonly, allow keyboard nav
160
+ [this.element.find('input'), {
161
+ focus: $.proxy(this.show, this),
162
+ keyup: $.proxy(this.update, this),
163
+ keydown: $.proxy(this.keydown, this)
164
+ }],
165
+ [this.component, {
166
+ click: $.proxy(this.show, this)
167
+ }]
168
+ ];
169
+ }
170
+ else if (this.element.is('div')) { // inline datepicker
171
+ this.isInline = true;
172
+ }
173
+ else {
174
+ this._events = [
175
+ [this.element, {
176
+ click: $.proxy(this.show, this)
177
+ }]
178
+ ];
179
+ }
180
+ for (var i=0, el, ev; i<this._events.length; i++){
181
+ el = this._events[i][0];
182
+ ev = this._events[i][1];
183
+ el.on(ev);
184
+ }
185
+ },
186
+ _detachEvents: function(){
187
+ for (var i=0, el, ev; i<this._events.length; i++){
188
+ el = this._events[i][0];
189
+ ev = this._events[i][1];
190
+ el.off(ev);
191
+ }
192
+ this._events = [];
193
+ },
194
+
195
+ show: function(e) {
196
+ this.picker.show();
197
+ this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
198
+ this.update();
199
+ this.place();
200
+ $(window).on('resize', $.proxy(this.place, this));
201
+ if (e ) {
202
+ e.stopPropagation();
203
+ e.preventDefault();
204
+ }
205
+ this.element.trigger({
206
+ type: 'show',
207
+ date: this.date
208
+ });
209
+ },
210
+
211
+ hide: function(e){
212
+ if(this.isInline) return;
213
+ if (!this.picker.is(':visible')) return;
214
+ this.picker.hide();
215
+ $(window).off('resize', this.place);
216
+ this.viewMode = this.startViewMode;
217
+ this.showMode();
218
+ if (!this.isInput) {
219
+ $(document).off('mousedown', this.hide);
220
+ }
221
+
222
+ if (
223
+ this.forceParse &&
224
+ (
225
+ this.isInput && this.element.val() ||
226
+ this.hasInput && this.element.find('input').val()
227
+ )
228
+ )
229
+ this.setValue();
230
+ this.element.trigger({
231
+ type: 'hide',
232
+ date: this.date
233
+ });
234
+ },
235
+
236
+ remove: function() {
237
+ this._detachEvents();
238
+ this.picker.remove();
239
+ delete this.element.data().datepicker;
240
+ },
241
+
242
+ getDate: function() {
243
+ var d = this.getUTCDate();
244
+ return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
245
+ },
246
+
247
+ getUTCDate: function() {
248
+ return this.date;
249
+ },
250
+
251
+ setDate: function(d) {
252
+ this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
253
+ },
254
+
255
+ setUTCDate: function(d) {
256
+ this.date = d;
257
+ this.setValue();
258
+ },
259
+
260
+ setValue: function() {
261
+ var formatted = this.getFormattedDate();
262
+ if (!this.isInput) {
263
+ if (this.component){
264
+ this.element.find('input').val(formatted);
265
+ }
266
+ this.element.data('date', formatted);
267
+ } else {
268
+ this.element.val(formatted);
269
+ }
270
+ },
271
+
272
+ getFormattedDate: function(format) {
273
+ if (format === undefined)
274
+ format = this.format;
275
+ return DPGlobal.formatDate(this.date, format, this.language);
276
+ },
277
+
278
+ setStartDate: function(startDate){
279
+ this.startDate = startDate||-Infinity;
280
+ if (this.startDate !== -Infinity) {
281
+ this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language);
282
+ }
283
+ this.update();
284
+ this.updateNavArrows();
285
+ },
286
+
287
+ setEndDate: function(endDate){
288
+ this.endDate = endDate||Infinity;
289
+ if (this.endDate !== Infinity) {
290
+ this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language);
291
+ }
292
+ this.update();
293
+ this.updateNavArrows();
294
+ },
295
+
296
+ setDaysOfWeekDisabled: function(daysOfWeekDisabled){
297
+ this.daysOfWeekDisabled = daysOfWeekDisabled||[];
298
+ if (!$.isArray(this.daysOfWeekDisabled)) {
299
+ this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
300
+ }
301
+ this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) {
302
+ return parseInt(d, 10);
303
+ });
304
+ this.update();
305
+ this.updateNavArrows();
306
+ },
307
+
308
+ place: function(){
309
+ if(this.isInline) return;
310
+ var zIndex = parseInt(this.element.parents().filter(function() {
311
+ return $(this).css('z-index') != 'auto';
312
+ }).first().css('z-index'))+10;
313
+ var offset = this.component ? this.component.offset() : this.element.offset();
314
+ var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(true);
315
+ this.picker.css({
316
+ top: offset.top + height,
317
+ left: offset.left,
318
+ zIndex: zIndex
319
+ });
320
+ },
321
+
322
+ update: function(){
323
+ var date, fromArgs = false;
324
+ if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {
325
+ date = arguments[0];
326
+ fromArgs = true;
327
+ } else {
328
+ date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val();
329
+ }
330
+
331
+ this.date = DPGlobal.parseDate(date, this.format, this.language);
332
+
333
+ if(fromArgs) this.setValue();
334
+
335
+ if (this.date < this.startDate) {
336
+ this.viewDate = new Date(this.startDate);
337
+ } else if (this.date > this.endDate) {
338
+ this.viewDate = new Date(this.endDate);
339
+ } else {
340
+ this.viewDate = new Date(this.date);
341
+ }
342
+ this.fill();
343
+ },
344
+
345
+ fillDow: function(){
346
+ var dowCnt = this.weekStart,
347
+ html = '<tr>';
348
+ if(this.calendarWeeks){
349
+ var cell = '<th class="cw">&nbsp;</th>';
350
+ html += cell;
351
+ this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
352
+ }
353
+ while (dowCnt < this.weekStart + 7) {
354
+ html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>';
355
+ }
356
+ html += '</tr>';
357
+ this.picker.find('.datepicker-days thead').append(html);
358
+ },
359
+
360
+ fillMonths: function(){
361
+ var html = '',
362
+ i = 0;
363
+ while (i < 12) {
364
+ html += '<span class="month">'+dates[this.language].monthsShort[i++]+'</span>';
365
+ }
366
+ this.picker.find('.datepicker-months td').html(html);
367
+ },
368
+
369
+ fill: function() {
370
+ var d = new Date(this.viewDate),
371
+ year = d.getUTCFullYear(),
372
+ month = d.getUTCMonth(),
373
+ startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
374
+ startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
375
+ endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
376
+ endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
377
+ currentDate = this.date && this.date.valueOf(),
378
+ today = new Date();
379
+ this.picker.find('.datepicker-days thead th.switch')
380
+ .text(dates[this.language].months[month]+' '+year);
381
+ this.picker.find('tfoot th.today')
382
+ .text(dates[this.language].today)
383
+ .toggle(this.todayBtn !== false);
384
+ this.updateNavArrows();
385
+ this.fillMonths();
386
+ var prevMonth = UTCDate(year, month-1, 28,0,0,0,0),
387
+ day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
388
+ prevMonth.setUTCDate(day);
389
+ prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
390
+ var nextMonth = new Date(prevMonth);
391
+ nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
392
+ nextMonth = nextMonth.valueOf();
393
+ var html = [];
394
+ var clsName;
395
+ while(prevMonth.valueOf() < nextMonth) {
396
+ if (prevMonth.getUTCDay() == this.weekStart) {
397
+ html.push('<tr>');
398
+ if(this.calendarWeeks){
399
+ // adapted from https://github.com/timrwood/moment/blob/master/moment.js#L128
400
+ var a = new Date(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth(), prevMonth.getUTCDate() - prevMonth.getDay() + 10 - (this.weekStart && this.weekStart%7 < 5 && 7)),
401
+ b = new Date(a.getFullYear(), 0, 4),
402
+ calWeek = ~~((a - b) / 864e5 / 7 + 1.5);
403
+ html.push('<td class="cw">'+ calWeek +'</td>');
404
+ }
405
+ }
406
+ clsName = '';
407
+ if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
408
+ clsName += ' old';
409
+ } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
410
+ clsName += ' new';
411
+ }
412
+ // Compare internal UTC date with local today, not UTC today
413
+ if (this.todayHighlight &&
414
+ prevMonth.getUTCFullYear() == today.getFullYear() &&
415
+ prevMonth.getUTCMonth() == today.getMonth() &&
416
+ prevMonth.getUTCDate() == today.getDate()) {
417
+ clsName += ' today';
418
+ }
419
+ if (currentDate && prevMonth.valueOf() == currentDate) {
420
+ clsName += ' active';
421
+ }
422
+ if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
423
+ $.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) {
424
+ clsName += ' disabled';
425
+ }
426
+ html.push('<td class="day'+clsName+'">'+prevMonth.getUTCDate() + '</td>');
427
+ if (prevMonth.getUTCDay() == this.weekEnd) {
428
+ html.push('</tr>');
429
+ }
430
+ prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
431
+ }
432
+ this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
433
+ var currentYear = this.date && this.date.getUTCFullYear();
434
+
435
+ var months = this.picker.find('.datepicker-months')
436
+ .find('th:eq(1)')
437
+ .text(year)
438
+ .end()
439
+ .find('span').removeClass('active');
440
+ if (currentYear && currentYear == year) {
441
+ months.eq(this.date.getUTCMonth()).addClass('active');
442
+ }
443
+ if (year < startYear || year > endYear) {
444
+ months.addClass('disabled');
445
+ }
446
+ if (year == startYear) {
447
+ months.slice(0, startMonth).addClass('disabled');
448
+ }
449
+ if (year == endYear) {
450
+ months.slice(endMonth+1).addClass('disabled');
451
+ }
452
+
453
+ html = '';
454
+ year = parseInt(year/10, 10) * 10;
455
+ var yearCont = this.picker.find('.datepicker-years')
456
+ .find('th:eq(1)')
457
+ .text(year + '-' + (year + 9))
458
+ .end()
459
+ .find('td');
460
+ year -= 1;
461
+ for (var i = -1; i < 11; i++) {
462
+ html += '<span class="year'+(i == -1 || i == 10 ? ' old' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>';
463
+ year += 1;
464
+ }
465
+ yearCont.html(html);
466
+ },
467
+
468
+ updateNavArrows: function() {
469
+ var d = new Date(this.viewDate),
470
+ year = d.getUTCFullYear(),
471
+ month = d.getUTCMonth();
472
+ switch (this.viewMode) {
473
+ case 0:
474
+ if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
475
+ this.picker.find('.prev').css({visibility: 'hidden'});
476
+ } else {
477
+ this.picker.find('.prev').css({visibility: 'visible'});
478
+ }
479
+ if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
480
+ this.picker.find('.next').css({visibility: 'hidden'});
481
+ } else {
482
+ this.picker.find('.next').css({visibility: 'visible'});
483
+ }
484
+ break;
485
+ case 1:
486
+ case 2:
487
+ if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
488
+ this.picker.find('.prev').css({visibility: 'hidden'});
489
+ } else {
490
+ this.picker.find('.prev').css({visibility: 'visible'});
491
+ }
492
+ if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
493
+ this.picker.find('.next').css({visibility: 'hidden'});
494
+ } else {
495
+ this.picker.find('.next').css({visibility: 'visible'});
496
+ }
497
+ break;
498
+ }
499
+ },
500
+
501
+ click: function(e) {
502
+ e.stopPropagation();
503
+ e.preventDefault();
504
+ var target = $(e.target).closest('span, td, th');
505
+ if (target.length == 1) {
506
+ switch(target[0].nodeName.toLowerCase()) {
507
+ case 'th':
508
+ switch(target[0].className) {
509
+ case 'switch':
510
+ this.showMode(1);
511
+ break;
512
+ case 'prev':
513
+ case 'next':
514
+ var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
515
+ switch(this.viewMode){
516
+ case 0:
517
+ this.viewDate = this.moveMonth(this.viewDate, dir);
518
+ break;
519
+ case 1:
520
+ case 2:
521
+ this.viewDate = this.moveYear(this.viewDate, dir);
522
+ break;
523
+ }
524
+ this.fill();
525
+ break;
526
+ case 'today':
527
+ var date = new Date();
528
+ date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
529
+
530
+ this.showMode(-2);
531
+ var which = this.todayBtn == 'linked' ? null : 'view';
532
+ this._setDate(date, which);
533
+ break;
534
+ }
535
+ break;
536
+ case 'span':
537
+ if (!target.is('.disabled')) {
538
+ this.viewDate.setUTCDate(1);
539
+ if (target.is('.month')) {
540
+ var month = target.parent().find('span').index(target);
541
+ this.viewDate.setUTCMonth(month);
542
+ this.element.trigger({
543
+ type: 'changeMonth',
544
+ date: this.viewDate
545
+ });
546
+ } else {
547
+ var year = parseInt(target.text(), 10)||0;
548
+ this.viewDate.setUTCFullYear(year);
549
+ this.element.trigger({
550
+ type: 'changeYear',
551
+ date: this.viewDate
552
+ });
553
+ }
554
+ this.showMode(-1);
555
+ this.fill();
556
+ }
557
+ break;
558
+ case 'td':
559
+ if (target.is('.day') && !target.is('.disabled')){
560
+ var day = parseInt(target.text(), 10)||1;
561
+ var year = this.viewDate.getUTCFullYear(),
562
+ month = this.viewDate.getUTCMonth();
563
+ if (target.is('.old')) {
564
+ if (month === 0) {
565
+ month = 11;
566
+ year -= 1;
567
+ } else {
568
+ month -= 1;
569
+ }
570
+ } else if (target.is('.new')) {
571
+ if (month == 11) {
572
+ month = 0;
573
+ year += 1;
574
+ } else {
575
+ month += 1;
576
+ }
577
+ }
578
+ this._setDate(UTCDate(year, month, day,0,0,0,0));
579
+ }
580
+ break;
581
+ }
582
+ }
583
+ },
584
+
585
+ _setDate: function(date, which){
586
+ if (!which || which == 'date')
587
+ this.date = date;
588
+ if (!which || which == 'view')
589
+ this.viewDate = date;
590
+ this.fill();
591
+ this.setValue();
592
+ this.element.trigger({
593
+ type: 'changeDate',
594
+ date: this.date
595
+ });
596
+ var element;
597
+ if (this.isInput) {
598
+ element = this.element;
599
+ } else if (this.component){
600
+ element = this.element.find('input');
601
+ }
602
+ if (element) {
603
+ element.change();
604
+ if (this.autoclose && (!which || which == 'date')) {
605
+ this.hide();
606
+ }
607
+ }
608
+ },
609
+
610
+ moveMonth: function(date, dir){
611
+ if (!dir) return date;
612
+ var new_date = new Date(date.valueOf()),
613
+ day = new_date.getUTCDate(),
614
+ month = new_date.getUTCMonth(),
615
+ mag = Math.abs(dir),
616
+ new_month, test;
617
+ dir = dir > 0 ? 1 : -1;
618
+ if (mag == 1){
619
+ test = dir == -1
620
+ // If going back one month, make sure month is not current month
621
+ // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
622
+ ? function(){ return new_date.getUTCMonth() == month; }
623
+ // If going forward one month, make sure month is as expected
624
+ // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
625
+ : function(){ return new_date.getUTCMonth() != new_month; };
626
+ new_month = month + dir;
627
+ new_date.setUTCMonth(new_month);
628
+ // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
629
+ if (new_month < 0 || new_month > 11)
630
+ new_month = (new_month + 12) % 12;
631
+ } else {
632
+ // For magnitudes >1, move one month at a time...
633
+ for (var i=0; i<mag; i++)
634
+ // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
635
+ new_date = this.moveMonth(new_date, dir);
636
+ // ...then reset the day, keeping it in the new month
637
+ new_month = new_date.getUTCMonth();
638
+ new_date.setUTCDate(day);
639
+ test = function(){ return new_month != new_date.getUTCMonth(); };
640
+ }
641
+ // Common date-resetting loop -- if date is beyond end of month, make it
642
+ // end of month
643
+ while (test()){
644
+ new_date.setUTCDate(--day);
645
+ new_date.setUTCMonth(new_month);
646
+ }
647
+ return new_date;
648
+ },
649
+
650
+ moveYear: function(date, dir){
651
+ return this.moveMonth(date, dir*12);
652
+ },
653
+
654
+ dateWithinRange: function(date){
655
+ return date >= this.startDate && date <= this.endDate;
656
+ },
657
+
658
+ keydown: function(e){
659
+ if (this.picker.is(':not(:visible)')){
660
+ if (e.keyCode == 27) // allow escape to hide and re-show picker
661
+ this.show();
662
+ return;
663
+ }
664
+ var dateChanged = false,
665
+ dir, day, month,
666
+ newDate, newViewDate;
667
+ switch(e.keyCode){
668
+ case 27: // escape
669
+ this.hide();
670
+ e.preventDefault();
671
+ break;
672
+ case 37: // left
673
+ case 39: // right
674
+ if (!this.keyboardNavigation) break;
675
+ dir = e.keyCode == 37 ? -1 : 1;
676
+ if (e.ctrlKey){
677
+ newDate = this.moveYear(this.date, dir);
678
+ newViewDate = this.moveYear(this.viewDate, dir);
679
+ } else if (e.shiftKey){
680
+ newDate = this.moveMonth(this.date, dir);
681
+ newViewDate = this.moveMonth(this.viewDate, dir);
682
+ } else {
683
+ newDate = new Date(this.date);
684
+ newDate.setUTCDate(this.date.getUTCDate() + dir);
685
+ newViewDate = new Date(this.viewDate);
686
+ newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
687
+ }
688
+ if (this.dateWithinRange(newDate)){
689
+ this.date = newDate;
690
+ this.viewDate = newViewDate;
691
+ this.setValue();
692
+ this.update();
693
+ e.preventDefault();
694
+ dateChanged = true;
695
+ }
696
+ break;
697
+ case 38: // up
698
+ case 40: // down
699
+ if (!this.keyboardNavigation) break;
700
+ dir = e.keyCode == 38 ? -1 : 1;
701
+ if (e.ctrlKey){
702
+ newDate = this.moveYear(this.date, dir);
703
+ newViewDate = this.moveYear(this.viewDate, dir);
704
+ } else if (e.shiftKey){
705
+ newDate = this.moveMonth(this.date, dir);
706
+ newViewDate = this.moveMonth(this.viewDate, dir);
707
+ } else {
708
+ newDate = new Date(this.date);
709
+ newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
710
+ newViewDate = new Date(this.viewDate);
711
+ newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
712
+ }
713
+ if (this.dateWithinRange(newDate)){
714
+ this.date = newDate;
715
+ this.viewDate = newViewDate;
716
+ this.setValue();
717
+ this.update();
718
+ e.preventDefault();
719
+ dateChanged = true;
720
+ }
721
+ break;
722
+ case 13: // enter
723
+ this.setValue();
724
+ this.update();
725
+ e.preventDefault();
726
+ dateChanged = true;
727
+ this.hide();
728
+ break;
729
+ case 9: // tab
730
+ this.hide();
731
+ break;
732
+ }
733
+ if (dateChanged){
734
+ this.element.trigger({
735
+ type: 'changeDate',
736
+ date: this.date
737
+ });
738
+ var element;
739
+ if (this.isInput) {
740
+ element = this.element;
741
+ } else if (this.component){
742
+ element = this.element.find('input');
743
+ }
744
+ if (element) {
745
+ element.change();
746
+ }
747
+ }
748
+ },
749
+
750
+ showMode: function(dir) {
751
+ if (dir) {
752
+ this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
753
+ }
754
+ /*
755
+ vitalets: fixing bug of very special conditions:
756
+ jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover.
757
+ Method show() does not set display css correctly and datepicker is not shown.
758
+ Changed to .css('display', 'block') solve the problem.
759
+ See https://github.com/vitalets/x-editable/issues/37
760
+
761
+ In jquery 1.7.2+ everything works fine.
762
+ */
763
+ //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
764
+ this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
765
+ this.updateNavArrows();
766
+ }
767
+ };
768
+
769
+ $.fn.datepicker = function ( option ) {
770
+ var args = Array.apply(null, arguments);
771
+ args.shift();
772
+ return this.each(function () {
773
+ var $this = $(this),
774
+ data = $this.data('datepicker'),
775
+ options = typeof option == 'object' && option;
776
+ if (!data) {
777
+ $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
778
+ }
779
+ if (typeof option == 'string' && typeof data[option] == 'function') {
780
+ data[option].apply(data, args);
781
+ }
782
+ });
783
+ };
784
+
785
+ $.fn.datepicker.defaults = {
786
+ };
787
+ $.fn.datepicker.Constructor = Datepicker;
788
+ var dates = $.fn.datepicker.dates = {
789
+ en: {
790
+ days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
791
+ daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
792
+ daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
793
+ months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
794
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
795
+ today: "Today"
796
+ }
797
+ };
798
+
799
+ var DPGlobal = {
800
+ modes: [
801
+ {
802
+ clsName: 'days',
803
+ navFnc: 'Month',
804
+ navStep: 1
805
+ },
806
+ {
807
+ clsName: 'months',
808
+ navFnc: 'FullYear',
809
+ navStep: 1
810
+ },
811
+ {
812
+ clsName: 'years',
813
+ navFnc: 'FullYear',
814
+ navStep: 10
815
+ }],
816
+ isLeapYear: function (year) {
817
+ return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
818
+ },
819
+ getDaysInMonth: function (year, month) {
820
+ return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
821
+ },
822
+ validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
823
+ nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
824
+ parseFormat: function(format){
825
+ // IE treats \0 as a string end in inputs (truncating the value),
826
+ // so it's a bad format delimiter, anyway
827
+ var separators = format.replace(this.validParts, '\0').split('\0'),
828
+ parts = format.match(this.validParts);
829
+ if (!separators || !separators.length || !parts || parts.length === 0){
830
+ throw new Error("Invalid date format.");
831
+ }
832
+ return {separators: separators, parts: parts};
833
+ },
834
+ parseDate: function(date, format, language) {
835
+ if (date instanceof Date) return date;
836
+ if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {
837
+ var part_re = /([\-+]\d+)([dmwy])/,
838
+ parts = date.match(/([\-+]\d+)([dmwy])/g),
839
+ part, dir;
840
+ date = new Date();
841
+ for (var i=0; i<parts.length; i++) {
842
+ part = part_re.exec(parts[i]);
843
+ dir = parseInt(part[1]);
844
+ switch(part[2]){
845
+ case 'd':
846
+ date.setUTCDate(date.getUTCDate() + dir);
847
+ break;
848
+ case 'm':
849
+ date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
850
+ break;
851
+ case 'w':
852
+ date.setUTCDate(date.getUTCDate() + dir * 7);
853
+ break;
854
+ case 'y':
855
+ date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
856
+ break;
857
+ }
858
+ }
859
+ return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
860
+ }
861
+ var parts = date && date.match(this.nonpunctuation) || [],
862
+ date = new Date(),
863
+ parsed = {},
864
+ setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
865
+ setters_map = {
866
+ yyyy: function(d,v){ return d.setUTCFullYear(v); },
867
+ yy: function(d,v){ return d.setUTCFullYear(2000+v); },
868
+ m: function(d,v){
869
+ v -= 1;
870
+ while (v<0) v += 12;
871
+ v %= 12;
872
+ d.setUTCMonth(v);
873
+ while (d.getUTCMonth() != v)
874
+ d.setUTCDate(d.getUTCDate()-1);
875
+ return d;
876
+ },
877
+ d: function(d,v){ return d.setUTCDate(v); }
878
+ },
879
+ val, filtered, part;
880
+ setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
881
+ setters_map['dd'] = setters_map['d'];
882
+ date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
883
+ var fparts = format.parts.slice();
884
+ // Remove noop parts
885
+ if (parts.length != fparts.length) {
886
+ fparts = $(fparts).filter(function(i,p){
887
+ return $.inArray(p, setters_order) !== -1;
888
+ }).toArray();
889
+ }
890
+ // Process remainder
891
+ if (parts.length == fparts.length) {
892
+ for (var i=0, cnt = fparts.length; i < cnt; i++) {
893
+ val = parseInt(parts[i], 10);
894
+ part = fparts[i];
895
+ if (isNaN(val)) {
896
+ switch(part) {
897
+ case 'MM':
898
+ filtered = $(dates[language].months).filter(function(){
899
+ var m = this.slice(0, parts[i].length),
900
+ p = parts[i].slice(0, m.length);
901
+ return m == p;
902
+ });
903
+ val = $.inArray(filtered[0], dates[language].months) + 1;
904
+ break;
905
+ case 'M':
906
+ filtered = $(dates[language].monthsShort).filter(function(){
907
+ var m = this.slice(0, parts[i].length),
908
+ p = parts[i].slice(0, m.length);
909
+ return m == p;
910
+ });
911
+ val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
912
+ break;
913
+ }
914
+ }
915
+ parsed[part] = val;
916
+ }
917
+ for (var i=0, s; i<setters_order.length; i++){
918
+ s = setters_order[i];
919
+ if (s in parsed && !isNaN(parsed[s]))
920
+ setters_map[s](date, parsed[s]);
921
+ }
922
+ }
923
+ return date;
924
+ },
925
+ formatDate: function(date, format, language){
926
+ var val = {
927
+ d: date.getUTCDate(),
928
+ D: dates[language].daysShort[date.getUTCDay()],
929
+ DD: dates[language].days[date.getUTCDay()],
930
+ m: date.getUTCMonth() + 1,
931
+ M: dates[language].monthsShort[date.getUTCMonth()],
932
+ MM: dates[language].months[date.getUTCMonth()],
933
+ yy: date.getUTCFullYear().toString().substring(2),
934
+ yyyy: date.getUTCFullYear()
935
+ };
936
+ val.dd = (val.d < 10 ? '0' : '') + val.d;
937
+ val.mm = (val.m < 10 ? '0' : '') + val.m;
938
+ var date = [],
939
+ seps = $.extend([], format.separators);
940
+ for (var i=0, cnt = format.parts.length; i < cnt; i++) {
941
+ if (seps.length)
942
+ date.push(seps.shift());
943
+ date.push(val[format.parts[i]]);
944
+ }
945
+ return date.join('');
946
+ },
947
+ headTemplate: '<thead>'+
948
+ '<tr>'+
949
+ '<th class="prev"><i class="icon-arrow-left"/></th>'+
950
+ '<th colspan="5" class="switch"></th>'+
951
+ '<th class="next"><i class="icon-arrow-right"/></th>'+
952
+ '</tr>'+
953
+ '</thead>',
954
+ contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
955
+ footTemplate: '<tfoot><tr><th colspan="7" class="today"></th></tr></tfoot>'
956
+ };
957
+ DPGlobal.template = '<div class="datepicker">'+
958
+ '<div class="datepicker-days">'+
959
+ '<table class=" table-condensed">'+
960
+ DPGlobal.headTemplate+
961
+ '<tbody></tbody>'+
962
+ DPGlobal.footTemplate+
963
+ '</table>'+
964
+ '</div>'+
965
+ '<div class="datepicker-months">'+
966
+ '<table class="table-condensed">'+
967
+ DPGlobal.headTemplate+
968
+ DPGlobal.contTemplate+
969
+ DPGlobal.footTemplate+
970
+ '</table>'+
971
+ '</div>'+
972
+ '<div class="datepicker-years">'+
973
+ '<table class="table-condensed">'+
974
+ DPGlobal.headTemplate+
975
+ DPGlobal.contTemplate+
976
+ DPGlobal.footTemplate+
977
+ '</table>'+
978
+ '</div>'+
979
+ '</div>';
980
+
981
+ $.fn.datepicker.DPGlobal = DPGlobal;
982
+
983
+ }( window.jQuery );