beautiful_scaffold 0.3.3 → 0.3.4

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 (43) hide show
  1. data/CHANGELOG +9 -0
  2. data/beautiful_scaffold.gemspec +1 -1
  3. data/lib/generators/beautiful_devisecancan_generator.rb +2 -2
  4. data/lib/generators/beautiful_locale_generator.rb +32 -19
  5. data/lib/generators/beautiful_scaffold_common_methods.rb +7 -4
  6. data/lib/generators/beautiful_scaffold_generator.rb +6 -2
  7. data/lib/generators/templates/app/assets/javascripts/application-bs.js +2 -8
  8. data/lib/generators/templates/app/assets/javascripts/beautiful_scaffold.js +11 -11
  9. data/lib/generators/templates/app/assets/javascripts/bootstrap-colorpicker.js +1 -1
  10. data/lib/generators/templates/app/assets/javascripts/bootstrap-datepicker.js +799 -799
  11. data/lib/generators/templates/app/assets/javascripts/bootstrap-datetimepicker-for-beautiful-scaffold.js +17 -15
  12. data/lib/generators/templates/app/assets/javascripts/bootstrap-timepicker.js +135 -131
  13. data/lib/generators/templates/app/assets/javascripts/bootstrap-wysihtml5.js +24 -16
  14. data/lib/generators/templates/app/assets/javascripts/fixed_menu.js +7 -7
  15. data/lib/generators/templates/app/assets/stylesheets/application-bs.css +1 -0
  16. data/lib/generators/templates/app/assets/stylesheets/beautiful-scaffold.css.scss +4 -4
  17. data/lib/generators/templates/app/assets/stylesheets/bootstrap_and_overrides.css.less +40 -0
  18. data/lib/generators/templates/app/assets/stylesheets/colorpicker.css +1 -1
  19. data/lib/generators/templates/app/assets/stylesheets/datepicker.css +2 -2
  20. data/lib/generators/templates/app/assets/stylesheets/timepicker.css +3 -6
  21. data/lib/generators/templates/app/controllers/base.rb +4 -4
  22. data/lib/generators/templates/app/controllers/master_base.rb +1 -1
  23. data/lib/generators/templates/app/helpers/beautiful_helper.rb +31 -33
  24. data/lib/generators/templates/app/initializers/link_renderer.rb +5 -5
  25. data/lib/generators/templates/app/views/_form.html.erb +2 -2
  26. data/lib/generators/templates/app/views/_form_habtm_tag.html.erb +2 -2
  27. data/lib/generators/templates/app/views/_mass_inserting.html.erb +6 -6
  28. data/lib/generators/templates/app/views/_modal_columns.html.erb +19 -15
  29. data/lib/generators/templates/app/views/edit.html.erb +1 -1
  30. data/lib/generators/templates/app/views/index.html.erb +36 -34
  31. data/lib/generators/templates/app/views/layout.html.erb +19 -28
  32. data/lib/generators/templates/app/views/new.html.erb +1 -1
  33. data/lib/generators/templates/app/views/partials/_forget_password.html.erb +21 -17
  34. data/lib/generators/templates/app/views/partials/_form_field.html.erb +40 -58
  35. data/lib/generators/templates/app/views/partials/_index_batch.html.erb +2 -2
  36. data/lib/generators/templates/app/views/partials/_index_column.html.erb +17 -17
  37. data/lib/generators/templates/app/views/partials/_index_header.html.erb +7 -7
  38. data/lib/generators/templates/app/views/partials/_index_search.html.erb +1 -1
  39. data/lib/generators/templates/app/views/partials/_index_search_default_fields.html.erb +1 -1
  40. data/lib/generators/templates/app/views/partials/_register_form.html.erb +38 -34
  41. data/lib/generators/templates/app/views/partials/_sign_in_form.html.erb +4 -4
  42. data/lib/generators/templates/app/views/show.html.erb +2 -2
  43. metadata +40 -20
data/CHANGELOG CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.3.4
2
+
3
+ * bugfix
4
+ * Show number element in table (i18n bug)
5
+ * Improve translation (keep manual translation and check previous translated string)
6
+ * alert-error -> alert-danger (bootstrap 3)
7
+ * Insert field to search-and-filter div before the accordion panel
8
+ * Columns and sort in table fixed (2 commits)
9
+
1
10
  == 0.3.3
2
11
 
3
12
  * enhancement
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "beautiful_scaffold"
6
- s.version = "0.3.3"
6
+ s.version = "0.3.4"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.summary = "Beautiful Scaffold generate fully customizable scaffold"
9
9
  s.email = "claudel.sylvain@gmail.com"
@@ -39,7 +39,7 @@ class BeautifulDevisecancanGenerator < Rails::Generators::Base
39
39
 
40
40
 
41
41
  # Limited access (Must be commented if use cancan)
42
- inject_into_file("app/controllers/beautiful_controller.rb","before_filter :authenticate_#{model}!, :except => [:dashboard]", :after => 'layout "beautiful_layout"' + "\n")
42
+ inject_into_file("app/controllers/beautiful_controller.rb","before_action :authenticate_#{model}!, :except => [:dashboard]", :after => 'layout "beautiful_layout"' + "\n")
43
43
 
44
44
  # Custom redirect
45
45
  inject_into_file("app/controllers/application_controller.rb","
@@ -123,6 +123,6 @@ class BeautifulDevisecancanGenerator < Rails::Generators::Base
123
123
  ", :after => "class ApplicationController < ActionController::Base\n")
124
124
 
125
125
  # Access controlled by CanCan (in beautiful_scaffold)
126
- inject_into_file("app/controllers/application_controller.rb", "#", :before => "before_filter :authenticate_#{model}!, :except => [:dashboard]")
126
+ inject_into_file("app/controllers/application_controller.rb", "#", :before => "before_action :authenticate_#{model}!, :except => [:dashboard]")
127
127
  end
128
128
  end
@@ -60,12 +60,20 @@ class BeautifulLocaleGenerator < Rails::Generators::Base
60
60
  begin
61
61
  hi18n = YAML.load_file(filepath)
62
62
  rescue
63
+ puts "Error loading locale file : #{filepath}"
63
64
  end
65
+
64
66
  hi18n ||= { name.downcase => {} }
65
67
  hi18n[name.downcase] ||= { 'app' => {} }
66
68
  hi18n[name.downcase]['app'] ||= { 'models' => {} }
67
69
  hi18n[name.downcase]['app']['models'] ||= {}
68
70
 
71
+ # Feed data already translated
72
+ hi18n[name.downcase]['app']['models'].each{ |modelname,hshtranslations|
73
+ hshtranslations['bs_attributes'].each{ |attr, translated_attr|
74
+ already_processed[name.downcase][attr] = translated_attr
75
+ }
76
+ }
69
77
 
70
78
  Dir.glob("app/models/**/*").each { |model_file|
71
79
  puts model_file
@@ -79,37 +87,42 @@ class BeautifulLocaleGenerator < Rails::Generators::Base
79
87
  next
80
88
  end
81
89
 
90
+ newmodel = !hi18n[name.downcase]['app']['models'].has_key?(model)
91
+
82
92
  hi18n[name.downcase]['app']['models'][model] ||= {
83
93
  'bs_caption' => model,
84
94
  'bs_caption_plural' => model.pluralize,
85
95
  'bs_attributes' => {},
86
96
  }
87
97
 
88
- begin
89
- bs_caption = translate_string(name.downcase, model)
90
- rescue
91
- bs_caption = model
92
- end
93
- hi18n[name.downcase]['app']['models'][model]['bs_caption'] = bs_caption
94
- begin
95
- bs_caption_plural = translate_string(name.downcase, model.pluralize)
96
- rescue
97
- bs_caption_plural = model.pluralize
98
+ if newmodel then
99
+ bs_caption = (begin translate_string(name.downcase, model) rescue model end)
100
+ bs_caption_plural = (begin translate_string(name.downcase, model.pluralize) rescue model.pluralize end)
101
+
102
+ hi18n[name.downcase]['app']['models'][model]['bs_caption'] = bs_caption
103
+ hi18n[name.downcase]['app']['models'][model]['bs_caption_plural'] = bs_caption_plural
98
104
  end
99
- hi18n[name.downcase]['app']['models'][model]['bs_caption_plural'] = bs_caption_plural
105
+
100
106
  hi18n[name.downcase]['app']['models'][model]['bs_attributes'] ||= {}
101
107
 
102
108
  sorted_attr.each { |k|
103
- if already_processed[name.downcase][k].nil? then
104
- begin
105
- attr_translate = translate_string(name.downcase, k)
106
- already_processed[name.downcase][k] = attr_translate
107
- rescue
108
- puts "Plantage translate API"
109
- attr_translate = k
109
+ # Si pas déjà renseigné
110
+ if hi18n[name.downcase]['app']['models'][model]['bs_attributes'][k].blank? then
111
+ # Si pas déjà traduit
112
+ if already_processed[name.downcase][k].nil? then
113
+ begin
114
+ attr_translate = translate_string(name.downcase, k)
115
+ already_processed[name.downcase][k] = attr_translate
116
+ rescue
117
+ puts "Plantage translate API"
118
+ attr_translate = k
119
+ end
120
+ else
121
+ attr_translate = already_processed[name.downcase][k]
110
122
  end
111
123
  else
112
- attr_translate = already_processed[name.downcase][k]
124
+ # Récupère l'attribut traduit
125
+ attr_translate = hi18n[name.downcase]['app']['models'][model]['bs_attributes'][k]
113
126
  end
114
127
 
115
128
  hi18n[name.downcase]['app']['models'][model]['bs_attributes'][k] = attr_translate
@@ -157,17 +157,20 @@ module BeautifulScaffoldCommonMethods
157
157
 
158
158
  def require_gems
159
159
  # for jquery-ui add "2.3.0" version for jquery-rails
160
- say_status("Warning", "Set 2.0.1 version for jquery-rails (for a good compatibility with beautiful_scaffold)", :yellow)
160
+ #say_status("Warning", "Set 2.0.1 version for jquery-rails (for a good compatibility with beautiful_scaffold)", :yellow)
161
161
 
162
+ gem('less-rails', :github => "CQQL/less-rails", :branch => 'less-2.5')
162
163
  gem('will_paginate')
163
- gem('ransack', :github => 'ernie/ransack', :branch => 'rails-4')
164
- gem('prawn', '1.0.0.rc2')
164
+ gem('ransack', :github => 'activerecord-hackery/ransack', :branch => 'rails-4.1')
165
+ gem('polyamorous', :github => 'activerecord-hackery/polyamorous')
166
+ gem('jquery-ui-rails')
167
+ gem('prawn', '1.0.0')
165
168
  gem('RedCloth')
166
169
  gem('bb-ruby')
167
170
  gem('bluecloth')
168
171
  gem('rdiscount')
169
172
  gem('sanitize')
170
- gem('twitter-bootstrap-rails')
173
+ gem('twitter-bootstrap-rails', :github => 'seyhunak/twitter-bootstrap-rails', :branch => 'bootstrap3')
171
174
  gem('chardinjs-rails')
172
175
  end
173
176
 
@@ -91,7 +91,11 @@ class BeautifulScaffoldGenerator < Rails::Generators::Base
91
91
  dir_image = "app/assets/images"
92
92
  directory dir_image, dir_image
93
93
 
94
- generate("bootstrap:install","static")
94
+ # Old method
95
+ #generate("bootstrap:install","static")
96
+ # New method
97
+ copy_file "#{stylesheetspath}bootstrap_and_overrides.css.less",
98
+ "#{stylesheetspath}bootstrap_and_overrides.css.less"
95
99
  end
96
100
 
97
101
  def generate_layout
@@ -205,7 +209,7 @@ class BeautifulScaffoldGenerator < Rails::Generators::Base
205
209
  end
206
210
 
207
211
  def install_willpaginate_renderer_for_bootstrap
208
- copy_file "app/initializers/link_renderer.rb", "config/initializers/beautiful_helper.rb"
212
+ copy_file "app/initializers/link_renderer.rb", "config/initializers/link_renderer.rb"
209
213
  end
210
214
 
211
215
  def routes
@@ -1,13 +1,7 @@
1
1
  //= require jquery
2
- //= require jquery-ui
2
+ //= require jquery.ui.all
3
3
  //= require jquery_ujs
4
- //= require twitter/bootstrap/bootstrap-transition
5
- //= require twitter/bootstrap/bootstrap-alert
6
- //= require twitter/bootstrap/bootstrap-modal
7
- //= require twitter/bootstrap/bootstrap-button
8
- //= require twitter/bootstrap/bootstrap-collapse
9
- //= require twitter/bootstrap/bootstrap-dropdown
10
- //= require twitter/bootstrap/bootstrap-tooltip
4
+ //= require twitter/bootstrap
11
5
  //= require jquery.livequery
12
6
  //= require turbolinks
13
7
  //= require a-wysihtml5-0.3.0.min
@@ -4,7 +4,7 @@ function bs_init(){
4
4
  $('.select-richtext').click(function(){
5
5
  $('.label-richtext-type[for=' + $(this).attr('id') + ']').trigger('click');
6
6
  });
7
- $('.label-richtext-type').live("click", function(){
7
+ $(document).on("click", '.label-richtext-type', function(){
8
8
  elt = $('#' + $(this).attr('for'));
9
9
  newSet = elt.val();
10
10
  idspleditor = elt.attr('data-spleditor');
@@ -69,12 +69,12 @@ function bs_init(){
69
69
  $('.color').colorpicker({format: 'rgba'});
70
70
 
71
71
  // Processing
72
- $('#checkall').click(function(){
72
+ $(document).on('click', '#checkall', function(){
73
73
  $('.cbbatch').attr('checked', ($(this).attr('checked') != undefined));
74
74
  });
75
75
 
76
76
  // Filter columns
77
- $('#filter-columns').on('click', function(){
77
+ $(document).on('click', '#filter-columns', function(){
78
78
  var return_json = [];
79
79
  $.each($('input[name^="field"]:checked'), function(index, value) {
80
80
  return_json.push($(value).val());
@@ -84,20 +84,20 @@ function bs_init(){
84
84
  url: url,
85
85
  data: { 'fields' : return_json },
86
86
  success: function(data) {
87
- $('table.table th[class^="col"], table.table td[class^="col"]').css('display', 'none');
87
+ $('table.table th[class^="bs-col"], table.table td[class^="bs-col"]').css('display', 'none');
88
88
  $.each(return_json, function(index, value) {
89
- $('table.table th.col-' + value + ', table.table td.col-' + value).css('display', 'table-cell');
89
+ $('table.table th.bs-col-' + value + ', table.table td.bs-col-' + value).css('display', 'table-cell');
90
90
  });
91
- $('div[class^="col"]').css('display', 'none');
91
+ $('div[class^="bs-col"]').css('display', 'none');
92
92
  $.each(return_json, function(index, value) {
93
- $('div.col-' + value).css('display', 'inline');
93
+ $('div.bs-col-' + value).css('display', 'inline');
94
94
  });
95
95
  $('#modal-columns').modal('hide');
96
96
  }
97
97
  });
98
98
  return false;
99
99
  });
100
- $('#cancel-filter-columns').on('click', function(){
100
+ $(document).on('click', '#cancel-filter-columns', function(){
101
101
  $('#modal-columns').modal('hide');
102
102
  return false;
103
103
  });
@@ -148,14 +148,14 @@ function bs_init(){
148
148
  });
149
149
 
150
150
  // Chardinjs (overlay instructions)
151
- $(".bs-chardinjs").on("click", function(){
151
+ $(document).on("click", ".bs-chardinjs", function(){
152
152
  var selector = $(this).attr("data-selector");
153
153
  $(selector).chardinJs('toggle');
154
154
  return false;
155
155
  });
156
156
 
157
157
  // Add Error Form style with bootstrap
158
- $("div.control-group>div.field_with_errors").parent().addClass("error");
158
+ $("div.form-group>div.field_with_errors").parent().addClass("has-error");
159
159
  $("#error_explanation").addClass("text-error");
160
160
 
161
161
  // Collapse without IDS (next)
@@ -167,7 +167,7 @@ function bs_init(){
167
167
 
168
168
  // Mass inserting set focus
169
169
  $(function() {
170
- var elt = $('form.mass-inserting div[style*="inline"][class*="col"] .input-small').first();
170
+ var elt = $('form.mass-inserting div[style*="inline"][class*="bs-col"] input').first();
171
171
  if($('form.mass-inserting').hasClass('setfocus')){
172
172
  elt.focus();
173
173
  }
@@ -135,7 +135,7 @@
135
135
  var format = options.format||this.element.data('color-format')||'hex';
136
136
  this.format = CPGlobal.translateFormats[format];
137
137
  this.isInput = this.element.is('input');
138
- this.component = this.element.is('.color') ? this.element.find('.add-on') : false;
138
+ this.component = this.element.is('.color') ? this.element.find('.input-group-addon') : false;
139
139
 
140
140
  this.picker = $(CPGlobal.template)
141
141
  .appendTo('body')
@@ -22,56 +22,56 @@
22
22
 
23
23
  // Picker object
24
24
 
25
- var Datepicker = function(element, options){
26
- this.element = $(element);
27
- this.language = options.language||this.element.data('date-language')||"en";
28
- this.language = this.language in dates ? this.language : "en";
29
- this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
30
- this.picker = $(DPGlobal.template)
31
- .appendTo('body')
32
- .on({
33
- click: $.proxy(this.click, this),
34
- mousedown: $.proxy(this.mousedown, this)
35
- });
36
- this.isInput = this.element.is('input');
37
- this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
38
- if(this.component && this.component.length === 0)
39
- this.component = false;
40
-
41
- if (this.isInput) {
42
- this.element.on({
43
- focus: $.proxy(this.show, this),
44
- blur: $.proxy(this._hide, this),
45
- keyup: $.proxy(this.update, this),
46
- keydown: $.proxy(this.keydown, this)
47
- });
48
- } else {
49
- if (this.component){
50
- // For components that are not readonly, allow keyboard nav
51
- this.element.find('input').on({
52
- focus: $.proxy(this.show, this),
53
- blur: $.proxy(this._hide, this),
54
- keyup: $.proxy(this.update, this),
55
- keydown: $.proxy(this.keydown, this)
56
- });
57
-
58
- this.component.on('click', $.proxy(this.show, this));
59
- var element = this.element.find('input');
60
- element.on({
61
- blur: $.proxy(this._hide, this)
62
- })
63
- } else {
64
- this.element.on('click', $.proxy(this.show, this));
65
- }
66
- }
67
-
68
- this.autoclose = false;
69
- if ('autoclose' in options) {
70
- this.autoclose = options.autoclose;
71
- } else if ('dateAutoclose' in this.element.data()) {
72
- this.autoclose = this.element.data('date-autoclose');
73
- }
74
-
25
+ var Datepicker = function(element, options){
26
+ this.element = $(element);
27
+ this.language = options.language||this.element.data('date-language')||"en";
28
+ this.language = this.language in dates ? this.language : "en";
29
+ this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
30
+ this.picker = $(DPGlobal.template)
31
+ .appendTo('body')
32
+ .on({
33
+ click: $.proxy(this.click, this),
34
+ mousedown: $.proxy(this.mousedown, this)
35
+ });
36
+ this.isInput = this.element.is('input');
37
+ this.component = this.element.is('.date') ? this.element.find('.input-group-addon') : false;
38
+ if(this.component && this.component.length === 0)
39
+ this.component = false;
40
+
41
+ if (this.isInput) {
42
+ this.element.on({
43
+ focus: $.proxy(this.show, this),
44
+ blur: $.proxy(this._hide, this),
45
+ keyup: $.proxy(this.update, this),
46
+ keydown: $.proxy(this.keydown, this)
47
+ });
48
+ } else {
49
+ if (this.component){
50
+ // For components that are not readonly, allow keyboard nav
51
+ this.element.find('input').on({
52
+ focus: $.proxy(this.show, this),
53
+ blur: $.proxy(this._hide, this),
54
+ keyup: $.proxy(this.update, this),
55
+ keydown: $.proxy(this.keydown, this)
56
+ });
57
+
58
+ this.component.on('click', $.proxy(this.show, this));
59
+ var element = this.element.find('input');
60
+ element.on({
61
+ blur: $.proxy(this._hide, this)
62
+ })
63
+ } else {
64
+ this.element.on('click', $.proxy(this.show, this));
65
+ }
66
+ }
67
+
68
+ this.autoclose = false;
69
+ if ('autoclose' in options) {
70
+ this.autoclose = options.autoclose;
71
+ } else if ('dateAutoclose' in this.element.data()) {
72
+ this.autoclose = this.element.data('date-autoclose');
73
+ }
74
+
75
75
  this.keyboardNavigation = true;
76
76
  if ('keyboardNavigation' in options) {
77
77
  this.keyboardNavigation = options.keyboardNavigation;
@@ -79,756 +79,756 @@
79
79
  this.keyboardNavigation = this.element.data('date-keyboard-navigation');
80
80
  }
81
81
 
82
- switch(options.startView || this.element.data('date-start-view')){
83
- case 2:
84
- case 'decade':
85
- this.viewMode = this.startViewMode = 2;
86
- break;
87
- case 1:
88
- case 'year':
89
- this.viewMode = this.startViewMode = 1;
90
- break;
91
- case 0:
92
- case 'month':
93
- default:
94
- this.viewMode = this.startViewMode = 0;
95
- break;
96
- }
97
-
98
- this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7);
99
- this.weekEnd = ((this.weekStart + 6) % 7);
100
- this.startDate = -Infinity;
101
- this.endDate = Infinity;
102
- this.setStartDate(options.startDate||this.element.data('date-startdate'));
103
- this.setEndDate(options.endDate||this.element.data('date-enddate'));
104
- this.fillDow();
105
- this.fillMonths();
106
- this.update();
107
- this.showMode();
108
- };
109
-
110
- Datepicker.prototype = {
111
- constructor: Datepicker,
112
-
113
- show: function(e) {
114
- this.picker.show();
115
- this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
116
- this.update();
117
- this.place();
118
- $(window).on('resize', $.proxy(this.place, this));
119
- if (e ) {
120
- e.stopPropagation();
121
- e.preventDefault();
122
- }
123
- if (!this.isInput) {
124
- $(document).on('mousedown', $.proxy(this.hide, this));
125
- }
126
- this.element.trigger({
127
- type: 'show',
128
- date: this.date
129
- });
130
- },
131
-
132
- _hide: function(e){
133
- // When going from the input to the picker, IE handles the blur/click
134
- // events differently than other browsers, in such a way that the blur
135
- // event triggers a hide before the click event can stop propagation.
136
- if ($.browser.msie) {
137
- var t = this, args = arguments;
138
-
139
- function cancel_hide(){
140
- clearTimeout(hide_timeout);
141
- e.target.focus();
142
- t.picker.off('click', cancel_hide);
143
- }
144
-
145
- function do_hide(){
146
- t.hide.apply(t, args);
147
- t.picker.off('click', cancel_hide);
148
- }
149
-
150
- this.picker.on('click', cancel_hide);
151
- var hide_timeout = setTimeout(do_hide, 100);
152
- } else {
153
- return this.hide.apply(this, arguments);
154
- }
155
- },
156
-
157
- hide: function(e){
158
- this.picker.hide();
159
- $(window).off('resize', this.place);
160
- this.viewMode = this.startViewMode;
161
- this.showMode();
162
- if (!this.isInput) {
163
- $(document).off('mousedown', this.hide);
164
- }
165
- if (e && e.currentTarget.value)
166
- this.setValue();
167
- this.element.trigger({
168
- type: 'hide',
169
- date: this.date
170
- });
171
- },
172
-
173
- setValue: function() {
174
- var formatted = DPGlobal.formatDate(this.date, this.format, this.language);
175
- if (!this.isInput) {
176
- if (this.component){
177
- this.element.find('input').prop('value', formatted);
178
- }
179
- this.element.data('date', formatted);
180
- } else {
181
- this.element.prop('value', formatted);
182
- }
183
- },
184
-
185
- setStartDate: function(startDate){
186
- this.startDate = startDate||-Infinity;
187
- if (this.startDate !== -Infinity) {
188
- this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language);
189
- }
190
- this.update();
191
- this.updateNavArrows();
192
- },
193
-
194
- setEndDate: function(endDate){
195
- this.endDate = endDate||Infinity;
196
- if (this.endDate !== Infinity) {
197
- this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language);
198
- }
199
- this.update();
200
- this.updateNavArrows();
201
- },
202
-
203
- place: function(){
204
- var zIndex = parseInt(this.element.parents().filter(function() {
205
- return $(this).css('z-index') != 'auto';
206
- }).first().css('z-index'))+10;
207
- var offset = this.component ? this.component.offset() : this.element.offset();
208
- this.picker.css({
209
- top: offset.top + this.height,
210
- left: offset.left,
211
- zIndex: zIndex
212
- });
213
- },
214
-
215
- update: function(){
216
- this.date = DPGlobal.parseDate(
217
- this.isInput ? this.element.prop('value') : this.element.data('date') || this.element.find('input').prop('value'),
218
- this.format, this.language
219
- );
220
- if (this.date < this.startDate) {
221
- this.viewDate = new Date(this.startDate);
222
- } else if (this.date > this.endDate) {
223
- this.viewDate = new Date(this.endDate);
224
- } else {
225
- this.viewDate = new Date(this.date);
226
- }
227
- this.fill();
228
- },
229
-
230
- fillDow: function(){
231
- var dowCnt = this.weekStart;
232
- var html = '<tr>';
233
- while (dowCnt < this.weekStart + 7) {
234
- html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>';
235
- }
236
- html += '</tr>';
237
- this.picker.find('.datepicker-days thead').append(html);
238
- },
239
-
240
- fillMonths: function(){
241
- var html = '';
242
- var i = 0
243
- while (i < 12) {
244
- html += '<span class="month">'+dates[this.language].monthsShort[i++]+'</span>';
245
- }
246
- this.picker.find('.datepicker-months td').html(html);
247
- },
248
-
249
- fill: function() {
250
- var d = new Date(this.viewDate),
251
- year = d.getFullYear(),
252
- month = d.getMonth(),
253
- startYear = this.startDate !== -Infinity ? this.startDate.getFullYear() : -Infinity,
254
- startMonth = this.startDate !== -Infinity ? this.startDate.getMonth() : -Infinity,
255
- endYear = this.endDate !== Infinity ? this.endDate.getFullYear() : Infinity,
256
- endMonth = this.endDate !== Infinity ? this.endDate.getMonth() : Infinity,
257
- currentDate = this.date.valueOf();
258
- this.picker.find('.datepicker-days th:eq(1)')
259
- .text(dates[this.language].months[month]+' '+year);
260
- this.updateNavArrows();
261
- this.fillMonths();
262
- var prevMonth = new Date(year, month-1, 28,0,0,0,0),
263
- day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()),
264
- prevDate, dstDay = 0, date;
265
- prevMonth.setDate(day);
266
- prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7);
267
- var nextMonth = new Date(prevMonth);
268
- nextMonth.setDate(nextMonth.getDate() + 42);
269
- nextMonth = nextMonth.valueOf();
270
- var html = [];
271
- var clsName;
272
- while(prevMonth.valueOf() < nextMonth) {
273
- if (prevMonth.getDay() == this.weekStart) {
274
- html.push('<tr>');
275
- }
276
- clsName = '';
277
- if (prevMonth.getFullYear() < year || (prevMonth.getFullYear() == year && prevMonth.getMonth() < month)) {
278
- clsName += ' old';
279
- } else if (prevMonth.getFullYear() > year || (prevMonth.getFullYear() == year && prevMonth.getMonth() > month)) {
280
- clsName += ' new';
281
- }
282
- if (prevMonth.valueOf() == currentDate) {
283
- clsName += ' active';
284
- }
285
- if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate) {
286
- clsName += ' disabled';
287
- }
288
- date = prevMonth.getDate();
289
- if (dstDay == -1) date++;
290
- html.push('<td class="day'+clsName+'">'+date+ '</td>');
291
- if (prevMonth.getDay() == this.weekEnd) {
292
- html.push('</tr>');
293
- }
294
- prevDate = prevMonth.getDate();
295
- prevMonth.setDate(prevMonth.getDate()+1);
296
- if (prevMonth.getHours() != 0) {
297
- // Fix for DST bug: if we are no longer at start of day, a DST jump probably happened
298
- // We either fell back (eg, Jan 1 00:00 -> Jan 1 23:00)
299
- // or jumped forward (eg, Jan 1 00:00 -> Jan 2 01:00)
300
- // Unfortunately, I can think of no way to test this in the unit tests, as it depends
301
- // on the TZ of the client system.
302
- if (!dstDay) {
303
- // We are not currently handling a dst day (next round will deal with it)
304
- if (prevMonth.getDate() == prevDate)
305
- // We must compensate for fall-back
306
- dstDay = -1;
307
- else
308
- // We must compensate for a jump-ahead
309
- dstDay = +1;
310
- }
311
- else {
312
- // The last round was our dst day (hours are still non-zero)
313
- if (dstDay == -1)
314
- // For a fall-back, fast-forward to next midnight
315
- prevMonth.setHours(24);
316
- else
317
- // For a jump-ahead, just reset to 0
318
- prevMonth.setHours(0);
319
- // Reset minutes, as some TZs may be off by portions of an hour
320
- prevMonth.setMinutes(0);
321
- dstDay = 0;
322
- }
323
- }
324
- }
325
- this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
326
- var currentYear = this.date.getFullYear();
327
-
328
- var months = this.picker.find('.datepicker-months')
329
- .find('th:eq(1)')
330
- .text(year)
331
- .end()
332
- .find('span').removeClass('active');
333
- if (currentYear == year) {
334
- months.eq(this.date.getMonth()).addClass('active');
335
- }
336
- if (year < startYear || year > endYear) {
337
- months.addClass('disabled');
338
- }
339
- if (year == startYear) {
340
- months.slice(0, startMonth).addClass('disabled');
341
- }
342
- if (year == endYear) {
343
- months.slice(endMonth+1).addClass('disabled');
344
- }
345
-
346
- html = '';
347
- year = parseInt(year/10, 10) * 10;
348
- var yearCont = this.picker.find('.datepicker-years')
349
- .find('th:eq(1)')
350
- .text(year + '-' + (year + 9))
351
- .end()
352
- .find('td');
353
- year -= 1;
354
- for (var i = -1; i < 11; i++) {
355
- html += '<span class="year'+(i == -1 || i == 10 ? ' old' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>';
356
- year += 1;
357
- }
358
- yearCont.html(html);
359
- },
360
-
361
- updateNavArrows: function() {
362
- var d = new Date(this.viewDate),
363
- year = d.getFullYear(),
364
- month = d.getMonth();
365
- switch (this.viewMode) {
366
- case 0:
367
- if (this.startDate !== -Infinity && year <= this.startDate.getFullYear() && month <= this.startDate.getMonth()) {
368
- this.picker.find('.prev').css({visibility: 'hidden'});
369
- } else {
370
- this.picker.find('.prev').css({visibility: 'visible'});
371
- }
372
- if (this.endDate !== Infinity && year >= this.endDate.getFullYear() && month >= this.endDate.getMonth()) {
373
- this.picker.find('.next').css({visibility: 'hidden'});
374
- } else {
375
- this.picker.find('.next').css({visibility: 'visible'});
376
- }
377
- break;
378
- case 1:
379
- case 2:
380
- if (this.startDate !== -Infinity && year <= this.startDate.getFullYear()) {
381
- this.picker.find('.prev').css({visibility: 'hidden'});
382
- } else {
383
- this.picker.find('.prev').css({visibility: 'visible'});
384
- }
385
- if (this.endDate !== Infinity && year >= this.endDate.getFullYear()) {
386
- this.picker.find('.next').css({visibility: 'hidden'});
387
- } else {
388
- this.picker.find('.next').css({visibility: 'visible'});
389
- }
390
- break;
391
- }
392
- },
393
-
394
- click: function(e) {
395
- e.stopPropagation();
396
- e.preventDefault();
397
- var target = $(e.target).closest('span, td, th');
398
- if (target.length == 1) {
399
- switch(target[0].nodeName.toLowerCase()) {
400
- case 'th':
401
- switch(target[0].className) {
402
- case 'switch':
403
- this.showMode(1);
404
- break;
405
- case 'prev':
406
- case 'next':
407
- var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
408
- switch(this.viewMode){
409
- case 0:
410
- this.viewDate = this.moveMonth(this.viewDate, dir);
411
- break;
412
- case 1:
413
- case 2:
414
- this.viewDate = this.moveYear(this.viewDate, dir);
415
- break;
416
- }
417
- this.fill();
418
- break;
419
- }
420
- break;
421
- case 'span':
422
- if (!target.is('.disabled')) {
423
- this.viewDate.setDate(1);
424
- if (target.is('.month')) {
425
- var month = target.parent().find('span').index(target);
426
- this.viewDate.setMonth(month);
427
- this.element.trigger({
428
- type: 'changeMonth',
429
- date: this.viewDate
430
- });
431
- } else {
432
- var year = parseInt(target.text(), 10)||0;
433
- this.viewDate.setFullYear(year);
434
- this.element.trigger({
435
- type: 'changeYear',
436
- date: this.viewDate
437
- });
438
- }
439
- this.showMode(-1);
440
- this.fill();
441
- }
442
- break;
443
- case 'td':
444
- if (target.is('.day') && !target.is('.disabled')){
445
- var day = parseInt(target.text(), 10)||1;
446
- var year = this.viewDate.getFullYear(),
447
- month = this.viewDate.getMonth();
448
- if (target.is('.old')) {
449
- if (month == 0) {
450
- month = 11;
451
- year -= 1;
452
- } else {
453
- month -= 1;
454
- }
455
- } else if (target.is('.new')) {
456
- if (month == 11) {
457
- month = 0;
458
- year += 1;
459
- } else {
460
- month += 1;
461
- }
462
- }
463
- this.date = new Date(year, month, day,0,0,0,0);
464
- this.viewDate = new Date(year, month, day,0,0,0,0);
465
- this.fill();
466
- this.setValue();
467
- this.element.trigger({
468
- type: 'changeDate',
469
- date: this.date
470
- });
471
- var element;
472
- if (this.isInput) {
473
- element = this.element;
474
- } else if (this.component){
475
- element = this.element.find('input');
476
- }
477
- if (element) {
478
- element.change();
479
- if (this.autoclose) {
480
- element.blur();
481
- }
482
- }
483
- }
484
- break;
485
- }
486
- }
487
- },
488
-
489
- mousedown: function(e){
490
- e.stopPropagation();
491
- e.preventDefault();
492
- },
493
-
494
- moveMonth: function(date, dir){
495
- if (!dir) return date;
496
- var new_date = new Date(date.valueOf()),
497
- day = new_date.getDate(),
498
- month = new_date.getMonth(),
499
- mag = Math.abs(dir),
500
- new_month, test;
501
- dir = dir > 0 ? 1 : -1;
502
- if (mag == 1){
503
- test = dir == -1
504
- // If going back one month, make sure month is not current month
505
- // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
506
- ? function(){ return new_date.getMonth() == month; }
507
- // If going forward one month, make sure month is as expected
508
- // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
509
- : function(){ return new_date.getMonth() != new_month; };
510
- new_month = month + dir;
511
- new_date.setMonth(new_month);
512
- // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
513
- if (new_month < 0 || new_month > 11)
514
- new_month = (new_month + 12) % 12;
515
- } else {
516
- // For magnitudes >1, move one month at a time...
517
- for (var i=0; i<mag; i++)
518
- // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
519
- new_date = this.moveMonth(new_date, dir);
520
- // ...then reset the day, keeping it in the new month
521
- new_month = new_date.getMonth();
522
- new_date.setDate(day);
523
- test = function(){ return new_month != new_date.getMonth(); };
524
- }
525
- // Common date-resetting loop -- if date is beyond end of month, make it
526
- // end of month
527
- while (test()){
528
- new_date.setDate(--day);
529
- new_date.setMonth(new_month);
530
- }
531
- return new_date;
532
- },
533
-
534
- moveYear: function(date, dir){
535
- return this.moveMonth(date, dir*12);
536
- },
537
-
538
- dateWithinRange: function(date){
539
- return date >= this.startDate && date <= this.endDate;
540
- },
541
-
542
- keydown: function(e){
543
- if (this.picker.is(':not(:visible)')){
544
- if (e.keyCode == 27) // allow escape to hide and re-show picker
545
- this.show();
546
- return;
547
- }
548
- var dateChanged = false,
549
- dir, day, month,
550
- newDate, newViewDate;
551
- switch(e.keyCode){
552
- case 27: // escape
553
- this.hide();
554
- e.preventDefault();
555
- break;
556
- case 37: // left
557
- case 39: // right
82
+ switch(options.startView || this.element.data('date-start-view')){
83
+ case 2:
84
+ case 'decade':
85
+ this.viewMode = this.startViewMode = 2;
86
+ break;
87
+ case 1:
88
+ case 'year':
89
+ this.viewMode = this.startViewMode = 1;
90
+ break;
91
+ case 0:
92
+ case 'month':
93
+ default:
94
+ this.viewMode = this.startViewMode = 0;
95
+ break;
96
+ }
97
+
98
+ this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7);
99
+ this.weekEnd = ((this.weekStart + 6) % 7);
100
+ this.startDate = -Infinity;
101
+ this.endDate = Infinity;
102
+ this.setStartDate(options.startDate||this.element.data('date-startdate'));
103
+ this.setEndDate(options.endDate||this.element.data('date-enddate'));
104
+ this.fillDow();
105
+ this.fillMonths();
106
+ this.update();
107
+ this.showMode();
108
+ };
109
+
110
+ Datepicker.prototype = {
111
+ constructor: Datepicker,
112
+
113
+ show: function(e) {
114
+ this.picker.show();
115
+ this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
116
+ this.update();
117
+ this.place();
118
+ $(window).on('resize', $.proxy(this.place, this));
119
+ if (e ) {
120
+ e.stopPropagation();
121
+ e.preventDefault();
122
+ }
123
+ if (!this.isInput) {
124
+ $(document).on('mousedown', $.proxy(this.hide, this));
125
+ }
126
+ this.element.trigger({
127
+ type: 'show',
128
+ date: this.date
129
+ });
130
+ },
131
+
132
+ _hide: function(e){
133
+ // When going from the input to the picker, IE handles the blur/click
134
+ // events differently than other browsers, in such a way that the blur
135
+ // event triggers a hide before the click event can stop propagation.
136
+ if (false){ //TODO rivsc jquery 1.9 $.browser.msie) {
137
+ var t = this, args = arguments;
138
+
139
+ function cancel_hide(){
140
+ clearTimeout(hide_timeout);
141
+ e.target.focus();
142
+ t.picker.off('click', cancel_hide);
143
+ }
144
+
145
+ function do_hide(){
146
+ t.hide.apply(t, args);
147
+ t.picker.off('click', cancel_hide);
148
+ }
149
+
150
+ this.picker.on('click', cancel_hide);
151
+ var hide_timeout = setTimeout(do_hide, 100);
152
+ } else {
153
+ return this.hide.apply(this, arguments);
154
+ }
155
+ },
156
+
157
+ hide: function(e){
158
+ this.picker.hide();
159
+ $(window).off('resize', this.place);
160
+ this.viewMode = this.startViewMode;
161
+ this.showMode();
162
+ if (!this.isInput) {
163
+ $(document).off('mousedown', this.hide);
164
+ }
165
+ if (e && e.currentTarget.value)
166
+ this.setValue();
167
+ this.element.trigger({
168
+ type: 'hide',
169
+ date: this.date
170
+ });
171
+ },
172
+
173
+ setValue: function() {
174
+ var formatted = DPGlobal.formatDate(this.date, this.format, this.language);
175
+ if (!this.isInput) {
176
+ if (this.component){
177
+ this.element.find('input').prop('value', formatted);
178
+ }
179
+ this.element.data('date', formatted);
180
+ } else {
181
+ this.element.prop('value', formatted);
182
+ }
183
+ },
184
+
185
+ setStartDate: function(startDate){
186
+ this.startDate = startDate||-Infinity;
187
+ if (this.startDate !== -Infinity) {
188
+ this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language);
189
+ }
190
+ this.update();
191
+ this.updateNavArrows();
192
+ },
193
+
194
+ setEndDate: function(endDate){
195
+ this.endDate = endDate||Infinity;
196
+ if (this.endDate !== Infinity) {
197
+ this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language);
198
+ }
199
+ this.update();
200
+ this.updateNavArrows();
201
+ },
202
+
203
+ place: function(){
204
+ var zIndex = parseInt(this.element.parents().filter(function() {
205
+ return $(this).css('z-index') != 'auto';
206
+ }).first().css('z-index'))+10;
207
+ var offset = this.component ? this.component.offset() : this.element.offset();
208
+ this.picker.css({
209
+ top: offset.top + this.height,
210
+ left: offset.left,
211
+ zIndex: zIndex
212
+ });
213
+ },
214
+
215
+ update: function(){
216
+ this.date = DPGlobal.parseDate(
217
+ this.isInput ? this.element.prop('value') : this.element.data('date') || this.element.find('input').prop('value'),
218
+ this.format, this.language
219
+ );
220
+ if (this.date < this.startDate) {
221
+ this.viewDate = new Date(this.startDate);
222
+ } else if (this.date > this.endDate) {
223
+ this.viewDate = new Date(this.endDate);
224
+ } else {
225
+ this.viewDate = new Date(this.date);
226
+ }
227
+ this.fill();
228
+ },
229
+
230
+ fillDow: function(){
231
+ var dowCnt = this.weekStart;
232
+ var html = '<tr>';
233
+ while (dowCnt < this.weekStart + 7) {
234
+ html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>';
235
+ }
236
+ html += '</tr>';
237
+ this.picker.find('.datepicker-days thead').append(html);
238
+ },
239
+
240
+ fillMonths: function(){
241
+ var html = '';
242
+ var i = 0
243
+ while (i < 12) {
244
+ html += '<span class="month">'+dates[this.language].monthsShort[i++]+'</span>';
245
+ }
246
+ this.picker.find('.datepicker-months td').html(html);
247
+ },
248
+
249
+ fill: function() {
250
+ var d = new Date(this.viewDate),
251
+ year = d.getFullYear(),
252
+ month = d.getMonth(),
253
+ startYear = this.startDate !== -Infinity ? this.startDate.getFullYear() : -Infinity,
254
+ startMonth = this.startDate !== -Infinity ? this.startDate.getMonth() : -Infinity,
255
+ endYear = this.endDate !== Infinity ? this.endDate.getFullYear() : Infinity,
256
+ endMonth = this.endDate !== Infinity ? this.endDate.getMonth() : Infinity,
257
+ currentDate = this.date.valueOf();
258
+ this.picker.find('.datepicker-days th:eq(1)')
259
+ .text(dates[this.language].months[month]+' '+year);
260
+ this.updateNavArrows();
261
+ this.fillMonths();
262
+ var prevMonth = new Date(year, month-1, 28,0,0,0,0),
263
+ day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth()),
264
+ prevDate, dstDay = 0, date;
265
+ prevMonth.setDate(day);
266
+ prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7);
267
+ var nextMonth = new Date(prevMonth);
268
+ nextMonth.setDate(nextMonth.getDate() + 42);
269
+ nextMonth = nextMonth.valueOf();
270
+ var html = [];
271
+ var clsName;
272
+ while(prevMonth.valueOf() < nextMonth) {
273
+ if (prevMonth.getDay() == this.weekStart) {
274
+ html.push('<tr>');
275
+ }
276
+ clsName = '';
277
+ if (prevMonth.getFullYear() < year || (prevMonth.getFullYear() == year && prevMonth.getMonth() < month)) {
278
+ clsName += ' old';
279
+ } else if (prevMonth.getFullYear() > year || (prevMonth.getFullYear() == year && prevMonth.getMonth() > month)) {
280
+ clsName += ' new';
281
+ }
282
+ if (prevMonth.valueOf() == currentDate) {
283
+ clsName += ' active';
284
+ }
285
+ if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate) {
286
+ clsName += ' disabled';
287
+ }
288
+ date = prevMonth.getDate();
289
+ if (dstDay == -1) date++;
290
+ html.push('<td class="day'+clsName+'">'+date+ '</td>');
291
+ if (prevMonth.getDay() == this.weekEnd) {
292
+ html.push('</tr>');
293
+ }
294
+ prevDate = prevMonth.getDate();
295
+ prevMonth.setDate(prevMonth.getDate()+1);
296
+ if (prevMonth.getHours() != 0) {
297
+ // Fix for DST bug: if we are no longer at start of day, a DST jump probably happened
298
+ // We either fell back (eg, Jan 1 00:00 -> Jan 1 23:00)
299
+ // or jumped forward (eg, Jan 1 00:00 -> Jan 2 01:00)
300
+ // Unfortunately, I can think of no way to test this in the unit tests, as it depends
301
+ // on the TZ of the client system.
302
+ if (!dstDay) {
303
+ // We are not currently handling a dst day (next round will deal with it)
304
+ if (prevMonth.getDate() == prevDate)
305
+ // We must compensate for fall-back
306
+ dstDay = -1;
307
+ else
308
+ // We must compensate for a jump-ahead
309
+ dstDay = +1;
310
+ }
311
+ else {
312
+ // The last round was our dst day (hours are still non-zero)
313
+ if (dstDay == -1)
314
+ // For a fall-back, fast-forward to next midnight
315
+ prevMonth.setHours(24);
316
+ else
317
+ // For a jump-ahead, just reset to 0
318
+ prevMonth.setHours(0);
319
+ // Reset minutes, as some TZs may be off by portions of an hour
320
+ prevMonth.setMinutes(0);
321
+ dstDay = 0;
322
+ }
323
+ }
324
+ }
325
+ this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
326
+ var currentYear = this.date.getFullYear();
327
+
328
+ var months = this.picker.find('.datepicker-months')
329
+ .find('th:eq(1)')
330
+ .text(year)
331
+ .end()
332
+ .find('span').removeClass('active');
333
+ if (currentYear == year) {
334
+ months.eq(this.date.getMonth()).addClass('active');
335
+ }
336
+ if (year < startYear || year > endYear) {
337
+ months.addClass('disabled');
338
+ }
339
+ if (year == startYear) {
340
+ months.slice(0, startMonth).addClass('disabled');
341
+ }
342
+ if (year == endYear) {
343
+ months.slice(endMonth+1).addClass('disabled');
344
+ }
345
+
346
+ html = '';
347
+ year = parseInt(year/10, 10) * 10;
348
+ var yearCont = this.picker.find('.datepicker-years')
349
+ .find('th:eq(1)')
350
+ .text(year + '-' + (year + 9))
351
+ .end()
352
+ .find('td');
353
+ year -= 1;
354
+ for (var i = -1; i < 11; i++) {
355
+ html += '<span class="year'+(i == -1 || i == 10 ? ' old' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>';
356
+ year += 1;
357
+ }
358
+ yearCont.html(html);
359
+ },
360
+
361
+ updateNavArrows: function() {
362
+ var d = new Date(this.viewDate),
363
+ year = d.getFullYear(),
364
+ month = d.getMonth();
365
+ switch (this.viewMode) {
366
+ case 0:
367
+ if (this.startDate !== -Infinity && year <= this.startDate.getFullYear() && month <= this.startDate.getMonth()) {
368
+ this.picker.find('.prev').css({visibility: 'hidden'});
369
+ } else {
370
+ this.picker.find('.prev').css({visibility: 'visible'});
371
+ }
372
+ if (this.endDate !== Infinity && year >= this.endDate.getFullYear() && month >= this.endDate.getMonth()) {
373
+ this.picker.find('.next').css({visibility: 'hidden'});
374
+ } else {
375
+ this.picker.find('.next').css({visibility: 'visible'});
376
+ }
377
+ break;
378
+ case 1:
379
+ case 2:
380
+ if (this.startDate !== -Infinity && year <= this.startDate.getFullYear()) {
381
+ this.picker.find('.prev').css({visibility: 'hidden'});
382
+ } else {
383
+ this.picker.find('.prev').css({visibility: 'visible'});
384
+ }
385
+ if (this.endDate !== Infinity && year >= this.endDate.getFullYear()) {
386
+ this.picker.find('.next').css({visibility: 'hidden'});
387
+ } else {
388
+ this.picker.find('.next').css({visibility: 'visible'});
389
+ }
390
+ break;
391
+ }
392
+ },
393
+
394
+ click: function(e) {
395
+ e.stopPropagation();
396
+ e.preventDefault();
397
+ var target = $(e.target).closest('span, td, th');
398
+ if (target.length == 1) {
399
+ switch(target[0].nodeName.toLowerCase()) {
400
+ case 'th':
401
+ switch(target[0].className) {
402
+ case 'switch':
403
+ this.showMode(1);
404
+ break;
405
+ case 'prev':
406
+ case 'next':
407
+ var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
408
+ switch(this.viewMode){
409
+ case 0:
410
+ this.viewDate = this.moveMonth(this.viewDate, dir);
411
+ break;
412
+ case 1:
413
+ case 2:
414
+ this.viewDate = this.moveYear(this.viewDate, dir);
415
+ break;
416
+ }
417
+ this.fill();
418
+ break;
419
+ }
420
+ break;
421
+ case 'span':
422
+ if (!target.is('.disabled')) {
423
+ this.viewDate.setDate(1);
424
+ if (target.is('.month')) {
425
+ var month = target.parent().find('span').index(target);
426
+ this.viewDate.setMonth(month);
427
+ this.element.trigger({
428
+ type: 'changeMonth',
429
+ date: this.viewDate
430
+ });
431
+ } else {
432
+ var year = parseInt(target.text(), 10)||0;
433
+ this.viewDate.setFullYear(year);
434
+ this.element.trigger({
435
+ type: 'changeYear',
436
+ date: this.viewDate
437
+ });
438
+ }
439
+ this.showMode(-1);
440
+ this.fill();
441
+ }
442
+ break;
443
+ case 'td':
444
+ if (target.is('.day') && !target.is('.disabled')){
445
+ var day = parseInt(target.text(), 10)||1;
446
+ var year = this.viewDate.getFullYear(),
447
+ month = this.viewDate.getMonth();
448
+ if (target.is('.old')) {
449
+ if (month == 0) {
450
+ month = 11;
451
+ year -= 1;
452
+ } else {
453
+ month -= 1;
454
+ }
455
+ } else if (target.is('.new')) {
456
+ if (month == 11) {
457
+ month = 0;
458
+ year += 1;
459
+ } else {
460
+ month += 1;
461
+ }
462
+ }
463
+ this.date = new Date(year, month, day,0,0,0,0);
464
+ this.viewDate = new Date(year, month, day,0,0,0,0);
465
+ this.fill();
466
+ this.setValue();
467
+ this.element.trigger({
468
+ type: 'changeDate',
469
+ date: this.date
470
+ });
471
+ var element;
472
+ if (this.isInput) {
473
+ element = this.element;
474
+ } else if (this.component){
475
+ element = this.element.find('input');
476
+ }
477
+ if (element) {
478
+ element.change();
479
+ if (this.autoclose) {
480
+ element.blur();
481
+ }
482
+ }
483
+ }
484
+ break;
485
+ }
486
+ }
487
+ },
488
+
489
+ mousedown: function(e){
490
+ e.stopPropagation();
491
+ e.preventDefault();
492
+ },
493
+
494
+ moveMonth: function(date, dir){
495
+ if (!dir) return date;
496
+ var new_date = new Date(date.valueOf()),
497
+ day = new_date.getDate(),
498
+ month = new_date.getMonth(),
499
+ mag = Math.abs(dir),
500
+ new_month, test;
501
+ dir = dir > 0 ? 1 : -1;
502
+ if (mag == 1){
503
+ test = dir == -1
504
+ // If going back one month, make sure month is not current month
505
+ // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
506
+ ? function(){ return new_date.getMonth() == month; }
507
+ // If going forward one month, make sure month is as expected
508
+ // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
509
+ : function(){ return new_date.getMonth() != new_month; };
510
+ new_month = month + dir;
511
+ new_date.setMonth(new_month);
512
+ // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
513
+ if (new_month < 0 || new_month > 11)
514
+ new_month = (new_month + 12) % 12;
515
+ } else {
516
+ // For magnitudes >1, move one month at a time...
517
+ for (var i=0; i<mag; i++)
518
+ // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
519
+ new_date = this.moveMonth(new_date, dir);
520
+ // ...then reset the day, keeping it in the new month
521
+ new_month = new_date.getMonth();
522
+ new_date.setDate(day);
523
+ test = function(){ return new_month != new_date.getMonth(); };
524
+ }
525
+ // Common date-resetting loop -- if date is beyond end of month, make it
526
+ // end of month
527
+ while (test()){
528
+ new_date.setDate(--day);
529
+ new_date.setMonth(new_month);
530
+ }
531
+ return new_date;
532
+ },
533
+
534
+ moveYear: function(date, dir){
535
+ return this.moveMonth(date, dir*12);
536
+ },
537
+
538
+ dateWithinRange: function(date){
539
+ return date >= this.startDate && date <= this.endDate;
540
+ },
541
+
542
+ keydown: function(e){
543
+ if (this.picker.is(':not(:visible)')){
544
+ if (e.keyCode == 27) // allow escape to hide and re-show picker
545
+ this.show();
546
+ return;
547
+ }
548
+ var dateChanged = false,
549
+ dir, day, month,
550
+ newDate, newViewDate;
551
+ switch(e.keyCode){
552
+ case 27: // escape
553
+ this.hide();
554
+ e.preventDefault();
555
+ break;
556
+ case 37: // left
557
+ case 39: // right
558
558
  if (!this.keyboardNavigation) break;
559
- dir = e.keyCode == 37 ? -1 : 1;
560
- if (e.ctrlKey){
561
- newDate = this.moveYear(this.date, dir);
562
- newViewDate = this.moveYear(this.viewDate, dir);
563
- } else if (e.shiftKey){
564
- newDate = this.moveMonth(this.date, dir);
565
- newViewDate = this.moveMonth(this.viewDate, dir);
566
- } else {
567
- newDate = new Date(this.date);
568
- newDate.setDate(this.date.getDate() + dir);
569
- newViewDate = new Date(this.viewDate);
570
- newViewDate.setDate(this.viewDate.getDate() + dir);
571
- }
572
- if (this.dateWithinRange(newDate)){
573
- this.date = newDate;
574
- this.viewDate = newViewDate;
575
- this.setValue();
576
- this.update();
577
- e.preventDefault();
578
- dateChanged = true;
579
- }
580
- break;
581
- case 38: // up
582
- case 40: // down
559
+ dir = e.keyCode == 37 ? -1 : 1;
560
+ if (e.ctrlKey){
561
+ newDate = this.moveYear(this.date, dir);
562
+ newViewDate = this.moveYear(this.viewDate, dir);
563
+ } else if (e.shiftKey){
564
+ newDate = this.moveMonth(this.date, dir);
565
+ newViewDate = this.moveMonth(this.viewDate, dir);
566
+ } else {
567
+ newDate = new Date(this.date);
568
+ newDate.setDate(this.date.getDate() + dir);
569
+ newViewDate = new Date(this.viewDate);
570
+ newViewDate.setDate(this.viewDate.getDate() + dir);
571
+ }
572
+ if (this.dateWithinRange(newDate)){
573
+ this.date = newDate;
574
+ this.viewDate = newViewDate;
575
+ this.setValue();
576
+ this.update();
577
+ e.preventDefault();
578
+ dateChanged = true;
579
+ }
580
+ break;
581
+ case 38: // up
582
+ case 40: // down
583
583
  if (!this.keyboardNavigation) break;
584
- dir = e.keyCode == 38 ? -1 : 1;
585
- if (e.ctrlKey){
586
- newDate = this.moveYear(this.date, dir);
587
- newViewDate = this.moveYear(this.viewDate, dir);
588
- } else if (e.shiftKey){
589
- newDate = this.moveMonth(this.date, dir);
590
- newViewDate = this.moveMonth(this.viewDate, dir);
591
- } else {
592
- newDate = new Date(this.date);
593
- newDate.setDate(this.date.getDate() + dir * 7);
594
- newViewDate = new Date(this.viewDate);
595
- newViewDate.setDate(this.viewDate.getDate() + dir * 7);
596
- }
597
- if (this.dateWithinRange(newDate)){
598
- this.date = newDate;
599
- this.viewDate = newViewDate;
600
- this.setValue();
601
- this.update();
602
- e.preventDefault();
603
- dateChanged = true;
604
- }
605
- break;
606
- case 13: // enter
607
- this.hide();
608
- e.preventDefault();
609
- break;
610
- }
611
- if (dateChanged){
612
- this.element.trigger({
613
- type: 'changeDate',
614
- date: this.date
615
- });
616
- var element;
617
- if (this.isInput) {
618
- element = this.element;
619
- } else if (this.component){
620
- element = this.element.find('input');
621
- }
622
- if (element) {
623
- element.change();
624
- }
625
- }
626
- },
627
-
628
- showMode: function(dir) {
629
- if (dir) {
630
- this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
631
- }
632
- this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
633
- this.updateNavArrows();
634
- }
635
- };
636
-
637
- $.fn.datepicker = function ( option ) {
638
- var args = Array.apply(null, arguments);
639
- args.shift();
640
- return this.each(function () {
641
- var $this = $(this),
642
- data = $this.data('datepicker'),
643
- options = typeof option == 'object' && option;
644
- if (!data) {
645
- $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
646
- }
647
- if (typeof option == 'string' && typeof data[option] == 'function') {
648
- data[option].apply(data, args);
649
- }
650
- });
651
- };
652
-
653
- $.fn.datepicker.defaults = {
654
- };
655
- $.fn.datepicker.Constructor = Datepicker;
656
- var dates = $.fn.datepicker.dates = {
657
- en: {
658
- days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
659
- daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
660
- daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
661
- months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
662
- monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
663
- }
664
- }
665
-
666
- var DPGlobal = {
667
- modes: [
668
- {
669
- clsName: 'days',
670
- navFnc: 'Month',
671
- navStep: 1
672
- },
673
- {
674
- clsName: 'months',
675
- navFnc: 'FullYear',
676
- navStep: 1
677
- },
678
- {
679
- clsName: 'years',
680
- navFnc: 'FullYear',
681
- navStep: 10
682
- }],
683
- isLeapYear: function (year) {
684
- return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
685
- },
686
- getDaysInMonth: function (year, month) {
687
- return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
688
- },
689
- validParts: /dd?|mm?|MM?|yy(?:yy)?/g,
690
- nonpunctuation: /[^ -\/:-@\[-`{-~\t\n\r]+/g,
691
- parseFormat: function(format){
692
- // IE treats \0 as a string end in inputs (truncating the value),
693
- // so it's a bad format delimiter, anyway
694
- var separators = format.replace(this.validParts, '\0').split('\0'),
695
- parts = format.match(this.validParts);
696
- if (!separators || !separators.length || !parts || parts.length == 0){
697
- throw new Error("Invalid date format.");
698
- }
699
- return {separators: separators, parts: parts};
700
- },
701
- parseDate: function(date, format, language) {
702
- if (date instanceof Date) return date;
703
- if (/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(date)) {
704
- var part_re = /([-+]\d+)([dmwy])/,
705
- parts = date.match(/([-+]\d+)([dmwy])/g),
706
- part, dir;
707
- date = new Date();
708
- for (var i=0; i<parts.length; i++) {
709
- part = part_re.exec(parts[i]);
710
- dir = parseInt(part[1]);
711
- switch(part[2]){
712
- case 'd':
713
- date.setDate(date.getDate() + dir);
714
- break;
715
- case 'm':
716
- date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
717
- break;
718
- case 'w':
719
- date.setDate(date.getDate() + dir * 7);
720
- break;
721
- case 'y':
722
- date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
723
- break;
724
- }
725
- }
726
- return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
727
- }
728
- var parts = date && date.match(this.nonpunctuation) || [],
729
- date = new Date(),
730
- parsed = {},
731
- setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
732
- setters_map = {
733
- yyyy: function(d,v){ return d.setFullYear(v); },
734
- yy: function(d,v){ return d.setFullYear(2000+v); },
735
- m: function(d,v){
736
- v -= 1;
737
- while (v<0) v += 12;
738
- v %= 12;
739
- d.setMonth(v);
740
- while (d.getMonth() != v)
741
- d.setDate(d.getDate()-1);
742
- return d;
743
- },
744
- d: function(d,v){ return d.setDate(v); }
745
- },
746
- val, filtered, part;
747
- setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
748
- setters_map['dd'] = setters_map['d'];
749
- date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
750
- if (parts.length == format.parts.length) {
751
- for (var i=0, cnt = format.parts.length; i < cnt; i++) {
752
- val = parseInt(parts[i], 10);
753
- part = format.parts[i];
754
- if (isNaN(val)) {
755
- switch(part) {
756
- case 'MM':
757
- filtered = $(dates[language].months).filter(function(){
758
- var m = this.slice(0, parts[i].length),
759
- p = parts[i].slice(0, m.length);
760
- return m == p;
761
- });
762
- val = $.inArray(filtered[0], dates[language].months) + 1;
763
- break;
764
- case 'M':
765
- filtered = $(dates[language].monthsShort).filter(function(){
766
- var m = this.slice(0, parts[i].length),
767
- p = parts[i].slice(0, m.length);
768
- return m == p;
769
- });
770
- val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
771
- break;
772
- }
773
- }
774
- parsed[part] = val;
775
- }
776
- for (var i=0, s; i<setters_order.length; i++){
777
- s = setters_order[i];
778
- if (s in parsed)
779
- setters_map[s](date, parsed[s])
780
- }
781
- }
782
- return date;
783
- },
784
- formatDate: function(date, format, language){
785
- var val = {
786
- d: date.getDate(),
787
- m: date.getMonth() + 1,
788
- M: dates[language].monthsShort[date.getMonth()],
789
- MM: dates[language].months[date.getMonth()],
790
- yy: date.getFullYear().toString().substring(2),
791
- yyyy: date.getFullYear()
792
- };
793
- val.dd = (val.d < 10 ? '0' : '') + val.d;
794
- val.mm = (val.m < 10 ? '0' : '') + val.m;
795
- var date = [],
796
- seps = $.extend([], format.separators);
797
- for (var i=0, cnt = format.parts.length; i < cnt; i++) {
798
- if (seps.length)
799
- date.push(seps.shift())
800
- date.push(val[format.parts[i]]);
801
- }
802
- return date.join('');
803
- },
804
- headTemplate: '<thead>'+
805
- '<tr>'+
806
- '<th class="prev"><i class="icon-arrow-left"/></th>'+
807
- '<th colspan="5" class="switch"></th>'+
808
- '<th class="next"><i class="icon-arrow-right"/></th>'+
809
- '</tr>'+
810
- '</thead>',
811
- contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
812
- };
813
- DPGlobal.template = '<div class="datepicker dropdown-menu">'+
814
- '<div class="datepicker-days">'+
815
- '<table class=" table-condensed">'+
816
- DPGlobal.headTemplate+
817
- '<tbody></tbody>'+
818
- '</table>'+
819
- '</div>'+
820
- '<div class="datepicker-months">'+
821
- '<table class="table-condensed">'+
822
- DPGlobal.headTemplate+
823
- DPGlobal.contTemplate+
824
- '</table>'+
825
- '</div>'+
826
- '<div class="datepicker-years">'+
827
- '<table class="table-condensed">'+
828
- DPGlobal.headTemplate+
829
- DPGlobal.contTemplate+
830
- '</table>'+
831
- '</div>'+
832
- '</div>';
584
+ dir = e.keyCode == 38 ? -1 : 1;
585
+ if (e.ctrlKey){
586
+ newDate = this.moveYear(this.date, dir);
587
+ newViewDate = this.moveYear(this.viewDate, dir);
588
+ } else if (e.shiftKey){
589
+ newDate = this.moveMonth(this.date, dir);
590
+ newViewDate = this.moveMonth(this.viewDate, dir);
591
+ } else {
592
+ newDate = new Date(this.date);
593
+ newDate.setDate(this.date.getDate() + dir * 7);
594
+ newViewDate = new Date(this.viewDate);
595
+ newViewDate.setDate(this.viewDate.getDate() + dir * 7);
596
+ }
597
+ if (this.dateWithinRange(newDate)){
598
+ this.date = newDate;
599
+ this.viewDate = newViewDate;
600
+ this.setValue();
601
+ this.update();
602
+ e.preventDefault();
603
+ dateChanged = true;
604
+ }
605
+ break;
606
+ case 13: // enter
607
+ this.hide();
608
+ e.preventDefault();
609
+ break;
610
+ }
611
+ if (dateChanged){
612
+ this.element.trigger({
613
+ type: 'changeDate',
614
+ date: this.date
615
+ });
616
+ var element;
617
+ if (this.isInput) {
618
+ element = this.element;
619
+ } else if (this.component){
620
+ element = this.element.find('input');
621
+ }
622
+ if (element) {
623
+ element.change();
624
+ }
625
+ }
626
+ },
627
+
628
+ showMode: function(dir) {
629
+ if (dir) {
630
+ this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir));
631
+ }
632
+ this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
633
+ this.updateNavArrows();
634
+ }
635
+ };
636
+
637
+ $.fn.datepicker = function ( option ) {
638
+ var args = Array.apply(null, arguments);
639
+ args.shift();
640
+ return this.each(function () {
641
+ var $this = $(this),
642
+ data = $this.data('datepicker'),
643
+ options = typeof option == 'object' && option;
644
+ if (!data) {
645
+ $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
646
+ }
647
+ if (typeof option == 'string' && typeof data[option] == 'function') {
648
+ data[option].apply(data, args);
649
+ }
650
+ });
651
+ };
652
+
653
+ $.fn.datepicker.defaults = {
654
+ };
655
+ $.fn.datepicker.Constructor = Datepicker;
656
+ var dates = $.fn.datepicker.dates = {
657
+ en: {
658
+ days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
659
+ daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
660
+ daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
661
+ months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
662
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
663
+ }
664
+ }
665
+
666
+ var DPGlobal = {
667
+ modes: [
668
+ {
669
+ clsName: 'days',
670
+ navFnc: 'Month',
671
+ navStep: 1
672
+ },
673
+ {
674
+ clsName: 'months',
675
+ navFnc: 'FullYear',
676
+ navStep: 1
677
+ },
678
+ {
679
+ clsName: 'years',
680
+ navFnc: 'FullYear',
681
+ navStep: 10
682
+ }],
683
+ isLeapYear: function (year) {
684
+ return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
685
+ },
686
+ getDaysInMonth: function (year, month) {
687
+ return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
688
+ },
689
+ validParts: /dd?|mm?|MM?|yy(?:yy)?/g,
690
+ nonpunctuation: /[^ -\/:-@\[-`{-~\t\n\r]+/g,
691
+ parseFormat: function(format){
692
+ // IE treats \0 as a string end in inputs (truncating the value),
693
+ // so it's a bad format delimiter, anyway
694
+ var separators = format.replace(this.validParts, '\0').split('\0'),
695
+ parts = format.match(this.validParts);
696
+ if (!separators || !separators.length || !parts || parts.length == 0){
697
+ throw new Error("Invalid date format.");
698
+ }
699
+ return {separators: separators, parts: parts};
700
+ },
701
+ parseDate: function(date, format, language) {
702
+ if (date instanceof Date) return date;
703
+ if (/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(date)) {
704
+ var part_re = /([-+]\d+)([dmwy])/,
705
+ parts = date.match(/([-+]\d+)([dmwy])/g),
706
+ part, dir;
707
+ date = new Date();
708
+ for (var i=0; i<parts.length; i++) {
709
+ part = part_re.exec(parts[i]);
710
+ dir = parseInt(part[1]);
711
+ switch(part[2]){
712
+ case 'd':
713
+ date.setDate(date.getDate() + dir);
714
+ break;
715
+ case 'm':
716
+ date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
717
+ break;
718
+ case 'w':
719
+ date.setDate(date.getDate() + dir * 7);
720
+ break;
721
+ case 'y':
722
+ date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
723
+ break;
724
+ }
725
+ }
726
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
727
+ }
728
+ var parts = date && date.match(this.nonpunctuation) || [],
729
+ date = new Date(),
730
+ parsed = {},
731
+ setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
732
+ setters_map = {
733
+ yyyy: function(d,v){ return d.setFullYear(v); },
734
+ yy: function(d,v){ return d.setFullYear(2000+v); },
735
+ m: function(d,v){
736
+ v -= 1;
737
+ while (v<0) v += 12;
738
+ v %= 12;
739
+ d.setMonth(v);
740
+ while (d.getMonth() != v)
741
+ d.setDate(d.getDate()-1);
742
+ return d;
743
+ },
744
+ d: function(d,v){ return d.setDate(v); }
745
+ },
746
+ val, filtered, part;
747
+ setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
748
+ setters_map['dd'] = setters_map['d'];
749
+ date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
750
+ if (parts.length == format.parts.length) {
751
+ for (var i=0, cnt = format.parts.length; i < cnt; i++) {
752
+ val = parseInt(parts[i], 10);
753
+ part = format.parts[i];
754
+ if (isNaN(val)) {
755
+ switch(part) {
756
+ case 'MM':
757
+ filtered = $(dates[language].months).filter(function(){
758
+ var m = this.slice(0, parts[i].length),
759
+ p = parts[i].slice(0, m.length);
760
+ return m == p;
761
+ });
762
+ val = $.inArray(filtered[0], dates[language].months) + 1;
763
+ break;
764
+ case 'M':
765
+ filtered = $(dates[language].monthsShort).filter(function(){
766
+ var m = this.slice(0, parts[i].length),
767
+ p = parts[i].slice(0, m.length);
768
+ return m == p;
769
+ });
770
+ val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
771
+ break;
772
+ }
773
+ }
774
+ parsed[part] = val;
775
+ }
776
+ for (var i=0, s; i<setters_order.length; i++){
777
+ s = setters_order[i];
778
+ if (s in parsed)
779
+ setters_map[s](date, parsed[s])
780
+ }
781
+ }
782
+ return date;
783
+ },
784
+ formatDate: function(date, format, language){
785
+ var val = {
786
+ d: date.getDate(),
787
+ m: date.getMonth() + 1,
788
+ M: dates[language].monthsShort[date.getMonth()],
789
+ MM: dates[language].months[date.getMonth()],
790
+ yy: date.getFullYear().toString().substring(2),
791
+ yyyy: date.getFullYear()
792
+ };
793
+ val.dd = (val.d < 10 ? '0' : '') + val.d;
794
+ val.mm = (val.m < 10 ? '0' : '') + val.m;
795
+ var date = [],
796
+ seps = $.extend([], format.separators);
797
+ for (var i=0, cnt = format.parts.length; i < cnt; i++) {
798
+ if (seps.length)
799
+ date.push(seps.shift())
800
+ date.push(val[format.parts[i]]);
801
+ }
802
+ return date.join('');
803
+ },
804
+ headTemplate: '<thead>'+
805
+ '<tr>'+
806
+ '<th class="prev"><i class="fa fa-arrow-left"/></th>'+
807
+ '<th colspan="5" class="switch"></th>'+
808
+ '<th class="next"><i class="fa fa-arrow-right"/></th>'+
809
+ '</tr>'+
810
+ '</thead>',
811
+ contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
812
+ };
813
+ DPGlobal.template = '<div class="datepicker dropdown-menu">'+
814
+ '<div class="datepicker-days">'+
815
+ '<table class=" table-condensed">'+
816
+ DPGlobal.headTemplate+
817
+ '<tbody></tbody>'+
818
+ '</table>'+
819
+ '</div>'+
820
+ '<div class="datepicker-months">'+
821
+ '<table class="table-condensed">'+
822
+ DPGlobal.headTemplate+
823
+ DPGlobal.contTemplate+
824
+ '</table>'+
825
+ '</div>'+
826
+ '<div class="datepicker-years">'+
827
+ '<table class="table-condensed">'+
828
+ DPGlobal.headTemplate+
829
+ DPGlobal.contTemplate+
830
+ '</table>'+
831
+ '</div>'+
832
+ '</div>';
833
833
 
834
834
  }( window.jQuery );