camaleon_cms 2.1.1 → 2.1.1.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of camaleon_cms might be problematic. Click here for more details.

Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -1
  3. data/app/apps/plugins/attack/config/locales/translation.yml +20 -1
  4. data/app/apps/plugins/contact_form/config/locales/translation.yml +106 -1
  5. data/app/apps/plugins/contact_form/contact_form_helper.rb +44 -27
  6. data/app/apps/plugins/front_cache/config/locales/translation.yml +21 -1
  7. data/app/apps/plugins/front_cache/front_cache_helper.rb +1 -1
  8. data/app/apps/plugins/visibility_post/assets/js/form.js +1 -3
  9. data/app/apps/plugins/visibility_post/visibility_post_helper.rb +2 -4
  10. data/app/assets/images/camaleon_cms/language/de.png +0 -0
  11. data/app/assets/images/camaleon_cms/language/en.png +0 -0
  12. data/app/assets/images/camaleon_cms/language/es.png +0 -0
  13. data/app/assets/images/camaleon_cms/language/fr.png +0 -0
  14. data/app/assets/images/camaleon_cms/language/it.png +0 -0
  15. data/app/assets/images/camaleon_cms/language/nl.png +0 -0
  16. data/app/assets/images/camaleon_cms/language/pl.png +0 -0
  17. data/app/assets/images/camaleon_cms/language/pt.png +0 -0
  18. data/app/assets/images/camaleon_cms/language/pt_br.png +0 -0
  19. data/app/assets/images/camaleon_cms/language/ru.png +0 -0
  20. data/app/assets/images/camaleon_cms/language/zh.png +0 -0
  21. data/app/assets/javascripts/camaleon_cms/admin/_custom_fields.js +3 -11
  22. data/app/assets/javascripts/camaleon_cms/admin/_data.js +2 -6
  23. data/app/assets/javascripts/camaleon_cms/admin/_libraries.js +11 -229
  24. data/app/assets/javascripts/camaleon_cms/admin/_modal.js +11 -37
  25. data/app/assets/javascripts/camaleon_cms/admin/_post.js +27 -22
  26. data/app/assets/javascripts/camaleon_cms/admin/_translator.js +2 -1
  27. data/app/assets/javascripts/camaleon_cms/admin/admin-manifest.js +6 -2
  28. data/app/assets/javascripts/camaleon_cms/admin/bootstrap-datepicker.js +2557 -1689
  29. data/app/assets/javascripts/camaleon_cms/admin/jquery.validate.js +119 -1361
  30. data/app/assets/javascripts/camaleon_cms/admin/jquery_validate/nl.js +33 -0
  31. data/app/assets/javascripts/camaleon_cms/admin/momentjs/_moment.js +3606 -0
  32. data/app/assets/javascripts/camaleon_cms/admin/momentjs/ar.js +136 -0
  33. data/app/assets/javascripts/camaleon_cms/admin/momentjs/ca.js +79 -0
  34. data/app/assets/javascripts/camaleon_cms/admin/momentjs/de.js +76 -0
  35. data/app/assets/javascripts/camaleon_cms/admin/momentjs/es.js +79 -0
  36. data/app/assets/javascripts/camaleon_cms/admin/momentjs/fr.js +62 -0
  37. data/app/assets/javascripts/camaleon_cms/admin/momentjs/it.js +70 -0
  38. data/app/assets/javascripts/camaleon_cms/admin/momentjs/ja.js +65 -0
  39. data/app/assets/javascripts/camaleon_cms/admin/momentjs/nl.js +71 -0
  40. data/app/assets/javascripts/camaleon_cms/admin/momentjs/pl.js +105 -0
  41. data/app/assets/javascripts/camaleon_cms/admin/momentjs/pt.js +64 -0
  42. data/app/assets/javascripts/camaleon_cms/admin/momentjs/pt_br.js +60 -0
  43. data/app/assets/javascripts/camaleon_cms/admin/momentjs/ru.js +166 -0
  44. data/app/assets/javascripts/camaleon_cms/admin/momentjs/zh.js +127 -0
  45. data/app/assets/javascripts/camaleon_cms/admin/nav-menu.js +15 -25
  46. data/app/assets/javascripts/camaleon_cms/admin/tinymce/langs/nl.js +219 -0
  47. data/app/assets/javascripts/camaleon_cms/admin/uploader/_media_manager.js.coffee +82 -19
  48. data/app/assets/javascripts/camaleon_cms/admin/user_profile.js +8 -8
  49. data/app/assets/stylesheets/camaleon_cms/admin/_custom_admin.css.scss +19 -2
  50. data/app/assets/stylesheets/camaleon_cms/admin/admin-manifest.css +0 -4
  51. data/app/assets/stylesheets/camaleon_cms/admin/bootstrap-datepicker.css.scss +315 -414
  52. data/app/assets/stylesheets/camaleon_cms/admin/uploader/_uploadfile.css.scss +7 -3
  53. data/app/controllers/camaleon_cms/admin/appearances/nav_menus_controller.rb +9 -5
  54. data/app/controllers/camaleon_cms/admin/categories_controller.rb +5 -0
  55. data/app/controllers/camaleon_cms/admin/media_controller.rb +27 -10
  56. data/app/controllers/camaleon_cms/admin/posts_controller.rb +9 -19
  57. data/app/controllers/camaleon_cms/admin/sessions_controller.rb +3 -10
  58. data/app/controllers/camaleon_cms/admin/settings/custom_fields_controller.rb +0 -1
  59. data/app/controllers/camaleon_cms/admin/settings/sites_controller.rb +6 -1
  60. data/app/controllers/camaleon_cms/admin/users_controller.rb +1 -8
  61. data/app/controllers/camaleon_cms/admin_controller.rb +5 -4
  62. data/app/controllers/camaleon_cms/apps/plugins_front_controller.rb +0 -8
  63. data/app/controllers/camaleon_cms/camaleon_controller.rb +6 -1
  64. data/app/controllers/camaleon_cms/frontend_controller.rb +11 -8
  65. data/app/decorators/camaleon_cms/category_decorator.rb +2 -1
  66. data/app/decorators/camaleon_cms/post_decorator.rb +28 -1
  67. data/app/decorators/camaleon_cms/post_tag_decorator.rb +1 -0
  68. data/app/decorators/camaleon_cms/post_type_decorator.rb +17 -0
  69. data/app/decorators/camaleon_cms/site_decorator.rb +22 -7
  70. data/app/decorators/camaleon_cms/user_decorator.rb +1 -0
  71. data/app/helpers/camaleon_cms/admin/application_helper.rb +3 -2
  72. data/app/helpers/camaleon_cms/admin/custom_fields_helper.rb +13 -25
  73. data/app/helpers/camaleon_cms/admin/post_type_helper.rb +27 -2
  74. data/app/helpers/camaleon_cms/camaleon_helper.rb +0 -16
  75. data/app/helpers/camaleon_cms/captcha_helper.rb +9 -3
  76. data/app/helpers/camaleon_cms/email_helper.rb +27 -8
  77. data/app/helpers/camaleon_cms/frontend/nav_menu_helper.rb +21 -17
  78. data/app/helpers/camaleon_cms/frontend/seo_helper.rb +5 -3
  79. data/app/helpers/camaleon_cms/html_helper.rb +2 -2
  80. data/app/helpers/camaleon_cms/site_helper.rb +10 -14
  81. data/app/helpers/camaleon_cms/uploader_helper.rb +119 -31
  82. data/app/mailers/camaleon_cms/html_mailer.rb +26 -20
  83. data/app/models/camaleon_cms/custom_field.rb +1 -0
  84. data/app/models/camaleon_cms/custom_field_group.rb +2 -1
  85. data/app/models/camaleon_cms/nav_menu.rb +6 -7
  86. data/app/models/camaleon_cms/nav_menu_item.rb +2 -1
  87. data/app/models/camaleon_cms/post.rb +29 -2
  88. data/app/models/camaleon_cms/post_type.rb +20 -1
  89. data/app/models/camaleon_cms/site.rb +19 -19
  90. data/app/models/camaleon_cms/term_taxonomy.rb +1 -1
  91. data/app/models/concerns/camaleon_cms/custom_fields_read.rb +6 -4
  92. data/app/models/concerns/camaleon_cms/metas.rb +5 -4
  93. data/app/views/camaleon_cms/admin/appearances/nav_menus/_custom_fields.html.erb +4 -2
  94. data/app/views/camaleon_cms/admin/appearances/nav_menus/_external_menu.html.erb +1 -1
  95. data/app/views/camaleon_cms/admin/appearances/nav_menus/index.html.erb +3 -6
  96. data/app/views/camaleon_cms/admin/categories/index.html.erb +1 -0
  97. data/app/views/camaleon_cms/admin/media/_files_list.html.erb +3 -3
  98. data/app/views/camaleon_cms/admin/media/_render_file_item.html.erb +3 -2
  99. data/app/views/camaleon_cms/admin/media/index.html.erb +31 -4
  100. data/app/views/camaleon_cms/admin/posts/_sidebar.html.erb +10 -1
  101. data/app/views/camaleon_cms/admin/posts/form.html.erb +6 -2
  102. data/app/views/camaleon_cms/admin/posts/index.html.erb +4 -4
  103. data/app/views/camaleon_cms/admin/search.html.erb +5 -3
  104. data/app/views/camaleon_cms/admin/settings/_file_system_settings.html.erb +5 -5
  105. data/app/views/camaleon_cms/admin/settings/custom_fields/_get_items.html.erb +2 -1
  106. data/app/views/camaleon_cms/admin/settings/custom_fields/_render.html.erb +1 -1
  107. data/app/views/camaleon_cms/admin/settings/custom_fields/fields/_date.html.erb +3 -4
  108. data/app/views/camaleon_cms/admin/settings/custom_fields/fields/_image.html.erb +1 -1
  109. data/app/views/camaleon_cms/admin/settings/custom_fields/form.html.erb +2 -2
  110. data/app/views/camaleon_cms/admin/settings/post_types/_form.html.erb +11 -1
  111. data/app/views/camaleon_cms/admin/settings/post_types/index.html.erb +1 -0
  112. data/app/views/camaleon_cms/admin/users/form.html.erb +30 -55
  113. data/app/views/camaleon_cms/html_mailer/mailer.html.erb +1 -1
  114. data/app/views/camaleon_cms/html_mailer/password_reset.html.erb +3 -0
  115. data/app/views/layouts/camaleon_cms/admin.html.erb +4 -1
  116. data/app/views/layouts/camaleon_cms/admin/_ajax.html.erb +3 -1
  117. data/app/views/layouts/camaleon_cms/admin/_footer.html.erb +1 -1
  118. data/app/views/layouts/camaleon_cms/admin/_header.html.erb +1 -1
  119. data/config/initializers/assets.rb +4 -2
  120. data/config/initializers/model_alias.rb +11 -0
  121. data/config/locales/camaleon_cms/admin/en.yml +2 -0
  122. data/config/locales/camaleon_cms/admin/es.yml +2 -1
  123. data/config/locales/camaleon_cms/admin/it.yml +1 -0
  124. data/config/locales/camaleon_cms/admin/js.yml +42 -1
  125. data/config/locales/camaleon_cms/admin/nl.yml +659 -0
  126. data/config/locales/camaleon_cms/admin/pt_br.yml +1 -0
  127. data/config/locales/camaleon_cms/admin/ru.yml +659 -0
  128. data/config/locales/camaleon_cms/common.yml +127 -0
  129. data/config/locales/camaleon_cms/languages.yml +16 -0
  130. data/config/locales/camaleon_cms/routes.yml +8 -0
  131. data/config/locales/nl.yml +209 -0
  132. data/config/routes.rb +1 -1
  133. data/config/routes/admin.rb +5 -4
  134. data/config/routes/frontend.rb +16 -3
  135. data/config/system.json +2 -3
  136. data/lib/camaleon_cms/engine.rb +5 -1
  137. data/lib/camaleon_cms/version.rb +1 -1
  138. data/lib/ext/array.rb +5 -0
  139. data/lib/generators/camaleon_cms/gem_plugin_generator.rb +1 -1
  140. data/lib/generators/camaleon_cms/gem_plugin_template/app/models/plugins/my_plugin/my_plugin.rb +1 -2
  141. data/lib/generators/camaleon_cms/gem_plugin_template/config/{custom_models.rb → initializers/custom_models.rb} +0 -0
  142. data/lib/plugin_routes.rb +38 -63
  143. data/lib/tasks/camaleon_cms/camaleon_tasks.rake +18 -0
  144. data/lib/tasks/camaleon_cms/rspec_test.rake +7 -4
  145. metadata +43 -54
  146. data/app/assets/javascripts/camaleon_cms/admin/bootstrap-datetimepicker.min.js +0 -26
  147. data/app/assets/javascripts/camaleon_cms/admin/plugins.js +0 -637
  148. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-cool.gif +0 -0
  149. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-cry.gif +0 -0
  150. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-embarassed.gif +0 -0
  151. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif +0 -0
  152. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-frown.gif +0 -0
  153. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-innocent.gif +0 -0
  154. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-kiss.gif +0 -0
  155. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-laughing.gif +0 -0
  156. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-money-mouth.gif +0 -0
  157. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-sealed.gif +0 -0
  158. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-smile.gif +0 -0
  159. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-surprised.gif +0 -0
  160. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-tongue-out.gif +0 -0
  161. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-undecided.gif +0 -0
  162. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-wink.gif +0 -0
  163. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/emoticons/img/smiley-yell.gif +0 -0
  164. data/app/assets/javascripts/camaleon_cms/admin/tinymce/plugins/visualblocks/css/visualblocks.css +0 -135
  165. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/content.min.css.scss +0 -4
  166. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/fonts/tinymce-small.eot +0 -0
  167. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/fonts/tinymce-small.svg +0 -62
  168. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/fonts/tinymce-small.ttf +0 -0
  169. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/fonts/tinymce-small.woff +0 -0
  170. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/fonts/tinymce.eot +0 -0
  171. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/fonts/tinymce.svg +0 -83
  172. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/fonts/tinymce.ttf +0 -0
  173. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/fonts/tinymce.woff +0 -0
  174. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/img/anchor.gif +0 -0
  175. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/img/loader.gif +0 -0
  176. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/img/object.gif +0 -0
  177. data/app/assets/javascripts/camaleon_cms/admin/tinymce/skins/lightgray/img/trans.gif +0 -0
  178. data/app/assets/javascripts/camaleon_cms/admin/tinymce/themes/modern/theme.min.js +0 -1
  179. data/app/assets/javascripts/camaleon_cms/admin/tinymce/tinymce.min.js +0 -11
  180. data/app/assets/stylesheets/camaleon_cms/admin/bootstrap-datetimepicker.css.scss +0 -339
@@ -12,10 +12,12 @@ jQuery(function(){
12
12
  var title = $(this).attr("title");
13
13
  title = (title == "")? $(this).attr("data-original-title") : title
14
14
  var def = {title: title?title:$(this).data("title"), mode: "ajax", url: $(this).attr("href"), show_footer: $(this).data("show_footer")};
15
+ if($(this).attr('data-modal_size')) def["modal_size"] = $(this).attr('data-modal_size');
15
16
  var c_settings = $.extend({}, def, settings);
16
17
  open_modal(c_settings);
17
18
  e.preventDefault();
18
19
  });
20
+ return this;
19
21
  }
20
22
 
21
23
  // custom alert dialog
@@ -24,7 +26,7 @@ jQuery(function(){
24
26
  // type: error | warning | success
25
27
  $.fn.alert = function (options) {
26
28
  hideLoading();
27
- var default_options = {title: I18n("msg.updated_success"), type: "success" };
29
+ var default_options = {title: I18n("msg.updated_success"), type: "success", zindex: '99999999', id: 'cama_alert_modal' };
28
30
  options = $.extend(default_options, options || {});
29
31
  if(options.type == "error") options.type = "danger";
30
32
  if(options.type == "alert") options.type = "warning";
@@ -33,40 +35,6 @@ jQuery(function(){
33
35
  options.title = "";
34
36
  }
35
37
  open_modal(options);
36
- return;
37
-
38
-
39
-
40
- if (options.type == "error") options.type = "danger";
41
- if (options.type == "alert") options.type = "warning";
42
-
43
- var html = '<div class="message-box message-box-'+options.type+' animated fadeIn open" >'+
44
- '<div class="mb-container">'+
45
- '<div class="mb-middle">'+
46
- '<div class="mb-title"><span class="fa fa-'+options.icon+'"></span> '+options.title+'</div>' +
47
- '<div class="mb-content">'+
48
- options.content+
49
- '</div>'+
50
- '<div class="mb-footer">'+
51
- '<button class="btn btn-default btn-lg pull-right mb-control-close">'+options.close+'</button>'+
52
- '</div>'+
53
- '</div>' +
54
- '</div>' +
55
- '</div>' ;
56
-
57
- if(options.type === 'warning')
58
- playAudio('alert');
59
-
60
- if(options.type === 'danger')
61
- playAudio('fail');
62
-
63
- var $html = $(html);
64
- $html.find('.mb-control-close').click(function(){
65
- $html.remove();
66
- return false;
67
- })
68
- $('body').append($html);
69
-
70
38
  };
71
39
  });
72
40
 
@@ -85,12 +53,17 @@ jQuery(function(){
85
53
  * type: modal color (primary|default|success)
86
54
  * zindex: Integer zindex position (default null)
87
55
  * on_submit: Function executed after submit button click (if this is present, enable the submit button beside cancel button)
56
+ * on_close: function executed after modal closed
88
57
  * return modal object
89
58
  */
90
59
  function open_modal(settings){
91
- var def = {title: "", content: null, url: null, show_footer: false, mode: "inline", ajax_params: {}, zindex: null, modal_size: "", type: '', modal_settings:{}, on_submit: null, callback: function(){}}
60
+ var def = {title: "", content: null, url: null, show_footer: false, mode: "inline", ajax_params: {}, id: 'ow_inline_modal', zindex: null, modal_size: "", type: '', modal_settings:{}, on_submit: null, callback: function(){}, on_close: function(){}}
92
61
  settings = $.extend({}, def, settings);
93
- var modal = $('<div id="ow_inline_modal" class="modal fade modal-'+settings.type+'">'+
62
+ if(settings.id){
63
+ var hidden_modal = $("#"+settings.id);
64
+ if(hidden_modal.size()){ hidden_modal.modal('show'); return hidden_modal; }
65
+ }
66
+ var modal = $('<div id="'+settings.id+'" class="modal fade modal-'+settings.type+'">'+
94
67
  '<div class="modal-dialog '+settings.modal_size+'">'+
95
68
  '<div class="modal-content">'+
96
69
  '<div class="modal-header">'+
@@ -105,6 +78,7 @@ function open_modal(settings){
105
78
 
106
79
  // on modal hide
107
80
  modal.on("hidden.bs.modal", function(e){
81
+ settings.on_close(modal);
108
82
  if(!$(e["currentTarget"]).attr("data-skip_destroy")) $(e["currentTarget"]).remove();
109
83
  modal_fix_multiple();
110
84
  });
@@ -56,16 +56,16 @@ function init_post(obj) {
56
56
  window["post_editor_draft_intrval"] = setInterval(function () { if($form.length == 0){ clearInterval(window["post_editor_draft_intrval"]); } else{ App_post.save_draft_ajax(null, true); } }, 3 * 60 * 1000);
57
57
  window.save_draft = App_post.save_draft_ajax;
58
58
 
59
- if ($(".title-post" + class_translate).size() == 0) class_translate = '';
60
- $(".title-post" + class_translate).each(function () {
59
+ if($form.find(".title-post" + class_translate).size() == 0) class_translate = '';
60
+ $form.find(".title-post" + class_translate).each(function () {
61
61
  var $this = $(this);
62
62
  if (!$this.hasClass('sluged')) {
63
63
  if (class_translate) {
64
- var lng = $this.attr("name").match(/-(.*)-/i).pop();
65
- var $input_slug = $('.slug-post' + class_translate + '[name^="translation-' + lng + '"]')
64
+ var lng = $this.attr("data-translation_l");
65
+ var $input_slug = $form.find('.slug-post' + class_translate + '[data-translation_l="' + lng + '"]');
66
66
  var post_path = obj._post_urls[lng];
67
67
  } else {
68
- var $input_slug = $('.slug-post');
68
+ var $input_slug = $form.find('.slug-post');
69
69
  var post_path = obj._post_urls[Object.keys(obj._post_urls)[0]];
70
70
  }
71
71
 
@@ -104,9 +104,7 @@ function init_post(obj) {
104
104
  }
105
105
 
106
106
  function set_meta_slug() {
107
- $('#meta_slug').val($('.slug-post' + class_translate).map(function () {
108
- return this.value;
109
- }).get().join(","));
107
+ $('#meta_slug').val($form.find('.slug-post' + class_translate).map(function () { return this.value; }).get().join(","));
110
108
  }
111
109
 
112
110
  var slug_tmp = null;
@@ -120,7 +118,6 @@ function init_post(obj) {
120
118
 
121
119
  $this.change(function () {
122
120
  if (slug_tmp) ajax_set_slug(slug_tmp);
123
- //if (!_draft_inited) App_post.save_draft_ajax();
124
121
  });
125
122
  if ($input_slug.val()) {
126
123
  set_slug($input_slug.val());
@@ -192,7 +189,7 @@ function init_post(obj) {
192
189
  // here all later actions
193
190
  var form_later_actions = function () {
194
191
  /*********** scroller (fix buttons position) ***************/
195
- var panel_scroll = $("#form-post > .content-frame-right");
192
+ var panel_scroll = $("#form-post > #post_right_bar");
196
193
  var fixed_position = panel_scroll.children(":first");
197
194
  var fixed_offset_top = panel_scroll.offset().top;
198
195
  $(window).scroll(function () {
@@ -237,9 +234,9 @@ function init_post(obj) {
237
234
  });
238
235
 
239
236
  // sidebar toggle
240
- $("#admin_content .content-frame-right-toggle").on("click", function () {
241
- $(".content-frame-right").is(":visible") ? $(".content-frame-right").hide() : $(".content-frame-right").show();
242
- });
237
+ //$("#admin_content #post_right_bar-toggle").on("click", function () {
238
+ // $("#post_right_bar").is(":visible") ? $("#post_right_bar").hide() : $("#post_right_bar").show();
239
+ //});
243
240
 
244
241
  /*********** control save changes before unload form. ***************/
245
242
  $form.submit(function () {
@@ -255,6 +252,18 @@ function init_post(obj) {
255
252
  return;
256
253
  return "You sure to leave the page without saving changes?";
257
254
  };
255
+
256
+ /*********** link to create categories *************/
257
+ $form.find("#post_add_new_category").ajax_modal({modal_size: 'modal-lg', mode: 'iframe', callback: function(modal){
258
+ modal.find('iframe').on('load', function(){
259
+ $(this).contents().find("#main-header, #sidebar-menu, #main-footer").hide();
260
+ $(this).contents().find('#admin_content').parent().css("margin-left", 0);
261
+ });
262
+ }, on_close: function(modal){
263
+ var panel_cats = $form.find("#post_right_bar .list-categories");
264
+ $.get($form.find("#post_add_new_category").data('reload-url'), {categories: panel_cats.find("input:checkbox:checked").map(function(i, el){ return $(this).val(); }).get()}, function(res){ panel_cats.html(res); });
265
+ }});
266
+ /*********** end *************/
258
267
  }
259
268
  setTimeout(form_later_actions, 1000);
260
269
 
@@ -288,15 +297,11 @@ function upload_feature_image() {
288
297
  $.fn.upload_filemanager({
289
298
  formats: "image",
290
299
  selected: function (image) {
291
- if (image.mime && image.mime.indexOf("image") > -1) {
292
- var image_url = image.url;
293
- $('#feature-image img').attr('src', image_url);
294
- $('#feature-image input').val(image_url);
295
- $('#feature-image .meta strong').html(image.name);
296
- $('#feature-image').show();
297
- } else {
298
- alert("You must upload an image");
299
- }
300
+ var image_url = image.url;
301
+ $('#feature-image img').attr('src', image_url);
302
+ $('#feature-image input').val(image_url);
303
+ $('#feature-image .meta strong').html(image.name);
304
+ $('#feature-image').show();
300
305
  }
301
306
  });
302
307
  }
@@ -70,7 +70,8 @@ jQuery(function($){
70
70
  var l = languages[ii];
71
71
  var key = "translation-"+l+"-"+TRANSLATOR_counter;
72
72
  tabs_title.push('<li role="presentation" class="pull-right '+(ii==0?"active":"")+'"><a href="#pane-'+key+'" role="tab" data-toggle="tab">'+ l.titleize()+'</a></li>');
73
- var clone = ele.clone(true).attr({id: key, name: key}).addClass("translate-item").val(get_translation(translations, l));
73
+ var clone = ele.clone(true).attr({id: key, name: key, "data-name": key, 'data-translation_l': l, 'data-translation': "translation-"+l}).addClass("translate-item").val(get_translation(translations, l));
74
+ if(ii > 0 && !clone.hasClass('required_all_langs')) clone.removeClass('required'); // to permit enter empty values for secondary languages
74
75
  inputs[l] = clone;
75
76
  clone.wrap("<div class='tab-pane "+class_group+" trans_tab_item "+(ii==0?"active":"")+"' id='pane-"+key+"'/>");
76
77
  tabs_content.push(clone.parent());
@@ -17,6 +17,10 @@
17
17
  //= require ./_underscore
18
18
  //= require ./jquery.validate
19
19
 
20
+ // date picker
21
+ //= require ./momentjs/_moment
22
+ //= require ./bootstrap-datepicker
23
+
20
24
  //= require jquery_ujs
21
25
 
22
26
  //= require ./_jquery.slugify
@@ -38,9 +42,9 @@
38
42
  //= require ./lte/app
39
43
 
40
44
  // tinymce
41
- //= require ./tinymce/tinymce.min
45
+ //= require tinymce-jquery
42
46
  //= require ./tinymce/plugins/filemanager/plugin.min
43
47
 
44
48
  // post
45
49
  //= require ./_jquery.tagsinput.min
46
- //= require ./_post
50
+ //= require ./_post
@@ -1,1690 +1,2558 @@
1
- /* =========================================================
2
- * bootstrap-datepicker.js
3
- * Repo: https://github.com/eternicode/bootstrap-datepicker/
4
- * Demo: http://eternicode.github.io/bootstrap-datepicker/
5
- * Docs: http://bootstrap-datepicker.readthedocs.org/
6
- * Forked from http://www.eyecon.ro/bootstrap-datepicker
7
- * =========================================================
8
- * Started by Stefan Petre; improvements by Andrew Rowls + contributors
9
- *
10
- * Licensed under the Apache License, Version 2.0 (the "License");
11
- * you may not use this file except in compliance with the License.
12
- * You may obtain a copy of the License at
13
- *
14
- * http://www.apache.org/licenses/LICENSE-2.0
15
- *
16
- * Unless required by applicable law or agreed to in writing, software
17
- * distributed under the License is distributed on an "AS IS" BASIS,
18
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
- * See the License for the specific language governing permissions and
20
- * limitations under the License.
21
- * ========================================================= */
22
-
23
- (function($, undefined){
24
-
25
- var $window = $(window);
26
-
27
- function UTCDate(){
28
- return new Date(Date.UTC.apply(Date, arguments));
29
- }
30
- function UTCToday(){
31
- var today = new Date();
32
- return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
33
- }
34
- function alias(method){
35
- return function(){
36
- return this[method].apply(this, arguments);
37
- };
38
- }
39
-
40
- var DateArray = (function(){
41
- var extras = {
42
- get: function(i){
43
- return this.slice(i)[0];
44
- },
45
- contains: function(d){
46
- // Array.indexOf is not cross-browser;
47
- // $.inArray doesn't work with Dates
48
- var val = d && d.valueOf();
49
- for (var i=0, l=this.length; i < l; i++)
50
- if (this[i].valueOf() === val)
51
- return i;
52
- return -1;
53
- },
54
- remove: function(i){
55
- this.splice(i,1);
56
- },
57
- replace: function(new_array){
58
- if (!new_array)
59
- return;
60
- if (!$.isArray(new_array))
61
- new_array = [new_array];
62
- this.clear();
63
- this.push.apply(this, new_array);
64
- },
65
- clear: function(){
66
- this.length = 0;
67
- },
68
- copy: function(){
69
- var a = new DateArray();
70
- a.replace(this);
71
- return a;
72
- }
73
- };
74
-
75
- return function(){
76
- var a = [];
77
- a.push.apply(a, arguments);
78
- $.extend(a, extras);
79
- return a;
80
- };
81
- })();
82
-
83
-
84
- // Picker object
85
-
86
- var Datepicker = function(element, options){
87
- this.dates = new DateArray();
88
- this.viewDate = UTCToday();
89
- this.focusDate = null;
90
-
91
- this._process_options(options);
92
-
93
- this.element = $(element);
94
- this.isInline = false;
95
- this.isInput = this.element.is('input');
96
- this.component = this.element.is('.date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
97
- this.hasInput = this.component && this.element.find('input').length;
98
- if (this.component && this.component.length === 0)
99
- this.component = false;
100
-
101
- this.picker = $(DPGlobal.template);
102
- this._buildEvents();
103
- this._attachEvents();
104
-
105
- if (this.isInline){
106
- this.picker.addClass('datepicker-inline').appendTo(this.element);
107
- }
108
- else {
109
- this.picker.addClass('datepicker-dropdown dropdown-menu');
110
- }
111
-
112
- if (this.o.rtl){
113
- this.picker.addClass('datepicker-rtl');
114
- }
115
-
116
- this.viewMode = this.o.startView;
117
-
118
- if (this.o.calendarWeeks)
119
- this.picker.find('tfoot th.today, tfoot th.clear')
120
- .attr('colspan', function(i, val){
121
- return parseInt(val) + 1;
122
- });
123
-
124
- this._allow_update = false;
125
-
126
- this.setStartDate(this._o.startDate);
127
- this.setEndDate(this._o.endDate);
128
- this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
129
-
130
- this.fillDow();
131
- this.fillMonths();
132
-
133
- this._allow_update = true;
134
-
135
- this.update();
136
- this.showMode();
137
-
138
- if (this.isInline){
139
- this.show();
140
- }
141
- };
142
-
143
- Datepicker.prototype = {
144
- constructor: Datepicker,
145
-
146
- _process_options: function(opts){
147
- // Store raw options for reference
148
- this._o = $.extend({}, this._o, opts);
149
- // Processed options
150
- var o = this.o = $.extend({}, this._o);
151
-
152
- // Check if "de-DE" style date is available, if not language should
153
- // fallback to 2 letter code eg "de"
154
- var lang = o.language;
155
- if (!dates[lang]){
156
- lang = lang.split('-')[0];
157
- if (!dates[lang])
158
- lang = defaults.language;
159
- }
160
- o.language = lang;
161
-
162
- switch (o.startView){
163
- case 2:
164
- case 'decade':
165
- o.startView = 2;
166
- break;
167
- case 1:
168
- case 'year':
169
- o.startView = 1;
170
- break;
171
- default:
172
- o.startView = 0;
173
- }
174
-
175
- switch (o.minViewMode){
176
- case 1:
177
- case 'months':
178
- o.minViewMode = 1;
179
- break;
180
- case 2:
181
- case 'years':
182
- o.minViewMode = 2;
183
- break;
184
- default:
185
- o.minViewMode = 0;
186
- }
187
-
188
- o.startView = Math.max(o.startView, o.minViewMode);
189
-
190
- // true, false, or Number > 0
191
- if (o.multidate !== true){
192
- o.multidate = Number(o.multidate) || false;
193
- if (o.multidate !== false)
194
- o.multidate = Math.max(0, o.multidate);
195
- else
196
- o.multidate = 1;
197
- }
198
- o.multidateSeparator = String(o.multidateSeparator);
199
-
200
- o.weekStart %= 7;
201
- o.weekEnd = ((o.weekStart + 6) % 7);
202
-
203
- var format = DPGlobal.parseFormat(o.format);
204
- if (o.startDate !== -Infinity){
205
- if (!!o.startDate){
206
- if (o.startDate instanceof Date)
207
- o.startDate = this._local_to_utc(this._zero_time(o.startDate));
208
- else
209
- o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);
210
- }
211
- else {
212
- o.startDate = -Infinity;
213
- }
214
- }
215
- if (o.endDate !== Infinity){
216
- if (!!o.endDate){
217
- if (o.endDate instanceof Date)
218
- o.endDate = this._local_to_utc(this._zero_time(o.endDate));
219
- else
220
- o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);
221
- }
222
- else {
223
- o.endDate = Infinity;
224
- }
225
- }
226
-
227
- o.daysOfWeekDisabled = o.daysOfWeekDisabled||[];
228
- if (!$.isArray(o.daysOfWeekDisabled))
229
- o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
230
- o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d){
231
- return parseInt(d, 10);
232
- });
233
-
234
- var plc = String(o.orientation).toLowerCase().split(/\s+/g),
235
- _plc = o.orientation.toLowerCase();
236
- plc = $.grep(plc, function(word){
237
- return (/^auto|left|right|top|bottom$/).test(word);
238
- });
239
- o.orientation = {x: 'auto', y: 'auto'};
240
- if (!_plc || _plc === 'auto')
241
- ; // no action
242
- else if (plc.length === 1){
243
- switch (plc[0]){
244
- case 'top':
245
- case 'bottom':
246
- o.orientation.y = plc[0];
247
- break;
248
- case 'left':
249
- case 'right':
250
- o.orientation.x = plc[0];
251
- break;
252
- }
253
- }
254
- else {
255
- _plc = $.grep(plc, function(word){
256
- return (/^left|right$/).test(word);
257
- });
258
- o.orientation.x = _plc[0] || 'auto';
259
-
260
- _plc = $.grep(plc, function(word){
261
- return (/^top|bottom$/).test(word);
262
- });
263
- o.orientation.y = _plc[0] || 'auto';
264
- }
265
- },
266
- _events: [],
267
- _secondaryEvents: [],
268
- _applyEvents: function(evs){
269
- for (var i=0, el, ch, ev; i < evs.length; i++){
270
- el = evs[i][0];
271
- if (evs[i].length === 2){
272
- ch = undefined;
273
- ev = evs[i][1];
274
- }
275
- else if (evs[i].length === 3){
276
- ch = evs[i][1];
277
- ev = evs[i][2];
278
- }
279
- el.on(ev, ch);
280
- }
281
- },
282
- _unapplyEvents: function(evs){
283
- for (var i=0, el, ev, ch; i < evs.length; i++){
284
- el = evs[i][0];
285
- if (evs[i].length === 2){
286
- ch = undefined;
287
- ev = evs[i][1];
288
- }
289
- else if (evs[i].length === 3){
290
- ch = evs[i][1];
291
- ev = evs[i][2];
292
- }
293
- el.off(ev, ch);
294
- }
295
- },
296
- _buildEvents: function(){
297
- if (this.isInput){ // single input
298
- this._events = [
299
- [this.element, {
300
- focus: $.proxy(this.show, this),
301
- keyup: $.proxy(function(e){
302
- if ($.inArray(e.keyCode, [27,37,39,38,40,32,13,9]) === -1)
303
- this.update();
304
- }, this),
305
- keydown: $.proxy(this.keydown, this)
306
- }]
307
- ];
308
- }
309
- else if (this.component && this.hasInput){ // component: input + button
310
- this._events = [
311
- // For components that are not readonly, allow keyboard nav
312
- [this.element.find('input'), {
313
- focus: $.proxy(this.show, this),
314
- keyup: $.proxy(function(e){
315
- if ($.inArray(e.keyCode, [27,37,39,38,40,32,13,9]) === -1)
316
- this.update();
317
- }, this),
318
- keydown: $.proxy(this.keydown, this)
319
- }],
320
- [this.component, {
321
- click: $.proxy(this.show, this)
322
- }]
323
- ];
324
- }
325
- else if (this.element.is('div')){ // inline datepicker
326
- this.isInline = true;
327
- }
328
- else {
329
- this._events = [
330
- [this.element, {
331
- click: $.proxy(this.show, this)
332
- }]
333
- ];
334
- }
335
- this._events.push(
336
- // Component: listen for blur on element descendants
337
- [this.element, '*', {
338
- blur: $.proxy(function(e){
339
- this._focused_from = e.target;
340
- }, this)
341
- }],
342
- // Input: listen for blur on element
343
- [this.element, {
344
- blur: $.proxy(function(e){
345
- this._focused_from = e.target;
346
- }, this)
347
- }]
348
- );
349
-
350
- this._secondaryEvents = [
351
- [this.picker, {
352
- click: $.proxy(this.click, this)
353
- }],
354
- [$(window), {
355
- resize: $.proxy(this.place, this)
356
- }],
357
- [$(document), {
358
- 'mousedown touchstart': $.proxy(function(e){
359
- // Clicked outside the datepicker, hide it
360
- if (!(
361
- this.element.is(e.target) ||
362
- this.element.find(e.target).length ||
363
- this.picker.is(e.target) ||
364
- this.picker.find(e.target).length
365
- )){
366
- this.hide();
367
- }
368
- }, this)
369
- }]
370
- ];
371
- },
372
- _attachEvents: function(){
373
- this._detachEvents();
374
- this._applyEvents(this._events);
375
- },
376
- _detachEvents: function(){
377
- this._unapplyEvents(this._events);
378
- },
379
- _attachSecondaryEvents: function(){
380
- this._detachSecondaryEvents();
381
- this._applyEvents(this._secondaryEvents);
382
- },
383
- _detachSecondaryEvents: function(){
384
- this._unapplyEvents(this._secondaryEvents);
385
- },
386
- _trigger: function(event, altdate){
387
- var date = altdate || this.dates.get(-1),
388
- local_date = this._utc_to_local(date);
389
-
390
- this.element.trigger({
391
- type: event,
392
- date: local_date,
393
- dates: $.map(this.dates, this._utc_to_local),
394
- format: $.proxy(function(ix, format){
395
- if (arguments.length === 0){
396
- ix = this.dates.length - 1;
397
- format = this.o.format;
398
- }
399
- else if (typeof ix === 'string'){
400
- format = ix;
401
- ix = this.dates.length - 1;
402
- }
403
- format = format || this.o.format;
404
- var date = this.dates.get(ix);
405
- return DPGlobal.formatDate(date, format, this.o.language);
406
- }, this)
407
- });
408
- },
409
-
410
- show: function(){
411
- if (!this.isInline)
412
- this.picker.appendTo('body');
413
- this.picker.show();
414
- this.place();
415
- this._attachSecondaryEvents();
416
- this._trigger('show');
417
- },
418
-
419
- hide: function(){
420
- if (this.isInline)
421
- return;
422
- if (!this.picker.is(':visible'))
423
- return;
424
- this.focusDate = null;
425
- this.picker.hide().detach();
426
- this._detachSecondaryEvents();
427
- this.viewMode = this.o.startView;
428
- this.showMode();
429
-
430
- if (
431
- this.o.forceParse &&
432
- (
433
- this.isInput && this.element.val() ||
434
- this.hasInput && this.element.find('input').val()
435
- )
436
- )
437
- this.setValue();
438
- this._trigger('hide');
439
- },
440
-
441
- remove: function(){
442
- this.hide();
443
- this._detachEvents();
444
- this._detachSecondaryEvents();
445
- this.picker.remove();
446
- delete this.element.data().datepicker;
447
- if (!this.isInput){
448
- delete this.element.data().date;
449
- }
450
- },
451
-
452
- _utc_to_local: function(utc){
453
- return utc && new Date(utc.getTime() + (utc.getTimezoneOffset()*60000));
454
- },
455
- _local_to_utc: function(local){
456
- return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
457
- },
458
- _zero_time: function(local){
459
- return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
460
- },
461
- _zero_utc_time: function(utc){
462
- return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));
463
- },
464
-
465
- getDates: function(){
466
- return $.map(this.dates, this._utc_to_local);
467
- },
468
-
469
- getUTCDates: function(){
470
- return $.map(this.dates, function(d){
471
- return new Date(d);
472
- });
473
- },
474
-
475
- getDate: function(){
476
- return this._utc_to_local(this.getUTCDate());
477
- },
478
-
479
- getUTCDate: function(){
480
- return new Date(this.dates.get(-1));
481
- },
482
-
483
- setDates: function(){
484
- var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
485
- this.update.apply(this, args);
486
- this._trigger('changeDate');
487
- this.setValue();
488
- },
489
-
490
- setUTCDates: function(){
491
- var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
492
- this.update.apply(this, $.map(args, this._utc_to_local));
493
- this._trigger('changeDate');
494
- this.setValue();
495
- },
496
-
497
- setDate: alias('setDates'),
498
- setUTCDate: alias('setUTCDates'),
499
-
500
- setValue: function(){
501
- var formatted = this.getFormattedDate();
502
- if (!this.isInput){
503
- if (this.component){
504
- this.element.find('input').val(formatted).change();
505
- }
506
- }
507
- else {
508
- this.element.val(formatted).change();
509
- }
510
- },
511
-
512
- getFormattedDate: function(format){
513
- if (format === undefined)
514
- format = this.o.format;
515
-
516
- var lang = this.o.language;
517
- return $.map(this.dates, function(d){
518
- return DPGlobal.formatDate(d, format, lang);
519
- }).join(this.o.multidateSeparator);
520
- },
521
-
522
- setStartDate: function(startDate){
523
- this._process_options({startDate: startDate});
524
- this.update();
525
- this.updateNavArrows();
526
- },
527
-
528
- setEndDate: function(endDate){
529
- this._process_options({endDate: endDate});
530
- this.update();
531
- this.updateNavArrows();
532
- },
533
-
534
- setDaysOfWeekDisabled: function(daysOfWeekDisabled){
535
- this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
536
- this.update();
537
- this.updateNavArrows();
538
- },
539
-
540
- place: function(){
541
- if (this.isInline)
542
- return;
543
- var calendarWidth = this.picker.outerWidth(),
544
- calendarHeight = this.picker.outerHeight(),
545
- visualPadding = 10,
546
- windowWidth = $window.width(),
547
- windowHeight = $window.height(),
548
- scrollTop = $window.scrollTop();
549
-
550
- var parentsZindex = [];
551
- this.element.parents().each(function() {
552
- var itemZIndex = $(this).css('z-index');
553
- if ( itemZIndex !== 'auto' && itemZIndex !== 0 ) parentsZindex.push( parseInt( itemZIndex ) );
554
- });
555
- var zIndex = Math.max.apply( Math, parentsZindex ) + 10;
556
- var offset = this.component ? this.component.parent().offset() : this.element.offset();
557
- var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
558
- var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
559
- var left = offset.left,
560
- top = offset.top;
561
-
562
- this.picker.removeClass(
563
- 'datepicker-orient-top datepicker-orient-bottom '+
564
- 'datepicker-orient-right datepicker-orient-left'
565
- );
566
-
567
- if (this.o.orientation.x !== 'auto'){
568
- this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
569
- if (this.o.orientation.x === 'right')
570
- left -= calendarWidth - width;
571
- }
572
- // auto x orientation is best-placement: if it crosses a window
573
- // edge, fudge it sideways
574
- else {
575
- // Default to left
576
- this.picker.addClass('datepicker-orient-left');
577
- if (offset.left < 0)
578
- left -= offset.left - visualPadding;
579
- else if (offset.left + calendarWidth > windowWidth)
580
- left = windowWidth - calendarWidth - visualPadding;
581
- }
582
-
583
- // auto y orientation is best-situation: top or bottom, no fudging,
584
- // decision based on which shows more of the calendar
585
- var yorient = this.o.orientation.y,
586
- top_overflow, bottom_overflow;
587
- if (yorient === 'auto'){
588
- top_overflow = -scrollTop + offset.top - calendarHeight;
589
- bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight);
590
- if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)
591
- yorient = 'top';
592
- else
593
- yorient = 'bottom';
594
- }
595
- this.picker.addClass('datepicker-orient-' + yorient);
596
- if (yorient === 'top')
597
- top += height;
598
- else
599
- top -= calendarHeight + parseInt(this.picker.css('padding-top'));
600
-
601
- this.picker.css({
602
- top: top,
603
- left: left,
604
- zIndex: zIndex
605
- });
606
- },
607
-
608
- _allow_update: true,
609
- update: function(){
610
- if (!this._allow_update)
611
- return;
612
-
613
- var oldDates = this.dates.copy(),
614
- dates = [],
615
- fromArgs = false;
616
- if (arguments.length){
617
- $.each(arguments, $.proxy(function(i, date){
618
- if (date instanceof Date)
619
- date = this._local_to_utc(date);
620
- dates.push(date);
621
- }, this));
622
- fromArgs = true;
623
- }
624
- else {
625
- dates = this.isInput
626
- ? this.element.val()
627
- : this.element.data('date') || this.element.find('input').val();
628
- if (dates && this.o.multidate)
629
- dates = dates.split(this.o.multidateSeparator);
630
- else
631
- dates = [dates];
632
- delete this.element.data().date;
633
- }
634
-
635
- dates = $.map(dates, $.proxy(function(date){
636
- return DPGlobal.parseDate(date, this.o.format, this.o.language);
637
- }, this));
638
- dates = $.grep(dates, $.proxy(function(date){
639
- return (
640
- date < this.o.startDate ||
641
- date > this.o.endDate ||
642
- !date
643
- );
644
- }, this), true);
645
- this.dates.replace(dates);
646
-
647
- if (this.dates.length)
648
- this.viewDate = new Date(this.dates.get(-1));
649
- else if (this.viewDate < this.o.startDate)
650
- this.viewDate = new Date(this.o.startDate);
651
- else if (this.viewDate > this.o.endDate)
652
- this.viewDate = new Date(this.o.endDate);
653
-
654
- if (fromArgs){
655
- // setting date by clicking
656
- this.setValue();
657
- }
658
- else if (dates.length){
659
- // setting date by typing
660
- if (String(oldDates) !== String(this.dates))
661
- this._trigger('changeDate');
662
- }
663
- if (!this.dates.length && oldDates.length)
664
- this._trigger('clearDate');
665
-
666
- this.fill();
667
- },
668
-
669
- fillDow: function(){
670
- var dowCnt = this.o.weekStart,
671
- html = '<tr>';
672
- if (this.o.calendarWeeks){
673
- var cell = '<th class="cw">&nbsp;</th>';
674
- html += cell;
675
- this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
676
- }
677
- while (dowCnt < this.o.weekStart + 7){
678
- html += '<th class="dow">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
679
- }
680
- html += '</tr>';
681
- this.picker.find('.datepicker-days thead').append(html);
682
- },
683
-
684
- fillMonths: function(){
685
- var html = '',
686
- i = 0;
687
- while (i < 12){
688
- html += '<span class="month">'+dates[this.o.language].monthsShort[i++]+'</span>';
689
- }
690
- this.picker.find('.datepicker-months td').html(html);
691
- },
692
-
693
- setRange: function(range){
694
- if (!range || !range.length)
695
- delete this.range;
696
- else
697
- this.range = $.map(range, function(d){
698
- return d.valueOf();
699
- });
700
- this.fill();
701
- },
702
-
703
- getClassNames: function(date){
704
- var cls = [],
705
- year = this.viewDate.getUTCFullYear(),
706
- month = this.viewDate.getUTCMonth(),
707
- today = new Date();
708
- if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
709
- cls.push('old');
710
- }
711
- else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
712
- cls.push('new');
713
- }
714
- if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
715
- cls.push('focused');
716
- // Compare internal UTC date with local today, not UTC today
717
- if (this.o.todayHighlight &&
718
- date.getUTCFullYear() === today.getFullYear() &&
719
- date.getUTCMonth() === today.getMonth() &&
720
- date.getUTCDate() === today.getDate()){
721
- cls.push('today');
722
- }
723
- if (this.dates.contains(date) !== -1)
724
- cls.push('active');
725
- if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||
726
- $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1){
727
- cls.push('disabled');
728
- }
729
- if (this.range){
730
- if (date > this.range[0] && date < this.range[this.range.length-1]){
731
- cls.push('range');
732
- }
733
- if ($.inArray(date.valueOf(), this.range) !== -1){
734
- cls.push('selected');
735
- }
736
- }
737
- return cls;
738
- },
739
-
740
- fill: function(){
741
- var d = new Date(this.viewDate),
742
- year = d.getUTCFullYear(),
743
- month = d.getUTCMonth(),
744
- startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
745
- startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
746
- endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
747
- endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
748
- todaytxt = dates[this.o.language].today || dates['en'].today || '',
749
- cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
750
- tooltip;
751
- if (isNaN(year) || isNaN(month)) return;
752
- this.picker.find('.datepicker-days thead th.datepicker-switch')
753
- .text(dates[this.o.language].months[month]+' '+year);
754
- this.picker.find('tfoot th.today')
755
- .text(todaytxt)
756
- .toggle(this.o.todayBtn !== false);
757
- this.picker.find('tfoot th.clear')
758
- .text(cleartxt)
759
- .toggle(this.o.clearBtn !== false);
760
- this.updateNavArrows();
761
- this.fillMonths();
762
- var prevMonth = UTCDate(year, month-1, 28),
763
- day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
764
- prevMonth.setUTCDate(day);
765
- prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
766
- var nextMonth = new Date(prevMonth);
767
- nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
768
- nextMonth = nextMonth.valueOf();
769
- var html = [];
770
- var clsName;
771
- while (prevMonth.valueOf() < nextMonth){
772
- if (prevMonth.getUTCDay() === this.o.weekStart){
773
- html.push('<tr>');
774
- if (this.o.calendarWeeks){
775
- // ISO 8601: First week contains first thursday.
776
- // ISO also states week starts on Monday, but we can be more abstract here.
777
- var
778
- // Start of current week: based on weekstart/current date
779
- ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
780
- // Thursday of this week
781
- th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
782
- // First Thursday of year, year from thursday
783
- yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
784
- // Calendar week: ms between thursdays, div ms per day, div 7 days
785
- calWeek = (th - yth) / 864e5 / 7 + 1;
786
- html.push('<td class="cw">'+ calWeek +'</td>');
787
-
788
- }
789
- }
790
- clsName = this.getClassNames(prevMonth);
791
- clsName.push('day');
792
-
793
- if (this.o.beforeShowDay !== $.noop){
794
- var before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
795
- if (before === undefined)
796
- before = {};
797
- else if (typeof(before) === 'boolean')
798
- before = {enabled: before};
799
- else if (typeof(before) === 'string')
800
- before = {classes: before};
801
- if (before.enabled === false)
802
- clsName.push('disabled');
803
- if (before.classes)
804
- clsName = clsName.concat(before.classes.split(/\s+/));
805
- if (before.tooltip)
806
- tooltip = before.tooltip;
807
- }
808
-
809
- clsName = $.unique(clsName);
810
- html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>');
811
- tooltip = null;
812
- if (prevMonth.getUTCDay() === this.o.weekEnd){
813
- html.push('</tr>');
814
- }
815
- prevMonth.setUTCDate(prevMonth.getUTCDate()+1);
816
- }
817
- this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
818
-
819
- var months = this.picker.find('.datepicker-months')
820
- .find('th:eq(1)')
821
- .text(year)
822
- .end()
823
- .find('span').removeClass('active');
824
-
825
- $.each(this.dates, function(i, d){
826
- if (d.getUTCFullYear() === year)
827
- months.eq(d.getUTCMonth()).addClass('active');
828
- });
829
-
830
- if (year < startYear || year > endYear){
831
- months.addClass('disabled');
832
- }
833
- if (year === startYear){
834
- months.slice(0, startMonth).addClass('disabled');
835
- }
836
- if (year === endYear){
837
- months.slice(endMonth+1).addClass('disabled');
838
- }
839
-
840
- html = '';
841
- year = parseInt(year/10, 10) * 10;
842
- var yearCont = this.picker.find('.datepicker-years')
843
- .find('th:eq(1)')
844
- .text(year + '-' + (year + 9))
845
- .end()
846
- .find('td');
847
- year -= 1;
848
- var years = $.map(this.dates, function(d){
849
- return d.getUTCFullYear();
850
- }),
851
- classes;
852
- for (var i = -1; i < 11; i++){
853
- classes = ['year'];
854
- if (i === -1)
855
- classes.push('old');
856
- else if (i === 10)
857
- classes.push('new');
858
- if ($.inArray(year, years) !== -1)
859
- classes.push('active');
860
- if (year < startYear || year > endYear)
861
- classes.push('disabled');
862
- html += '<span class="' + classes.join(' ') + '">'+year+'</span>';
863
- year += 1;
864
- }
865
- yearCont.html(html);
866
- },
867
-
868
- updateNavArrows: function(){
869
- if (!this._allow_update)
870
- return;
871
-
872
- var d = new Date(this.viewDate),
873
- year = d.getUTCFullYear(),
874
- month = d.getUTCMonth();
875
- switch (this.viewMode){
876
- case 0:
877
- if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()){
878
- this.picker.find('.prev').css({visibility: 'hidden'});
879
- }
880
- else {
881
- this.picker.find('.prev').css({visibility: 'visible'});
882
- }
883
- if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()){
884
- this.picker.find('.next').css({visibility: 'hidden'});
885
- }
886
- else {
887
- this.picker.find('.next').css({visibility: 'visible'});
888
- }
889
- break;
890
- case 1:
891
- case 2:
892
- if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()){
893
- this.picker.find('.prev').css({visibility: 'hidden'});
894
- }
895
- else {
896
- this.picker.find('.prev').css({visibility: 'visible'});
897
- }
898
- if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()){
899
- this.picker.find('.next').css({visibility: 'hidden'});
900
- }
901
- else {
902
- this.picker.find('.next').css({visibility: 'visible'});
903
- }
904
- break;
905
- }
906
- },
907
-
908
- click: function(e){
909
- e.preventDefault();
910
- var target = $(e.target).closest('span, td, th'),
911
- year, month, day;
912
- if (target.length === 1){
913
- switch (target[0].nodeName.toLowerCase()){
914
- case 'th':
915
- switch (target[0].className){
916
- case 'datepicker-switch':
917
- this.showMode(1);
918
- break;
919
- case 'prev':
920
- case 'next':
921
- var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1);
922
- switch (this.viewMode){
923
- case 0:
924
- this.viewDate = this.moveMonth(this.viewDate, dir);
925
- this._trigger('changeMonth', this.viewDate);
926
- break;
927
- case 1:
928
- case 2:
929
- this.viewDate = this.moveYear(this.viewDate, dir);
930
- if (this.viewMode === 1)
931
- this._trigger('changeYear', this.viewDate);
932
- break;
933
- }
934
- this.fill();
935
- break;
936
- case 'today':
937
- var date = new Date();
938
- date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
939
-
940
- this.showMode(-2);
941
- var which = this.o.todayBtn === 'linked' ? null : 'view';
942
- this._setDate(date, which);
943
- break;
944
- case 'clear':
945
- var element;
946
- if (this.isInput)
947
- element = this.element;
948
- else if (this.component)
949
- element = this.element.find('input');
950
- if (element)
951
- element.val("").change();
952
- this.update();
953
- this._trigger('changeDate');
954
- if (this.o.autoclose)
955
- this.hide();
956
- break;
957
- }
958
- break;
959
- case 'span':
960
- if (!target.is('.disabled')){
961
- this.viewDate.setUTCDate(1);
962
- if (target.is('.month')){
963
- day = 1;
964
- month = target.parent().find('span').index(target);
965
- year = this.viewDate.getUTCFullYear();
966
- this.viewDate.setUTCMonth(month);
967
- this._trigger('changeMonth', this.viewDate);
968
- if (this.o.minViewMode === 1){
969
- this._setDate(UTCDate(year, month, day));
970
- }
971
- }
972
- else {
973
- day = 1;
974
- month = 0;
975
- year = parseInt(target.text(), 10)||0;
976
- this.viewDate.setUTCFullYear(year);
977
- this._trigger('changeYear', this.viewDate);
978
- if (this.o.minViewMode === 2){
979
- this._setDate(UTCDate(year, month, day));
980
- }
981
- }
982
- this.showMode(-1);
983
- this.fill();
984
- }
985
- break;
986
- case 'td':
987
- if (target.is('.day') && !target.is('.disabled')){
988
- day = parseInt(target.text(), 10)||1;
989
- year = this.viewDate.getUTCFullYear();
990
- month = this.viewDate.getUTCMonth();
991
- if (target.is('.old')){
992
- if (month === 0){
993
- month = 11;
994
- year -= 1;
995
- }
996
- else {
997
- month -= 1;
998
- }
999
- }
1000
- else if (target.is('.new')){
1001
- if (month === 11){
1002
- month = 0;
1003
- year += 1;
1004
- }
1005
- else {
1006
- month += 1;
1007
- }
1008
- }
1009
- this._setDate(UTCDate(year, month, day));
1010
- }
1011
- break;
1012
- }
1013
- }
1014
- if (this.picker.is(':visible') && this._focused_from){
1015
- $(this._focused_from).focus();
1016
- }
1017
- delete this._focused_from;
1018
- },
1019
-
1020
- _toggle_multidate: function(date){
1021
- var ix = this.dates.contains(date);
1022
- if (!date){
1023
- this.dates.clear();
1024
- }
1025
- if (this.o.multidate === 1 && ix === 0){
1026
- // single datepicker, don't remove selected date
1027
- }
1028
- else if (ix !== -1){
1029
- this.dates.remove(ix);
1030
- }
1031
- else {
1032
- this.dates.push(date);
1033
- }
1034
- if (typeof this.o.multidate === 'number')
1035
- while (this.dates.length > this.o.multidate)
1036
- this.dates.remove(0);
1037
- },
1038
-
1039
- _setDate: function(date, which){
1040
- if (!which || which === 'date')
1041
- this._toggle_multidate(date && new Date(date));
1042
- if (!which || which === 'view')
1043
- this.viewDate = date && new Date(date);
1044
-
1045
- this.fill();
1046
- this.setValue();
1047
- this._trigger('changeDate');
1048
- var element;
1049
- if (this.isInput){
1050
- element = this.element;
1051
- }
1052
- else if (this.component){
1053
- element = this.element.find('input');
1054
- }
1055
- if (element){
1056
- element.change();
1057
- }
1058
- if (this.o.autoclose && (!which || which === 'date')){
1059
- this.hide();
1060
- }
1061
- },
1062
-
1063
- moveMonth: function(date, dir){
1064
- if (!date)
1065
- return undefined;
1066
- if (!dir)
1067
- return date;
1068
- var new_date = new Date(date.valueOf()),
1069
- day = new_date.getUTCDate(),
1070
- month = new_date.getUTCMonth(),
1071
- mag = Math.abs(dir),
1072
- new_month, test;
1073
- dir = dir > 0 ? 1 : -1;
1074
- if (mag === 1){
1075
- test = dir === -1
1076
- // If going back one month, make sure month is not current month
1077
- // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
1078
- ? function(){
1079
- return new_date.getUTCMonth() === month;
1080
- }
1081
- // If going forward one month, make sure month is as expected
1082
- // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
1083
- : function(){
1084
- return new_date.getUTCMonth() !== new_month;
1085
- };
1086
- new_month = month + dir;
1087
- new_date.setUTCMonth(new_month);
1088
- // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
1089
- if (new_month < 0 || new_month > 11)
1090
- new_month = (new_month + 12) % 12;
1091
- }
1092
- else {
1093
- // For magnitudes >1, move one month at a time...
1094
- for (var i=0; i < mag; i++)
1095
- // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
1096
- new_date = this.moveMonth(new_date, dir);
1097
- // ...then reset the day, keeping it in the new month
1098
- new_month = new_date.getUTCMonth();
1099
- new_date.setUTCDate(day);
1100
- test = function(){
1101
- return new_month !== new_date.getUTCMonth();
1102
- };
1103
- }
1104
- // Common date-resetting loop -- if date is beyond end of month, make it
1105
- // end of month
1106
- while (test()){
1107
- new_date.setUTCDate(--day);
1108
- new_date.setUTCMonth(new_month);
1109
- }
1110
- return new_date;
1111
- },
1112
-
1113
- moveYear: function(date, dir){
1114
- return this.moveMonth(date, dir*12);
1115
- },
1116
-
1117
- dateWithinRange: function(date){
1118
- return date >= this.o.startDate && date <= this.o.endDate;
1119
- },
1120
-
1121
- keydown: function(e){
1122
- if (this.picker.is(':not(:visible)')){
1123
- if (e.keyCode === 27) // allow escape to hide and re-show picker
1124
- this.show();
1125
- return;
1126
- }
1127
- var dateChanged = false,
1128
- dir, newDate, newViewDate,
1129
- focusDate = this.focusDate || this.viewDate;
1130
- switch (e.keyCode){
1131
- case 27: // escape
1132
- if (this.focusDate){
1133
- this.focusDate = null;
1134
- this.viewDate = this.dates.get(-1) || this.viewDate;
1135
- this.fill();
1136
- }
1137
- else
1138
- this.hide();
1139
- e.preventDefault();
1140
- break;
1141
- case 37: // left
1142
- case 39: // right
1143
- if (!this.o.keyboardNavigation)
1144
- break;
1145
- dir = e.keyCode === 37 ? -1 : 1;
1146
- if (e.ctrlKey){
1147
- newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
1148
- newViewDate = this.moveYear(focusDate, dir);
1149
- this._trigger('changeYear', this.viewDate);
1150
- }
1151
- else if (e.shiftKey){
1152
- newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
1153
- newViewDate = this.moveMonth(focusDate, dir);
1154
- this._trigger('changeMonth', this.viewDate);
1155
- }
1156
- else {
1157
- newDate = new Date(this.dates.get(-1) || UTCToday());
1158
- newDate.setUTCDate(newDate.getUTCDate() + dir);
1159
- newViewDate = new Date(focusDate);
1160
- newViewDate.setUTCDate(focusDate.getUTCDate() + dir);
1161
- }
1162
- if (this.dateWithinRange(newDate)){
1163
- this.focusDate = this.viewDate = newViewDate;
1164
- this.setValue();
1165
- this.fill();
1166
- e.preventDefault();
1167
- }
1168
- break;
1169
- case 38: // up
1170
- case 40: // down
1171
- if (!this.o.keyboardNavigation)
1172
- break;
1173
- dir = e.keyCode === 38 ? -1 : 1;
1174
- if (e.ctrlKey){
1175
- newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
1176
- newViewDate = this.moveYear(focusDate, dir);
1177
- this._trigger('changeYear', this.viewDate);
1178
- }
1179
- else if (e.shiftKey){
1180
- newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
1181
- newViewDate = this.moveMonth(focusDate, dir);
1182
- this._trigger('changeMonth', this.viewDate);
1183
- }
1184
- else {
1185
- newDate = new Date(this.dates.get(-1) || UTCToday());
1186
- newDate.setUTCDate(newDate.getUTCDate() + dir * 7);
1187
- newViewDate = new Date(focusDate);
1188
- newViewDate.setUTCDate(focusDate.getUTCDate() + dir * 7);
1189
- }
1190
- if (this.dateWithinRange(newDate)){
1191
- this.focusDate = this.viewDate = newViewDate;
1192
- this.setValue();
1193
- this.fill();
1194
- e.preventDefault();
1195
- }
1196
- break;
1197
- case 32: // spacebar
1198
- // Spacebar is used in manually typing dates in some formats.
1199
- // As such, its behavior should not be hijacked.
1200
- break;
1201
- case 13: // enter
1202
- focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
1203
- if (this.o.keyboardNavigation) {
1204
- this._toggle_multidate(focusDate);
1205
- dateChanged = true;
1206
- }
1207
- this.focusDate = null;
1208
- this.viewDate = this.dates.get(-1) || this.viewDate;
1209
- this.setValue();
1210
- this.fill();
1211
- if (this.picker.is(':visible')){
1212
- e.preventDefault();
1213
- if (this.o.autoclose)
1214
- this.hide();
1215
- }
1216
- break;
1217
- case 9: // tab
1218
- this.focusDate = null;
1219
- this.viewDate = this.dates.get(-1) || this.viewDate;
1220
- this.fill();
1221
- this.hide();
1222
- break;
1223
- }
1224
- if (dateChanged){
1225
- if (this.dates.length)
1226
- this._trigger('changeDate');
1227
- else
1228
- this._trigger('clearDate');
1229
- var element;
1230
- if (this.isInput){
1231
- element = this.element;
1232
- }
1233
- else if (this.component){
1234
- element = this.element.find('input');
1235
- }
1236
- if (element){
1237
- element.change();
1238
- }
1239
- }
1240
- },
1241
-
1242
- showMode: function(dir){
1243
- if (dir){
1244
- this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
1245
- }
1246
- this.picker
1247
- .find('>div')
1248
- .hide()
1249
- .filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName)
1250
- .css('display', 'block');
1251
- this.updateNavArrows();
1252
- }
1253
- };
1254
-
1255
- var DateRangePicker = function(element, options){
1256
- this.element = $(element);
1257
- this.inputs = $.map(options.inputs, function(i){
1258
- return i.jquery ? i[0] : i;
1259
- });
1260
- delete options.inputs;
1261
-
1262
- $(this.inputs)
1263
- .datepicker(options)
1264
- .bind('changeDate', $.proxy(this.dateUpdated, this));
1265
-
1266
- this.pickers = $.map(this.inputs, function(i){
1267
- return $(i).data('datepicker');
1268
- });
1269
- this.updateDates();
1270
- };
1271
- DateRangePicker.prototype = {
1272
- updateDates: function(){
1273
- this.dates = $.map(this.pickers, function(i){
1274
- return i.getUTCDate();
1275
- });
1276
- this.updateRanges();
1277
- },
1278
- updateRanges: function(){
1279
- var range = $.map(this.dates, function(d){
1280
- return d.valueOf();
1281
- });
1282
- $.each(this.pickers, function(i, p){
1283
- p.setRange(range);
1284
- });
1285
- },
1286
- dateUpdated: function(e){
1287
- // `this.updating` is a workaround for preventing infinite recursion
1288
- // between `changeDate` triggering and `setUTCDate` calling. Until
1289
- // there is a better mechanism.
1290
- if (this.updating)
1291
- return;
1292
- this.updating = true;
1293
-
1294
- var dp = $(e.target).data('datepicker'),
1295
- new_date = dp.getUTCDate(),
1296
- i = $.inArray(e.target, this.inputs),
1297
- l = this.inputs.length;
1298
- if (i === -1)
1299
- return;
1300
-
1301
- $.each(this.pickers, function(i, p){
1302
- if (!p.getUTCDate())
1303
- p.setUTCDate(new_date);
1304
- });
1305
-
1306
- if (new_date < this.dates[i]){
1307
- // Date being moved earlier/left
1308
- while (i >= 0 && new_date < this.dates[i]){
1309
- this.pickers[i--].setUTCDate(new_date);
1310
- }
1311
- }
1312
- else if (new_date > this.dates[i]){
1313
- // Date being moved later/right
1314
- while (i < l && new_date > this.dates[i]){
1315
- this.pickers[i++].setUTCDate(new_date);
1316
- }
1317
- }
1318
- this.updateDates();
1319
-
1320
- delete this.updating;
1321
- },
1322
- remove: function(){
1323
- $.map(this.pickers, function(p){ p.remove(); });
1324
- delete this.element.data().datepicker;
1325
- }
1326
- };
1327
-
1328
- function opts_from_el(el, prefix){
1329
- // Derive options from element data-attrs
1330
- var data = $(el).data(),
1331
- out = {}, inkey,
1332
- replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
1333
- prefix = new RegExp('^' + prefix.toLowerCase());
1334
- function re_lower(_,a){
1335
- return a.toLowerCase();
1336
- }
1337
- for (var key in data)
1338
- if (prefix.test(key)){
1339
- inkey = key.replace(replace, re_lower);
1340
- out[inkey] = data[key];
1341
- }
1342
- return out;
1343
- }
1344
-
1345
- function opts_from_locale(lang){
1346
- // Derive options from locale plugins
1347
- var out = {};
1348
- // Check if "de-DE" style date is available, if not language should
1349
- // fallback to 2 letter code eg "de"
1350
- if (!dates[lang]){
1351
- lang = lang.split('-')[0];
1352
- if (!dates[lang])
1353
- return;
1354
- }
1355
- var d = dates[lang];
1356
- $.each(locale_opts, function(i,k){
1357
- if (k in d)
1358
- out[k] = d[k];
1359
- });
1360
- return out;
1361
- }
1362
-
1363
- var old = $.fn.datepicker;
1364
- $.fn.datepicker = function(option){
1365
- var args = Array.apply(null, arguments);
1366
- args.shift();
1367
- var internal_return;
1368
- this.each(function(){
1369
- var $this = $(this),
1370
- data = $this.data('datepicker'),
1371
- options = typeof option === 'object' && option;
1372
- if (!data){
1373
- var elopts = opts_from_el(this, 'date'),
1374
- // Preliminary otions
1375
- xopts = $.extend({}, defaults, elopts, options),
1376
- locopts = opts_from_locale(xopts.language),
1377
- // Options priority: js args, data-attrs, locales, defaults
1378
- opts = $.extend({}, defaults, locopts, elopts, options);
1379
- if ($this.is('.input-daterange') || opts.inputs){
1380
- var ropts = {
1381
- inputs: opts.inputs || $this.find('input').toArray()
1382
- };
1383
- $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts))));
1384
- }
1385
- else {
1386
- $this.data('datepicker', (data = new Datepicker(this, opts)));
1387
- }
1388
- }
1389
- if (typeof option === 'string' && typeof data[option] === 'function'){
1390
- internal_return = data[option].apply(data, args);
1391
- if (internal_return !== undefined)
1392
- return false;
1393
- }
1394
- });
1395
- if (internal_return !== undefined)
1396
- return internal_return;
1397
- else
1398
- return this;
1399
- };
1400
-
1401
- var defaults = $.fn.datepicker.defaults = {
1402
- autoclose: false,
1403
- beforeShowDay: $.noop,
1404
- calendarWeeks: false,
1405
- clearBtn: false,
1406
- daysOfWeekDisabled: [],
1407
- endDate: Infinity,
1408
- forceParse: true,
1409
- format: 'mm/dd/yyyy',
1410
- keyboardNavigation: true,
1411
- language: 'en',
1412
- minViewMode: 0,
1413
- multidate: false,
1414
- multidateSeparator: ',',
1415
- orientation: "auto",
1416
- rtl: false,
1417
- startDate: -Infinity,
1418
- startView: 0,
1419
- todayBtn: false,
1420
- todayHighlight: false,
1421
- weekStart: 0
1422
- };
1423
- var locale_opts = $.fn.datepicker.locale_opts = [
1424
- 'format',
1425
- 'rtl',
1426
- 'weekStart'
1427
- ];
1428
- $.fn.datepicker.Constructor = Datepicker;
1429
- var dates = $.fn.datepicker.dates = {
1430
- en: {
1431
- days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
1432
- daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
1433
- daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
1434
- months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
1435
- monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
1436
- today: "Today",
1437
- clear: "Clear"
1438
- },
1439
- es: {
1440
- days: ["Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo"],
1441
- daysShort: ["Dom", "Lun", "Mar", "Mie", "Jue", "Vie", "Sab", "Dom"],
1442
- daysMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa", "Do"],
1443
- months: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
1444
- monthsShort: ["Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic"],
1445
- today: "Hoy",
1446
- clear: "Borrar"
1
+ /*! version : 4.17.37
2
+ =========================================================
3
+ bootstrap-datetimejs
4
+ https://github.com/Eonasdan/bootstrap-datetimepicker
5
+ Copyright (c) 2015 Jonathan Peterson
6
+ =========================================================
7
+ */
8
+ /*
9
+ The MIT License (MIT)
10
+
11
+ Copyright (c) 2015 Jonathan Peterson
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in
21
+ all copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
+ THE SOFTWARE.
30
+ */
31
+ /*global define:false */
32
+ /*global exports:false */
33
+ /*global require:false */
34
+ /*global jQuery:false */
35
+ /*global moment:false */
36
+ (function (factory) {
37
+ 'use strict';
38
+ if (typeof define === 'function' && define.amd) {
39
+ // AMD is used - Register as an anonymous module.
40
+ define(['jquery', 'moment'], factory);
41
+ } else if (typeof exports === 'object') {
42
+ factory(require('jquery'), require('moment'));
43
+ } else {
44
+ // Neither AMD nor CommonJS used. Use global variables.
45
+ if (typeof jQuery === 'undefined') {
46
+ throw 'bootstrap-datetimepicker requires jQuery to be loaded first';
1447
47
  }
1448
- };
1449
-
1450
- var DPGlobal = {
1451
- modes: [
1452
- {
1453
- clsName: 'days',
1454
- navFnc: 'Month',
1455
- navStep: 1
1456
- },
1457
- {
1458
- clsName: 'months',
1459
- navFnc: 'FullYear',
1460
- navStep: 1
1461
- },
1462
- {
1463
- clsName: 'years',
1464
- navFnc: 'FullYear',
1465
- navStep: 10
1466
- }],
1467
- isLeapYear: function(year){
1468
- return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
1469
- },
1470
- getDaysInMonth: function(year, month){
1471
- return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
1472
- },
1473
- validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
1474
- nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
1475
- parseFormat: function(format){
1476
- // IE treats \0 as a string end in inputs (truncating the value),
1477
- // so it's a bad format delimiter, anyway
1478
- var separators = format.replace(this.validParts, '\0').split('\0'),
1479
- parts = format.match(this.validParts);
1480
- if (!separators || !separators.length || !parts || parts.length === 0){
1481
- throw new Error("Invalid date format.");
1482
- }
1483
- return {separators: separators, parts: parts};
1484
- },
1485
- parseDate: function(date, format, language){
1486
- if (!date)
1487
- return undefined;
1488
- if (date instanceof Date)
1489
- return date;
1490
- if (typeof format === 'string')
1491
- format = DPGlobal.parseFormat(format);
1492
- var part_re = /([\-+]\d+)([dmwy])/,
1493
- parts = date.match(/([\-+]\d+)([dmwy])/g),
1494
- part, dir, i;
1495
- if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)){
1496
- date = new Date();
1497
- for (i=0; i < parts.length; i++){
1498
- part = part_re.exec(parts[i]);
1499
- dir = parseInt(part[1]);
1500
- switch (part[2]){
1501
- case 'd':
1502
- date.setUTCDate(date.getUTCDate() + dir);
1503
- break;
1504
- case 'm':
1505
- date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
1506
- break;
1507
- case 'w':
1508
- date.setUTCDate(date.getUTCDate() + dir * 7);
1509
- break;
1510
- case 'y':
1511
- date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
1512
- break;
1513
- }
1514
- }
1515
- return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
1516
- }
1517
- parts = date && date.match(this.nonpunctuation) || [];
1518
- date = new Date();
1519
- var parsed = {},
1520
- setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
1521
- setters_map = {
1522
- yyyy: function(d,v){
1523
- return d.setUTCFullYear(v);
1524
- },
1525
- yy: function(d,v){
1526
- return d.setUTCFullYear(2000+v);
1527
- },
1528
- m: function(d,v){
1529
- if (isNaN(d))
1530
- return d;
1531
- v -= 1;
1532
- while (v < 0) v += 12;
1533
- v %= 12;
1534
- d.setUTCMonth(v);
1535
- while (d.getUTCMonth() !== v)
1536
- d.setUTCDate(d.getUTCDate()-1);
1537
- return d;
1538
- },
1539
- d: function(d,v){
1540
- return d.setUTCDate(v);
1541
- }
1542
- },
1543
- val, filtered;
1544
- setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
1545
- setters_map['dd'] = setters_map['d'];
1546
- date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
1547
- var fparts = format.parts.slice();
1548
- // Remove noop parts
1549
- if (parts.length !== fparts.length){
1550
- fparts = $(fparts).filter(function(i,p){
1551
- return $.inArray(p, setters_order) !== -1;
1552
- }).toArray();
1553
- }
1554
- // Process remainder
1555
- function match_part(){
1556
- var m = this.slice(0, parts[i].length),
1557
- p = parts[i].slice(0, m.length);
1558
- return m === p;
1559
- }
1560
- if (parts.length === fparts.length){
1561
- var cnt;
1562
- for (i=0, cnt = fparts.length; i < cnt; i++){
1563
- val = parseInt(parts[i], 10);
1564
- part = fparts[i];
1565
- if (isNaN(val)){
1566
- switch (part){
1567
- case 'MM':
1568
- filtered = $(dates[language].months).filter(match_part);
1569
- val = $.inArray(filtered[0], dates[language].months) + 1;
1570
- break;
1571
- case 'M':
1572
- filtered = $(dates[language].monthsShort).filter(match_part);
1573
- val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
1574
- break;
1575
- }
1576
- }
1577
- parsed[part] = val;
1578
- }
1579
- var _date, s;
1580
- for (i=0; i < setters_order.length; i++){
1581
- s = setters_order[i];
1582
- if (s in parsed && !isNaN(parsed[s])){
1583
- _date = new Date(date);
1584
- setters_map[s](_date, parsed[s]);
1585
- if (!isNaN(_date))
1586
- date = _date;
1587
- }
1588
- }
1589
- }
1590
- return date;
1591
- },
1592
- formatDate: function(date, format, language){
1593
- if (!date)
1594
- return '';
1595
- if (typeof format === 'string')
1596
- format = DPGlobal.parseFormat(format);
1597
- var val = {
1598
- d: date.getUTCDate(),
1599
- D: dates[language].daysShort[date.getUTCDay()],
1600
- DD: dates[language].days[date.getUTCDay()],
1601
- m: date.getUTCMonth() + 1,
1602
- M: dates[language].monthsShort[date.getUTCMonth()],
1603
- MM: dates[language].months[date.getUTCMonth()],
1604
- yy: date.getUTCFullYear().toString().substring(2),
1605
- yyyy: date.getUTCFullYear()
1606
- };
1607
- val.dd = (val.d < 10 ? '0' : '') + val.d;
1608
- val.mm = (val.m < 10 ? '0' : '') + val.m;
1609
- date = [];
1610
- var seps = $.extend([], format.separators);
1611
- for (var i=0, cnt = format.parts.length; i <= cnt; i++){
1612
- if (seps.length)
1613
- date.push(seps.shift());
1614
- date.push(val[format.parts[i]]);
1615
- }
1616
- return date.join('');
1617
- },
1618
- headTemplate: '<thead>'+
1619
- '<tr>'+
1620
- '<th class="prev">&laquo;</th>'+
1621
- '<th colspan="5" class="datepicker-switch"></th>'+
1622
- '<th class="next">&raquo;</th>'+
1623
- '</tr>'+
1624
- '</thead>',
1625
- contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
1626
- footTemplate: '<tfoot>'+
1627
- '<tr>'+
1628
- '<th colspan="7" class="today"></th>'+
1629
- '</tr>'+
1630
- '<tr>'+
1631
- '<th colspan="7" class="clear"></th>'+
1632
- '</tr>'+
1633
- '</tfoot>'
1634
- };
1635
- DPGlobal.template = '<div class="datepicker">'+
1636
- '<div class="datepicker-days">'+
1637
- '<table class=" table-condensed">'+
1638
- DPGlobal.headTemplate+
1639
- '<tbody></tbody>'+
1640
- DPGlobal.footTemplate+
1641
- '</table>'+
1642
- '</div>'+
1643
- '<div class="datepicker-months">'+
1644
- '<table class="table-condensed">'+
1645
- DPGlobal.headTemplate+
1646
- DPGlobal.contTemplate+
1647
- DPGlobal.footTemplate+
1648
- '</table>'+
1649
- '</div>'+
1650
- '<div class="datepicker-years">'+
1651
- '<table class="table-condensed">'+
1652
- DPGlobal.headTemplate+
1653
- DPGlobal.contTemplate+
1654
- DPGlobal.footTemplate+
1655
- '</table>'+
1656
- '</div>'+
1657
- '</div>';
1658
-
1659
- $.fn.datepicker.DPGlobal = DPGlobal;
1660
-
1661
-
1662
- /* DATEPICKER NO CONFLICT
1663
- * =================== */
1664
-
1665
- $.fn.datepicker.noConflict = function(){
1666
- $.fn.datepicker = old;
1667
- return this;
1668
- };
1669
-
1670
-
1671
- /* DATEPICKER DATA-API
1672
- * ================== */
1673
-
1674
- $(document).on(
1675
- 'focus.datepicker.data-api click.datepicker.data-api',
1676
- '[data-provide="datepicker"]',
1677
- function(e){
1678
- var $this = $(this);
1679
- if ($this.data('datepicker'))
1680
- return;
1681
- e.preventDefault();
1682
- // component click requires us to explicitly show it
1683
- $this.datepicker('show');
1684
- }
1685
- );
1686
- $(function(){
1687
- $('[data-provide="datepicker-inline"]').datepicker();
1688
- });
1689
-
1690
- }(window.jQuery));
48
+ if (typeof moment === 'undefined') {
49
+ throw 'bootstrap-datetimepicker requires Moment.js to be loaded first';
50
+ }
51
+ factory(jQuery, moment);
52
+ }
53
+ }(function ($, moment) {
54
+ 'use strict';
55
+ if (!moment) {
56
+ throw new Error('bootstrap-datetimepicker requires Moment.js to be loaded first');
57
+ }
58
+
59
+ var dateTimePicker = function (element, options) {
60
+ var picker = {},
61
+ date,
62
+ viewDate,
63
+ unset = true,
64
+ input,
65
+ component = false,
66
+ widget = false,
67
+ use24Hours,
68
+ minViewModeNumber = 0,
69
+ actualFormat,
70
+ parseFormats,
71
+ currentViewMode,
72
+ datePickerModes = [
73
+ {
74
+ clsName: 'days',
75
+ navFnc: 'M',
76
+ navStep: 1
77
+ },
78
+ {
79
+ clsName: 'months',
80
+ navFnc: 'y',
81
+ navStep: 1
82
+ },
83
+ {
84
+ clsName: 'years',
85
+ navFnc: 'y',
86
+ navStep: 10
87
+ },
88
+ {
89
+ clsName: 'decades',
90
+ navFnc: 'y',
91
+ navStep: 100
92
+ }
93
+ ],
94
+ viewModes = ['days', 'months', 'years', 'decades'],
95
+ verticalModes = ['top', 'bottom', 'auto'],
96
+ horizontalModes = ['left', 'right', 'auto'],
97
+ toolbarPlacements = ['default', 'top', 'bottom'],
98
+ keyMap = {
99
+ 'up': 38,
100
+ 38: 'up',
101
+ 'down': 40,
102
+ 40: 'down',
103
+ 'left': 37,
104
+ 37: 'left',
105
+ 'right': 39,
106
+ 39: 'right',
107
+ 'tab': 9,
108
+ 9: 'tab',
109
+ 'escape': 27,
110
+ 27: 'escape',
111
+ 'enter': 13,
112
+ 13: 'enter',
113
+ 'pageUp': 33,
114
+ 33: 'pageUp',
115
+ 'pageDown': 34,
116
+ 34: 'pageDown',
117
+ 'shift': 16,
118
+ 16: 'shift',
119
+ 'control': 17,
120
+ 17: 'control',
121
+ 'space': 32,
122
+ 32: 'space',
123
+ 't': 84,
124
+ 84: 't',
125
+ 'delete': 46,
126
+ 46: 'delete'
127
+ },
128
+ keyState = {},
129
+
130
+ /********************************************************************************
131
+ *
132
+ * Private functions
133
+ *
134
+ ********************************************************************************/
135
+ getMoment = function (d) {
136
+ var tzEnabled = false,
137
+ returnMoment,
138
+ currentZoneOffset,
139
+ incomingZoneOffset,
140
+ timeZoneIndicator,
141
+ dateWithTimeZoneInfo;
142
+
143
+ if (moment.tz !== undefined && options.timeZone !== undefined && options.timeZone !== null && options.timeZone !== '') {
144
+ tzEnabled = true;
145
+ }
146
+ if (d === undefined || d === null) {
147
+ if (tzEnabled) {
148
+ returnMoment = moment().tz(options.timeZone).startOf('d');
149
+ } else {
150
+ returnMoment = moment().startOf('d');
151
+ }
152
+ } else {
153
+ if (tzEnabled) {
154
+ currentZoneOffset = moment().tz(options.timeZone).utcOffset();
155
+ incomingZoneOffset = moment(d, parseFormats, options.useStrict).utcOffset();
156
+ if (incomingZoneOffset !== currentZoneOffset) {
157
+ timeZoneIndicator = moment().tz(options.timeZone).format('Z');
158
+ dateWithTimeZoneInfo = moment(d, parseFormats, options.useStrict).format('YYYY-MM-DD[T]HH:mm:ss') + timeZoneIndicator;
159
+ returnMoment = moment(dateWithTimeZoneInfo, parseFormats, options.useStrict).tz(options.timeZone);
160
+ } else {
161
+ returnMoment = moment(d, parseFormats, options.useStrict).tz(options.timeZone);
162
+ }
163
+ } else {
164
+ returnMoment = moment(d, parseFormats, options.useStrict);
165
+ }
166
+ }
167
+ return returnMoment;
168
+ },
169
+ isEnabled = function (granularity) {
170
+ if (typeof granularity !== 'string' || granularity.length > 1) {
171
+ throw new TypeError('isEnabled expects a single character string parameter');
172
+ }
173
+ switch (granularity) {
174
+ case 'y':
175
+ return actualFormat.indexOf('Y') !== -1;
176
+ case 'M':
177
+ return actualFormat.indexOf('M') !== -1;
178
+ case 'd':
179
+ return actualFormat.toLowerCase().indexOf('d') !== -1;
180
+ case 'h':
181
+ case 'H':
182
+ return actualFormat.toLowerCase().indexOf('h') !== -1;
183
+ case 'm':
184
+ return actualFormat.indexOf('m') !== -1;
185
+ case 's':
186
+ return actualFormat.indexOf('s') !== -1;
187
+ default:
188
+ return false;
189
+ }
190
+ },
191
+ hasTime = function () {
192
+ return (isEnabled('h') || isEnabled('m') || isEnabled('s'));
193
+ },
194
+
195
+ hasDate = function () {
196
+ return (isEnabled('y') || isEnabled('M') || isEnabled('d'));
197
+ },
198
+
199
+ getDatePickerTemplate = function () {
200
+ var headTemplate = $('<thead>')
201
+ .append($('<tr>')
202
+ .append($('<th>').addClass('prev').attr('data-action', 'previous')
203
+ .append($('<span>').addClass(options.icons.previous))
204
+ )
205
+ .append($('<th>').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5')))
206
+ .append($('<th>').addClass('next').attr('data-action', 'next')
207
+ .append($('<span>').addClass(options.icons.next))
208
+ )
209
+ ),
210
+ contTemplate = $('<tbody>')
211
+ .append($('<tr>')
212
+ .append($('<td>').attr('colspan', (options.calendarWeeks ? '8' : '7')))
213
+ );
214
+
215
+ return [
216
+ $('<div>').addClass('datepicker-days')
217
+ .append($('<table>').addClass('table-condensed')
218
+ .append(headTemplate)
219
+ .append($('<tbody>'))
220
+ ),
221
+ $('<div>').addClass('datepicker-months')
222
+ .append($('<table>').addClass('table-condensed')
223
+ .append(headTemplate.clone())
224
+ .append(contTemplate.clone())
225
+ ),
226
+ $('<div>').addClass('datepicker-years')
227
+ .append($('<table>').addClass('table-condensed')
228
+ .append(headTemplate.clone())
229
+ .append(contTemplate.clone())
230
+ ),
231
+ $('<div>').addClass('datepicker-decades')
232
+ .append($('<table>').addClass('table-condensed')
233
+ .append(headTemplate.clone())
234
+ .append(contTemplate.clone())
235
+ )
236
+ ];
237
+ },
238
+
239
+ getTimePickerMainTemplate = function () {
240
+ var topRow = $('<tr>'),
241
+ middleRow = $('<tr>'),
242
+ bottomRow = $('<tr>');
243
+
244
+ if (isEnabled('h')) {
245
+ topRow.append($('<td>')
246
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementHour}).addClass('btn').attr('data-action', 'incrementHours')
247
+ .append($('<span>').addClass(options.icons.up))));
248
+ middleRow.append($('<td>')
249
+ .append($('<span>').addClass('timepicker-hour').attr({'data-time-component':'hours', 'title': options.tooltips.pickHour}).attr('data-action', 'showHours')));
250
+ bottomRow.append($('<td>')
251
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementHour}).addClass('btn').attr('data-action', 'decrementHours')
252
+ .append($('<span>').addClass(options.icons.down))));
253
+ }
254
+ if (isEnabled('m')) {
255
+ if (isEnabled('h')) {
256
+ topRow.append($('<td>').addClass('separator'));
257
+ middleRow.append($('<td>').addClass('separator').html(':'));
258
+ bottomRow.append($('<td>').addClass('separator'));
259
+ }
260
+ topRow.append($('<td>')
261
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementMinute}).addClass('btn').attr('data-action', 'incrementMinutes')
262
+ .append($('<span>').addClass(options.icons.up))));
263
+ middleRow.append($('<td>')
264
+ .append($('<span>').addClass('timepicker-minute').attr({'data-time-component': 'minutes', 'title': options.tooltips.pickMinute}).attr('data-action', 'showMinutes')));
265
+ bottomRow.append($('<td>')
266
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementMinute}).addClass('btn').attr('data-action', 'decrementMinutes')
267
+ .append($('<span>').addClass(options.icons.down))));
268
+ }
269
+ if (isEnabled('s')) {
270
+ if (isEnabled('m')) {
271
+ topRow.append($('<td>').addClass('separator'));
272
+ middleRow.append($('<td>').addClass('separator').html(':'));
273
+ bottomRow.append($('<td>').addClass('separator'));
274
+ }
275
+ topRow.append($('<td>')
276
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementSecond}).addClass('btn').attr('data-action', 'incrementSeconds')
277
+ .append($('<span>').addClass(options.icons.up))));
278
+ middleRow.append($('<td>')
279
+ .append($('<span>').addClass('timepicker-second').attr({'data-time-component': 'seconds', 'title': options.tooltips.pickSecond}).attr('data-action', 'showSeconds')));
280
+ bottomRow.append($('<td>')
281
+ .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementSecond}).addClass('btn').attr('data-action', 'decrementSeconds')
282
+ .append($('<span>').addClass(options.icons.down))));
283
+ }
284
+
285
+ if (!use24Hours) {
286
+ topRow.append($('<td>').addClass('separator'));
287
+ middleRow.append($('<td>')
288
+ .append($('<button>').addClass('btn btn-primary').attr({'data-action': 'togglePeriod', tabindex: '-1', 'title': options.tooltips.togglePeriod})));
289
+ bottomRow.append($('<td>').addClass('separator'));
290
+ }
291
+
292
+ return $('<div>').addClass('timepicker-picker')
293
+ .append($('<table>').addClass('table-condensed')
294
+ .append([topRow, middleRow, bottomRow]));
295
+ },
296
+
297
+ getTimePickerTemplate = function () {
298
+ var hoursView = $('<div>').addClass('timepicker-hours')
299
+ .append($('<table>').addClass('table-condensed')),
300
+ minutesView = $('<div>').addClass('timepicker-minutes')
301
+ .append($('<table>').addClass('table-condensed')),
302
+ secondsView = $('<div>').addClass('timepicker-seconds')
303
+ .append($('<table>').addClass('table-condensed')),
304
+ ret = [getTimePickerMainTemplate()];
305
+
306
+ if (isEnabled('h')) {
307
+ ret.push(hoursView);
308
+ }
309
+ if (isEnabled('m')) {
310
+ ret.push(minutesView);
311
+ }
312
+ if (isEnabled('s')) {
313
+ ret.push(secondsView);
314
+ }
315
+
316
+ return ret;
317
+ },
318
+
319
+ getToolbar = function () {
320
+ var row = [];
321
+ if (options.showTodayButton) {
322
+ row.push($('<td>').append($('<a>').attr({'data-action':'today', 'title': options.tooltips.today}).append($('<span>').addClass(options.icons.today))));
323
+ }
324
+ if (!options.sideBySide && hasDate() && hasTime()) {
325
+ row.push($('<td>').append($('<a>').attr({'data-action':'togglePicker', 'title': options.tooltips.selectTime}).append($('<span>').addClass(options.icons.time))));
326
+ }
327
+ if (options.showClear) {
328
+ row.push($('<td>').append($('<a>').attr({'data-action':'clear', 'title': options.tooltips.clear}).append($('<span>').addClass(options.icons.clear))));
329
+ }
330
+ if (options.showClose) {
331
+ row.push($('<td>').append($('<a>').attr({'data-action':'close', 'title': options.tooltips.close}).append($('<span>').addClass(options.icons.close))));
332
+ }
333
+ return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row)));
334
+ },
335
+
336
+ getTemplate = function () {
337
+ var template = $('<div>').addClass('bootstrap-datetimepicker-widget dropdown-menu'),
338
+ dateView = $('<div>').addClass('datepicker').append(getDatePickerTemplate()),
339
+ timeView = $('<div>').addClass('timepicker').append(getTimePickerTemplate()),
340
+ content = $('<ul>').addClass('list-unstyled'),
341
+ toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar());
342
+
343
+ if (options.inline) {
344
+ template.removeClass('dropdown-menu');
345
+ }
346
+
347
+ if (use24Hours) {
348
+ template.addClass('usetwentyfour');
349
+ }
350
+ if (isEnabled('s') && !use24Hours) {
351
+ template.addClass('wider');
352
+ }
353
+
354
+ if (options.sideBySide && hasDate() && hasTime()) {
355
+ template.addClass('timepicker-sbs');
356
+ if (options.toolbarPlacement === 'top') {
357
+ template.append(toolbar);
358
+ }
359
+ template.append(
360
+ $('<div>').addClass('row')
361
+ .append(dateView.addClass('col-md-6'))
362
+ .append(timeView.addClass('col-md-6'))
363
+ );
364
+ if (options.toolbarPlacement === 'bottom') {
365
+ template.append(toolbar);
366
+ }
367
+ return template;
368
+ }
369
+
370
+ if (options.toolbarPlacement === 'top') {
371
+ content.append(toolbar);
372
+ }
373
+ if (hasDate()) {
374
+ content.append($('<li>').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView));
375
+ }
376
+ if (options.toolbarPlacement === 'default') {
377
+ content.append(toolbar);
378
+ }
379
+ if (hasTime()) {
380
+ content.append($('<li>').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView));
381
+ }
382
+ if (options.toolbarPlacement === 'bottom') {
383
+ content.append(toolbar);
384
+ }
385
+ return template.append(content);
386
+ },
387
+
388
+ dataToOptions = function () {
389
+ var eData,
390
+ dataOptions = {};
391
+
392
+ if (element.is('input') || options.inline) {
393
+ eData = element.data();
394
+ } else {
395
+ eData = element.find('input').data();
396
+ }
397
+
398
+ if (eData.dateOptions && eData.dateOptions instanceof Object) {
399
+ dataOptions = $.extend(true, dataOptions, eData.dateOptions);
400
+ }
401
+
402
+ $.each(options, function (key) {
403
+ var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1);
404
+ if (eData[attributeName] !== undefined) {
405
+ dataOptions[key] = eData[attributeName];
406
+ }
407
+ });
408
+ return dataOptions;
409
+ },
410
+
411
+ place = function () {
412
+ var position = (component || element).position(),
413
+ offset = (component || element).offset(),
414
+ vertical = options.widgetPositioning.vertical,
415
+ horizontal = options.widgetPositioning.horizontal,
416
+ parent;
417
+
418
+ if (options.widgetParent) {
419
+ parent = options.widgetParent.append(widget);
420
+ } else if (element.is('input')) {
421
+ parent = element.after(widget).parent();
422
+ } else if (options.inline) {
423
+ parent = element.append(widget);
424
+ return;
425
+ } else {
426
+ parent = element;
427
+ element.children().first().after(widget);
428
+ }
429
+
430
+ // Top and bottom logic
431
+ if (vertical === 'auto') {
432
+ if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() &&
433
+ widget.height() + element.outerHeight() < offset.top) {
434
+ vertical = 'top';
435
+ } else {
436
+ vertical = 'bottom';
437
+ }
438
+ }
439
+
440
+ // Left and right logic
441
+ if (horizontal === 'auto') {
442
+ if (parent.width() < offset.left + widget.outerWidth() / 2 &&
443
+ offset.left + widget.outerWidth() > $(window).width()) {
444
+ horizontal = 'right';
445
+ } else {
446
+ horizontal = 'left';
447
+ }
448
+ }
449
+
450
+ if (vertical === 'top') {
451
+ widget.addClass('top').removeClass('bottom');
452
+ } else {
453
+ widget.addClass('bottom').removeClass('top');
454
+ }
455
+
456
+ if (horizontal === 'right') {
457
+ widget.addClass('pull-right');
458
+ } else {
459
+ widget.removeClass('pull-right');
460
+ }
461
+
462
+ // find the first parent element that has a relative css positioning
463
+ if (parent.css('position') !== 'relative') {
464
+ parent = parent.parents().filter(function () {
465
+ return $(this).css('position') === 'relative';
466
+ }).first();
467
+ }
468
+
469
+ if (parent.length === 0) {
470
+ throw new Error('datetimepicker component should be placed within a relative positioned container');
471
+ }
472
+
473
+ widget.css({
474
+ top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(),
475
+ bottom: vertical === 'top' ? position.top + element.outerHeight() : 'auto',
476
+ left: horizontal === 'left' ? (parent === element ? 0 : position.left) : 'auto',
477
+ right: horizontal === 'left' ? 'auto' : parent.outerWidth() - element.outerWidth() - (parent === element ? 0 : position.left)
478
+ });
479
+ },
480
+
481
+ notifyEvent = function (e) {
482
+ if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) {
483
+ return;
484
+ }
485
+ element.trigger(e);
486
+ },
487
+
488
+ viewUpdate = function (e) {
489
+ if (e === 'y') {
490
+ e = 'YYYY';
491
+ }
492
+ notifyEvent({
493
+ type: 'dp.update',
494
+ change: e,
495
+ viewDate: viewDate.clone()
496
+ });
497
+ },
498
+
499
+ showMode = function (dir) {
500
+ if (!widget) {
501
+ return;
502
+ }
503
+ if (dir) {
504
+ currentViewMode = Math.max(minViewModeNumber, Math.min(3, currentViewMode + dir));
505
+ }
506
+ widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show();
507
+ },
508
+
509
+ fillDow = function () {
510
+ var row = $('<tr>'),
511
+ currentDate = viewDate.clone().startOf('w').startOf('d');
512
+
513
+ if (options.calendarWeeks === true) {
514
+ row.append($('<th>').addClass('cw').text('#'));
515
+ }
516
+
517
+ while (currentDate.isBefore(viewDate.clone().endOf('w'))) {
518
+ row.append($('<th>').addClass('dow').text(currentDate.format('dd')));
519
+ currentDate.add(1, 'd');
520
+ }
521
+ widget.find('.datepicker-days thead').append(row);
522
+ },
523
+
524
+ isInDisabledDates = function (testDate) {
525
+ return options.disabledDates[testDate.format('YYYY-MM-DD')] === true;
526
+ },
527
+
528
+ isInEnabledDates = function (testDate) {
529
+ return options.enabledDates[testDate.format('YYYY-MM-DD')] === true;
530
+ },
531
+
532
+ isInDisabledHours = function (testDate) {
533
+ return options.disabledHours[testDate.format('H')] === true;
534
+ },
535
+
536
+ isInEnabledHours = function (testDate) {
537
+ return options.enabledHours[testDate.format('H')] === true;
538
+ },
539
+
540
+ isValid = function (targetMoment, granularity) {
541
+ if (!targetMoment.isValid()) {
542
+ return false;
543
+ }
544
+ if (options.disabledDates && granularity === 'd' && isInDisabledDates(targetMoment)) {
545
+ return false;
546
+ }
547
+ if (options.enabledDates && granularity === 'd' && !isInEnabledDates(targetMoment)) {
548
+ return false;
549
+ }
550
+ if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) {
551
+ return false;
552
+ }
553
+ if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) {
554
+ return false;
555
+ }
556
+ if (options.daysOfWeekDisabled && granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
557
+ return false;
558
+ }
559
+ if (options.disabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && isInDisabledHours(targetMoment)) {
560
+ return false;
561
+ }
562
+ if (options.enabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && !isInEnabledHours(targetMoment)) {
563
+ return false;
564
+ }
565
+ if (options.disabledTimeIntervals && (granularity === 'h' || granularity === 'm' || granularity === 's')) {
566
+ var found = false;
567
+ $.each(options.disabledTimeIntervals, function () {
568
+ if (targetMoment.isBetween(this[0], this[1])) {
569
+ found = true;
570
+ return false;
571
+ }
572
+ });
573
+ if (found) {
574
+ return false;
575
+ }
576
+ }
577
+ return true;
578
+ },
579
+
580
+ fillMonths = function () {
581
+ var spans = [],
582
+ monthsShort = viewDate.clone().startOf('y').startOf('d');
583
+ while (monthsShort.isSame(viewDate, 'y')) {
584
+ spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM')));
585
+ monthsShort.add(1, 'M');
586
+ }
587
+ widget.find('.datepicker-months td').empty().append(spans);
588
+ },
589
+
590
+ updateMonths = function () {
591
+ var monthsView = widget.find('.datepicker-months'),
592
+ monthsViewHeader = monthsView.find('th'),
593
+ months = monthsView.find('tbody').find('span');
594
+
595
+ monthsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevYear);
596
+ monthsViewHeader.eq(1).attr('title', options.tooltips.selectYear);
597
+ monthsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextYear);
598
+
599
+ monthsView.find('.disabled').removeClass('disabled');
600
+
601
+ if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) {
602
+ monthsViewHeader.eq(0).addClass('disabled');
603
+ }
604
+
605
+ monthsViewHeader.eq(1).text(viewDate.year());
606
+
607
+ if (!isValid(viewDate.clone().add(1, 'y'), 'y')) {
608
+ monthsViewHeader.eq(2).addClass('disabled');
609
+ }
610
+
611
+ months.removeClass('active');
612
+ if (date.isSame(viewDate, 'y') && !unset) {
613
+ months.eq(date.month()).addClass('active');
614
+ }
615
+
616
+ months.each(function (index) {
617
+ if (!isValid(viewDate.clone().month(index), 'M')) {
618
+ $(this).addClass('disabled');
619
+ }
620
+ });
621
+ },
622
+
623
+ updateYears = function () {
624
+ var yearsView = widget.find('.datepicker-years'),
625
+ yearsViewHeader = yearsView.find('th'),
626
+ startYear = viewDate.clone().subtract(5, 'y'),
627
+ endYear = viewDate.clone().add(6, 'y'),
628
+ html = '';
629
+
630
+ yearsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevDecade);
631
+ yearsViewHeader.eq(1).attr('title', options.tooltips.selectDecade);
632
+ yearsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextDecade);
633
+
634
+ yearsView.find('.disabled').removeClass('disabled');
635
+
636
+ if (options.minDate && options.minDate.isAfter(startYear, 'y')) {
637
+ yearsViewHeader.eq(0).addClass('disabled');
638
+ }
639
+
640
+ yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year());
641
+
642
+ if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) {
643
+ yearsViewHeader.eq(2).addClass('disabled');
644
+ }
645
+
646
+ while (!startYear.isAfter(endYear, 'y')) {
647
+ html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') && !unset ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>';
648
+ startYear.add(1, 'y');
649
+ }
650
+
651
+ yearsView.find('td').html(html);
652
+ },
653
+
654
+ updateDecades = function () {
655
+ var decadesView = widget.find('.datepicker-decades'),
656
+ decadesViewHeader = decadesView.find('th'),
657
+ startDecade = moment({y: viewDate.year() - (viewDate.year() % 100) - 1}),
658
+ endDecade = startDecade.clone().add(100, 'y'),
659
+ startedAt = startDecade.clone(),
660
+ html = '';
661
+
662
+ decadesViewHeader.eq(0).find('span').attr('title', options.tooltips.prevCentury);
663
+ decadesViewHeader.eq(2).find('span').attr('title', options.tooltips.nextCentury);
664
+
665
+ decadesView.find('.disabled').removeClass('disabled');
666
+
667
+ if (startDecade.isSame(moment({y: 1900})) || (options.minDate && options.minDate.isAfter(startDecade, 'y'))) {
668
+ decadesViewHeader.eq(0).addClass('disabled');
669
+ }
670
+
671
+ decadesViewHeader.eq(1).text(startDecade.year() + '-' + endDecade.year());
672
+
673
+ if (startDecade.isSame(moment({y: 2000})) || (options.maxDate && options.maxDate.isBefore(endDecade, 'y'))) {
674
+ decadesViewHeader.eq(2).addClass('disabled');
675
+ }
676
+
677
+ while (!startDecade.isAfter(endDecade, 'y')) {
678
+ html += '<span data-action="selectDecade" class="decade' + (startDecade.isSame(date, 'y') ? ' active' : '') +
679
+ (!isValid(startDecade, 'y') ? ' disabled' : '') + '" data-selection="' + (startDecade.year() + 6) + '">' + (startDecade.year() + 1) + ' - ' + (startDecade.year() + 12) + '</span>';
680
+ startDecade.add(12, 'y');
681
+ }
682
+ html += '<span></span><span></span><span></span>'; //push the dangling block over, at least this way it's even
683
+
684
+ decadesView.find('td').html(html);
685
+ decadesViewHeader.eq(1).text((startedAt.year() + 1) + '-' + (startDecade.year()));
686
+ },
687
+
688
+ fillDate = function () {
689
+ var daysView = widget.find('.datepicker-days'),
690
+ daysViewHeader = daysView.find('th'),
691
+ currentDate,
692
+ html = [],
693
+ row,
694
+ clsName,
695
+ i;
696
+
697
+ if (!hasDate()) {
698
+ return;
699
+ }
700
+
701
+ daysViewHeader.eq(0).find('span').attr('title', options.tooltips.prevMonth);
702
+ daysViewHeader.eq(1).attr('title', options.tooltips.selectMonth);
703
+ daysViewHeader.eq(2).find('span').attr('title', options.tooltips.nextMonth);
704
+
705
+ daysView.find('.disabled').removeClass('disabled');
706
+ daysViewHeader.eq(1).text(viewDate.format(options.dayViewHeaderFormat));
707
+
708
+ if (!isValid(viewDate.clone().subtract(1, 'M'), 'M')) {
709
+ daysViewHeader.eq(0).addClass('disabled');
710
+ }
711
+ if (!isValid(viewDate.clone().add(1, 'M'), 'M')) {
712
+ daysViewHeader.eq(2).addClass('disabled');
713
+ }
714
+
715
+ currentDate = viewDate.clone().startOf('M').startOf('w').startOf('d');
716
+
717
+ for (i = 0; i < 42; i++) { //always display 42 days (should show 6 weeks)
718
+ if (currentDate.weekday() === 0) {
719
+ row = $('<tr>');
720
+ if (options.calendarWeeks) {
721
+ row.append('<td class="cw">' + currentDate.week() + '</td>');
722
+ }
723
+ html.push(row);
724
+ }
725
+ clsName = '';
726
+ if (currentDate.isBefore(viewDate, 'M')) {
727
+ clsName += ' old';
728
+ }
729
+ if (currentDate.isAfter(viewDate, 'M')) {
730
+ clsName += ' new';
731
+ }
732
+ if (currentDate.isSame(date, 'd') && !unset) {
733
+ clsName += ' active';
734
+ }
735
+ if (!isValid(currentDate, 'd')) {
736
+ clsName += ' disabled';
737
+ }
738
+ if (currentDate.isSame(getMoment(), 'd')) {
739
+ clsName += ' today';
740
+ }
741
+ if (currentDate.day() === 0 || currentDate.day() === 6) {
742
+ clsName += ' weekend';
743
+ }
744
+ row.append('<td data-action="selectDay" data-day="' + currentDate.format('L') + '" class="day' + clsName + '">' + currentDate.date() + '</td>');
745
+ currentDate.add(1, 'd');
746
+ }
747
+
748
+ daysView.find('tbody').empty().append(html);
749
+
750
+ updateMonths();
751
+
752
+ updateYears();
753
+
754
+ updateDecades();
755
+ },
756
+
757
+ fillHours = function () {
758
+ var table = widget.find('.timepicker-hours table'),
759
+ currentHour = viewDate.clone().startOf('d'),
760
+ html = [],
761
+ row = $('<tr>');
762
+
763
+ if (viewDate.hour() > 11 && !use24Hours) {
764
+ currentHour.hour(12);
765
+ }
766
+ while (currentHour.isSame(viewDate, 'd') && (use24Hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) {
767
+ if (currentHour.hour() % 4 === 0) {
768
+ row = $('<tr>');
769
+ html.push(row);
770
+ }
771
+ row.append('<td data-action="selectHour" class="hour' + (!isValid(currentHour, 'h') ? ' disabled' : '') + '">' + currentHour.format(use24Hours ? 'HH' : 'hh') + '</td>');
772
+ currentHour.add(1, 'h');
773
+ }
774
+ table.empty().append(html);
775
+ },
776
+
777
+ fillMinutes = function () {
778
+ var table = widget.find('.timepicker-minutes table'),
779
+ currentMinute = viewDate.clone().startOf('h'),
780
+ html = [],
781
+ row = $('<tr>'),
782
+ step = options.stepping === 1 ? 5 : options.stepping;
783
+
784
+ while (viewDate.isSame(currentMinute, 'h')) {
785
+ if (currentMinute.minute() % (step * 4) === 0) {
786
+ row = $('<tr>');
787
+ html.push(row);
788
+ }
789
+ row.append('<td data-action="selectMinute" class="minute' + (!isValid(currentMinute, 'm') ? ' disabled' : '') + '">' + currentMinute.format('mm') + '</td>');
790
+ currentMinute.add(step, 'm');
791
+ }
792
+ table.empty().append(html);
793
+ },
794
+
795
+ fillSeconds = function () {
796
+ var table = widget.find('.timepicker-seconds table'),
797
+ currentSecond = viewDate.clone().startOf('m'),
798
+ html = [],
799
+ row = $('<tr>');
800
+
801
+ while (viewDate.isSame(currentSecond, 'm')) {
802
+ if (currentSecond.second() % 20 === 0) {
803
+ row = $('<tr>');
804
+ html.push(row);
805
+ }
806
+ row.append('<td data-action="selectSecond" class="second' + (!isValid(currentSecond, 's') ? ' disabled' : '') + '">' + currentSecond.format('ss') + '</td>');
807
+ currentSecond.add(5, 's');
808
+ }
809
+
810
+ table.empty().append(html);
811
+ },
812
+
813
+ fillTime = function () {
814
+ var toggle, newDate, timeComponents = widget.find('.timepicker span[data-time-component]');
815
+
816
+ if (!use24Hours) {
817
+ toggle = widget.find('.timepicker [data-action=togglePeriod]');
818
+ newDate = date.clone().add((date.hours() >= 12) ? -12 : 12, 'h');
819
+
820
+ toggle.text(date.format('A'));
821
+
822
+ if (isValid(newDate, 'h')) {
823
+ toggle.removeClass('disabled');
824
+ } else {
825
+ toggle.addClass('disabled');
826
+ }
827
+ }
828
+ timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh'));
829
+ timeComponents.filter('[data-time-component=minutes]').text(date.format('mm'));
830
+ timeComponents.filter('[data-time-component=seconds]').text(date.format('ss'));
831
+
832
+ fillHours();
833
+ fillMinutes();
834
+ fillSeconds();
835
+ },
836
+
837
+ update = function () {
838
+ if (!widget) {
839
+ return;
840
+ }
841
+ fillDate();
842
+ fillTime();
843
+ },
844
+
845
+ setValue = function (targetMoment) {
846
+ var oldDate = unset ? null : date;
847
+
848
+ // case of calling setValue(null or false)
849
+ if (!targetMoment) {
850
+ unset = true;
851
+ input.val('');
852
+ element.data('date', '');
853
+ notifyEvent({
854
+ type: 'dp.change',
855
+ date: false,
856
+ oldDate: oldDate
857
+ });
858
+ update();
859
+ return;
860
+ }
861
+
862
+ targetMoment = targetMoment.clone().locale(options.locale);
863
+
864
+ if (options.stepping !== 1) {
865
+ targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0);
866
+ }
867
+
868
+ if (isValid(targetMoment)) {
869
+ date = targetMoment;
870
+ viewDate = date.clone();
871
+ input.val(date.format(actualFormat));
872
+ element.data('date', date.format(actualFormat));
873
+ unset = false;
874
+ update();
875
+ notifyEvent({
876
+ type: 'dp.change',
877
+ date: date.clone(),
878
+ oldDate: oldDate
879
+ });
880
+ } else {
881
+ if (!options.keepInvalid) {
882
+ input.val(unset ? '' : date.format(actualFormat));
883
+ }
884
+ notifyEvent({
885
+ type: 'dp.error',
886
+ date: targetMoment
887
+ });
888
+ }
889
+ },
890
+
891
+ hide = function () {
892
+ ///<summary>Hides the widget. Possibly will emit dp.hide</summary>
893
+ var transitioning = false;
894
+ if (!widget) {
895
+ return picker;
896
+ }
897
+ // Ignore event if in the middle of a picker transition
898
+ widget.find('.collapse').each(function () {
899
+ var collapseData = $(this).data('collapse');
900
+ if (collapseData && collapseData.transitioning) {
901
+ transitioning = true;
902
+ return false;
903
+ }
904
+ return true;
905
+ });
906
+ if (transitioning) {
907
+ return picker;
908
+ }
909
+ if (component && component.hasClass('btn')) {
910
+ component.toggleClass('active');
911
+ }
912
+ widget.hide();
913
+
914
+ $(window).off('resize', place);
915
+ widget.off('click', '[data-action]');
916
+ widget.off('mousedown', false);
917
+
918
+ widget.remove();
919
+ widget = false;
920
+
921
+ notifyEvent({
922
+ type: 'dp.hide',
923
+ date: date.clone()
924
+ });
925
+
926
+ input.blur();
927
+
928
+ return picker;
929
+ },
930
+
931
+ clear = function () {
932
+ setValue(null);
933
+ },
934
+
935
+ /********************************************************************************
936
+ *
937
+ * Widget UI interaction functions
938
+ *
939
+ ********************************************************************************/
940
+ actions = {
941
+ next: function () {
942
+ var navFnc = datePickerModes[currentViewMode].navFnc;
943
+ viewDate.add(datePickerModes[currentViewMode].navStep, navFnc);
944
+ fillDate();
945
+ viewUpdate(navFnc);
946
+ },
947
+
948
+ previous: function () {
949
+ var navFnc = datePickerModes[currentViewMode].navFnc;
950
+ viewDate.subtract(datePickerModes[currentViewMode].navStep, navFnc);
951
+ fillDate();
952
+ viewUpdate(navFnc);
953
+ },
954
+
955
+ pickerSwitch: function () {
956
+ showMode(1);
957
+ },
958
+
959
+ selectMonth: function (e) {
960
+ var month = $(e.target).closest('tbody').find('span').index($(e.target));
961
+ viewDate.month(month);
962
+ if (currentViewMode === minViewModeNumber) {
963
+ setValue(date.clone().year(viewDate.year()).month(viewDate.month()));
964
+ if (!options.inline) {
965
+ hide();
966
+ }
967
+ } else {
968
+ showMode(-1);
969
+ fillDate();
970
+ }
971
+ viewUpdate('M');
972
+ },
973
+
974
+ selectYear: function (e) {
975
+ var year = parseInt($(e.target).text(), 10) || 0;
976
+ viewDate.year(year);
977
+ if (currentViewMode === minViewModeNumber) {
978
+ setValue(date.clone().year(viewDate.year()));
979
+ if (!options.inline) {
980
+ hide();
981
+ }
982
+ } else {
983
+ showMode(-1);
984
+ fillDate();
985
+ }
986
+ viewUpdate('YYYY');
987
+ },
988
+
989
+ selectDecade: function (e) {
990
+ var year = parseInt($(e.target).data('selection'), 10) || 0;
991
+ viewDate.year(year);
992
+ if (currentViewMode === minViewModeNumber) {
993
+ setValue(date.clone().year(viewDate.year()));
994
+ if (!options.inline) {
995
+ hide();
996
+ }
997
+ } else {
998
+ showMode(-1);
999
+ fillDate();
1000
+ }
1001
+ viewUpdate('YYYY');
1002
+ },
1003
+
1004
+ selectDay: function (e) {
1005
+ var day = viewDate.clone();
1006
+ if ($(e.target).is('.old')) {
1007
+ day.subtract(1, 'M');
1008
+ }
1009
+ if ($(e.target).is('.new')) {
1010
+ day.add(1, 'M');
1011
+ }
1012
+ setValue(day.date(parseInt($(e.target).text(), 10)));
1013
+ if (!hasTime() && !options.keepOpen && !options.inline) {
1014
+ hide();
1015
+ }
1016
+ },
1017
+
1018
+ incrementHours: function () {
1019
+ var newDate = date.clone().add(1, 'h');
1020
+ if (isValid(newDate, 'h')) {
1021
+ setValue(newDate);
1022
+ }
1023
+ },
1024
+
1025
+ incrementMinutes: function () {
1026
+ var newDate = date.clone().add(options.stepping, 'm');
1027
+ if (isValid(newDate, 'm')) {
1028
+ setValue(newDate);
1029
+ }
1030
+ },
1031
+
1032
+ incrementSeconds: function () {
1033
+ var newDate = date.clone().add(1, 's');
1034
+ if (isValid(newDate, 's')) {
1035
+ setValue(newDate);
1036
+ }
1037
+ },
1038
+
1039
+ decrementHours: function () {
1040
+ var newDate = date.clone().subtract(1, 'h');
1041
+ if (isValid(newDate, 'h')) {
1042
+ setValue(newDate);
1043
+ }
1044
+ },
1045
+
1046
+ decrementMinutes: function () {
1047
+ var newDate = date.clone().subtract(options.stepping, 'm');
1048
+ if (isValid(newDate, 'm')) {
1049
+ setValue(newDate);
1050
+ }
1051
+ },
1052
+
1053
+ decrementSeconds: function () {
1054
+ var newDate = date.clone().subtract(1, 's');
1055
+ if (isValid(newDate, 's')) {
1056
+ setValue(newDate);
1057
+ }
1058
+ },
1059
+
1060
+ togglePeriod: function () {
1061
+ setValue(date.clone().add((date.hours() >= 12) ? -12 : 12, 'h'));
1062
+ },
1063
+
1064
+ togglePicker: function (e) {
1065
+ var $this = $(e.target),
1066
+ $parent = $this.closest('ul'),
1067
+ expanded = $parent.find('.in'),
1068
+ closed = $parent.find('.collapse:not(.in)'),
1069
+ collapseData;
1070
+
1071
+ if (expanded && expanded.length) {
1072
+ collapseData = expanded.data('collapse');
1073
+ if (collapseData && collapseData.transitioning) {
1074
+ return;
1075
+ }
1076
+ if (expanded.collapse) { // if collapse plugin is available through bootstrap.js then use it
1077
+ expanded.collapse('hide');
1078
+ closed.collapse('show');
1079
+ } else { // otherwise just toggle in class on the two views
1080
+ expanded.removeClass('in');
1081
+ closed.addClass('in');
1082
+ }
1083
+ if ($this.is('span')) {
1084
+ $this.toggleClass(options.icons.time + ' ' + options.icons.date);
1085
+ } else {
1086
+ $this.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
1087
+ }
1088
+
1089
+ // NOTE: uncomment if toggled state will be restored in show()
1090
+ //if (component) {
1091
+ // component.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
1092
+ //}
1093
+ }
1094
+ },
1095
+
1096
+ showPicker: function () {
1097
+ widget.find('.timepicker > div:not(.timepicker-picker)').hide();
1098
+ widget.find('.timepicker .timepicker-picker').show();
1099
+ },
1100
+
1101
+ showHours: function () {
1102
+ widget.find('.timepicker .timepicker-picker').hide();
1103
+ widget.find('.timepicker .timepicker-hours').show();
1104
+ },
1105
+
1106
+ showMinutes: function () {
1107
+ widget.find('.timepicker .timepicker-picker').hide();
1108
+ widget.find('.timepicker .timepicker-minutes').show();
1109
+ },
1110
+
1111
+ showSeconds: function () {
1112
+ widget.find('.timepicker .timepicker-picker').hide();
1113
+ widget.find('.timepicker .timepicker-seconds').show();
1114
+ },
1115
+
1116
+ selectHour: function (e) {
1117
+ var hour = parseInt($(e.target).text(), 10);
1118
+
1119
+ if (!use24Hours) {
1120
+ if (date.hours() >= 12) {
1121
+ if (hour !== 12) {
1122
+ hour += 12;
1123
+ }
1124
+ } else {
1125
+ if (hour === 12) {
1126
+ hour = 0;
1127
+ }
1128
+ }
1129
+ }
1130
+ setValue(date.clone().hours(hour));
1131
+ actions.showPicker.call(picker);
1132
+ },
1133
+
1134
+ selectMinute: function (e) {
1135
+ setValue(date.clone().minutes(parseInt($(e.target).text(), 10)));
1136
+ actions.showPicker.call(picker);
1137
+ },
1138
+
1139
+ selectSecond: function (e) {
1140
+ setValue(date.clone().seconds(parseInt($(e.target).text(), 10)));
1141
+ actions.showPicker.call(picker);
1142
+ },
1143
+
1144
+ clear: clear,
1145
+
1146
+ today: function () {
1147
+ var todaysDate = getMoment();
1148
+ if (isValid(todaysDate, 'd')) {
1149
+ setValue(todaysDate);
1150
+ }
1151
+ },
1152
+
1153
+ close: hide
1154
+ },
1155
+
1156
+ doAction = function (e) {
1157
+ if ($(e.currentTarget).is('.disabled')) {
1158
+ return false;
1159
+ }
1160
+ actions[$(e.currentTarget).data('action')].apply(picker, arguments);
1161
+ return false;
1162
+ },
1163
+
1164
+ show = function () {
1165
+ ///<summary>Shows the widget. Possibly will emit dp.show and dp.change</summary>
1166
+ var currentMoment,
1167
+ useCurrentGranularity = {
1168
+ 'year': function (m) {
1169
+ return m.month(0).date(1).hours(0).seconds(0).minutes(0);
1170
+ },
1171
+ 'month': function (m) {
1172
+ return m.date(1).hours(0).seconds(0).minutes(0);
1173
+ },
1174
+ 'day': function (m) {
1175
+ return m.hours(0).seconds(0).minutes(0);
1176
+ },
1177
+ 'hour': function (m) {
1178
+ return m.seconds(0).minutes(0);
1179
+ },
1180
+ 'minute': function (m) {
1181
+ return m.seconds(0);
1182
+ }
1183
+ };
1184
+
1185
+ if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) {
1186
+ return picker;
1187
+ }
1188
+ if (input.val() !== undefined && input.val().trim().length !== 0) {
1189
+ setValue(parseInputDate(input.val().trim()));
1190
+ } else if (options.useCurrent && unset && ((input.is('input') && input.val().trim().length === 0) || options.inline)) {
1191
+ currentMoment = getMoment();
1192
+ if (typeof options.useCurrent === 'string') {
1193
+ currentMoment = useCurrentGranularity[options.useCurrent](currentMoment);
1194
+ }
1195
+ setValue(currentMoment);
1196
+ }
1197
+
1198
+ widget = getTemplate();
1199
+
1200
+ fillDow();
1201
+ fillMonths();
1202
+
1203
+ widget.find('.timepicker-hours').hide();
1204
+ widget.find('.timepicker-minutes').hide();
1205
+ widget.find('.timepicker-seconds').hide();
1206
+
1207
+ update();
1208
+ showMode();
1209
+
1210
+ $(window).on('resize', place);
1211
+ widget.on('click', '[data-action]', doAction); // this handles clicks on the widget
1212
+ widget.on('mousedown', false);
1213
+
1214
+ if (component && component.hasClass('btn')) {
1215
+ component.toggleClass('active');
1216
+ }
1217
+ widget.show();
1218
+ place();
1219
+
1220
+ if (options.focusOnShow && !input.is(':focus')) {
1221
+ input.focus();
1222
+ }
1223
+
1224
+ notifyEvent({
1225
+ type: 'dp.show'
1226
+ });
1227
+ return picker;
1228
+ },
1229
+
1230
+ toggle = function () {
1231
+ /// <summary>Shows or hides the widget</summary>
1232
+ return (widget ? hide() : show());
1233
+ },
1234
+
1235
+ parseInputDate = function (inputDate) {
1236
+ if (options.parseInputDate === undefined) {
1237
+ if (moment.isMoment(inputDate) || inputDate instanceof Date) {
1238
+ inputDate = moment(inputDate);
1239
+ } else {
1240
+ inputDate = getMoment(inputDate);
1241
+ }
1242
+ } else {
1243
+ inputDate = options.parseInputDate(inputDate);
1244
+ }
1245
+ inputDate.locale(options.locale);
1246
+ return inputDate;
1247
+ },
1248
+
1249
+ keydown = function (e) {
1250
+ var handler = null,
1251
+ index,
1252
+ index2,
1253
+ pressedKeys = [],
1254
+ pressedModifiers = {},
1255
+ currentKey = e.which,
1256
+ keyBindKeys,
1257
+ allModifiersPressed,
1258
+ pressed = 'p';
1259
+
1260
+ keyState[currentKey] = pressed;
1261
+
1262
+ for (index in keyState) {
1263
+ if (keyState.hasOwnProperty(index) && keyState[index] === pressed) {
1264
+ pressedKeys.push(index);
1265
+ if (parseInt(index, 10) !== currentKey) {
1266
+ pressedModifiers[index] = true;
1267
+ }
1268
+ }
1269
+ }
1270
+
1271
+ for (index in options.keyBinds) {
1272
+ if (options.keyBinds.hasOwnProperty(index) && typeof (options.keyBinds[index]) === 'function') {
1273
+ keyBindKeys = index.split(' ');
1274
+ if (keyBindKeys.length === pressedKeys.length && keyMap[currentKey] === keyBindKeys[keyBindKeys.length - 1]) {
1275
+ allModifiersPressed = true;
1276
+ for (index2 = keyBindKeys.length - 2; index2 >= 0; index2--) {
1277
+ if (!(keyMap[keyBindKeys[index2]] in pressedModifiers)) {
1278
+ allModifiersPressed = false;
1279
+ break;
1280
+ }
1281
+ }
1282
+ if (allModifiersPressed) {
1283
+ handler = options.keyBinds[index];
1284
+ break;
1285
+ }
1286
+ }
1287
+ }
1288
+ }
1289
+
1290
+ if (handler) {
1291
+ handler.call(picker, widget);
1292
+ e.stopPropagation();
1293
+ e.preventDefault();
1294
+ }
1295
+ },
1296
+
1297
+ keyup = function (e) {
1298
+ keyState[e.which] = 'r';
1299
+ e.stopPropagation();
1300
+ e.preventDefault();
1301
+ },
1302
+
1303
+ change = function (e) {
1304
+ var val = $(e.target).val().trim(),
1305
+ parsedDate = val ? parseInputDate(val) : null;
1306
+ setValue(parsedDate);
1307
+ e.stopImmediatePropagation();
1308
+ return false;
1309
+ },
1310
+
1311
+ attachDatePickerElementEvents = function () {
1312
+ input.on({
1313
+ 'change': change,
1314
+ 'blur': options.debug ? '' : hide,
1315
+ 'keydown': keydown,
1316
+ 'keyup': keyup,
1317
+ 'focus': options.allowInputToggle ? show : ''
1318
+ });
1319
+
1320
+ if (element.is('input')) {
1321
+ input.on({
1322
+ 'focus': show
1323
+ });
1324
+ } else if (component) {
1325
+ component.on('click', toggle);
1326
+ component.on('mousedown', false);
1327
+ }
1328
+ },
1329
+
1330
+ detachDatePickerElementEvents = function () {
1331
+ input.off({
1332
+ 'change': change,
1333
+ 'blur': blur,
1334
+ 'keydown': keydown,
1335
+ 'keyup': keyup,
1336
+ 'focus': options.allowInputToggle ? hide : ''
1337
+ });
1338
+
1339
+ if (element.is('input')) {
1340
+ input.off({
1341
+ 'focus': show
1342
+ });
1343
+ } else if (component) {
1344
+ component.off('click', toggle);
1345
+ component.off('mousedown', false);
1346
+ }
1347
+ },
1348
+
1349
+ indexGivenDates = function (givenDatesArray) {
1350
+ // Store given enabledDates and disabledDates as keys.
1351
+ // This way we can check their existence in O(1) time instead of looping through whole array.
1352
+ // (for example: options.enabledDates['2014-02-27'] === true)
1353
+ var givenDatesIndexed = {};
1354
+ $.each(givenDatesArray, function () {
1355
+ var dDate = parseInputDate(this);
1356
+ if (dDate.isValid()) {
1357
+ givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true;
1358
+ }
1359
+ });
1360
+ return (Object.keys(givenDatesIndexed).length) ? givenDatesIndexed : false;
1361
+ },
1362
+
1363
+ indexGivenHours = function (givenHoursArray) {
1364
+ // Store given enabledHours and disabledHours as keys.
1365
+ // This way we can check their existence in O(1) time instead of looping through whole array.
1366
+ // (for example: options.enabledHours['2014-02-27'] === true)
1367
+ var givenHoursIndexed = {};
1368
+ $.each(givenHoursArray, function () {
1369
+ givenHoursIndexed[this] = true;
1370
+ });
1371
+ return (Object.keys(givenHoursIndexed).length) ? givenHoursIndexed : false;
1372
+ },
1373
+
1374
+ initFormatting = function () {
1375
+ var format = options.format || 'L LT';
1376
+
1377
+ actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput) {
1378
+ var newinput = date.localeData().longDateFormat(formatInput) || formatInput;
1379
+ return newinput.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput2) { //temp fix for #740
1380
+ return date.localeData().longDateFormat(formatInput2) || formatInput2;
1381
+ });
1382
+ });
1383
+
1384
+
1385
+ parseFormats = options.extraFormats ? options.extraFormats.slice() : [];
1386
+ if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) {
1387
+ parseFormats.push(actualFormat);
1388
+ }
1389
+
1390
+ use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.replace(/\[.*?\]/g, '').indexOf('h') < 1);
1391
+
1392
+ if (isEnabled('y')) {
1393
+ minViewModeNumber = 2;
1394
+ }
1395
+ if (isEnabled('M')) {
1396
+ minViewModeNumber = 1;
1397
+ }
1398
+ if (isEnabled('d')) {
1399
+ minViewModeNumber = 0;
1400
+ }
1401
+
1402
+ currentViewMode = Math.max(minViewModeNumber, currentViewMode);
1403
+
1404
+ if (!unset) {
1405
+ setValue(date);
1406
+ }
1407
+ };
1408
+
1409
+ /********************************************************************************
1410
+ *
1411
+ * Public API functions
1412
+ * =====================
1413
+ *
1414
+ * Important: Do not expose direct references to private objects or the options
1415
+ * object to the outer world. Always return a clone when returning values or make
1416
+ * a clone when setting a private variable.
1417
+ *
1418
+ ********************************************************************************/
1419
+ picker.destroy = function () {
1420
+ ///<summary>Destroys the widget and removes all attached event listeners</summary>
1421
+ hide();
1422
+ detachDatePickerElementEvents();
1423
+ element.removeData('DateTimePicker');
1424
+ element.removeData('date');
1425
+ };
1426
+
1427
+ picker.toggle = toggle;
1428
+
1429
+ picker.show = show;
1430
+
1431
+ picker.hide = hide;
1432
+
1433
+ picker.disable = function () {
1434
+ ///<summary>Disables the input element, the component is attached to, by adding a disabled="true" attribute to it.
1435
+ ///If the widget was visible before that call it is hidden. Possibly emits dp.hide</summary>
1436
+ hide();
1437
+ if (component && component.hasClass('btn')) {
1438
+ component.addClass('disabled');
1439
+ }
1440
+ input.prop('disabled', true);
1441
+ return picker;
1442
+ };
1443
+
1444
+ picker.enable = function () {
1445
+ ///<summary>Enables the input element, the component is attached to, by removing disabled attribute from it.</summary>
1446
+ if (component && component.hasClass('btn')) {
1447
+ component.removeClass('disabled');
1448
+ }
1449
+ input.prop('disabled', false);
1450
+ return picker;
1451
+ };
1452
+
1453
+ picker.ignoreReadonly = function (ignoreReadonly) {
1454
+ if (arguments.length === 0) {
1455
+ return options.ignoreReadonly;
1456
+ }
1457
+ if (typeof ignoreReadonly !== 'boolean') {
1458
+ throw new TypeError('ignoreReadonly () expects a boolean parameter');
1459
+ }
1460
+ options.ignoreReadonly = ignoreReadonly;
1461
+ return picker;
1462
+ };
1463
+
1464
+ picker.options = function (newOptions) {
1465
+ if (arguments.length === 0) {
1466
+ return $.extend(true, {}, options);
1467
+ }
1468
+
1469
+ if (!(newOptions instanceof Object)) {
1470
+ throw new TypeError('options() options parameter should be an object');
1471
+ }
1472
+ $.extend(true, options, newOptions);
1473
+ $.each(options, function (key, value) {
1474
+ if (picker[key] !== undefined) {
1475
+ picker[key](value);
1476
+ } else {
1477
+ //throw new TypeError('option ' + key + ' is not recognized!');
1478
+ }
1479
+ });
1480
+ return picker;
1481
+ };
1482
+
1483
+ picker.date = function (newDate) {
1484
+ ///<signature helpKeyword="$.fn.datetimepicker.date">
1485
+ ///<summary>Returns the component's model current date, a moment object or null if not set.</summary>
1486
+ ///<returns type="Moment">date.clone()</returns>
1487
+ ///</signature>
1488
+ ///<signature>
1489
+ ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary>
1490
+ ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, Date, moment, null parameter.</param>
1491
+ ///</signature>
1492
+ if (arguments.length === 0) {
1493
+ if (unset) {
1494
+ return null;
1495
+ }
1496
+ return date.clone();
1497
+ }
1498
+
1499
+ if (newDate !== null && typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
1500
+ throw new TypeError('date() parameter must be one of [null, string, moment or Date]');
1501
+ }
1502
+
1503
+ setValue(newDate === null ? null : parseInputDate(newDate));
1504
+ return picker;
1505
+ };
1506
+
1507
+ picker.format = function (newFormat) {
1508
+ ///<summary>test su</summary>
1509
+ ///<param name="newFormat">info about para</param>
1510
+ ///<returns type="string|boolean">returns foo</returns>
1511
+ if (arguments.length === 0) {
1512
+ return options.format;
1513
+ }
1514
+
1515
+ if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) {
1516
+ throw new TypeError('format() expects a sting or boolean:false parameter ' + newFormat);
1517
+ }
1518
+
1519
+ options.format = newFormat;
1520
+ if (actualFormat) {
1521
+ initFormatting(); // reinit formatting
1522
+ }
1523
+ return picker;
1524
+ };
1525
+
1526
+ picker.timeZone = function (newZone) {
1527
+ if (arguments.length === 0) {
1528
+ return options.timeZone;
1529
+ }
1530
+
1531
+ options.timeZone = newZone;
1532
+
1533
+ return picker;
1534
+ };
1535
+
1536
+ picker.dayViewHeaderFormat = function (newFormat) {
1537
+ if (arguments.length === 0) {
1538
+ return options.dayViewHeaderFormat;
1539
+ }
1540
+
1541
+ if (typeof newFormat !== 'string') {
1542
+ throw new TypeError('dayViewHeaderFormat() expects a string parameter');
1543
+ }
1544
+
1545
+ options.dayViewHeaderFormat = newFormat;
1546
+ return picker;
1547
+ };
1548
+
1549
+ picker.extraFormats = function (formats) {
1550
+ if (arguments.length === 0) {
1551
+ return options.extraFormats;
1552
+ }
1553
+
1554
+ if (formats !== false && !(formats instanceof Array)) {
1555
+ throw new TypeError('extraFormats() expects an array or false parameter');
1556
+ }
1557
+
1558
+ options.extraFormats = formats;
1559
+ if (parseFormats) {
1560
+ initFormatting(); // reinit formatting
1561
+ }
1562
+ return picker;
1563
+ };
1564
+
1565
+ picker.disabledDates = function (dates) {
1566
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledDates">
1567
+ ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
1568
+ ///<returns type="array">options.disabledDates</returns>
1569
+ ///</signature>
1570
+ ///<signature>
1571
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
1572
+ ///options.enabledDates if such exist.</summary>
1573
+ ///<param name="dates" locid="$.fn.datetimepicker.disabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
1574
+ ///</signature>
1575
+ if (arguments.length === 0) {
1576
+ return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates);
1577
+ }
1578
+
1579
+ if (!dates) {
1580
+ options.disabledDates = false;
1581
+ update();
1582
+ return picker;
1583
+ }
1584
+ if (!(dates instanceof Array)) {
1585
+ throw new TypeError('disabledDates() expects an array parameter');
1586
+ }
1587
+ options.disabledDates = indexGivenDates(dates);
1588
+ options.enabledDates = false;
1589
+ update();
1590
+ return picker;
1591
+ };
1592
+
1593
+ picker.enabledDates = function (dates) {
1594
+ ///<signature helpKeyword="$.fn.datetimepicker.enabledDates">
1595
+ ///<summary>Returns an array with the currently set enabled dates on the component.</summary>
1596
+ ///<returns type="array">options.enabledDates</returns>
1597
+ ///</signature>
1598
+ ///<signature>
1599
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledDates if such exist.</summary>
1600
+ ///<param name="dates" locid="$.fn.datetimepicker.enabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
1601
+ ///</signature>
1602
+ if (arguments.length === 0) {
1603
+ return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates);
1604
+ }
1605
+
1606
+ if (!dates) {
1607
+ options.enabledDates = false;
1608
+ update();
1609
+ return picker;
1610
+ }
1611
+ if (!(dates instanceof Array)) {
1612
+ throw new TypeError('enabledDates() expects an array parameter');
1613
+ }
1614
+ options.enabledDates = indexGivenDates(dates);
1615
+ options.disabledDates = false;
1616
+ update();
1617
+ return picker;
1618
+ };
1619
+
1620
+ picker.daysOfWeekDisabled = function (daysOfWeekDisabled) {
1621
+ if (arguments.length === 0) {
1622
+ return options.daysOfWeekDisabled.splice(0);
1623
+ }
1624
+
1625
+ if ((typeof daysOfWeekDisabled === 'boolean') && !daysOfWeekDisabled) {
1626
+ options.daysOfWeekDisabled = false;
1627
+ update();
1628
+ return picker;
1629
+ }
1630
+
1631
+ if (!(daysOfWeekDisabled instanceof Array)) {
1632
+ throw new TypeError('daysOfWeekDisabled() expects an array parameter');
1633
+ }
1634
+ options.daysOfWeekDisabled = daysOfWeekDisabled.reduce(function (previousValue, currentValue) {
1635
+ currentValue = parseInt(currentValue, 10);
1636
+ if (currentValue > 6 || currentValue < 0 || isNaN(currentValue)) {
1637
+ return previousValue;
1638
+ }
1639
+ if (previousValue.indexOf(currentValue) === -1) {
1640
+ previousValue.push(currentValue);
1641
+ }
1642
+ return previousValue;
1643
+ }, []).sort();
1644
+ if (options.useCurrent && !options.keepInvalid) {
1645
+ var tries = 0;
1646
+ while (!isValid(date, 'd')) {
1647
+ date.add(1, 'd');
1648
+ if (tries === 7) {
1649
+ throw 'Tried 7 times to find a valid date';
1650
+ }
1651
+ tries++;
1652
+ }
1653
+ setValue(date);
1654
+ }
1655
+ update();
1656
+ return picker;
1657
+ };
1658
+
1659
+ picker.maxDate = function (maxDate) {
1660
+ if (arguments.length === 0) {
1661
+ return options.maxDate ? options.maxDate.clone() : options.maxDate;
1662
+ }
1663
+
1664
+ if ((typeof maxDate === 'boolean') && maxDate === false) {
1665
+ options.maxDate = false;
1666
+ update();
1667
+ return picker;
1668
+ }
1669
+
1670
+ if (typeof maxDate === 'string') {
1671
+ if (maxDate === 'now' || maxDate === 'moment') {
1672
+ maxDate = getMoment();
1673
+ }
1674
+ }
1675
+
1676
+ var parsedDate = parseInputDate(maxDate);
1677
+
1678
+ if (!parsedDate.isValid()) {
1679
+ throw new TypeError('maxDate() Could not parse date parameter: ' + maxDate);
1680
+ }
1681
+ if (options.minDate && parsedDate.isBefore(options.minDate)) {
1682
+ throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat));
1683
+ }
1684
+ options.maxDate = parsedDate;
1685
+ if (options.useCurrent && !options.keepInvalid && date.isAfter(maxDate)) {
1686
+ setValue(options.maxDate);
1687
+ }
1688
+ if (viewDate.isAfter(parsedDate)) {
1689
+ viewDate = parsedDate.clone().subtract(options.stepping, 'm');
1690
+ }
1691
+ update();
1692
+ return picker;
1693
+ };
1694
+
1695
+ picker.minDate = function (minDate) {
1696
+ if (arguments.length === 0) {
1697
+ return options.minDate ? options.minDate.clone() : options.minDate;
1698
+ }
1699
+
1700
+ if ((typeof minDate === 'boolean') && minDate === false) {
1701
+ options.minDate = false;
1702
+ update();
1703
+ return picker;
1704
+ }
1705
+
1706
+ if (typeof minDate === 'string') {
1707
+ if (minDate === 'now' || minDate === 'moment') {
1708
+ minDate = getMoment();
1709
+ }
1710
+ }
1711
+
1712
+ var parsedDate = parseInputDate(minDate);
1713
+
1714
+ if (!parsedDate.isValid()) {
1715
+ throw new TypeError('minDate() Could not parse date parameter: ' + minDate);
1716
+ }
1717
+ if (options.maxDate && parsedDate.isAfter(options.maxDate)) {
1718
+ throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat));
1719
+ }
1720
+ options.minDate = parsedDate;
1721
+ if (options.useCurrent && !options.keepInvalid && date.isBefore(minDate)) {
1722
+ setValue(options.minDate);
1723
+ }
1724
+ if (viewDate.isBefore(parsedDate)) {
1725
+ viewDate = parsedDate.clone().add(options.stepping, 'm');
1726
+ }
1727
+ update();
1728
+ return picker;
1729
+ };
1730
+
1731
+ picker.defaultDate = function (defaultDate) {
1732
+ ///<signature helpKeyword="$.fn.datetimepicker.defaultDate">
1733
+ ///<summary>Returns a moment with the options.defaultDate option configuration or false if not set</summary>
1734
+ ///<returns type="Moment">date.clone()</returns>
1735
+ ///</signature>
1736
+ ///<signature>
1737
+ ///<summary>Will set the picker's inital date. If a boolean:false value is passed the options.defaultDate parameter is cleared.</summary>
1738
+ ///<param name="defaultDate" locid="$.fn.datetimepicker.defaultDate_p:defaultDate">Takes a string, Date, moment, boolean:false</param>
1739
+ ///</signature>
1740
+ if (arguments.length === 0) {
1741
+ return options.defaultDate ? options.defaultDate.clone() : options.defaultDate;
1742
+ }
1743
+ if (!defaultDate) {
1744
+ options.defaultDate = false;
1745
+ return picker;
1746
+ }
1747
+
1748
+ if (typeof defaultDate === 'string') {
1749
+ if (defaultDate === 'now' || defaultDate === 'moment') {
1750
+ defaultDate = getMoment();
1751
+ }
1752
+ }
1753
+
1754
+ var parsedDate = parseInputDate(defaultDate);
1755
+ if (!parsedDate.isValid()) {
1756
+ throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate);
1757
+ }
1758
+ if (!isValid(parsedDate)) {
1759
+ throw new TypeError('defaultDate() date passed is invalid according to component setup validations');
1760
+ }
1761
+
1762
+ options.defaultDate = parsedDate;
1763
+
1764
+ if ((options.defaultDate && options.inline) || input.val().trim() === '') {
1765
+ setValue(options.defaultDate);
1766
+ }
1767
+ return picker;
1768
+ };
1769
+
1770
+ picker.locale = function (locale) {
1771
+ if (arguments.length === 0) {
1772
+ return options.locale;
1773
+ }
1774
+
1775
+ if (!moment.localeData(locale)) {
1776
+ throw new TypeError('locale() locale ' + locale + ' is not loaded from moment locales!');
1777
+ }
1778
+
1779
+ options.locale = locale;
1780
+ date.locale(options.locale);
1781
+ viewDate.locale(options.locale);
1782
+
1783
+ if (actualFormat) {
1784
+ initFormatting(); // reinit formatting
1785
+ }
1786
+ if (widget) {
1787
+ hide();
1788
+ show();
1789
+ }
1790
+ return picker;
1791
+ };
1792
+
1793
+ picker.stepping = function (stepping) {
1794
+ if (arguments.length === 0) {
1795
+ return options.stepping;
1796
+ }
1797
+
1798
+ stepping = parseInt(stepping, 10);
1799
+ if (isNaN(stepping) || stepping < 1) {
1800
+ stepping = 1;
1801
+ }
1802
+ options.stepping = stepping;
1803
+ return picker;
1804
+ };
1805
+
1806
+ picker.useCurrent = function (useCurrent) {
1807
+ var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute'];
1808
+ if (arguments.length === 0) {
1809
+ return options.useCurrent;
1810
+ }
1811
+
1812
+ if ((typeof useCurrent !== 'boolean') && (typeof useCurrent !== 'string')) {
1813
+ throw new TypeError('useCurrent() expects a boolean or string parameter');
1814
+ }
1815
+ if (typeof useCurrent === 'string' && useCurrentOptions.indexOf(useCurrent.toLowerCase()) === -1) {
1816
+ throw new TypeError('useCurrent() expects a string parameter of ' + useCurrentOptions.join(', '));
1817
+ }
1818
+ options.useCurrent = useCurrent;
1819
+ return picker;
1820
+ };
1821
+
1822
+ picker.collapse = function (collapse) {
1823
+ if (arguments.length === 0) {
1824
+ return options.collapse;
1825
+ }
1826
+
1827
+ if (typeof collapse !== 'boolean') {
1828
+ throw new TypeError('collapse() expects a boolean parameter');
1829
+ }
1830
+ if (options.collapse === collapse) {
1831
+ return picker;
1832
+ }
1833
+ options.collapse = collapse;
1834
+ if (widget) {
1835
+ hide();
1836
+ show();
1837
+ }
1838
+ return picker;
1839
+ };
1840
+
1841
+ picker.icons = function (icons) {
1842
+ if (arguments.length === 0) {
1843
+ return $.extend({}, options.icons);
1844
+ }
1845
+
1846
+ if (!(icons instanceof Object)) {
1847
+ throw new TypeError('icons() expects parameter to be an Object');
1848
+ }
1849
+ $.extend(options.icons, icons);
1850
+ if (widget) {
1851
+ hide();
1852
+ show();
1853
+ }
1854
+ return picker;
1855
+ };
1856
+
1857
+ picker.tooltips = function (tooltips) {
1858
+ if (arguments.length === 0) {
1859
+ return $.extend({}, options.tooltips);
1860
+ }
1861
+
1862
+ if (!(tooltips instanceof Object)) {
1863
+ throw new TypeError('tooltips() expects parameter to be an Object');
1864
+ }
1865
+ $.extend(options.tooltips, tooltips);
1866
+ if (widget) {
1867
+ hide();
1868
+ show();
1869
+ }
1870
+ return picker;
1871
+ };
1872
+
1873
+ picker.useStrict = function (useStrict) {
1874
+ if (arguments.length === 0) {
1875
+ return options.useStrict;
1876
+ }
1877
+
1878
+ if (typeof useStrict !== 'boolean') {
1879
+ throw new TypeError('useStrict() expects a boolean parameter');
1880
+ }
1881
+ options.useStrict = useStrict;
1882
+ return picker;
1883
+ };
1884
+
1885
+ picker.sideBySide = function (sideBySide) {
1886
+ if (arguments.length === 0) {
1887
+ return options.sideBySide;
1888
+ }
1889
+
1890
+ if (typeof sideBySide !== 'boolean') {
1891
+ throw new TypeError('sideBySide() expects a boolean parameter');
1892
+ }
1893
+ options.sideBySide = sideBySide;
1894
+ if (widget) {
1895
+ hide();
1896
+ show();
1897
+ }
1898
+ return picker;
1899
+ };
1900
+
1901
+ picker.viewMode = function (viewMode) {
1902
+ if (arguments.length === 0) {
1903
+ return options.viewMode;
1904
+ }
1905
+
1906
+ if (typeof viewMode !== 'string') {
1907
+ throw new TypeError('viewMode() expects a string parameter');
1908
+ }
1909
+
1910
+ if (viewModes.indexOf(viewMode) === -1) {
1911
+ throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value');
1912
+ }
1913
+
1914
+ options.viewMode = viewMode;
1915
+ currentViewMode = Math.max(viewModes.indexOf(viewMode), minViewModeNumber);
1916
+
1917
+ showMode();
1918
+ return picker;
1919
+ };
1920
+
1921
+ picker.toolbarPlacement = function (toolbarPlacement) {
1922
+ if (arguments.length === 0) {
1923
+ return options.toolbarPlacement;
1924
+ }
1925
+
1926
+ if (typeof toolbarPlacement !== 'string') {
1927
+ throw new TypeError('toolbarPlacement() expects a string parameter');
1928
+ }
1929
+ if (toolbarPlacements.indexOf(toolbarPlacement) === -1) {
1930
+ throw new TypeError('toolbarPlacement() parameter must be one of (' + toolbarPlacements.join(', ') + ') value');
1931
+ }
1932
+ options.toolbarPlacement = toolbarPlacement;
1933
+
1934
+ if (widget) {
1935
+ hide();
1936
+ show();
1937
+ }
1938
+ return picker;
1939
+ };
1940
+
1941
+ picker.widgetPositioning = function (widgetPositioning) {
1942
+ if (arguments.length === 0) {
1943
+ return $.extend({}, options.widgetPositioning);
1944
+ }
1945
+
1946
+ if (({}).toString.call(widgetPositioning) !== '[object Object]') {
1947
+ throw new TypeError('widgetPositioning() expects an object variable');
1948
+ }
1949
+ if (widgetPositioning.horizontal) {
1950
+ if (typeof widgetPositioning.horizontal !== 'string') {
1951
+ throw new TypeError('widgetPositioning() horizontal variable must be a string');
1952
+ }
1953
+ widgetPositioning.horizontal = widgetPositioning.horizontal.toLowerCase();
1954
+ if (horizontalModes.indexOf(widgetPositioning.horizontal) === -1) {
1955
+ throw new TypeError('widgetPositioning() expects horizontal parameter to be one of (' + horizontalModes.join(', ') + ')');
1956
+ }
1957
+ options.widgetPositioning.horizontal = widgetPositioning.horizontal;
1958
+ }
1959
+ if (widgetPositioning.vertical) {
1960
+ if (typeof widgetPositioning.vertical !== 'string') {
1961
+ throw new TypeError('widgetPositioning() vertical variable must be a string');
1962
+ }
1963
+ widgetPositioning.vertical = widgetPositioning.vertical.toLowerCase();
1964
+ if (verticalModes.indexOf(widgetPositioning.vertical) === -1) {
1965
+ throw new TypeError('widgetPositioning() expects vertical parameter to be one of (' + verticalModes.join(', ') + ')');
1966
+ }
1967
+ options.widgetPositioning.vertical = widgetPositioning.vertical;
1968
+ }
1969
+ update();
1970
+ return picker;
1971
+ };
1972
+
1973
+ picker.calendarWeeks = function (calendarWeeks) {
1974
+ if (arguments.length === 0) {
1975
+ return options.calendarWeeks;
1976
+ }
1977
+
1978
+ if (typeof calendarWeeks !== 'boolean') {
1979
+ throw new TypeError('calendarWeeks() expects parameter to be a boolean value');
1980
+ }
1981
+
1982
+ options.calendarWeeks = calendarWeeks;
1983
+ update();
1984
+ return picker;
1985
+ };
1986
+
1987
+ picker.showTodayButton = function (showTodayButton) {
1988
+ if (arguments.length === 0) {
1989
+ return options.showTodayButton;
1990
+ }
1991
+
1992
+ if (typeof showTodayButton !== 'boolean') {
1993
+ throw new TypeError('showTodayButton() expects a boolean parameter');
1994
+ }
1995
+
1996
+ options.showTodayButton = showTodayButton;
1997
+ if (widget) {
1998
+ hide();
1999
+ show();
2000
+ }
2001
+ return picker;
2002
+ };
2003
+
2004
+ picker.showClear = function (showClear) {
2005
+ if (arguments.length === 0) {
2006
+ return options.showClear;
2007
+ }
2008
+
2009
+ if (typeof showClear !== 'boolean') {
2010
+ throw new TypeError('showClear() expects a boolean parameter');
2011
+ }
2012
+
2013
+ options.showClear = showClear;
2014
+ if (widget) {
2015
+ hide();
2016
+ show();
2017
+ }
2018
+ return picker;
2019
+ };
2020
+
2021
+ picker.widgetParent = function (widgetParent) {
2022
+ if (arguments.length === 0) {
2023
+ return options.widgetParent;
2024
+ }
2025
+
2026
+ if (typeof widgetParent === 'string') {
2027
+ widgetParent = $(widgetParent);
2028
+ }
2029
+
2030
+ if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof $))) {
2031
+ throw new TypeError('widgetParent() expects a string or a jQuery object parameter');
2032
+ }
2033
+
2034
+ options.widgetParent = widgetParent;
2035
+ if (widget) {
2036
+ hide();
2037
+ show();
2038
+ }
2039
+ return picker;
2040
+ };
2041
+
2042
+ picker.keepOpen = function (keepOpen) {
2043
+ if (arguments.length === 0) {
2044
+ return options.keepOpen;
2045
+ }
2046
+
2047
+ if (typeof keepOpen !== 'boolean') {
2048
+ throw new TypeError('keepOpen() expects a boolean parameter');
2049
+ }
2050
+
2051
+ options.keepOpen = keepOpen;
2052
+ return picker;
2053
+ };
2054
+
2055
+ picker.focusOnShow = function (focusOnShow) {
2056
+ if (arguments.length === 0) {
2057
+ return options.focusOnShow;
2058
+ }
2059
+
2060
+ if (typeof focusOnShow !== 'boolean') {
2061
+ throw new TypeError('focusOnShow() expects a boolean parameter');
2062
+ }
2063
+
2064
+ options.focusOnShow = focusOnShow;
2065
+ return picker;
2066
+ };
2067
+
2068
+ picker.inline = function (inline) {
2069
+ if (arguments.length === 0) {
2070
+ return options.inline;
2071
+ }
2072
+
2073
+ if (typeof inline !== 'boolean') {
2074
+ throw new TypeError('inline() expects a boolean parameter');
2075
+ }
2076
+
2077
+ options.inline = inline;
2078
+ return picker;
2079
+ };
2080
+
2081
+ picker.clear = function () {
2082
+ clear();
2083
+ return picker;
2084
+ };
2085
+
2086
+ picker.keyBinds = function (keyBinds) {
2087
+ options.keyBinds = keyBinds;
2088
+ return picker;
2089
+ };
2090
+
2091
+ picker.getMoment = function (d) {
2092
+ return getMoment(d);
2093
+ };
2094
+
2095
+ picker.debug = function (debug) {
2096
+ if (typeof debug !== 'boolean') {
2097
+ throw new TypeError('debug() expects a boolean parameter');
2098
+ }
2099
+
2100
+ options.debug = debug;
2101
+ return picker;
2102
+ };
2103
+
2104
+ picker.allowInputToggle = function (allowInputToggle) {
2105
+ if (arguments.length === 0) {
2106
+ return options.allowInputToggle;
2107
+ }
2108
+
2109
+ if (typeof allowInputToggle !== 'boolean') {
2110
+ throw new TypeError('allowInputToggle() expects a boolean parameter');
2111
+ }
2112
+
2113
+ options.allowInputToggle = allowInputToggle;
2114
+ return picker;
2115
+ };
2116
+
2117
+ picker.showClose = function (showClose) {
2118
+ if (arguments.length === 0) {
2119
+ return options.showClose;
2120
+ }
2121
+
2122
+ if (typeof showClose !== 'boolean') {
2123
+ throw new TypeError('showClose() expects a boolean parameter');
2124
+ }
2125
+
2126
+ options.showClose = showClose;
2127
+ return picker;
2128
+ };
2129
+
2130
+ picker.keepInvalid = function (keepInvalid) {
2131
+ if (arguments.length === 0) {
2132
+ return options.keepInvalid;
2133
+ }
2134
+
2135
+ if (typeof keepInvalid !== 'boolean') {
2136
+ throw new TypeError('keepInvalid() expects a boolean parameter');
2137
+ }
2138
+ options.keepInvalid = keepInvalid;
2139
+ return picker;
2140
+ };
2141
+
2142
+ picker.datepickerInput = function (datepickerInput) {
2143
+ if (arguments.length === 0) {
2144
+ return options.datepickerInput;
2145
+ }
2146
+
2147
+ if (typeof datepickerInput !== 'string') {
2148
+ throw new TypeError('datepickerInput() expects a string parameter');
2149
+ }
2150
+
2151
+ options.datepickerInput = datepickerInput;
2152
+ return picker;
2153
+ };
2154
+
2155
+ picker.parseInputDate = function (parseInputDate) {
2156
+ if (arguments.length === 0) {
2157
+ return options.parseInputDate;
2158
+ }
2159
+
2160
+ if (typeof parseInputDate !== 'function') {
2161
+ throw new TypeError('parseInputDate() sholud be as function');
2162
+ }
2163
+
2164
+ options.parseInputDate = parseInputDate;
2165
+
2166
+ return picker;
2167
+ };
2168
+
2169
+ picker.disabledTimeIntervals = function (disabledTimeIntervals) {
2170
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledTimeIntervals">
2171
+ ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
2172
+ ///<returns type="array">options.disabledTimeIntervals</returns>
2173
+ ///</signature>
2174
+ ///<signature>
2175
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
2176
+ ///options.enabledDates if such exist.</summary>
2177
+ ///<param name="dates" locid="$.fn.datetimepicker.disabledTimeIntervals_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
2178
+ ///</signature>
2179
+ if (arguments.length === 0) {
2180
+ return (options.disabledTimeIntervals ? $.extend({}, options.disabledTimeIntervals) : options.disabledTimeIntervals);
2181
+ }
2182
+
2183
+ if (!disabledTimeIntervals) {
2184
+ options.disabledTimeIntervals = false;
2185
+ update();
2186
+ return picker;
2187
+ }
2188
+ if (!(disabledTimeIntervals instanceof Array)) {
2189
+ throw new TypeError('disabledTimeIntervals() expects an array parameter');
2190
+ }
2191
+ options.disabledTimeIntervals = disabledTimeIntervals;
2192
+ update();
2193
+ return picker;
2194
+ };
2195
+
2196
+ picker.disabledHours = function (hours) {
2197
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledHours">
2198
+ ///<summary>Returns an array with the currently set disabled hours on the component.</summary>
2199
+ ///<returns type="array">options.disabledHours</returns>
2200
+ ///</signature>
2201
+ ///<signature>
2202
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
2203
+ ///options.enabledHours if such exist.</summary>
2204
+ ///<param name="hours" locid="$.fn.datetimepicker.disabledHours_p:hours">Takes an [ int ] of values and disallows the user to select only from those hours.</param>
2205
+ ///</signature>
2206
+ if (arguments.length === 0) {
2207
+ return (options.disabledHours ? $.extend({}, options.disabledHours) : options.disabledHours);
2208
+ }
2209
+
2210
+ if (!hours) {
2211
+ options.disabledHours = false;
2212
+ update();
2213
+ return picker;
2214
+ }
2215
+ if (!(hours instanceof Array)) {
2216
+ throw new TypeError('disabledHours() expects an array parameter');
2217
+ }
2218
+ options.disabledHours = indexGivenHours(hours);
2219
+ options.enabledHours = false;
2220
+ if (options.useCurrent && !options.keepInvalid) {
2221
+ var tries = 0;
2222
+ while (!isValid(date, 'h')) {
2223
+ date.add(1, 'h');
2224
+ if (tries === 24) {
2225
+ throw 'Tried 24 times to find a valid date';
2226
+ }
2227
+ tries++;
2228
+ }
2229
+ setValue(date);
2230
+ }
2231
+ update();
2232
+ return picker;
2233
+ };
2234
+
2235
+ picker.enabledHours = function (hours) {
2236
+ ///<signature helpKeyword="$.fn.datetimepicker.enabledHours">
2237
+ ///<summary>Returns an array with the currently set enabled hours on the component.</summary>
2238
+ ///<returns type="array">options.enabledHours</returns>
2239
+ ///</signature>
2240
+ ///<signature>
2241
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledHours if such exist.</summary>
2242
+ ///<param name="hours" locid="$.fn.datetimepicker.enabledHours_p:hours">Takes an [ int ] of values and allows the user to select only from those hours.</param>
2243
+ ///</signature>
2244
+ if (arguments.length === 0) {
2245
+ return (options.enabledHours ? $.extend({}, options.enabledHours) : options.enabledHours);
2246
+ }
2247
+
2248
+ if (!hours) {
2249
+ options.enabledHours = false;
2250
+ update();
2251
+ return picker;
2252
+ }
2253
+ if (!(hours instanceof Array)) {
2254
+ throw new TypeError('enabledHours() expects an array parameter');
2255
+ }
2256
+ options.enabledHours = indexGivenHours(hours);
2257
+ options.disabledHours = false;
2258
+ if (options.useCurrent && !options.keepInvalid) {
2259
+ var tries = 0;
2260
+ while (!isValid(date, 'h')) {
2261
+ date.add(1, 'h');
2262
+ if (tries === 24) {
2263
+ throw 'Tried 24 times to find a valid date';
2264
+ }
2265
+ tries++;
2266
+ }
2267
+ setValue(date);
2268
+ }
2269
+ update();
2270
+ return picker;
2271
+ };
2272
+
2273
+ picker.viewDate = function (newDate) {
2274
+ ///<signature helpKeyword="$.fn.datetimepicker.viewDate">
2275
+ ///<summary>Returns the component's model current viewDate, a moment object or null if not set.</summary>
2276
+ ///<returns type="Moment">viewDate.clone()</returns>
2277
+ ///</signature>
2278
+ ///<signature>
2279
+ ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary>
2280
+ ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, viewDate, moment, null parameter.</param>
2281
+ ///</signature>
2282
+ if (arguments.length === 0) {
2283
+ return viewDate.clone();
2284
+ }
2285
+
2286
+ if (!newDate) {
2287
+ viewDate = date.clone();
2288
+ return picker;
2289
+ }
2290
+
2291
+ if (typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
2292
+ throw new TypeError('viewDate() parameter must be one of [string, moment or Date]');
2293
+ }
2294
+
2295
+ viewDate = parseInputDate(newDate);
2296
+ viewUpdate();
2297
+ return picker;
2298
+ };
2299
+
2300
+ // initializing element and component attributes
2301
+ if (element.is('input')) {
2302
+ input = element;
2303
+ } else {
2304
+ input = element.find(options.datepickerInput);
2305
+ if (input.size() === 0) {
2306
+ input = element.find('input');
2307
+ } else if (!input.is('input')) {
2308
+ throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element');
2309
+ }
2310
+ }
2311
+
2312
+ if (element.hasClass('input-group')) {
2313
+ // in case there is more then one 'input-group-addon' Issue #48
2314
+ if (element.find('.datepickerbutton').size() === 0) {
2315
+ component = element.find('.input-group-addon');
2316
+ } else {
2317
+ component = element.find('.datepickerbutton');
2318
+ }
2319
+ }
2320
+
2321
+ if (!options.inline && !input.is('input')) {
2322
+ throw new Error('Could not initialize DateTimePicker without an input element');
2323
+ }
2324
+
2325
+ // Set defaults for date here now instead of in var declaration
2326
+ date = getMoment();
2327
+ viewDate = date.clone();
2328
+
2329
+ $.extend(true, options, dataToOptions());
2330
+
2331
+ picker.options(options);
2332
+
2333
+ initFormatting();
2334
+
2335
+ attachDatePickerElementEvents();
2336
+
2337
+ if (input.prop('disabled')) {
2338
+ picker.disable();
2339
+ }
2340
+ if (input.is('input') && input.val().trim().length !== 0) {
2341
+ setValue(parseInputDate(input.val().trim()));
2342
+ }
2343
+ else if (options.defaultDate && input.attr('placeholder') === undefined) {
2344
+ setValue(options.defaultDate);
2345
+ }
2346
+ if (options.inline) {
2347
+ show();
2348
+ }
2349
+ return picker;
2350
+ };
2351
+
2352
+ /********************************************************************************
2353
+ *
2354
+ * jQuery plugin constructor and defaults object
2355
+ *
2356
+ ********************************************************************************/
2357
+
2358
+ $.fn.datetimepicker = function (options) {
2359
+ return this.each(function () {
2360
+ var $this = $(this);
2361
+ if (!$this.data('DateTimePicker')) {
2362
+ // create a private copy of the defaults object
2363
+ options = $.extend(true, {}, $.fn.datetimepicker.defaults, options);
2364
+ $this.data('DateTimePicker', dateTimePicker($this, options));
2365
+ }
2366
+ });
2367
+ };
2368
+
2369
+ $.fn.datetimepicker.defaults = {
2370
+ timeZone: 'Etc/UTC',
2371
+ format: false,
2372
+ dayViewHeaderFormat: 'MMMM YYYY',
2373
+ extraFormats: false,
2374
+ stepping: 1,
2375
+ minDate: false,
2376
+ maxDate: false,
2377
+ useCurrent: true,
2378
+ collapse: true,
2379
+ locale: CURRENT_LOCALE || moment.locale(),
2380
+ defaultDate: false,
2381
+ disabledDates: false,
2382
+ enabledDates: false,
2383
+ icons: {
2384
+ time: 'glyphicon glyphicon-time',
2385
+ date: 'glyphicon glyphicon-calendar',
2386
+ up: 'glyphicon glyphicon-chevron-up',
2387
+ down: 'glyphicon glyphicon-chevron-down',
2388
+ previous: 'glyphicon glyphicon-chevron-left',
2389
+ next: 'glyphicon glyphicon-chevron-right',
2390
+ today: 'glyphicon glyphicon-screenshot',
2391
+ clear: 'glyphicon glyphicon-trash',
2392
+ close: 'glyphicon glyphicon-remove'
2393
+ },
2394
+ tooltips: {
2395
+ today: 'Go to today',
2396
+ clear: 'Clear selection',
2397
+ close: 'Close the picker',
2398
+ selectMonth: 'Select Month',
2399
+ prevMonth: 'Previous Month',
2400
+ nextMonth: 'Next Month',
2401
+ selectYear: 'Select Year',
2402
+ prevYear: 'Previous Year',
2403
+ nextYear: 'Next Year',
2404
+ selectDecade: 'Select Decade',
2405
+ prevDecade: 'Previous Decade',
2406
+ nextDecade: 'Next Decade',
2407
+ prevCentury: 'Previous Century',
2408
+ nextCentury: 'Next Century',
2409
+ pickHour: 'Pick Hour',
2410
+ incrementHour: 'Increment Hour',
2411
+ decrementHour: 'Decrement Hour',
2412
+ pickMinute: 'Pick Minute',
2413
+ incrementMinute: 'Increment Minute',
2414
+ decrementMinute: 'Decrement Minute',
2415
+ pickSecond: 'Pick Second',
2416
+ incrementSecond: 'Increment Second',
2417
+ decrementSecond: 'Decrement Second',
2418
+ togglePeriod: 'Toggle Period',
2419
+ selectTime: 'Select Time'
2420
+ },
2421
+ useStrict: false,
2422
+ sideBySide: false,
2423
+ daysOfWeekDisabled: false,
2424
+ calendarWeeks: false,
2425
+ viewMode: 'days',
2426
+ toolbarPlacement: 'default',
2427
+ showTodayButton: false,
2428
+ showClear: false,
2429
+ showClose: false,
2430
+ widgetPositioning: {
2431
+ horizontal: 'auto',
2432
+ vertical: 'auto'
2433
+ },
2434
+ widgetParent: null,
2435
+ ignoreReadonly: false,
2436
+ keepOpen: false,
2437
+ focusOnShow: true,
2438
+ inline: false,
2439
+ keepInvalid: false,
2440
+ datepickerInput: '.datepickerinput',
2441
+ keyBinds: {
2442
+ up: function (widget) {
2443
+ if (!widget) {
2444
+ return;
2445
+ }
2446
+ var d = this.date() || this.getMoment();
2447
+ if (widget.find('.datepicker').is(':visible')) {
2448
+ this.date(d.clone().subtract(7, 'd'));
2449
+ } else {
2450
+ this.date(d.clone().add(this.stepping(), 'm'));
2451
+ }
2452
+ },
2453
+ down: function (widget) {
2454
+ if (!widget) {
2455
+ this.show();
2456
+ return;
2457
+ }
2458
+ var d = this.date() || this.getMoment();
2459
+ if (widget.find('.datepicker').is(':visible')) {
2460
+ this.date(d.clone().add(7, 'd'));
2461
+ } else {
2462
+ this.date(d.clone().subtract(this.stepping(), 'm'));
2463
+ }
2464
+ },
2465
+ 'control up': function (widget) {
2466
+ if (!widget) {
2467
+ return;
2468
+ }
2469
+ var d = this.date() || this.getMoment();
2470
+ if (widget.find('.datepicker').is(':visible')) {
2471
+ this.date(d.clone().subtract(1, 'y'));
2472
+ } else {
2473
+ this.date(d.clone().add(1, 'h'));
2474
+ }
2475
+ },
2476
+ 'control down': function (widget) {
2477
+ if (!widget) {
2478
+ return;
2479
+ }
2480
+ var d = this.date() || this.getMoment();
2481
+ if (widget.find('.datepicker').is(':visible')) {
2482
+ this.date(d.clone().add(1, 'y'));
2483
+ } else {
2484
+ this.date(d.clone().subtract(1, 'h'));
2485
+ }
2486
+ },
2487
+ left: function (widget) {
2488
+ if (!widget) {
2489
+ return;
2490
+ }
2491
+ var d = this.date() || this.getMoment();
2492
+ if (widget.find('.datepicker').is(':visible')) {
2493
+ this.date(d.clone().subtract(1, 'd'));
2494
+ }
2495
+ },
2496
+ right: function (widget) {
2497
+ if (!widget) {
2498
+ return;
2499
+ }
2500
+ var d = this.date() || this.getMoment();
2501
+ if (widget.find('.datepicker').is(':visible')) {
2502
+ this.date(d.clone().add(1, 'd'));
2503
+ }
2504
+ },
2505
+ pageUp: function (widget) {
2506
+ if (!widget) {
2507
+ return;
2508
+ }
2509
+ var d = this.date() || this.getMoment();
2510
+ if (widget.find('.datepicker').is(':visible')) {
2511
+ this.date(d.clone().subtract(1, 'M'));
2512
+ }
2513
+ },
2514
+ pageDown: function (widget) {
2515
+ if (!widget) {
2516
+ return;
2517
+ }
2518
+ var d = this.date() || this.getMoment();
2519
+ if (widget.find('.datepicker').is(':visible')) {
2520
+ this.date(d.clone().add(1, 'M'));
2521
+ }
2522
+ },
2523
+ enter: function () {
2524
+ this.hide();
2525
+ },
2526
+ escape: function () {
2527
+ this.hide();
2528
+ },
2529
+ //tab: function (widget) { //this break the flow of the form. disabling for now
2530
+ // var toggle = widget.find('.picker-switch a[data-action="togglePicker"]');
2531
+ // if(toggle.length > 0) toggle.click();
2532
+ //},
2533
+ 'control space': function (widget) {
2534
+ if (widget.find('.timepicker').is(':visible')) {
2535
+ widget.find('.btn[data-action="togglePeriod"]').click();
2536
+ }
2537
+ },
2538
+ t: function () {
2539
+ this.date(this.getMoment());
2540
+ },
2541
+ 'delete': function () {
2542
+ this.clear();
2543
+ }
2544
+ },
2545
+ debug: false,
2546
+ allowInputToggle: false,
2547
+ disabledTimeIntervals: false,
2548
+ disabledHours: false,
2549
+ enabledHours: false,
2550
+ viewDate: false
2551
+ };
2552
+
2553
+ $.fn.datepicker = function(args){
2554
+ args = args || {};
2555
+ if(!args["format"]) args["format"] = 'YYYY-MM-DD';
2556
+ $(this).datetimepicker(args);
2557
+ }
2558
+ }));