effective_bootstrap 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (335) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +93 -0
  4. data/app/assets/icons/activity.svg +13 -0
  5. data/app/assets/icons/airplay.svg +14 -0
  6. data/app/assets/icons/alert-circle.svg +15 -0
  7. data/app/assets/icons/alert-octagon.svg +15 -0
  8. data/app/assets/icons/alert-triangle.svg +15 -0
  9. data/app/assets/icons/align-center.svg +16 -0
  10. data/app/assets/icons/align-justify.svg +16 -0
  11. data/app/assets/icons/align-left.svg +16 -0
  12. data/app/assets/icons/align-right.svg +16 -0
  13. data/app/assets/icons/anchor.svg +15 -0
  14. data/app/assets/icons/aperture.svg +19 -0
  15. data/app/assets/icons/arrow-down-circle.svg +15 -0
  16. data/app/assets/icons/arrow-down-left.svg +14 -0
  17. data/app/assets/icons/arrow-down-right.svg +14 -0
  18. data/app/assets/icons/arrow-down.svg +14 -0
  19. data/app/assets/icons/arrow-left-circle.svg +15 -0
  20. data/app/assets/icons/arrow-left.svg +14 -0
  21. data/app/assets/icons/arrow-right-circle.svg +15 -0
  22. data/app/assets/icons/arrow-right.svg +14 -0
  23. data/app/assets/icons/arrow-up-circle.svg +15 -0
  24. data/app/assets/icons/arrow-up-left.svg +14 -0
  25. data/app/assets/icons/arrow-up-right.svg +14 -0
  26. data/app/assets/icons/arrow-up.svg +14 -0
  27. data/app/assets/icons/at-sign.svg +14 -0
  28. data/app/assets/icons/award.svg +14 -0
  29. data/app/assets/icons/bar-chart-2.svg +15 -0
  30. data/app/assets/icons/bar-chart.svg +15 -0
  31. data/app/assets/icons/battery-charging.svg +15 -0
  32. data/app/assets/icons/battery.svg +14 -0
  33. data/app/assets/icons/bell-off.svg +14 -0
  34. data/app/assets/icons/bell.svg +13 -0
  35. data/app/assets/icons/bluetooth.svg +13 -0
  36. data/app/assets/icons/bold.svg +14 -0
  37. data/app/assets/icons/book-open.svg +14 -0
  38. data/app/assets/icons/book.svg +14 -0
  39. data/app/assets/icons/bookmark.svg +13 -0
  40. data/app/assets/icons/box.svg +15 -0
  41. data/app/assets/icons/briefcase.svg +14 -0
  42. data/app/assets/icons/calendar.svg +16 -0
  43. data/app/assets/icons/camera-off.svg +14 -0
  44. data/app/assets/icons/camera.svg +14 -0
  45. data/app/assets/icons/cast.svg +14 -0
  46. data/app/assets/icons/check-circle.svg +14 -0
  47. data/app/assets/icons/check-square.svg +14 -0
  48. data/app/assets/icons/check.svg +13 -0
  49. data/app/assets/icons/chevron-down.svg +13 -0
  50. data/app/assets/icons/chevron-left.svg +13 -0
  51. data/app/assets/icons/chevron-right.svg +13 -0
  52. data/app/assets/icons/chevron-up.svg +13 -0
  53. data/app/assets/icons/chevrons-down.svg +14 -0
  54. data/app/assets/icons/chevrons-left.svg +14 -0
  55. data/app/assets/icons/chevrons-right.svg +14 -0
  56. data/app/assets/icons/chevrons-up.svg +14 -0
  57. data/app/assets/icons/chrome.svg +17 -0
  58. data/app/assets/icons/circle.svg +13 -0
  59. data/app/assets/icons/clipboard.svg +14 -0
  60. data/app/assets/icons/clock.svg +14 -0
  61. data/app/assets/icons/cloud-drizzle.svg +19 -0
  62. data/app/assets/icons/cloud-lightning.svg +14 -0
  63. data/app/assets/icons/cloud-off.svg +14 -0
  64. data/app/assets/icons/cloud-rain.svg +16 -0
  65. data/app/assets/icons/cloud-snow.svg +19 -0
  66. data/app/assets/icons/cloud.svg +13 -0
  67. data/app/assets/icons/code.svg +14 -0
  68. data/app/assets/icons/codepen.svg +17 -0
  69. data/app/assets/icons/command.svg +13 -0
  70. data/app/assets/icons/compass.svg +14 -0
  71. data/app/assets/icons/copy.svg +14 -0
  72. data/app/assets/icons/corner-down-left.svg +14 -0
  73. data/app/assets/icons/corner-down-right.svg +14 -0
  74. data/app/assets/icons/corner-left-down.svg +14 -0
  75. data/app/assets/icons/corner-left-up.svg +14 -0
  76. data/app/assets/icons/corner-right-down.svg +14 -0
  77. data/app/assets/icons/corner-right-up.svg +14 -0
  78. data/app/assets/icons/corner-up-left.svg +14 -0
  79. data/app/assets/icons/corner-up-right.svg +14 -0
  80. data/app/assets/icons/cpu.svg +22 -0
  81. data/app/assets/icons/credit-card.svg +14 -0
  82. data/app/assets/icons/crop.svg +14 -0
  83. data/app/assets/icons/crosshair.svg +17 -0
  84. data/app/assets/icons/database.svg +15 -0
  85. data/app/assets/icons/delete.svg +15 -0
  86. data/app/assets/icons/disc.svg +14 -0
  87. data/app/assets/icons/dollar-sign.svg +14 -0
  88. data/app/assets/icons/download-cloud.svg +15 -0
  89. data/app/assets/icons/download.svg +15 -0
  90. data/app/assets/icons/droplet.svg +13 -0
  91. data/app/assets/icons/edit-2.svg +13 -0
  92. data/app/assets/icons/edit-3.svg +14 -0
  93. data/app/assets/icons/edit.svg +14 -0
  94. data/app/assets/icons/external-link.svg +15 -0
  95. data/app/assets/icons/eye-off.svg +14 -0
  96. data/app/assets/icons/eye.svg +14 -0
  97. data/app/assets/icons/facebook.svg +13 -0
  98. data/app/assets/icons/fast-forward.svg +14 -0
  99. data/app/assets/icons/feather.svg +15 -0
  100. data/app/assets/icons/file-minus.svg +15 -0
  101. data/app/assets/icons/file-plus.svg +16 -0
  102. data/app/assets/icons/file-text.svg +17 -0
  103. data/app/assets/icons/file.svg +14 -0
  104. data/app/assets/icons/film.svg +20 -0
  105. data/app/assets/icons/filter.svg +13 -0
  106. data/app/assets/icons/flag.svg +14 -0
  107. data/app/assets/icons/folder-minus.svg +14 -0
  108. data/app/assets/icons/folder-plus.svg +15 -0
  109. data/app/assets/icons/folder.svg +13 -0
  110. data/app/assets/icons/git-branch.svg +16 -0
  111. data/app/assets/icons/git-commit.svg +15 -0
  112. data/app/assets/icons/git-merge.svg +15 -0
  113. data/app/assets/icons/git-pull-request.svg +16 -0
  114. data/app/assets/icons/github.svg +13 -0
  115. data/app/assets/icons/gitlab.svg +13 -0
  116. data/app/assets/icons/globe.svg +15 -0
  117. data/app/assets/icons/grid.svg +16 -0
  118. data/app/assets/icons/hard-drive.svg +16 -0
  119. data/app/assets/icons/hash.svg +16 -0
  120. data/app/assets/icons/headphones.svg +14 -0
  121. data/app/assets/icons/heart.svg +13 -0
  122. data/app/assets/icons/help-circle.svg +15 -0
  123. data/app/assets/icons/home.svg +14 -0
  124. data/app/assets/icons/image.svg +15 -0
  125. data/app/assets/icons/inbox.svg +14 -0
  126. data/app/assets/icons/info.svg +15 -0
  127. data/app/assets/icons/instagram.svg +15 -0
  128. data/app/assets/icons/italic.svg +15 -0
  129. data/app/assets/icons/layers.svg +15 -0
  130. data/app/assets/icons/layout.svg +15 -0
  131. data/app/assets/icons/life-buoy.svg +19 -0
  132. data/app/assets/icons/link-2.svg +14 -0
  133. data/app/assets/icons/link.svg +14 -0
  134. data/app/assets/icons/linkedin.svg +15 -0
  135. data/app/assets/icons/list.svg +18 -0
  136. data/app/assets/icons/loader.svg +20 -0
  137. data/app/assets/icons/lock.svg +14 -0
  138. data/app/assets/icons/log-in.svg +15 -0
  139. data/app/assets/icons/log-out.svg +15 -0
  140. data/app/assets/icons/mail.svg +14 -0
  141. data/app/assets/icons/map-pin.svg +14 -0
  142. data/app/assets/icons/map.svg +15 -0
  143. data/app/assets/icons/maximize-2.svg +16 -0
  144. data/app/assets/icons/maximize.svg +13 -0
  145. data/app/assets/icons/menu.svg +15 -0
  146. data/app/assets/icons/message-circle.svg +13 -0
  147. data/app/assets/icons/message-square.svg +13 -0
  148. data/app/assets/icons/mic-off.svg +17 -0
  149. data/app/assets/icons/mic.svg +16 -0
  150. data/app/assets/icons/minimize-2.svg +16 -0
  151. data/app/assets/icons/minimize.svg +13 -0
  152. data/app/assets/icons/minus-circle.svg +14 -0
  153. data/app/assets/icons/minus-square.svg +14 -0
  154. data/app/assets/icons/minus.svg +13 -0
  155. data/app/assets/icons/monitor.svg +15 -0
  156. data/app/assets/icons/moon.svg +13 -0
  157. data/app/assets/icons/more-horizontal.svg +15 -0
  158. data/app/assets/icons/more-vertical.svg +15 -0
  159. data/app/assets/icons/move.svg +18 -0
  160. data/app/assets/icons/music.svg +14 -0
  161. data/app/assets/icons/navigation-2.svg +13 -0
  162. data/app/assets/icons/navigation.svg +13 -0
  163. data/app/assets/icons/octagon.svg +13 -0
  164. data/app/assets/icons/package.svg +16 -0
  165. data/app/assets/icons/paperclip.svg +13 -0
  166. data/app/assets/icons/pause-circle.svg +15 -0
  167. data/app/assets/icons/pause.svg +14 -0
  168. data/app/assets/icons/percent.svg +15 -0
  169. data/app/assets/icons/phone-call.svg +13 -0
  170. data/app/assets/icons/phone-forwarded.svg +15 -0
  171. data/app/assets/icons/phone-incoming.svg +15 -0
  172. data/app/assets/icons/phone-missed.svg +15 -0
  173. data/app/assets/icons/phone-off.svg +14 -0
  174. data/app/assets/icons/phone-outgoing.svg +15 -0
  175. data/app/assets/icons/phone.svg +13 -0
  176. data/app/assets/icons/pie-chart.svg +14 -0
  177. data/app/assets/icons/play-circle.svg +14 -0
  178. data/app/assets/icons/play.svg +13 -0
  179. data/app/assets/icons/plus-circle.svg +15 -0
  180. data/app/assets/icons/plus-square.svg +15 -0
  181. data/app/assets/icons/plus.svg +14 -0
  182. data/app/assets/icons/pocket.svg +14 -0
  183. data/app/assets/icons/power.svg +14 -0
  184. data/app/assets/icons/printer.svg +15 -0
  185. data/app/assets/icons/radio.svg +14 -0
  186. data/app/assets/icons/refresh-ccw.svg +15 -0
  187. data/app/assets/icons/refresh-cw.svg +15 -0
  188. data/app/assets/icons/repeat.svg +16 -0
  189. data/app/assets/icons/rewind.svg +14 -0
  190. data/app/assets/icons/rotate-ccw.svg +14 -0
  191. data/app/assets/icons/rotate-cw.svg +14 -0
  192. data/app/assets/icons/rss.svg +15 -0
  193. data/app/assets/icons/save.svg +15 -0
  194. data/app/assets/icons/scissors.svg +17 -0
  195. data/app/assets/icons/search.svg +14 -0
  196. data/app/assets/icons/send.svg +14 -0
  197. data/app/assets/icons/server.svg +16 -0
  198. data/app/assets/icons/settings.svg +14 -0
  199. data/app/assets/icons/share-2.svg +17 -0
  200. data/app/assets/icons/share.svg +15 -0
  201. data/app/assets/icons/shield-off.svg +15 -0
  202. data/app/assets/icons/shield.svg +13 -0
  203. data/app/assets/icons/shopping-bag.svg +15 -0
  204. data/app/assets/icons/shopping-cart.svg +15 -0
  205. data/app/assets/icons/shuffle.svg +17 -0
  206. data/app/assets/icons/sidebar.svg +14 -0
  207. data/app/assets/icons/skip-back.svg +14 -0
  208. data/app/assets/icons/skip-forward.svg +14 -0
  209. data/app/assets/icons/slack.svg +17 -0
  210. data/app/assets/icons/slash.svg +14 -0
  211. data/app/assets/icons/sliders.svg +21 -0
  212. data/app/assets/icons/smartphone.svg +14 -0
  213. data/app/assets/icons/speaker.svg +15 -0
  214. data/app/assets/icons/spinner.svg +1 -0
  215. data/app/assets/icons/square.svg +13 -0
  216. data/app/assets/icons/star.svg +13 -0
  217. data/app/assets/icons/stop-circle.svg +14 -0
  218. data/app/assets/icons/sun.svg +21 -0
  219. data/app/assets/icons/sunrise.svg +20 -0
  220. data/app/assets/icons/sunset.svg +20 -0
  221. data/app/assets/icons/tablet.svg +22 -0
  222. data/app/assets/icons/tag.svg +14 -0
  223. data/app/assets/icons/target.svg +15 -0
  224. data/app/assets/icons/terminal.svg +14 -0
  225. data/app/assets/icons/thermometer.svg +13 -0
  226. data/app/assets/icons/thumbs-down.svg +13 -0
  227. data/app/assets/icons/thumbs-up.svg +13 -0
  228. data/app/assets/icons/toggle-left.svg +14 -0
  229. data/app/assets/icons/toggle-right.svg +14 -0
  230. data/app/assets/icons/trash-2.svg +16 -0
  231. data/app/assets/icons/trash.svg +14 -0
  232. data/app/assets/icons/trending-down.svg +14 -0
  233. data/app/assets/icons/trending-up.svg +14 -0
  234. data/app/assets/icons/triangle.svg +13 -0
  235. data/app/assets/icons/truck.svg +16 -0
  236. data/app/assets/icons/tv.svg +14 -0
  237. data/app/assets/icons/twitter.svg +13 -0
  238. data/app/assets/icons/type.svg +15 -0
  239. data/app/assets/icons/umbrella.svg +13 -0
  240. data/app/assets/icons/underline.svg +14 -0
  241. data/app/assets/icons/unlock.svg +14 -0
  242. data/app/assets/icons/upload-cloud.svg +16 -0
  243. data/app/assets/icons/upload.svg +15 -0
  244. data/app/assets/icons/user-check.svg +15 -0
  245. data/app/assets/icons/user-minus.svg +15 -0
  246. data/app/assets/icons/user-plus.svg +16 -0
  247. data/app/assets/icons/user-x.svg +16 -0
  248. data/app/assets/icons/user.svg +14 -0
  249. data/app/assets/icons/users.svg +16 -0
  250. data/app/assets/icons/video-off.svg +14 -0
  251. data/app/assets/icons/video.svg +14 -0
  252. data/app/assets/icons/voicemail.svg +15 -0
  253. data/app/assets/icons/volume-1.svg +14 -0
  254. data/app/assets/icons/volume-2.svg +14 -0
  255. data/app/assets/icons/volume-x.svg +15 -0
  256. data/app/assets/icons/volume.svg +13 -0
  257. data/app/assets/icons/watch.svg +15 -0
  258. data/app/assets/icons/wifi-off.svg +19 -0
  259. data/app/assets/icons/wifi.svg +16 -0
  260. data/app/assets/icons/wind.svg +13 -0
  261. data/app/assets/icons/x-circle.svg +15 -0
  262. data/app/assets/icons/x-square.svg +15 -0
  263. data/app/assets/icons/x.svg +14 -0
  264. data/app/assets/icons/zap-off.svg +16 -0
  265. data/app/assets/icons/zap.svg +13 -0
  266. data/app/assets/icons/zoom-in.svg +16 -0
  267. data/app/assets/icons/zoom-out.svg +15 -0
  268. data/app/assets/javascripts/effective_bootstrap.js +9 -0
  269. data/app/assets/javascripts/effective_bootstrap/base.js.coffee +37 -0
  270. data/app/assets/javascripts/effective_date/initialize.js.coffee +4 -0
  271. data/app/assets/javascripts/effective_date/input.js +5 -0
  272. data/app/assets/javascripts/effective_datetime/bootstrap-datetimepicker.js +2637 -0
  273. data/app/assets/javascripts/effective_datetime/initialize.js.coffee +4 -0
  274. data/app/assets/javascripts/effective_datetime/input.js +5 -0
  275. data/app/assets/javascripts/effective_datetime/moment.js +4535 -0
  276. data/app/assets/javascripts/effective_datetime/overrides.js.coffee +38 -0
  277. data/app/assets/javascripts/effective_datetime/turbolinks.js.coffee +5 -0
  278. data/app/assets/javascripts/effective_phone/initialize.js.coffee +4 -0
  279. data/app/assets/javascripts/effective_phone/input.js +2 -0
  280. data/app/assets/javascripts/effective_phone/jquery.maskedInput.js +182 -0
  281. data/app/assets/javascripts/effective_price/input.js.coffee +34 -0
  282. data/app/assets/javascripts/effective_select/initialize.js.coffee +45 -0
  283. data/app/assets/javascripts/effective_select/input.js +3 -0
  284. data/app/assets/javascripts/effective_select/overrides.js.coffee +45 -0
  285. data/app/assets/javascripts/effective_select/select2.js +5746 -0
  286. data/app/assets/javascripts/effective_time/initialize.js.coffee +4 -0
  287. data/app/assets/javascripts/effective_time/input.js +5 -0
  288. data/app/assets/stylesheets/effective_bootstrap.scss +8 -0
  289. data/app/assets/stylesheets/effective_bootstrap/base.scss +11 -0
  290. data/app/assets/stylesheets/effective_bootstrap/icons.scss +27 -0
  291. data/app/assets/stylesheets/effective_date/input.scss +1 -0
  292. data/app/assets/stylesheets/effective_datetime/bootstrap-datetimepicker.scss +374 -0
  293. data/app/assets/stylesheets/effective_datetime/input.scss +2 -0
  294. data/app/assets/stylesheets/effective_datetime/overrides.scss +28 -0
  295. data/app/assets/stylesheets/effective_select/bootstrap-theme.css +564 -0
  296. data/app/assets/stylesheets/effective_select/input.scss +3 -0
  297. data/app/assets/stylesheets/effective_select/overrides.scss +92 -0
  298. data/app/assets/stylesheets/effective_select/select2.css +484 -0
  299. data/app/assets/stylesheets/effective_time/input.scss +1 -0
  300. data/app/helpers/effective_bootstrap_helper.rb +52 -0
  301. data/app/helpers/effective_form_builder_helper.rb +23 -0
  302. data/app/helpers/effective_icons_helper.rb +46 -0
  303. data/app/models/effective/access_denied.rb +17 -0
  304. data/app/models/effective/form_builder.rb +100 -0
  305. data/app/models/effective/form_input.rb +319 -0
  306. data/app/models/effective/form_inputs/check_box.rb +62 -0
  307. data/app/models/effective/form_inputs/checks.rb +73 -0
  308. data/app/models/effective/form_inputs/collection_input.rb +144 -0
  309. data/app/models/effective/form_inputs/date_field.rb +22 -0
  310. data/app/models/effective/form_inputs/datetime_field.rb +53 -0
  311. data/app/models/effective/form_inputs/email_field.rb +15 -0
  312. data/app/models/effective/form_inputs/error_field.rb +47 -0
  313. data/app/models/effective/form_inputs/form_group.rb +26 -0
  314. data/app/models/effective/form_inputs/number_field.rb +6 -0
  315. data/app/models/effective/form_inputs/password_field.rb +24 -0
  316. data/app/models/effective/form_inputs/phone_field.rb +34 -0
  317. data/app/models/effective/form_inputs/price_field.rb +37 -0
  318. data/app/models/effective/form_inputs/radios.rb +74 -0
  319. data/app/models/effective/form_inputs/select.rb +87 -0
  320. data/app/models/effective/form_inputs/static_field.rb +20 -0
  321. data/app/models/effective/form_inputs/submit.rb +42 -0
  322. data/app/models/effective/form_inputs/text_area.rb +11 -0
  323. data/app/models/effective/form_inputs/text_field.rb +6 -0
  324. data/app/models/effective/form_inputs/time_field.rb +22 -0
  325. data/app/models/effective/form_inputs/url_field.rb +15 -0
  326. data/app/views/effective/style_guide/__fields.html.haml +42 -0
  327. data/app/views/effective/style_guide/__inline_fields.html.haml +4 -0
  328. data/app/views/effective/style_guide/_effective_form_with.html.haml +23 -0
  329. data/app/views/effective/style_guide/_feather_icons.html.haml +9 -0
  330. data/config/effective_bootstrap.rb +24 -0
  331. data/lib/effective_bootstrap.rb +31 -0
  332. data/lib/effective_bootstrap/engine.rb +11 -0
  333. data/lib/effective_bootstrap/version.rb +3 -0
  334. data/lib/generators/effective_bootstrap/install_generator.rb +14 -0
  335. metadata +419 -0
@@ -0,0 +1,15 @@
1
+ <svg
2
+ xmlns="http://www.w3.org/2000/svg"
3
+ width="24"
4
+ height="24"
5
+ viewBox="0 0 24 24"
6
+ fill="none"
7
+ stroke="currentColor"
8
+ stroke-width="2"
9
+ stroke-linecap="round"
10
+ stroke-linejoin="round"
11
+ >
12
+ <circle cx="11" cy="11" r="8" />
13
+ <line x1="21" y1="21" x2="16.65" y2="16.65" />
14
+ <line x1="8" y1="11" x2="14" y2="11" />
15
+ </svg>
@@ -0,0 +1,9 @@
1
+ //= require ./effective_bootstrap/base
2
+
3
+ //= require ./effective_datetime/input
4
+ //= require ./effective_date/input
5
+ //= require ./effective_time/input
6
+
7
+ //= require ./effective_phone/input
8
+ //= require ./effective_price/input
9
+ //= require ./effective_select/input
@@ -0,0 +1,37 @@
1
+ this.EffectiveBootstrap ||= new class
2
+ initialize: (target) ->
3
+ $(target || document).find('[data-input-js-options]:not(.initialized)').each (i, element) ->
4
+ $element = $(element)
5
+ options = $element.data('input-js-options')
6
+
7
+ method_name = options['method_name']
8
+ delete options['method_name']
9
+
10
+ unless EffectiveBootstrap[method_name]
11
+ return console.error("EffectiveBootstrap #{method_name} has not been implemented")
12
+
13
+ EffectiveBootstrap[method_name].call(this, $element, options)
14
+ $element.addClass('initialized')
15
+
16
+ validate: (form) ->
17
+ $form = $(form)
18
+
19
+ # Clear any server side validation on individual inputs
20
+ $form.find('.alert.is-invalid').remove()
21
+ $form.find('.is-invalid').removeClass('is-invalid')
22
+ $form.find('.is-valid').removeClass('is-valid')
23
+
24
+ valid = form.checkValidity()
25
+
26
+ if valid
27
+ $form.addClass('form-is-valid').removeClass('form-is-invalid')
28
+ else
29
+ $form.addClass('was-validated').addClass('form-is-invalid').removeClass('form-is-valid')
30
+
31
+ valid
32
+
33
+ $ -> EffectiveBootstrap.initialize()
34
+ $(document).on 'turbolinks:load', -> EffectiveBootstrap.initialize()
35
+ $(document).on 'cocoon:after-insert', -> EffectiveBootstrap.initialize()
36
+ $(document).on 'effective-bootstrap:initialize', (event) -> EffectiveBootstrap.initialize(event.currentTarget)
37
+
@@ -0,0 +1,4 @@
1
+ # http://eonasdan.github.io/bootstrap-datetimepicker/Options/
2
+ (this.EffectiveBootstrap || {}).effective_date = ($element, options) ->
3
+ $element.datetimepicker(options)
4
+ $element.trigger('dp.end_date_initialized') if ($element.attr('name') || '').indexOf('[end_') != -1
@@ -0,0 +1,5 @@
1
+ //= require ../effective_datetime/moment
2
+ //= require ../effective_datetime/bootstrap-datetimepicker
3
+ //= require ../effective_datetime/overrides
4
+ //= require ../effective_datetime/turbolinks
5
+ //= require ./initialize
@@ -0,0 +1,2637 @@
1
+ /*! version : 4.17.45
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
+ module.exports = 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';
47
+ }
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
+
136
+ hasTimeZone = function () {
137
+ return moment.tz !== undefined && options.timeZone !== undefined && options.timeZone !== null && options.timeZone !== '';
138
+ },
139
+
140
+ getMoment = function (d) {
141
+ var returnMoment;
142
+
143
+ if (d === undefined || d === null) {
144
+ returnMoment = moment(); //TODO should this use format? and locale?
145
+ } else if (moment.isDate(d) || moment.isMoment(d)) {
146
+ // If the date that is passed in is already a Date() or moment() object,
147
+ // pass it directly to moment.
148
+ returnMoment = moment(d);
149
+ } else if (hasTimeZone()) { // There is a string to parse and a default time zone
150
+ // parse with the tz function which takes a default time zone if it is not in the format string
151
+ returnMoment = moment.tz(d, parseFormats, options.useStrict, options.timeZone);
152
+ } else {
153
+ returnMoment = moment(d, parseFormats, options.useStrict);
154
+ }
155
+
156
+ if (hasTimeZone()) {
157
+ returnMoment.tz(options.timeZone);
158
+ }
159
+
160
+ return returnMoment;
161
+ },
162
+
163
+ isEnabled = function (granularity) {
164
+ if (typeof granularity !== 'string' || granularity.length > 1) {
165
+ throw new TypeError('isEnabled expects a single character string parameter');
166
+ }
167
+ switch (granularity) {
168
+ case 'y':
169
+ return actualFormat.indexOf('Y') !== -1;
170
+ case 'M':
171
+ return actualFormat.indexOf('M') !== -1;
172
+ case 'd':
173
+ return actualFormat.toLowerCase().indexOf('d') !== -1;
174
+ case 'h':
175
+ case 'H':
176
+ return actualFormat.toLowerCase().indexOf('h') !== -1;
177
+ case 'm':
178
+ return actualFormat.indexOf('m') !== -1;
179
+ case 's':
180
+ return actualFormat.indexOf('s') !== -1;
181
+ default:
182
+ return false;
183
+ }
184
+ },
185
+
186
+ hasTime = function () {
187
+ return (isEnabled('h') || isEnabled('m') || isEnabled('s'));
188
+ },
189
+
190
+ hasDate = function () {
191
+ return (isEnabled('y') || isEnabled('M') || isEnabled('d'));
192
+ },
193
+
194
+ getDatePickerTemplate = function () {
195
+ var headTemplate = $('<thead>')
196
+ .append($('<tr>')
197
+ .append($('<th>').addClass('prev').attr('data-action', 'previous')
198
+ .append($('<span>').addClass(options.icons.previous))
199
+ )
200
+ .append($('<th>').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5')))
201
+ .append($('<th>').addClass('next').attr('data-action', 'next')
202
+ .append($('<span>').addClass(options.icons.next))
203
+ )
204
+ ),
205
+ contTemplate = $('<tbody>')
206
+ .append($('<tr>')
207
+ .append($('<td>').attr('colspan', (options.calendarWeeks ? '8' : '7')))
208
+ );
209
+
210
+ return [
211
+ $('<div>').addClass('datepicker-days')
212
+ .append($('<table>').addClass('table-condensed')
213
+ .append(headTemplate)
214
+ .append($('<tbody>'))
215
+ ),
216
+ $('<div>').addClass('datepicker-months')
217
+ .append($('<table>').addClass('table-condensed')
218
+ .append(headTemplate.clone())
219
+ .append(contTemplate.clone())
220
+ ),
221
+ $('<div>').addClass('datepicker-years')
222
+ .append($('<table>').addClass('table-condensed')
223
+ .append(headTemplate.clone())
224
+ .append(contTemplate.clone())
225
+ ),
226
+ $('<div>').addClass('datepicker-decades')
227
+ .append($('<table>').addClass('table-condensed')
228
+ .append(headTemplate.clone())
229
+ .append(contTemplate.clone())
230
+ )
231
+ ];
232
+ },
233
+
234
+ getTimePickerMainTemplate = function () {
235
+ var topRow = $('<tr>'),
236
+ middleRow = $('<tr>'),
237
+ bottomRow = $('<tr>');
238
+
239
+ if (isEnabled('h')) {
240
+ topRow.append($('<td>')
241
+ .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementHour }).addClass('btn').attr('data-action', 'incrementHours').append($('<span>').addClass(options.icons.up))));
242
+ middleRow.append($('<td>')
243
+ .append($('<span>').addClass('timepicker-hour').attr({ 'data-time-component': 'hours', 'title': options.tooltips.pickHour }).attr('data-action', 'showHours')));
244
+ bottomRow.append($('<td>')
245
+ .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementHour }).addClass('btn').attr('data-action', 'decrementHours').append($('<span>').addClass(options.icons.down))));
246
+ }
247
+ if (isEnabled('m')) {
248
+ if (isEnabled('h')) {
249
+ topRow.append($('<td>').addClass('separator'));
250
+ middleRow.append($('<td>').addClass('separator').html(':'));
251
+ bottomRow.append($('<td>').addClass('separator'));
252
+ }
253
+ topRow.append($('<td>')
254
+ .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementMinute }).addClass('btn').attr('data-action', 'incrementMinutes')
255
+ .append($('<span>').addClass(options.icons.up))));
256
+ middleRow.append($('<td>')
257
+ .append($('<span>').addClass('timepicker-minute').attr({ 'data-time-component': 'minutes', 'title': options.tooltips.pickMinute }).attr('data-action', 'showMinutes')));
258
+ bottomRow.append($('<td>')
259
+ .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementMinute }).addClass('btn').attr('data-action', 'decrementMinutes')
260
+ .append($('<span>').addClass(options.icons.down))));
261
+ }
262
+ if (isEnabled('s')) {
263
+ if (isEnabled('m')) {
264
+ topRow.append($('<td>').addClass('separator'));
265
+ middleRow.append($('<td>').addClass('separator').html(':'));
266
+ bottomRow.append($('<td>').addClass('separator'));
267
+ }
268
+ topRow.append($('<td>')
269
+ .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.incrementSecond }).addClass('btn').attr('data-action', 'incrementSeconds')
270
+ .append($('<span>').addClass(options.icons.up))));
271
+ middleRow.append($('<td>')
272
+ .append($('<span>').addClass('timepicker-second').attr({ 'data-time-component': 'seconds', 'title': options.tooltips.pickSecond }).attr('data-action', 'showSeconds')));
273
+ bottomRow.append($('<td>')
274
+ .append($('<a>').attr({ href: '#', tabindex: '-1', 'title': options.tooltips.decrementSecond }).addClass('btn').attr('data-action', 'decrementSeconds')
275
+ .append($('<span>').addClass(options.icons.down))));
276
+ }
277
+
278
+ if (!use24Hours) {
279
+ topRow.append($('<td>').addClass('separator'));
280
+ middleRow.append($('<td>')
281
+ .append($('<button>').addClass('btn btn-primary').attr({ 'data-action': 'togglePeriod', tabindex: '-1', 'title': options.tooltips.togglePeriod })));
282
+ bottomRow.append($('<td>').addClass('separator'));
283
+ }
284
+
285
+ return $('<div>').addClass('timepicker-picker')
286
+ .append($('<table>').addClass('table-condensed')
287
+ .append([topRow, middleRow, bottomRow]));
288
+ },
289
+
290
+ getTimePickerTemplate = function () {
291
+ var hoursView = $('<div>').addClass('timepicker-hours')
292
+ .append($('<table>').addClass('table-condensed')),
293
+ minutesView = $('<div>').addClass('timepicker-minutes')
294
+ .append($('<table>').addClass('table-condensed')),
295
+ secondsView = $('<div>').addClass('timepicker-seconds')
296
+ .append($('<table>').addClass('table-condensed')),
297
+ ret = [getTimePickerMainTemplate()];
298
+
299
+ if (isEnabled('h')) {
300
+ ret.push(hoursView);
301
+ }
302
+ if (isEnabled('m')) {
303
+ ret.push(minutesView);
304
+ }
305
+ if (isEnabled('s')) {
306
+ ret.push(secondsView);
307
+ }
308
+
309
+ return ret;
310
+ },
311
+
312
+ getToolbar = function () {
313
+ var row = [];
314
+ if (options.showTodayButton) {
315
+ row.push($('<td>').append($('<a>').attr({ 'data-action': 'today', 'title': options.tooltips.today }).append($('<span>').addClass(options.icons.today))));
316
+ }
317
+ if (!options.sideBySide && hasDate() && hasTime()) {
318
+ row.push($('<td>').append($('<a>').attr({ 'data-action': 'togglePicker', 'title': options.tooltips.selectTime }).append($('<span>').addClass(options.icons.time))));
319
+ }
320
+ if (options.showClear) {
321
+ row.push($('<td>').append($('<a>').attr({ 'data-action': 'clear', 'title': options.tooltips.clear }).append($('<span>').addClass(options.icons.clear))));
322
+ }
323
+ if (options.showClose) {
324
+ row.push($('<td>').append($('<a>').attr({ 'data-action': 'close', 'title': options.tooltips.close }).append($('<span>').addClass(options.icons.close))));
325
+ }
326
+ return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row)));
327
+ },
328
+
329
+ getTemplate = function () {
330
+ var template = $('<div>').addClass('bootstrap-datetimepicker-widget dropdown-menu'),
331
+ dateView = $('<div>').addClass('datepicker').append(getDatePickerTemplate()),
332
+ timeView = $('<div>').addClass('timepicker').append(getTimePickerTemplate()),
333
+ content = $('<ul>').addClass('list-unstyled'),
334
+ toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar());
335
+
336
+ if (options.inline) {
337
+ template.removeClass('dropdown-menu');
338
+ }
339
+
340
+ if (use24Hours) {
341
+ template.addClass('usetwentyfour');
342
+ }
343
+
344
+ if (isEnabled('s') && !use24Hours) {
345
+ template.addClass('wider');
346
+ }
347
+
348
+ if (options.sideBySide && hasDate() && hasTime()) {
349
+ template.addClass('timepicker-sbs');
350
+ if (options.toolbarPlacement === 'top') {
351
+ template.append(toolbar);
352
+ }
353
+ template.append(
354
+ $('<div>').addClass('row')
355
+ .append(dateView.addClass('col-md-6'))
356
+ .append(timeView.addClass('col-md-6'))
357
+ );
358
+ if (options.toolbarPlacement === 'bottom') {
359
+ template.append(toolbar);
360
+ }
361
+ return template;
362
+ }
363
+
364
+ if (options.toolbarPlacement === 'top') {
365
+ content.append(toolbar);
366
+ }
367
+ if (hasDate()) {
368
+ content.append($('<li>').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView));
369
+ }
370
+ if (options.toolbarPlacement === 'default') {
371
+ content.append(toolbar);
372
+ }
373
+ if (hasTime()) {
374
+ content.append($('<li>').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView));
375
+ }
376
+ if (options.toolbarPlacement === 'bottom') {
377
+ content.append(toolbar);
378
+ }
379
+ return template.append(content);
380
+ },
381
+
382
+ dataToOptions = function () {
383
+ var eData,
384
+ dataOptions = {};
385
+
386
+ if (element.is('input') || options.inline) {
387
+ eData = element.data();
388
+ } else {
389
+ eData = element.find('input').data();
390
+ }
391
+
392
+ if (eData.dateOptions && eData.dateOptions instanceof Object) {
393
+ dataOptions = $.extend(true, dataOptions, eData.dateOptions);
394
+ }
395
+
396
+ $.each(options, function (key) {
397
+ var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1);
398
+ if (eData[attributeName] !== undefined) {
399
+ dataOptions[key] = eData[attributeName];
400
+ }
401
+ });
402
+ return dataOptions;
403
+ },
404
+
405
+ place = function () {
406
+ var position = (component || element).position(),
407
+ offset = (component || element).offset(),
408
+ vertical = options.widgetPositioning.vertical,
409
+ horizontal = options.widgetPositioning.horizontal,
410
+ parent;
411
+
412
+ if (options.widgetParent) {
413
+ parent = options.widgetParent.append(widget);
414
+ } else if (element.is('input')) {
415
+ parent = element.after(widget).parent();
416
+ } else if (options.inline) {
417
+ parent = element.append(widget);
418
+ return;
419
+ } else {
420
+ parent = element;
421
+ element.children().first().after(widget);
422
+ }
423
+
424
+ // Top and bottom logic
425
+ if (vertical === 'auto') {
426
+ if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() &&
427
+ widget.height() + element.outerHeight() < offset.top) {
428
+ vertical = 'top';
429
+ } else {
430
+ vertical = 'bottom';
431
+ }
432
+ }
433
+
434
+ // Left and right logic
435
+ if (horizontal === 'auto') {
436
+ if (parent.width() < offset.left + widget.outerWidth() / 2 &&
437
+ offset.left + widget.outerWidth() > $(window).width()) {
438
+ horizontal = 'right';
439
+ } else {
440
+ horizontal = 'left';
441
+ }
442
+ }
443
+
444
+ if (vertical === 'top') {
445
+ widget.addClass('top').removeClass('bottom');
446
+ } else {
447
+ widget.addClass('bottom').removeClass('top');
448
+ }
449
+
450
+ if (horizontal === 'right') {
451
+ widget.addClass('pull-right');
452
+ } else {
453
+ widget.removeClass('pull-right');
454
+ }
455
+
456
+ // find the first parent element that has a non-static css positioning
457
+ if (parent.css('position') === 'static') {
458
+ parent = parent.parents().filter(function () {
459
+ return $(this).css('position') !== 'static';
460
+ }).first();
461
+ }
462
+
463
+ if (parent.length === 0) {
464
+ throw new Error('datetimepicker component should be placed within a non-static positioned container');
465
+ }
466
+
467
+ widget.css({
468
+ top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(),
469
+ bottom: vertical === 'top' ? parent.outerHeight() - (parent === element ? 0 : position.top) : 'auto',
470
+ left: horizontal === 'left' ? (parent === element ? 0 : position.left) : 'auto',
471
+ right: horizontal === 'left' ? 'auto' : parent.outerWidth() - element.outerWidth() - (parent === element ? 0 : position.left)
472
+ });
473
+ },
474
+
475
+ notifyEvent = function (e) {
476
+ if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) {
477
+ return;
478
+ }
479
+ element.trigger(e);
480
+ },
481
+
482
+ viewUpdate = function (e) {
483
+ if (e === 'y') {
484
+ e = 'YYYY';
485
+ }
486
+ notifyEvent({
487
+ type: 'dp.update',
488
+ change: e,
489
+ viewDate: viewDate.clone()
490
+ });
491
+ },
492
+
493
+ showMode = function (dir) {
494
+ if (!widget) {
495
+ return;
496
+ }
497
+ if (dir) {
498
+ currentViewMode = Math.max(minViewModeNumber, Math.min(3, currentViewMode + dir));
499
+ }
500
+ widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show();
501
+ },
502
+
503
+ fillDow = function () {
504
+ var row = $('<tr>'),
505
+ currentDate = viewDate.clone().startOf('w').startOf('d');
506
+
507
+ if (options.calendarWeeks === true) {
508
+ row.append($('<th>').addClass('cw').text('#'));
509
+ }
510
+
511
+ while (currentDate.isBefore(viewDate.clone().endOf('w'))) {
512
+ row.append($('<th>').addClass('dow').text(currentDate.format('dd')));
513
+ currentDate.add(1, 'd');
514
+ }
515
+ widget.find('.datepicker-days thead').append(row);
516
+ },
517
+
518
+ isInDisabledDates = function (testDate) {
519
+ return options.disabledDates[testDate.format('YYYY-MM-DD')] === true;
520
+ },
521
+
522
+ isInEnabledDates = function (testDate) {
523
+ return options.enabledDates[testDate.format('YYYY-MM-DD')] === true;
524
+ },
525
+
526
+ isInDisabledHours = function (testDate) {
527
+ return options.disabledHours[testDate.format('H')] === true;
528
+ },
529
+
530
+ isInEnabledHours = function (testDate) {
531
+ return options.enabledHours[testDate.format('H')] === true;
532
+ },
533
+
534
+ isValid = function (targetMoment, granularity) {
535
+ if (!targetMoment.isValid()) {
536
+ return false;
537
+ }
538
+ if (options.disabledDates && granularity === 'd' && isInDisabledDates(targetMoment)) {
539
+ return false;
540
+ }
541
+ if (options.enabledDates && granularity === 'd' && !isInEnabledDates(targetMoment)) {
542
+ return false;
543
+ }
544
+ if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) {
545
+ return false;
546
+ }
547
+ if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) {
548
+ return false;
549
+ }
550
+ if (options.daysOfWeekDisabled && granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
551
+ return false;
552
+ }
553
+ if (options.disabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && isInDisabledHours(targetMoment)) {
554
+ return false;
555
+ }
556
+ if (options.enabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && !isInEnabledHours(targetMoment)) {
557
+ return false;
558
+ }
559
+ if (options.disabledTimeIntervals && (granularity === 'h' || granularity === 'm' || granularity === 's')) {
560
+ var found = false;
561
+ $.each(options.disabledTimeIntervals, function () {
562
+ if (targetMoment.isBetween(this[0], this[1])) {
563
+ found = true;
564
+ return false;
565
+ }
566
+ });
567
+ if (found) {
568
+ return false;
569
+ }
570
+ }
571
+ return true;
572
+ },
573
+
574
+ fillMonths = function () {
575
+ var spans = [],
576
+ monthsShort = viewDate.clone().startOf('y').startOf('d');
577
+ while (monthsShort.isSame(viewDate, 'y')) {
578
+ spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM')));
579
+ monthsShort.add(1, 'M');
580
+ }
581
+ widget.find('.datepicker-months td').empty().append(spans);
582
+ },
583
+
584
+ updateMonths = function () {
585
+ var monthsView = widget.find('.datepicker-months'),
586
+ monthsViewHeader = monthsView.find('th'),
587
+ months = monthsView.find('tbody').find('span');
588
+
589
+ monthsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevYear);
590
+ monthsViewHeader.eq(1).attr('title', options.tooltips.selectYear);
591
+ monthsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextYear);
592
+
593
+ monthsView.find('.disabled').removeClass('disabled');
594
+
595
+ if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) {
596
+ monthsViewHeader.eq(0).addClass('disabled');
597
+ }
598
+
599
+ monthsViewHeader.eq(1).text(viewDate.year());
600
+
601
+ if (!isValid(viewDate.clone().add(1, 'y'), 'y')) {
602
+ monthsViewHeader.eq(2).addClass('disabled');
603
+ }
604
+
605
+ months.removeClass('active');
606
+ if (date.isSame(viewDate, 'y') && !unset) {
607
+ months.eq(date.month()).addClass('active');
608
+ }
609
+
610
+ months.each(function (index) {
611
+ if (!isValid(viewDate.clone().month(index), 'M')) {
612
+ $(this).addClass('disabled');
613
+ }
614
+ });
615
+ },
616
+
617
+ updateYears = function () {
618
+ var yearsView = widget.find('.datepicker-years'),
619
+ yearsViewHeader = yearsView.find('th'),
620
+ startYear = viewDate.clone().subtract(5, 'y'),
621
+ endYear = viewDate.clone().add(6, 'y'),
622
+ html = '';
623
+
624
+ yearsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevDecade);
625
+ yearsViewHeader.eq(1).attr('title', options.tooltips.selectDecade);
626
+ yearsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextDecade);
627
+
628
+ yearsView.find('.disabled').removeClass('disabled');
629
+
630
+ if (options.minDate && options.minDate.isAfter(startYear, 'y')) {
631
+ yearsViewHeader.eq(0).addClass('disabled');
632
+ }
633
+
634
+ yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year());
635
+
636
+ if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) {
637
+ yearsViewHeader.eq(2).addClass('disabled');
638
+ }
639
+
640
+ while (!startYear.isAfter(endYear, 'y')) {
641
+ html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') && !unset ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>';
642
+ startYear.add(1, 'y');
643
+ }
644
+
645
+ yearsView.find('td').html(html);
646
+ },
647
+
648
+ updateDecades = function () {
649
+ var decadesView = widget.find('.datepicker-decades'),
650
+ decadesViewHeader = decadesView.find('th'),
651
+ startDecade = moment({ y: viewDate.year() - (viewDate.year() % 100) - 1 }),
652
+ endDecade = startDecade.clone().add(100, 'y'),
653
+ startedAt = startDecade.clone(),
654
+ minDateDecade = false,
655
+ maxDateDecade = false,
656
+ endDecadeYear,
657
+ html = '';
658
+
659
+ decadesViewHeader.eq(0).find('span').attr('title', options.tooltips.prevCentury);
660
+ decadesViewHeader.eq(2).find('span').attr('title', options.tooltips.nextCentury);
661
+
662
+ decadesView.find('.disabled').removeClass('disabled');
663
+
664
+ if (startDecade.isSame(moment({ y: 1900 })) || (options.minDate && options.minDate.isAfter(startDecade, 'y'))) {
665
+ decadesViewHeader.eq(0).addClass('disabled');
666
+ }
667
+
668
+ decadesViewHeader.eq(1).text(startDecade.year() + '-' + endDecade.year());
669
+
670
+ if (startDecade.isSame(moment({ y: 2000 })) || (options.maxDate && options.maxDate.isBefore(endDecade, 'y'))) {
671
+ decadesViewHeader.eq(2).addClass('disabled');
672
+ }
673
+
674
+ while (!startDecade.isAfter(endDecade, 'y')) {
675
+ endDecadeYear = startDecade.year() + 12;
676
+ minDateDecade = options.minDate && options.minDate.isAfter(startDecade, 'y') && options.minDate.year() <= endDecadeYear;
677
+ maxDateDecade = options.maxDate && options.maxDate.isAfter(startDecade, 'y') && options.maxDate.year() <= endDecadeYear;
678
+ html += '<span data-action="selectDecade" class="decade' + (date.isAfter(startDecade) && date.year() <= endDecadeYear ? ' active' : '') +
679
+ (!isValid(startDecade, 'y') && !minDateDecade && !maxDateDecade ? ' 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
+ clsNames = [],
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
+ clsNames = ['day'];
726
+ if (currentDate.isBefore(viewDate, 'M')) {
727
+ clsNames.push('old');
728
+ }
729
+ if (currentDate.isAfter(viewDate, 'M')) {
730
+ clsNames.push('new');
731
+ }
732
+ if (currentDate.isSame(date, 'd') && !unset) {
733
+ clsNames.push('active');
734
+ }
735
+ if (!isValid(currentDate, 'd')) {
736
+ clsNames.push('disabled');
737
+ }
738
+ if (currentDate.isSame(getMoment(), 'd')) {
739
+ clsNames.push('today');
740
+ }
741
+ if (currentDate.day() === 0 || currentDate.day() === 6) {
742
+ clsNames.push('weekend');
743
+ }
744
+ notifyEvent({
745
+ type: 'dp.classify',
746
+ date: currentDate,
747
+ classNames: clsNames
748
+ });
749
+ row.append('<td data-action="selectDay" data-day="' + currentDate.format('L') + '" class="' + clsNames.join(' ') + '">' + currentDate.date() + '</td>');
750
+ currentDate.add(1, 'd');
751
+ }
752
+
753
+ daysView.find('tbody').empty().append(html);
754
+
755
+ updateMonths();
756
+
757
+ updateYears();
758
+
759
+ updateDecades();
760
+ },
761
+
762
+ fillHours = function () {
763
+ var table = widget.find('.timepicker-hours table'),
764
+ currentHour = viewDate.clone().startOf('d'),
765
+ html = [],
766
+ row = $('<tr>');
767
+
768
+ if (viewDate.hour() > 11 && !use24Hours) {
769
+ currentHour.hour(12);
770
+ }
771
+ while (currentHour.isSame(viewDate, 'd') && (use24Hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) {
772
+ if (currentHour.hour() % 4 === 0) {
773
+ row = $('<tr>');
774
+ html.push(row);
775
+ }
776
+ row.append('<td data-action="selectHour" class="hour' + (!isValid(currentHour, 'h') ? ' disabled' : '') + '">' + currentHour.format(use24Hours ? 'HH' : 'hh') + '</td>');
777
+ currentHour.add(1, 'h');
778
+ }
779
+ table.empty().append(html);
780
+ },
781
+
782
+ fillMinutes = function () {
783
+ var table = widget.find('.timepicker-minutes table'),
784
+ currentMinute = viewDate.clone().startOf('h'),
785
+ html = [],
786
+ row = $('<tr>'),
787
+ step = options.stepping === 1 ? 5 : options.stepping;
788
+
789
+ while (viewDate.isSame(currentMinute, 'h')) {
790
+ if (currentMinute.minute() % (step * 4) === 0) {
791
+ row = $('<tr>');
792
+ html.push(row);
793
+ }
794
+ row.append('<td data-action="selectMinute" class="minute' + (!isValid(currentMinute, 'm') ? ' disabled' : '') + '">' + currentMinute.format('mm') + '</td>');
795
+ currentMinute.add(step, 'm');
796
+ }
797
+ table.empty().append(html);
798
+ },
799
+
800
+ fillSeconds = function () {
801
+ var table = widget.find('.timepicker-seconds table'),
802
+ currentSecond = viewDate.clone().startOf('m'),
803
+ html = [],
804
+ row = $('<tr>');
805
+
806
+ while (viewDate.isSame(currentSecond, 'm')) {
807
+ if (currentSecond.second() % 20 === 0) {
808
+ row = $('<tr>');
809
+ html.push(row);
810
+ }
811
+ row.append('<td data-action="selectSecond" class="second' + (!isValid(currentSecond, 's') ? ' disabled' : '') + '">' + currentSecond.format('ss') + '</td>');
812
+ currentSecond.add(5, 's');
813
+ }
814
+
815
+ table.empty().append(html);
816
+ },
817
+
818
+ fillTime = function () {
819
+ var toggle, newDate, timeComponents = widget.find('.timepicker span[data-time-component]');
820
+
821
+ if (!use24Hours) {
822
+ toggle = widget.find('.timepicker [data-action=togglePeriod]');
823
+ newDate = date.clone().add((date.hours() >= 12) ? -12 : 12, 'h');
824
+
825
+ toggle.text(date.format('A'));
826
+
827
+ if (isValid(newDate, 'h')) {
828
+ toggle.removeClass('disabled');
829
+ } else {
830
+ toggle.addClass('disabled');
831
+ }
832
+ }
833
+ timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh'));
834
+ timeComponents.filter('[data-time-component=minutes]').text(date.format('mm'));
835
+ timeComponents.filter('[data-time-component=seconds]').text(date.format('ss'));
836
+
837
+ fillHours();
838
+ fillMinutes();
839
+ fillSeconds();
840
+ },
841
+
842
+ update = function () {
843
+ if (!widget) {
844
+ return;
845
+ }
846
+ fillDate();
847
+ fillTime();
848
+ },
849
+
850
+ setValue = function (targetMoment) {
851
+ var oldDate = unset ? null : date;
852
+
853
+ // case of calling setValue(null or false)
854
+ if (!targetMoment) {
855
+ unset = true;
856
+ input.val('');
857
+ element.data('date', '');
858
+ notifyEvent({
859
+ type: 'dp.change',
860
+ date: false,
861
+ oldDate: oldDate
862
+ });
863
+ update();
864
+ return;
865
+ }
866
+
867
+ targetMoment = targetMoment.clone().locale(options.locale);
868
+
869
+ if (hasTimeZone()) {
870
+ targetMoment.tz(options.timeZone);
871
+ }
872
+
873
+ if (options.stepping !== 1) {
874
+ targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping)).seconds(0);
875
+
876
+ while (options.minDate && targetMoment.isBefore(options.minDate)) {
877
+ targetMoment.add(options.stepping, 'minutes');
878
+ }
879
+ }
880
+
881
+ if (isValid(targetMoment)) {
882
+ date = targetMoment;
883
+ viewDate = date.clone();
884
+ input.val(date.format(actualFormat));
885
+ element.data('date', date.format(actualFormat));
886
+ unset = false;
887
+ update();
888
+ notifyEvent({
889
+ type: 'dp.change',
890
+ date: date.clone(),
891
+ oldDate: oldDate
892
+ });
893
+ } else {
894
+ if (!options.keepInvalid) {
895
+ input.val(unset ? '' : date.format(actualFormat));
896
+ } else {
897
+ notifyEvent({
898
+ type: 'dp.change',
899
+ date: targetMoment,
900
+ oldDate: oldDate
901
+ });
902
+ }
903
+ notifyEvent({
904
+ type: 'dp.error',
905
+ date: targetMoment,
906
+ oldDate: oldDate
907
+ });
908
+ }
909
+ },
910
+
911
+ /**
912
+ * Hides the widget. Possibly will emit dp.hide
913
+ */
914
+ hide = function () {
915
+ var transitioning = false;
916
+ if (!widget) {
917
+ return picker;
918
+ }
919
+ // Ignore event if in the middle of a picker transition
920
+ widget.find('.collapse').each(function () {
921
+ var collapseData = $(this).data('collapse');
922
+ if (collapseData && collapseData.transitioning) {
923
+ transitioning = true;
924
+ return false;
925
+ }
926
+ return true;
927
+ });
928
+ if (transitioning) {
929
+ return picker;
930
+ }
931
+ if (component && component.hasClass('btn')) {
932
+ component.toggleClass('active');
933
+ }
934
+ widget.hide();
935
+
936
+ $(window).off('resize', place);
937
+ widget.off('click', '[data-action]');
938
+ widget.off('mousedown', false);
939
+
940
+ widget.remove();
941
+ widget = false;
942
+
943
+ notifyEvent({
944
+ type: 'dp.hide',
945
+ date: date.clone()
946
+ });
947
+
948
+ input.blur();
949
+
950
+ currentViewMode = 0;
951
+ viewDate = date.clone();
952
+
953
+ return picker;
954
+ },
955
+
956
+ clear = function () {
957
+ setValue(null);
958
+ },
959
+
960
+ parseInputDate = function (inputDate) {
961
+ if (options.parseInputDate === undefined) {
962
+ if (!moment.isMoment(inputDate) || inputDate instanceof Date) {
963
+ inputDate = getMoment(inputDate);
964
+ }
965
+ } else {
966
+ inputDate = options.parseInputDate(inputDate);
967
+ }
968
+ //inputDate.locale(options.locale);
969
+ return inputDate;
970
+ },
971
+
972
+ /********************************************************************************
973
+ *
974
+ * Widget UI interaction functions
975
+ *
976
+ ********************************************************************************/
977
+ actions = {
978
+ next: function () {
979
+ var navFnc = datePickerModes[currentViewMode].navFnc;
980
+ viewDate.add(datePickerModes[currentViewMode].navStep, navFnc);
981
+ fillDate();
982
+ viewUpdate(navFnc);
983
+ },
984
+
985
+ previous: function () {
986
+ var navFnc = datePickerModes[currentViewMode].navFnc;
987
+ viewDate.subtract(datePickerModes[currentViewMode].navStep, navFnc);
988
+ fillDate();
989
+ viewUpdate(navFnc);
990
+ },
991
+
992
+ pickerSwitch: function () {
993
+ showMode(1);
994
+ },
995
+
996
+ selectMonth: function (e) {
997
+ var month = $(e.target).closest('tbody').find('span').index($(e.target));
998
+ viewDate.month(month);
999
+ if (currentViewMode === minViewModeNumber) {
1000
+ setValue(date.clone().year(viewDate.year()).month(viewDate.month()));
1001
+ if (!options.inline) {
1002
+ hide();
1003
+ }
1004
+ } else {
1005
+ showMode(-1);
1006
+ fillDate();
1007
+ }
1008
+ viewUpdate('M');
1009
+ },
1010
+
1011
+ selectYear: function (e) {
1012
+ var year = parseInt($(e.target).text(), 10) || 0;
1013
+ viewDate.year(year);
1014
+ if (currentViewMode === minViewModeNumber) {
1015
+ setValue(date.clone().year(viewDate.year()));
1016
+ if (!options.inline) {
1017
+ hide();
1018
+ }
1019
+ } else {
1020
+ showMode(-1);
1021
+ fillDate();
1022
+ }
1023
+ viewUpdate('YYYY');
1024
+ },
1025
+
1026
+ selectDecade: function (e) {
1027
+ var year = parseInt($(e.target).data('selection'), 10) || 0;
1028
+ viewDate.year(year);
1029
+ if (currentViewMode === minViewModeNumber) {
1030
+ setValue(date.clone().year(viewDate.year()));
1031
+ if (!options.inline) {
1032
+ hide();
1033
+ }
1034
+ } else {
1035
+ showMode(-1);
1036
+ fillDate();
1037
+ }
1038
+ viewUpdate('YYYY');
1039
+ },
1040
+
1041
+ selectDay: function (e) {
1042
+ var day = viewDate.clone();
1043
+ if ($(e.target).is('.old')) {
1044
+ day.subtract(1, 'M');
1045
+ }
1046
+ if ($(e.target).is('.new')) {
1047
+ day.add(1, 'M');
1048
+ }
1049
+ setValue(day.date(parseInt($(e.target).text(), 10)));
1050
+ if (!hasTime() && !options.keepOpen && !options.inline) {
1051
+ hide();
1052
+ }
1053
+ },
1054
+
1055
+ incrementHours: function () {
1056
+ var newDate = date.clone().add(1, 'h');
1057
+ if (isValid(newDate, 'h')) {
1058
+ setValue(newDate);
1059
+ }
1060
+ },
1061
+
1062
+ incrementMinutes: function () {
1063
+ var newDate = date.clone().add(options.stepping, 'm');
1064
+ if (isValid(newDate, 'm')) {
1065
+ setValue(newDate);
1066
+ }
1067
+ },
1068
+
1069
+ incrementSeconds: function () {
1070
+ var newDate = date.clone().add(1, 's');
1071
+ if (isValid(newDate, 's')) {
1072
+ setValue(newDate);
1073
+ }
1074
+ },
1075
+
1076
+ decrementHours: function () {
1077
+ var newDate = date.clone().subtract(1, 'h');
1078
+ if (isValid(newDate, 'h')) {
1079
+ setValue(newDate);
1080
+ }
1081
+ },
1082
+
1083
+ decrementMinutes: function () {
1084
+ var newDate = date.clone().subtract(options.stepping, 'm');
1085
+ if (isValid(newDate, 'm')) {
1086
+ setValue(newDate);
1087
+ }
1088
+ },
1089
+
1090
+ decrementSeconds: function () {
1091
+ var newDate = date.clone().subtract(1, 's');
1092
+ if (isValid(newDate, 's')) {
1093
+ setValue(newDate);
1094
+ }
1095
+ },
1096
+
1097
+ togglePeriod: function () {
1098
+ setValue(date.clone().add((date.hours() >= 12) ? -12 : 12, 'h'));
1099
+ },
1100
+
1101
+ togglePicker: function (e) {
1102
+ var $this = $(e.target),
1103
+ $parent = $this.closest('ul'),
1104
+ expanded = $parent.find('.in'),
1105
+ closed = $parent.find('.collapse:not(.in)'),
1106
+ collapseData;
1107
+
1108
+ if (expanded && expanded.length) {
1109
+ collapseData = expanded.data('collapse');
1110
+ if (collapseData && collapseData.transitioning) {
1111
+ return;
1112
+ }
1113
+ if (expanded.collapse) { // if collapse plugin is available through bootstrap.js then use it
1114
+ expanded.collapse('hide');
1115
+ closed.collapse('show');
1116
+ } else { // otherwise just toggle in class on the two views
1117
+ expanded.removeClass('in');
1118
+ closed.addClass('in');
1119
+ }
1120
+ if ($this.is('span')) {
1121
+ $this.toggleClass(options.icons.time + ' ' + options.icons.date);
1122
+ } else {
1123
+ $this.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
1124
+ }
1125
+
1126
+ // NOTE: uncomment if toggled state will be restored in show()
1127
+ //if (component) {
1128
+ // component.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
1129
+ //}
1130
+ }
1131
+ },
1132
+
1133
+ showPicker: function () {
1134
+ widget.find('.timepicker > div:not(.timepicker-picker)').hide();
1135
+ widget.find('.timepicker .timepicker-picker').show();
1136
+ },
1137
+
1138
+ showHours: function () {
1139
+ widget.find('.timepicker .timepicker-picker').hide();
1140
+ widget.find('.timepicker .timepicker-hours').show();
1141
+ },
1142
+
1143
+ showMinutes: function () {
1144
+ widget.find('.timepicker .timepicker-picker').hide();
1145
+ widget.find('.timepicker .timepicker-minutes').show();
1146
+ },
1147
+
1148
+ showSeconds: function () {
1149
+ widget.find('.timepicker .timepicker-picker').hide();
1150
+ widget.find('.timepicker .timepicker-seconds').show();
1151
+ },
1152
+
1153
+ selectHour: function (e) {
1154
+ var hour = parseInt($(e.target).text(), 10);
1155
+
1156
+ if (!use24Hours) {
1157
+ if (date.hours() >= 12) {
1158
+ if (hour !== 12) {
1159
+ hour += 12;
1160
+ }
1161
+ } else {
1162
+ if (hour === 12) {
1163
+ hour = 0;
1164
+ }
1165
+ }
1166
+ }
1167
+ setValue(date.clone().hours(hour));
1168
+ actions.showPicker.call(picker);
1169
+ },
1170
+
1171
+ selectMinute: function (e) {
1172
+ setValue(date.clone().minutes(parseInt($(e.target).text(), 10)));
1173
+ actions.showPicker.call(picker);
1174
+ },
1175
+
1176
+ selectSecond: function (e) {
1177
+ setValue(date.clone().seconds(parseInt($(e.target).text(), 10)));
1178
+ actions.showPicker.call(picker);
1179
+ },
1180
+
1181
+ clear: clear,
1182
+
1183
+ today: function () {
1184
+ var todaysDate = getMoment();
1185
+ if (isValid(todaysDate, 'd')) {
1186
+ setValue(todaysDate);
1187
+ }
1188
+ },
1189
+
1190
+ close: hide
1191
+ },
1192
+
1193
+ doAction = function (e) {
1194
+ if ($(e.currentTarget).is('.disabled')) {
1195
+ return false;
1196
+ }
1197
+ actions[$(e.currentTarget).data('action')].apply(picker, arguments);
1198
+ return false;
1199
+ },
1200
+
1201
+ /**
1202
+ * Shows the widget. Possibly will emit dp.show and dp.change
1203
+ */
1204
+ show = function () {
1205
+ var currentMoment,
1206
+ useCurrentGranularity = {
1207
+ 'year': function (m) {
1208
+ return m.month(0).date(1).hours(0).seconds(0).minutes(0);
1209
+ },
1210
+ 'month': function (m) {
1211
+ return m.date(1).hours(0).seconds(0).minutes(0);
1212
+ },
1213
+ 'day': function (m) {
1214
+ return m.hours(0).seconds(0).minutes(0);
1215
+ },
1216
+ 'hour': function (m) {
1217
+ return m.seconds(0).minutes(0);
1218
+ },
1219
+ 'minute': function (m) {
1220
+ return m.seconds(0);
1221
+ }
1222
+ };
1223
+
1224
+ if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) {
1225
+ return picker;
1226
+ }
1227
+ if (input.val() !== undefined && input.val().trim().length !== 0) {
1228
+ setValue(parseInputDate(input.val().trim()));
1229
+ } else if (unset && options.useCurrent && (options.inline || (input.is('input') && input.val().trim().length === 0))) {
1230
+ currentMoment = getMoment();
1231
+ if (typeof options.useCurrent === 'string') {
1232
+ currentMoment = useCurrentGranularity[options.useCurrent](currentMoment);
1233
+ }
1234
+ setValue(currentMoment);
1235
+ }
1236
+ widget = getTemplate();
1237
+
1238
+ fillDow();
1239
+ fillMonths();
1240
+
1241
+ widget.find('.timepicker-hours').hide();
1242
+ widget.find('.timepicker-minutes').hide();
1243
+ widget.find('.timepicker-seconds').hide();
1244
+
1245
+ update();
1246
+ showMode();
1247
+
1248
+ $(window).on('resize', place);
1249
+ widget.on('click', '[data-action]', doAction); // this handles clicks on the widget
1250
+ widget.on('mousedown', false);
1251
+
1252
+ if (component && component.hasClass('btn')) {
1253
+ component.toggleClass('active');
1254
+ }
1255
+ place();
1256
+ widget.show();
1257
+ if (options.focusOnShow && !input.is(':focus')) {
1258
+ input.focus();
1259
+ }
1260
+
1261
+ notifyEvent({
1262
+ type: 'dp.show'
1263
+ });
1264
+ return picker;
1265
+ },
1266
+
1267
+ /**
1268
+ * Shows or hides the widget
1269
+ */
1270
+ toggle = function () {
1271
+ return (widget ? hide() : show());
1272
+ },
1273
+
1274
+ keydown = function (e) {
1275
+ var handler = null,
1276
+ index,
1277
+ index2,
1278
+ pressedKeys = [],
1279
+ pressedModifiers = {},
1280
+ currentKey = e.which,
1281
+ keyBindKeys,
1282
+ allModifiersPressed,
1283
+ pressed = 'p';
1284
+
1285
+ keyState[currentKey] = pressed;
1286
+
1287
+ for (index in keyState) {
1288
+ if (keyState.hasOwnProperty(index) && keyState[index] === pressed) {
1289
+ pressedKeys.push(index);
1290
+ if (parseInt(index, 10) !== currentKey) {
1291
+ pressedModifiers[index] = true;
1292
+ }
1293
+ }
1294
+ }
1295
+
1296
+ for (index in options.keyBinds) {
1297
+ if (options.keyBinds.hasOwnProperty(index) && typeof (options.keyBinds[index]) === 'function') {
1298
+ keyBindKeys = index.split(' ');
1299
+ if (keyBindKeys.length === pressedKeys.length && keyMap[currentKey] === keyBindKeys[keyBindKeys.length - 1]) {
1300
+ allModifiersPressed = true;
1301
+ for (index2 = keyBindKeys.length - 2; index2 >= 0; index2--) {
1302
+ if (!(keyMap[keyBindKeys[index2]] in pressedModifiers)) {
1303
+ allModifiersPressed = false;
1304
+ break;
1305
+ }
1306
+ }
1307
+ if (allModifiersPressed) {
1308
+ handler = options.keyBinds[index];
1309
+ break;
1310
+ }
1311
+ }
1312
+ }
1313
+ }
1314
+
1315
+ if (handler) {
1316
+ handler.call(picker, widget);
1317
+ e.stopPropagation();
1318
+ e.preventDefault();
1319
+ }
1320
+ },
1321
+
1322
+ keyup = function (e) {
1323
+ keyState[e.which] = 'r';
1324
+ e.stopPropagation();
1325
+ e.preventDefault();
1326
+ },
1327
+
1328
+ change = function (e) {
1329
+ var val = $(e.target).val().trim(),
1330
+ parsedDate = val ? parseInputDate(val) : null;
1331
+ setValue(parsedDate);
1332
+ e.stopImmediatePropagation();
1333
+ return false;
1334
+ },
1335
+
1336
+ attachDatePickerElementEvents = function () {
1337
+ input.on({
1338
+ 'change': change,
1339
+ 'blur': options.debug ? '' : hide,
1340
+ 'keydown': keydown,
1341
+ 'keyup': keyup,
1342
+ 'focus': options.allowInputToggle ? show : ''
1343
+ });
1344
+
1345
+ if (element.is('input')) {
1346
+ input.on({
1347
+ 'focus': show
1348
+ });
1349
+ } else if (component) {
1350
+ component.on('click', toggle);
1351
+ component.on('mousedown', false);
1352
+ }
1353
+ },
1354
+
1355
+ detachDatePickerElementEvents = function () {
1356
+ input.off({
1357
+ 'change': change,
1358
+ 'blur': blur,
1359
+ 'keydown': keydown,
1360
+ 'keyup': keyup,
1361
+ 'focus': options.allowInputToggle ? hide : ''
1362
+ });
1363
+
1364
+ if (element.is('input')) {
1365
+ input.off({
1366
+ 'focus': show
1367
+ });
1368
+ } else if (component) {
1369
+ component.off('click', toggle);
1370
+ component.off('mousedown', false);
1371
+ }
1372
+ },
1373
+
1374
+ indexGivenDates = function (givenDatesArray) {
1375
+ // Store given enabledDates and disabledDates as keys.
1376
+ // This way we can check their existence in O(1) time instead of looping through whole array.
1377
+ // (for example: options.enabledDates['2014-02-27'] === true)
1378
+ var givenDatesIndexed = {};
1379
+ $.each(givenDatesArray, function () {
1380
+ var dDate = parseInputDate(this);
1381
+ if (dDate.isValid()) {
1382
+ givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true;
1383
+ }
1384
+ });
1385
+ return (Object.keys(givenDatesIndexed).length) ? givenDatesIndexed : false;
1386
+ },
1387
+
1388
+ indexGivenHours = function (givenHoursArray) {
1389
+ // Store given enabledHours and disabledHours as keys.
1390
+ // This way we can check their existence in O(1) time instead of looping through whole array.
1391
+ // (for example: options.enabledHours['2014-02-27'] === true)
1392
+ var givenHoursIndexed = {};
1393
+ $.each(givenHoursArray, function () {
1394
+ givenHoursIndexed[this] = true;
1395
+ });
1396
+ return (Object.keys(givenHoursIndexed).length) ? givenHoursIndexed : false;
1397
+ },
1398
+
1399
+ initFormatting = function () {
1400
+ var format = options.format || 'L LT';
1401
+
1402
+ actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput) {
1403
+ var newinput = date.localeData().longDateFormat(formatInput) || formatInput;
1404
+ return newinput.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput2) { //temp fix for #740
1405
+ return date.localeData().longDateFormat(formatInput2) || formatInput2;
1406
+ });
1407
+ });
1408
+
1409
+
1410
+ parseFormats = options.extraFormats ? options.extraFormats.slice() : [];
1411
+ if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) {
1412
+ parseFormats.push(actualFormat);
1413
+ }
1414
+
1415
+ use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.replace(/\[.*?\]/g, '').indexOf('h') < 1);
1416
+
1417
+ if (isEnabled('y')) {
1418
+ minViewModeNumber = 2;
1419
+ }
1420
+ if (isEnabled('M')) {
1421
+ minViewModeNumber = 1;
1422
+ }
1423
+ if (isEnabled('d')) {
1424
+ minViewModeNumber = 0;
1425
+ }
1426
+
1427
+ currentViewMode = Math.max(minViewModeNumber, currentViewMode);
1428
+
1429
+ if (!unset) {
1430
+ setValue(date);
1431
+ }
1432
+ };
1433
+
1434
+ /********************************************************************************
1435
+ *
1436
+ * Public API functions
1437
+ * =====================
1438
+ *
1439
+ * Important: Do not expose direct references to private objects or the options
1440
+ * object to the outer world. Always return a clone when returning values or make
1441
+ * a clone when setting a private variable.
1442
+ *
1443
+ ********************************************************************************/
1444
+ picker.destroy = function () {
1445
+ ///<summary>Destroys the widget and removes all attached event listeners</summary>
1446
+ hide();
1447
+ detachDatePickerElementEvents();
1448
+ element.removeData('DateTimePicker');
1449
+ element.removeData('date');
1450
+ };
1451
+
1452
+ picker.toggle = toggle;
1453
+
1454
+ picker.show = show;
1455
+
1456
+ picker.hide = hide;
1457
+
1458
+ picker.disable = function () {
1459
+ ///<summary>Disables the input element, the component is attached to, by adding a disabled="true" attribute to it.
1460
+ ///If the widget was visible before that call it is hidden. Possibly emits dp.hide</summary>
1461
+ hide();
1462
+ if (component && component.hasClass('btn')) {
1463
+ component.addClass('disabled');
1464
+ }
1465
+ input.prop('disabled', true);
1466
+ return picker;
1467
+ };
1468
+
1469
+ picker.enable = function () {
1470
+ ///<summary>Enables the input element, the component is attached to, by removing disabled attribute from it.</summary>
1471
+ if (component && component.hasClass('btn')) {
1472
+ component.removeClass('disabled');
1473
+ }
1474
+ input.prop('disabled', false);
1475
+ return picker;
1476
+ };
1477
+
1478
+ picker.ignoreReadonly = function (ignoreReadonly) {
1479
+ if (arguments.length === 0) {
1480
+ return options.ignoreReadonly;
1481
+ }
1482
+ if (typeof ignoreReadonly !== 'boolean') {
1483
+ throw new TypeError('ignoreReadonly () expects a boolean parameter');
1484
+ }
1485
+ options.ignoreReadonly = ignoreReadonly;
1486
+ return picker;
1487
+ };
1488
+
1489
+ picker.options = function (newOptions) {
1490
+ if (arguments.length === 0) {
1491
+ return $.extend(true, {}, options);
1492
+ }
1493
+
1494
+ if (!(newOptions instanceof Object)) {
1495
+ throw new TypeError('options() options parameter should be an object');
1496
+ }
1497
+ $.extend(true, options, newOptions);
1498
+ $.each(options, function (key, value) {
1499
+ if (picker[key] !== undefined) {
1500
+ picker[key](value);
1501
+ } else {
1502
+ throw new TypeError('option ' + key + ' is not recognized!');
1503
+ }
1504
+ });
1505
+ return picker;
1506
+ };
1507
+
1508
+ picker.date = function (newDate) {
1509
+ ///<signature helpKeyword="$.fn.datetimepicker.date">
1510
+ ///<summary>Returns the component's model current date, a moment object or null if not set.</summary>
1511
+ ///<returns type="Moment">date.clone()</returns>
1512
+ ///</signature>
1513
+ ///<signature>
1514
+ ///<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>
1515
+ ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, Date, moment, null parameter.</param>
1516
+ ///</signature>
1517
+ if (arguments.length === 0) {
1518
+ if (unset) {
1519
+ return null;
1520
+ }
1521
+ return date.clone();
1522
+ }
1523
+
1524
+ if (newDate !== null && typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
1525
+ throw new TypeError('date() parameter must be one of [null, string, moment or Date]');
1526
+ }
1527
+
1528
+ setValue(newDate === null ? null : parseInputDate(newDate));
1529
+ return picker;
1530
+ };
1531
+
1532
+ picker.format = function (newFormat) {
1533
+ ///<summary>test su</summary>
1534
+ ///<param name="newFormat">info about para</param>
1535
+ ///<returns type="string|boolean">returns foo</returns>
1536
+ if (arguments.length === 0) {
1537
+ return options.format;
1538
+ }
1539
+
1540
+ if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) {
1541
+ throw new TypeError('format() expects a string or boolean:false parameter ' + newFormat);
1542
+ }
1543
+
1544
+ options.format = newFormat;
1545
+ if (actualFormat) {
1546
+ initFormatting(); // reinit formatting
1547
+ }
1548
+ return picker;
1549
+ };
1550
+
1551
+ picker.timeZone = function (newZone) {
1552
+ if (arguments.length === 0) {
1553
+ return options.timeZone;
1554
+ }
1555
+
1556
+ if (typeof newZone !== 'string') {
1557
+ throw new TypeError('newZone() expects a string parameter');
1558
+ }
1559
+
1560
+ options.timeZone = newZone;
1561
+
1562
+ return picker;
1563
+ };
1564
+
1565
+ picker.dayViewHeaderFormat = function (newFormat) {
1566
+ if (arguments.length === 0) {
1567
+ return options.dayViewHeaderFormat;
1568
+ }
1569
+
1570
+ if (typeof newFormat !== 'string') {
1571
+ throw new TypeError('dayViewHeaderFormat() expects a string parameter');
1572
+ }
1573
+
1574
+ options.dayViewHeaderFormat = newFormat;
1575
+ return picker;
1576
+ };
1577
+
1578
+ picker.extraFormats = function (formats) {
1579
+ if (arguments.length === 0) {
1580
+ return options.extraFormats;
1581
+ }
1582
+
1583
+ if (formats !== false && !(formats instanceof Array)) {
1584
+ throw new TypeError('extraFormats() expects an array or false parameter');
1585
+ }
1586
+
1587
+ options.extraFormats = formats;
1588
+ if (parseFormats) {
1589
+ initFormatting(); // reinit formatting
1590
+ }
1591
+ return picker;
1592
+ };
1593
+
1594
+ picker.disabledDates = function (dates) {
1595
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledDates">
1596
+ ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
1597
+ ///<returns type="array">options.disabledDates</returns>
1598
+ ///</signature>
1599
+ ///<signature>
1600
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
1601
+ ///options.enabledDates if such exist.</summary>
1602
+ ///<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>
1603
+ ///</signature>
1604
+ if (arguments.length === 0) {
1605
+ return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates);
1606
+ }
1607
+
1608
+ if (!dates) {
1609
+ options.disabledDates = false;
1610
+ update();
1611
+ return picker;
1612
+ }
1613
+ if (!(dates instanceof Array)) {
1614
+ throw new TypeError('disabledDates() expects an array parameter');
1615
+ }
1616
+ options.disabledDates = indexGivenDates(dates);
1617
+ options.enabledDates = false;
1618
+ update();
1619
+ return picker;
1620
+ };
1621
+
1622
+ picker.enabledDates = function (dates) {
1623
+ ///<signature helpKeyword="$.fn.datetimepicker.enabledDates">
1624
+ ///<summary>Returns an array with the currently set enabled dates on the component.</summary>
1625
+ ///<returns type="array">options.enabledDates</returns>
1626
+ ///</signature>
1627
+ ///<signature>
1628
+ ///<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>
1629
+ ///<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>
1630
+ ///</signature>
1631
+ if (arguments.length === 0) {
1632
+ return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates);
1633
+ }
1634
+
1635
+ if (!dates) {
1636
+ options.enabledDates = false;
1637
+ update();
1638
+ return picker;
1639
+ }
1640
+ if (!(dates instanceof Array)) {
1641
+ throw new TypeError('enabledDates() expects an array parameter');
1642
+ }
1643
+ options.enabledDates = indexGivenDates(dates);
1644
+ options.disabledDates = false;
1645
+ update();
1646
+ return picker;
1647
+ };
1648
+
1649
+ picker.daysOfWeekDisabled = function (daysOfWeekDisabled) {
1650
+ if (arguments.length === 0) {
1651
+ return options.daysOfWeekDisabled.splice(0);
1652
+ }
1653
+
1654
+ if ((typeof daysOfWeekDisabled === 'boolean') && !daysOfWeekDisabled) {
1655
+ options.daysOfWeekDisabled = false;
1656
+ update();
1657
+ return picker;
1658
+ }
1659
+
1660
+ if (!(daysOfWeekDisabled instanceof Array)) {
1661
+ throw new TypeError('daysOfWeekDisabled() expects an array parameter');
1662
+ }
1663
+ options.daysOfWeekDisabled = daysOfWeekDisabled.reduce(function (previousValue, currentValue) {
1664
+ currentValue = parseInt(currentValue, 10);
1665
+ if (currentValue > 6 || currentValue < 0 || isNaN(currentValue)) {
1666
+ return previousValue;
1667
+ }
1668
+ if (previousValue.indexOf(currentValue) === -1) {
1669
+ previousValue.push(currentValue);
1670
+ }
1671
+ return previousValue;
1672
+ }, []).sort();
1673
+ if (options.useCurrent && !options.keepInvalid) {
1674
+ var tries = 0;
1675
+ while (!isValid(date, 'd')) {
1676
+ date.add(1, 'd');
1677
+ if (tries === 31) {
1678
+ throw 'Tried 31 times to find a valid date';
1679
+ }
1680
+ tries++;
1681
+ }
1682
+ setValue(date);
1683
+ }
1684
+ update();
1685
+ return picker;
1686
+ };
1687
+
1688
+ picker.maxDate = function (maxDate) {
1689
+ if (arguments.length === 0) {
1690
+ return options.maxDate ? options.maxDate.clone() : options.maxDate;
1691
+ }
1692
+
1693
+ if ((typeof maxDate === 'boolean') && maxDate === false) {
1694
+ options.maxDate = false;
1695
+ update();
1696
+ return picker;
1697
+ }
1698
+
1699
+ if (typeof maxDate === 'string') {
1700
+ if (maxDate === 'now' || maxDate === 'moment') {
1701
+ maxDate = getMoment();
1702
+ }
1703
+ }
1704
+
1705
+ var parsedDate = parseInputDate(maxDate);
1706
+
1707
+ if (!parsedDate.isValid()) {
1708
+ throw new TypeError('maxDate() Could not parse date parameter: ' + maxDate);
1709
+ }
1710
+ if (options.minDate && parsedDate.isBefore(options.minDate)) {
1711
+ throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat));
1712
+ }
1713
+ options.maxDate = parsedDate;
1714
+ if (options.useCurrent && !options.keepInvalid && date.isAfter(maxDate)) {
1715
+ setValue(options.maxDate);
1716
+ }
1717
+ if (viewDate.isAfter(parsedDate)) {
1718
+ viewDate = parsedDate.clone().subtract(options.stepping, 'm');
1719
+ }
1720
+ update();
1721
+ return picker;
1722
+ };
1723
+
1724
+ picker.minDate = function (minDate) {
1725
+ if (arguments.length === 0) {
1726
+ return options.minDate ? options.minDate.clone() : options.minDate;
1727
+ }
1728
+
1729
+ if ((typeof minDate === 'boolean') && minDate === false) {
1730
+ options.minDate = false;
1731
+ update();
1732
+ return picker;
1733
+ }
1734
+
1735
+ if (typeof minDate === 'string') {
1736
+ if (minDate === 'now' || minDate === 'moment') {
1737
+ minDate = getMoment();
1738
+ }
1739
+ }
1740
+
1741
+ var parsedDate = parseInputDate(minDate);
1742
+
1743
+ if (!parsedDate.isValid()) {
1744
+ throw new TypeError('minDate() Could not parse date parameter: ' + minDate);
1745
+ }
1746
+ if (options.maxDate && parsedDate.isAfter(options.maxDate)) {
1747
+ throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat));
1748
+ }
1749
+ options.minDate = parsedDate;
1750
+ if (options.useCurrent && !options.keepInvalid && date.isBefore(minDate)) {
1751
+ setValue(options.minDate);
1752
+ }
1753
+ if (viewDate.isBefore(parsedDate)) {
1754
+ viewDate = parsedDate.clone().add(options.stepping, 'm');
1755
+ }
1756
+ update();
1757
+ return picker;
1758
+ };
1759
+
1760
+ picker.defaultDate = function (defaultDate) {
1761
+ ///<signature helpKeyword="$.fn.datetimepicker.defaultDate">
1762
+ ///<summary>Returns a moment with the options.defaultDate option configuration or false if not set</summary>
1763
+ ///<returns type="Moment">date.clone()</returns>
1764
+ ///</signature>
1765
+ ///<signature>
1766
+ ///<summary>Will set the picker's inital date. If a boolean:false value is passed the options.defaultDate parameter is cleared.</summary>
1767
+ ///<param name="defaultDate" locid="$.fn.datetimepicker.defaultDate_p:defaultDate">Takes a string, Date, moment, boolean:false</param>
1768
+ ///</signature>
1769
+ if (arguments.length === 0) {
1770
+ return options.defaultDate ? options.defaultDate.clone() : options.defaultDate;
1771
+ }
1772
+ if (!defaultDate) {
1773
+ options.defaultDate = false;
1774
+ return picker;
1775
+ }
1776
+
1777
+ if (typeof defaultDate === 'string') {
1778
+ if (defaultDate === 'now' || defaultDate === 'moment') {
1779
+ defaultDate = getMoment();
1780
+ } else {
1781
+ defaultDate = getMoment(defaultDate);
1782
+ }
1783
+ }
1784
+
1785
+ var parsedDate = parseInputDate(defaultDate);
1786
+ if (!parsedDate.isValid()) {
1787
+ throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate);
1788
+ }
1789
+ if (!isValid(parsedDate)) {
1790
+ throw new TypeError('defaultDate() date passed is invalid according to component setup validations');
1791
+ }
1792
+
1793
+ options.defaultDate = parsedDate;
1794
+
1795
+ if ((options.defaultDate && options.inline) || input.val().trim() === '') {
1796
+ setValue(options.defaultDate);
1797
+ }
1798
+ return picker;
1799
+ };
1800
+
1801
+ picker.locale = function (locale) {
1802
+ if (arguments.length === 0) {
1803
+ return options.locale;
1804
+ }
1805
+
1806
+ if (!moment.localeData(locale)) {
1807
+ throw new TypeError('locale() locale ' + locale + ' is not loaded from moment locales!');
1808
+ }
1809
+
1810
+ options.locale = locale;
1811
+ date.locale(options.locale);
1812
+ viewDate.locale(options.locale);
1813
+
1814
+ if (actualFormat) {
1815
+ initFormatting(); // reinit formatting
1816
+ }
1817
+ if (widget) {
1818
+ hide();
1819
+ show();
1820
+ }
1821
+ return picker;
1822
+ };
1823
+
1824
+ picker.stepping = function (stepping) {
1825
+ if (arguments.length === 0) {
1826
+ return options.stepping;
1827
+ }
1828
+
1829
+ stepping = parseInt(stepping, 10);
1830
+ if (isNaN(stepping) || stepping < 1) {
1831
+ stepping = 1;
1832
+ }
1833
+ options.stepping = stepping;
1834
+ return picker;
1835
+ };
1836
+
1837
+ picker.useCurrent = function (useCurrent) {
1838
+ var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute'];
1839
+ if (arguments.length === 0) {
1840
+ return options.useCurrent;
1841
+ }
1842
+
1843
+ if ((typeof useCurrent !== 'boolean') && (typeof useCurrent !== 'string')) {
1844
+ throw new TypeError('useCurrent() expects a boolean or string parameter');
1845
+ }
1846
+ if (typeof useCurrent === 'string' && useCurrentOptions.indexOf(useCurrent.toLowerCase()) === -1) {
1847
+ throw new TypeError('useCurrent() expects a string parameter of ' + useCurrentOptions.join(', '));
1848
+ }
1849
+ options.useCurrent = useCurrent;
1850
+ return picker;
1851
+ };
1852
+
1853
+ picker.collapse = function (collapse) {
1854
+ if (arguments.length === 0) {
1855
+ return options.collapse;
1856
+ }
1857
+
1858
+ if (typeof collapse !== 'boolean') {
1859
+ throw new TypeError('collapse() expects a boolean parameter');
1860
+ }
1861
+ if (options.collapse === collapse) {
1862
+ return picker;
1863
+ }
1864
+ options.collapse = collapse;
1865
+ if (widget) {
1866
+ hide();
1867
+ show();
1868
+ }
1869
+ return picker;
1870
+ };
1871
+
1872
+ picker.icons = function (icons) {
1873
+ if (arguments.length === 0) {
1874
+ return $.extend({}, options.icons);
1875
+ }
1876
+
1877
+ if (!(icons instanceof Object)) {
1878
+ throw new TypeError('icons() expects parameter to be an Object');
1879
+ }
1880
+ $.extend(options.icons, icons);
1881
+ if (widget) {
1882
+ hide();
1883
+ show();
1884
+ }
1885
+ return picker;
1886
+ };
1887
+
1888
+ picker.tooltips = function (tooltips) {
1889
+ if (arguments.length === 0) {
1890
+ return $.extend({}, options.tooltips);
1891
+ }
1892
+
1893
+ if (!(tooltips instanceof Object)) {
1894
+ throw new TypeError('tooltips() expects parameter to be an Object');
1895
+ }
1896
+ $.extend(options.tooltips, tooltips);
1897
+ if (widget) {
1898
+ hide();
1899
+ show();
1900
+ }
1901
+ return picker;
1902
+ };
1903
+
1904
+ picker.useStrict = function (useStrict) {
1905
+ if (arguments.length === 0) {
1906
+ return options.useStrict;
1907
+ }
1908
+
1909
+ if (typeof useStrict !== 'boolean') {
1910
+ throw new TypeError('useStrict() expects a boolean parameter');
1911
+ }
1912
+ options.useStrict = useStrict;
1913
+ return picker;
1914
+ };
1915
+
1916
+ picker.sideBySide = function (sideBySide) {
1917
+ if (arguments.length === 0) {
1918
+ return options.sideBySide;
1919
+ }
1920
+
1921
+ if (typeof sideBySide !== 'boolean') {
1922
+ throw new TypeError('sideBySide() expects a boolean parameter');
1923
+ }
1924
+ options.sideBySide = sideBySide;
1925
+ if (widget) {
1926
+ hide();
1927
+ show();
1928
+ }
1929
+ return picker;
1930
+ };
1931
+
1932
+ picker.viewMode = function (viewMode) {
1933
+ if (arguments.length === 0) {
1934
+ return options.viewMode;
1935
+ }
1936
+
1937
+ if (typeof viewMode !== 'string') {
1938
+ throw new TypeError('viewMode() expects a string parameter');
1939
+ }
1940
+
1941
+ if (viewModes.indexOf(viewMode) === -1) {
1942
+ throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value');
1943
+ }
1944
+
1945
+ options.viewMode = viewMode;
1946
+ currentViewMode = Math.max(viewModes.indexOf(viewMode), minViewModeNumber);
1947
+
1948
+ showMode();
1949
+ return picker;
1950
+ };
1951
+
1952
+ picker.toolbarPlacement = function (toolbarPlacement) {
1953
+ if (arguments.length === 0) {
1954
+ return options.toolbarPlacement;
1955
+ }
1956
+
1957
+ if (typeof toolbarPlacement !== 'string') {
1958
+ throw new TypeError('toolbarPlacement() expects a string parameter');
1959
+ }
1960
+ if (toolbarPlacements.indexOf(toolbarPlacement) === -1) {
1961
+ throw new TypeError('toolbarPlacement() parameter must be one of (' + toolbarPlacements.join(', ') + ') value');
1962
+ }
1963
+ options.toolbarPlacement = toolbarPlacement;
1964
+
1965
+ if (widget) {
1966
+ hide();
1967
+ show();
1968
+ }
1969
+ return picker;
1970
+ };
1971
+
1972
+ picker.widgetPositioning = function (widgetPositioning) {
1973
+ if (arguments.length === 0) {
1974
+ return $.extend({}, options.widgetPositioning);
1975
+ }
1976
+
1977
+ if (({}).toString.call(widgetPositioning) !== '[object Object]') {
1978
+ throw new TypeError('widgetPositioning() expects an object variable');
1979
+ }
1980
+ if (widgetPositioning.horizontal) {
1981
+ if (typeof widgetPositioning.horizontal !== 'string') {
1982
+ throw new TypeError('widgetPositioning() horizontal variable must be a string');
1983
+ }
1984
+ widgetPositioning.horizontal = widgetPositioning.horizontal.toLowerCase();
1985
+ if (horizontalModes.indexOf(widgetPositioning.horizontal) === -1) {
1986
+ throw new TypeError('widgetPositioning() expects horizontal parameter to be one of (' + horizontalModes.join(', ') + ')');
1987
+ }
1988
+ options.widgetPositioning.horizontal = widgetPositioning.horizontal;
1989
+ }
1990
+ if (widgetPositioning.vertical) {
1991
+ if (typeof widgetPositioning.vertical !== 'string') {
1992
+ throw new TypeError('widgetPositioning() vertical variable must be a string');
1993
+ }
1994
+ widgetPositioning.vertical = widgetPositioning.vertical.toLowerCase();
1995
+ if (verticalModes.indexOf(widgetPositioning.vertical) === -1) {
1996
+ throw new TypeError('widgetPositioning() expects vertical parameter to be one of (' + verticalModes.join(', ') + ')');
1997
+ }
1998
+ options.widgetPositioning.vertical = widgetPositioning.vertical;
1999
+ }
2000
+ update();
2001
+ return picker;
2002
+ };
2003
+
2004
+ picker.calendarWeeks = function (calendarWeeks) {
2005
+ if (arguments.length === 0) {
2006
+ return options.calendarWeeks;
2007
+ }
2008
+
2009
+ if (typeof calendarWeeks !== 'boolean') {
2010
+ throw new TypeError('calendarWeeks() expects parameter to be a boolean value');
2011
+ }
2012
+
2013
+ options.calendarWeeks = calendarWeeks;
2014
+ update();
2015
+ return picker;
2016
+ };
2017
+
2018
+ picker.showTodayButton = function (showTodayButton) {
2019
+ if (arguments.length === 0) {
2020
+ return options.showTodayButton;
2021
+ }
2022
+
2023
+ if (typeof showTodayButton !== 'boolean') {
2024
+ throw new TypeError('showTodayButton() expects a boolean parameter');
2025
+ }
2026
+
2027
+ options.showTodayButton = showTodayButton;
2028
+ if (widget) {
2029
+ hide();
2030
+ show();
2031
+ }
2032
+ return picker;
2033
+ };
2034
+
2035
+ picker.showClear = function (showClear) {
2036
+ if (arguments.length === 0) {
2037
+ return options.showClear;
2038
+ }
2039
+
2040
+ if (typeof showClear !== 'boolean') {
2041
+ throw new TypeError('showClear() expects a boolean parameter');
2042
+ }
2043
+
2044
+ options.showClear = showClear;
2045
+ if (widget) {
2046
+ hide();
2047
+ show();
2048
+ }
2049
+ return picker;
2050
+ };
2051
+
2052
+ picker.widgetParent = function (widgetParent) {
2053
+ if (arguments.length === 0) {
2054
+ return options.widgetParent;
2055
+ }
2056
+
2057
+ if (typeof widgetParent === 'string') {
2058
+ widgetParent = $(widgetParent);
2059
+ }
2060
+
2061
+ if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof $))) {
2062
+ throw new TypeError('widgetParent() expects a string or a jQuery object parameter');
2063
+ }
2064
+
2065
+ options.widgetParent = widgetParent;
2066
+ if (widget) {
2067
+ hide();
2068
+ show();
2069
+ }
2070
+ return picker;
2071
+ };
2072
+
2073
+ picker.keepOpen = function (keepOpen) {
2074
+ if (arguments.length === 0) {
2075
+ return options.keepOpen;
2076
+ }
2077
+
2078
+ if (typeof keepOpen !== 'boolean') {
2079
+ throw new TypeError('keepOpen() expects a boolean parameter');
2080
+ }
2081
+
2082
+ options.keepOpen = keepOpen;
2083
+ return picker;
2084
+ };
2085
+
2086
+ picker.focusOnShow = function (focusOnShow) {
2087
+ if (arguments.length === 0) {
2088
+ return options.focusOnShow;
2089
+ }
2090
+
2091
+ if (typeof focusOnShow !== 'boolean') {
2092
+ throw new TypeError('focusOnShow() expects a boolean parameter');
2093
+ }
2094
+
2095
+ options.focusOnShow = focusOnShow;
2096
+ return picker;
2097
+ };
2098
+
2099
+ picker.inline = function (inline) {
2100
+ if (arguments.length === 0) {
2101
+ return options.inline;
2102
+ }
2103
+
2104
+ if (typeof inline !== 'boolean') {
2105
+ throw new TypeError('inline() expects a boolean parameter');
2106
+ }
2107
+
2108
+ options.inline = inline;
2109
+ return picker;
2110
+ };
2111
+
2112
+ picker.clear = function () {
2113
+ clear();
2114
+ return picker;
2115
+ };
2116
+
2117
+ picker.keyBinds = function (keyBinds) {
2118
+ if (arguments.length === 0) {
2119
+ return options.keyBinds;
2120
+ }
2121
+
2122
+ options.keyBinds = keyBinds;
2123
+ return picker;
2124
+ };
2125
+
2126
+ picker.getMoment = function (d) {
2127
+ return getMoment(d);
2128
+ };
2129
+
2130
+ picker.debug = function (debug) {
2131
+ if (typeof debug !== 'boolean') {
2132
+ throw new TypeError('debug() expects a boolean parameter');
2133
+ }
2134
+
2135
+ options.debug = debug;
2136
+ return picker;
2137
+ };
2138
+
2139
+ picker.allowInputToggle = function (allowInputToggle) {
2140
+ if (arguments.length === 0) {
2141
+ return options.allowInputToggle;
2142
+ }
2143
+
2144
+ if (typeof allowInputToggle !== 'boolean') {
2145
+ throw new TypeError('allowInputToggle() expects a boolean parameter');
2146
+ }
2147
+
2148
+ options.allowInputToggle = allowInputToggle;
2149
+ return picker;
2150
+ };
2151
+
2152
+ picker.showClose = function (showClose) {
2153
+ if (arguments.length === 0) {
2154
+ return options.showClose;
2155
+ }
2156
+
2157
+ if (typeof showClose !== 'boolean') {
2158
+ throw new TypeError('showClose() expects a boolean parameter');
2159
+ }
2160
+
2161
+ options.showClose = showClose;
2162
+ return picker;
2163
+ };
2164
+
2165
+ picker.keepInvalid = function (keepInvalid) {
2166
+ if (arguments.length === 0) {
2167
+ return options.keepInvalid;
2168
+ }
2169
+
2170
+ if (typeof keepInvalid !== 'boolean') {
2171
+ throw new TypeError('keepInvalid() expects a boolean parameter');
2172
+ }
2173
+ options.keepInvalid = keepInvalid;
2174
+ return picker;
2175
+ };
2176
+
2177
+ picker.datepickerInput = function (datepickerInput) {
2178
+ if (arguments.length === 0) {
2179
+ return options.datepickerInput;
2180
+ }
2181
+
2182
+ if (typeof datepickerInput !== 'string') {
2183
+ throw new TypeError('datepickerInput() expects a string parameter');
2184
+ }
2185
+
2186
+ options.datepickerInput = datepickerInput;
2187
+ return picker;
2188
+ };
2189
+
2190
+ picker.parseInputDate = function (parseInputDate) {
2191
+ if (arguments.length === 0) {
2192
+ return options.parseInputDate;
2193
+ }
2194
+
2195
+ if (typeof parseInputDate !== 'function') {
2196
+ throw new TypeError('parseInputDate() sholud be as function');
2197
+ }
2198
+
2199
+ options.parseInputDate = parseInputDate;
2200
+
2201
+ return picker;
2202
+ };
2203
+
2204
+ picker.disabledTimeIntervals = function (disabledTimeIntervals) {
2205
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledTimeIntervals">
2206
+ ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
2207
+ ///<returns type="array">options.disabledTimeIntervals</returns>
2208
+ ///</signature>
2209
+ ///<signature>
2210
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
2211
+ ///options.enabledDates if such exist.</summary>
2212
+ ///<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>
2213
+ ///</signature>
2214
+ if (arguments.length === 0) {
2215
+ return (options.disabledTimeIntervals ? $.extend({}, options.disabledTimeIntervals) : options.disabledTimeIntervals);
2216
+ }
2217
+
2218
+ if (!disabledTimeIntervals) {
2219
+ options.disabledTimeIntervals = false;
2220
+ update();
2221
+ return picker;
2222
+ }
2223
+ if (!(disabledTimeIntervals instanceof Array)) {
2224
+ throw new TypeError('disabledTimeIntervals() expects an array parameter');
2225
+ }
2226
+ options.disabledTimeIntervals = disabledTimeIntervals;
2227
+ update();
2228
+ return picker;
2229
+ };
2230
+
2231
+ picker.disabledHours = function (hours) {
2232
+ ///<signature helpKeyword="$.fn.datetimepicker.disabledHours">
2233
+ ///<summary>Returns an array with the currently set disabled hours on the component.</summary>
2234
+ ///<returns type="array">options.disabledHours</returns>
2235
+ ///</signature>
2236
+ ///<signature>
2237
+ ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
2238
+ ///options.enabledHours if such exist.</summary>
2239
+ ///<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>
2240
+ ///</signature>
2241
+ if (arguments.length === 0) {
2242
+ return (options.disabledHours ? $.extend({}, options.disabledHours) : options.disabledHours);
2243
+ }
2244
+
2245
+ if (!hours) {
2246
+ options.disabledHours = false;
2247
+ update();
2248
+ return picker;
2249
+ }
2250
+ if (!(hours instanceof Array)) {
2251
+ throw new TypeError('disabledHours() expects an array parameter');
2252
+ }
2253
+ options.disabledHours = indexGivenHours(hours);
2254
+ options.enabledHours = false;
2255
+ if (options.useCurrent && !options.keepInvalid) {
2256
+ var tries = 0;
2257
+ while (!isValid(date, 'h')) {
2258
+ date.add(1, 'h');
2259
+ if (tries === 24) {
2260
+ throw 'Tried 24 times to find a valid date';
2261
+ }
2262
+ tries++;
2263
+ }
2264
+ setValue(date);
2265
+ }
2266
+ update();
2267
+ return picker;
2268
+ };
2269
+
2270
+ picker.enabledHours = function (hours) {
2271
+ ///<signature helpKeyword="$.fn.datetimepicker.enabledHours">
2272
+ ///<summary>Returns an array with the currently set enabled hours on the component.</summary>
2273
+ ///<returns type="array">options.enabledHours</returns>
2274
+ ///</signature>
2275
+ ///<signature>
2276
+ ///<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>
2277
+ ///<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>
2278
+ ///</signature>
2279
+ if (arguments.length === 0) {
2280
+ return (options.enabledHours ? $.extend({}, options.enabledHours) : options.enabledHours);
2281
+ }
2282
+
2283
+ if (!hours) {
2284
+ options.enabledHours = false;
2285
+ update();
2286
+ return picker;
2287
+ }
2288
+ if (!(hours instanceof Array)) {
2289
+ throw new TypeError('enabledHours() expects an array parameter');
2290
+ }
2291
+ options.enabledHours = indexGivenHours(hours);
2292
+ options.disabledHours = false;
2293
+ if (options.useCurrent && !options.keepInvalid) {
2294
+ var tries = 0;
2295
+ while (!isValid(date, 'h')) {
2296
+ date.add(1, 'h');
2297
+ if (tries === 24) {
2298
+ throw 'Tried 24 times to find a valid date';
2299
+ }
2300
+ tries++;
2301
+ }
2302
+ setValue(date);
2303
+ }
2304
+ update();
2305
+ return picker;
2306
+ };
2307
+ /**
2308
+ * Returns the component's model current viewDate, a moment object or null if not set. 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.
2309
+ * @param {Takes string, viewDate, moment, null parameter.} newDate
2310
+ * @returns {viewDate.clone()}
2311
+ */
2312
+ picker.viewDate = function (newDate) {
2313
+ if (arguments.length === 0) {
2314
+ return viewDate.clone();
2315
+ }
2316
+
2317
+ if (!newDate) {
2318
+ viewDate = date.clone();
2319
+ return picker;
2320
+ }
2321
+
2322
+ if (typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
2323
+ throw new TypeError('viewDate() parameter must be one of [string, moment or Date]');
2324
+ }
2325
+
2326
+ viewDate = parseInputDate(newDate);
2327
+ viewUpdate();
2328
+ return picker;
2329
+ };
2330
+
2331
+ // initializing element and component attributes
2332
+ if (element.is('input')) {
2333
+ input = element;
2334
+ } else {
2335
+ input = element.find(options.datepickerInput);
2336
+ if (input.length === 0) {
2337
+ input = element.find('input');
2338
+ } else if (!input.is('input')) {
2339
+ throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element');
2340
+ }
2341
+ }
2342
+
2343
+ if (element.hasClass('input-group')) {
2344
+ // in case there is more then one 'input-group-addon' Issue #48
2345
+ if (element.find('.datepickerbutton').length === 0) {
2346
+ component = element.find('.input-group-addon');
2347
+ } else {
2348
+ component = element.find('.datepickerbutton');
2349
+ }
2350
+ }
2351
+
2352
+ if (!options.inline && !input.is('input')) {
2353
+ throw new Error('Could not initialize DateTimePicker without an input element');
2354
+ }
2355
+
2356
+ // Set defaults for date here now instead of in var declaration
2357
+ date = getMoment();
2358
+ viewDate = date.clone();
2359
+
2360
+ $.extend(true, options, dataToOptions());
2361
+
2362
+ picker.options(options);
2363
+
2364
+ initFormatting();
2365
+
2366
+ attachDatePickerElementEvents();
2367
+
2368
+ if (input.prop('disabled')) {
2369
+ picker.disable();
2370
+ }
2371
+ if (input.is('input') && input.val().trim().length !== 0) {
2372
+ setValue(parseInputDate(input.val().trim()));
2373
+ }
2374
+ else if (options.defaultDate && input.attr('placeholder') === undefined) {
2375
+ setValue(options.defaultDate);
2376
+ }
2377
+ if (options.inline) {
2378
+ show();
2379
+ }
2380
+ return picker;
2381
+ };
2382
+
2383
+ /********************************************************************************
2384
+ *
2385
+ * jQuery plugin constructor and defaults object
2386
+ *
2387
+ ********************************************************************************/
2388
+
2389
+ /**
2390
+ * See (http://jquery.com/).
2391
+ * @name jQuery
2392
+ * @class
2393
+ * See the jQuery Library (http://jquery.com/) for full details. This just
2394
+ * documents the function and classes that are added to jQuery by this plug-in.
2395
+ */
2396
+ /**
2397
+ * See (http://jquery.com/)
2398
+ * @name fn
2399
+ * @class
2400
+ * See the jQuery Library (http://jquery.com/) for full details. This just
2401
+ * documents the function and classes that are added to jQuery by this plug-in.
2402
+ * @memberOf jQuery
2403
+ */
2404
+ /**
2405
+ * Show comments
2406
+ * @class datetimepicker
2407
+ * @memberOf jQuery.fn
2408
+ */
2409
+ $.fn.datetimepicker = function (options) {
2410
+ options = options || {};
2411
+
2412
+ var args = Array.prototype.slice.call(arguments, 1),
2413
+ isInstance = true,
2414
+ thisMethods = ['destroy', 'hide', 'show', 'toggle'],
2415
+ returnValue;
2416
+
2417
+ if (typeof options === 'object') {
2418
+ return this.each(function () {
2419
+ var $this = $(this),
2420
+ _options;
2421
+ if (!$this.data('DateTimePicker')) {
2422
+ // create a private copy of the defaults object
2423
+ _options = $.extend(true, {}, $.fn.datetimepicker.defaults, options);
2424
+ $this.data('DateTimePicker', dateTimePicker($this, _options));
2425
+ }
2426
+ });
2427
+ } else if (typeof options === 'string') {
2428
+ this.each(function () {
2429
+ var $this = $(this),
2430
+ instance = $this.data('DateTimePicker');
2431
+ if (!instance) {
2432
+ throw new Error('bootstrap-datetimepicker("' + options + '") method was called on an element that is not using DateTimePicker');
2433
+ }
2434
+
2435
+ returnValue = instance[options].apply(instance, args);
2436
+ isInstance = returnValue === instance;
2437
+ });
2438
+
2439
+ if (isInstance || $.inArray(options, thisMethods) > -1) {
2440
+ return this;
2441
+ }
2442
+
2443
+ return returnValue;
2444
+ }
2445
+
2446
+ throw new TypeError('Invalid arguments for DateTimePicker: ' + options);
2447
+ };
2448
+
2449
+ $.fn.datetimepicker.defaults = {
2450
+ timeZone: '',
2451
+ format: false,
2452
+ dayViewHeaderFormat: 'MMMM YYYY',
2453
+ extraFormats: false,
2454
+ stepping: 1,
2455
+ minDate: false,
2456
+ maxDate: false,
2457
+ useCurrent: true,
2458
+ collapse: true,
2459
+ locale: moment.locale(),
2460
+ defaultDate: false,
2461
+ disabledDates: false,
2462
+ enabledDates: false,
2463
+ icons: {
2464
+ time: 'glyphicon glyphicon-time',
2465
+ date: 'glyphicon glyphicon-calendar',
2466
+ up: 'glyphicon glyphicon-chevron-up',
2467
+ down: 'glyphicon glyphicon-chevron-down',
2468
+ previous: 'glyphicon glyphicon-chevron-left',
2469
+ next: 'glyphicon glyphicon-chevron-right',
2470
+ today: 'glyphicon glyphicon-screenshot',
2471
+ clear: 'glyphicon glyphicon-trash',
2472
+ close: 'glyphicon glyphicon-remove'
2473
+ },
2474
+ tooltips: {
2475
+ today: 'Go to today',
2476
+ clear: 'Clear selection',
2477
+ close: 'Close the picker',
2478
+ selectMonth: 'Select Month',
2479
+ prevMonth: 'Previous Month',
2480
+ nextMonth: 'Next Month',
2481
+ selectYear: 'Select Year',
2482
+ prevYear: 'Previous Year',
2483
+ nextYear: 'Next Year',
2484
+ selectDecade: 'Select Decade',
2485
+ prevDecade: 'Previous Decade',
2486
+ nextDecade: 'Next Decade',
2487
+ prevCentury: 'Previous Century',
2488
+ nextCentury: 'Next Century',
2489
+ pickHour: 'Pick Hour',
2490
+ incrementHour: 'Increment Hour',
2491
+ decrementHour: 'Decrement Hour',
2492
+ pickMinute: 'Pick Minute',
2493
+ incrementMinute: 'Increment Minute',
2494
+ decrementMinute: 'Decrement Minute',
2495
+ pickSecond: 'Pick Second',
2496
+ incrementSecond: 'Increment Second',
2497
+ decrementSecond: 'Decrement Second',
2498
+ togglePeriod: 'Toggle Period',
2499
+ selectTime: 'Select Time'
2500
+ },
2501
+ useStrict: false,
2502
+ sideBySide: false,
2503
+ daysOfWeekDisabled: false,
2504
+ calendarWeeks: false,
2505
+ viewMode: 'days',
2506
+ toolbarPlacement: 'default',
2507
+ showTodayButton: false,
2508
+ showClear: false,
2509
+ showClose: false,
2510
+ widgetPositioning: {
2511
+ horizontal: 'auto',
2512
+ vertical: 'auto'
2513
+ },
2514
+ widgetParent: null,
2515
+ ignoreReadonly: false,
2516
+ keepOpen: false,
2517
+ focusOnShow: true,
2518
+ inline: false,
2519
+ keepInvalid: false,
2520
+ datepickerInput: '.datepickerinput',
2521
+ keyBinds: {
2522
+ up: function (widget) {
2523
+ if (!widget) {
2524
+ return;
2525
+ }
2526
+ var d = this.date() || this.getMoment();
2527
+ if (widget.find('.datepicker').is(':visible')) {
2528
+ this.date(d.clone().subtract(7, 'd'));
2529
+ } else {
2530
+ this.date(d.clone().add(this.stepping(), 'm'));
2531
+ }
2532
+ },
2533
+ down: function (widget) {
2534
+ if (!widget) {
2535
+ this.show();
2536
+ return;
2537
+ }
2538
+ var d = this.date() || this.getMoment();
2539
+ if (widget.find('.datepicker').is(':visible')) {
2540
+ this.date(d.clone().add(7, 'd'));
2541
+ } else {
2542
+ this.date(d.clone().subtract(this.stepping(), 'm'));
2543
+ }
2544
+ },
2545
+ 'control up': function (widget) {
2546
+ if (!widget) {
2547
+ return;
2548
+ }
2549
+ var d = this.date() || this.getMoment();
2550
+ if (widget.find('.datepicker').is(':visible')) {
2551
+ this.date(d.clone().subtract(1, 'y'));
2552
+ } else {
2553
+ this.date(d.clone().add(1, 'h'));
2554
+ }
2555
+ },
2556
+ 'control down': function (widget) {
2557
+ if (!widget) {
2558
+ return;
2559
+ }
2560
+ var d = this.date() || this.getMoment();
2561
+ if (widget.find('.datepicker').is(':visible')) {
2562
+ this.date(d.clone().add(1, 'y'));
2563
+ } else {
2564
+ this.date(d.clone().subtract(1, 'h'));
2565
+ }
2566
+ },
2567
+ left: function (widget) {
2568
+ if (!widget) {
2569
+ return;
2570
+ }
2571
+ var d = this.date() || this.getMoment();
2572
+ if (widget.find('.datepicker').is(':visible')) {
2573
+ this.date(d.clone().subtract(1, 'd'));
2574
+ }
2575
+ },
2576
+ right: function (widget) {
2577
+ if (!widget) {
2578
+ return;
2579
+ }
2580
+ var d = this.date() || this.getMoment();
2581
+ if (widget.find('.datepicker').is(':visible')) {
2582
+ this.date(d.clone().add(1, 'd'));
2583
+ }
2584
+ },
2585
+ pageUp: function (widget) {
2586
+ if (!widget) {
2587
+ return;
2588
+ }
2589
+ var d = this.date() || this.getMoment();
2590
+ if (widget.find('.datepicker').is(':visible')) {
2591
+ this.date(d.clone().subtract(1, 'M'));
2592
+ }
2593
+ },
2594
+ pageDown: function (widget) {
2595
+ if (!widget) {
2596
+ return;
2597
+ }
2598
+ var d = this.date() || this.getMoment();
2599
+ if (widget.find('.datepicker').is(':visible')) {
2600
+ this.date(d.clone().add(1, 'M'));
2601
+ }
2602
+ },
2603
+ enter: function () {
2604
+ this.hide();
2605
+ },
2606
+ escape: function () {
2607
+ this.hide();
2608
+ },
2609
+ //tab: function (widget) { //this break the flow of the form. disabling for now
2610
+ // var toggle = widget.find('.picker-switch a[data-action="togglePicker"]');
2611
+ // if(toggle.length > 0) toggle.click();
2612
+ //},
2613
+ 'control space': function (widget) {
2614
+ if (!widget) {
2615
+ return;
2616
+ }
2617
+ if (widget.find('.timepicker').is(':visible')) {
2618
+ widget.find('.btn[data-action="togglePeriod"]').click();
2619
+ }
2620
+ },
2621
+ t: function () {
2622
+ this.date(this.getMoment());
2623
+ },
2624
+ 'delete': function () {
2625
+ this.clear();
2626
+ }
2627
+ },
2628
+ debug: false,
2629
+ allowInputToggle: false,
2630
+ disabledTimeIntervals: false,
2631
+ disabledHours: false,
2632
+ enabledHours: false,
2633
+ viewDate: false
2634
+ };
2635
+
2636
+ return $.fn.datetimepicker;
2637
+ }));