├── .gitignore
├── .versions
├── LICENSE
├── README.md
├── bootstrap-editable.css
├── editable.html
├── editable.js
├── img
├── clear.png
└── loading.gif
├── inputs
├── checklist
│ ├── checklist.html
│ └── checklist.js
├── combodate
│ ├── combodate.html
│ └── combodate.js
├── date
│ ├── date.html
│ └── date.js
├── datetime
│ ├── datetime.html
│ └── datetime.js
├── radiolist
│ ├── radiolist.html
│ └── radiolist.js
├── select
│ ├── select.html
│ └── select.js
├── select2
│ ├── select2.html
│ └── select2.js
├── text
│ ├── text.html
│ └── text.js
└── textarea
│ ├── textarea.html
│ └── textarea.js
├── lib
├── bootstrap-datetimepicker
│ ├── bootstrap-datetimepicker.css
│ └── bootstrap-datetimepicker.js
├── combodate
│ └── combodate.js
└── select2
│ ├── select2.css
│ ├── select2.js
│ ├── select2.png
│ └── select2x2.png
├── package.js
├── smart.json
└── versions.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .build*
2 | .idea
3 |
--------------------------------------------------------------------------------
/.versions:
--------------------------------------------------------------------------------
1 | allow-deny@1.0.4
2 | autoupdate@1.2.9
3 | babel-compiler@6.6.4
4 | babel-runtime@0.1.8
5 | base64@1.0.8
6 | binary-heap@1.0.8
7 | blaze@2.1.7
8 | blaze-tools@1.0.8
9 | boilerplate-generator@1.0.8
10 | caching-compiler@1.0.4
11 | caching-html-compiler@1.0.6
12 | callback-hook@1.0.8
13 | check@1.2.1
14 | ddp@1.2.5
15 | ddp-client@1.2.7
16 | ddp-common@1.2.5
17 | ddp-server@1.2.6
18 | deps@1.0.12
19 | diff-sequence@1.0.5
20 | ecmascript@0.4.3
21 | ecmascript-runtime@0.2.10
22 | ejson@1.0.11
23 | fastclick@1.0.11
24 | geojson-utils@1.0.8
25 | html-tools@1.0.9
26 | htmljs@1.0.9
27 | http@1.1.5
28 | id-map@1.0.7
29 | jquery@1.11.8
30 | launch-screen@1.0.11
31 | livedata@1.0.18
32 | logging@1.0.12
33 | meteor@1.1.14
34 | meteor-platform@1.2.6
35 | minifier-js@1.1.11
36 | minimongo@1.0.16
37 | mobile-status-bar@1.0.12
38 | modules@0.6.1
39 | modules-runtime@0.6.3
40 | mongo@1.1.7
41 | mongo-id@1.0.4
42 | npm-mongo@1.4.43
43 | observe-sequence@1.0.11
44 | ordered-dict@1.0.7
45 | promise@0.6.7
46 | random@1.0.9
47 | reactive-dict@1.1.7
48 | reactive-var@1.0.9
49 | reload@1.1.8
50 | retry@1.0.7
51 | routepolicy@1.0.10
52 | session@1.1.5
53 | spacebars@1.0.11
54 | spacebars-compiler@1.0.11
55 | templating@1.1.9
56 | templating-tools@1.0.4
57 | tracker@1.0.13
58 | ui@1.0.11
59 | underscore@1.0.8
60 | url@1.0.9
61 | webapp@1.2.8
62 | webapp-hashing@1.0.9
63 | workman:meteor-editable@0.2.0
64 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Dave Workman
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | meteor-editable
2 | ===============
3 |
4 | X-Editable inspired Meteor package for inline edits.
5 | Demo's and documentation here: http://meteor-editable.meteor.com
6 |
7 | License: MIT
--------------------------------------------------------------------------------
/bootstrap-editable.css:
--------------------------------------------------------------------------------
1 | /*! X-editable - v1.5.1
2 | * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
3 | * http://github.com/vitalets/x-editable
4 | * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
5 | .editableform {
6 | margin-bottom: 0; /* overwrites bootstrap margin */
7 | }
8 |
9 | .editableform .control-group {
10 | margin-bottom: 0; /* overwrites bootstrap margin */
11 | white-space: nowrap; /* prevent wrapping buttons on new line */
12 | line-height: 20px; /* overwriting bootstrap line-height. See #133 */
13 | }
14 |
15 | /*
16 | BS3 width:1005 for inputs breaks editable form in popup
17 | See: https://github.com/vitalets/x-editable/issues/393
18 | */
19 | .editableform .form-control {
20 | width: auto;
21 | }
22 |
23 | .editable-buttons {
24 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
25 | vertical-align: top;
26 | margin-left: 7px;
27 | /* inline-block emulation for IE7*/
28 | zoom: 1;
29 | *display: inline;
30 | }
31 |
32 | .editable-buttons.editable-buttons-bottom {
33 | display: block;
34 | margin-top: 7px;
35 | margin-left: 0;
36 | }
37 |
38 | .editable-input {
39 | vertical-align: top;
40 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
41 | width: auto; /* bootstrap-responsive has width: 100% that breakes layout */
42 | white-space: normal; /* reset white-space decalred in parent*/
43 | /* display-inline emulation for IE7*/
44 | zoom: 1;
45 | *display: inline;
46 | }
47 |
48 | .editable-buttons .editable-cancel {
49 | margin-left: 7px;
50 | }
51 |
52 | /*for jquery-ui buttons need set height to look more pretty*/
53 | .editable-buttons button.ui-button-icon-only {
54 | height: 24px;
55 | width: 30px;
56 | }
57 |
58 | .editableform-loading {
59 | background: url('/img/loading.gif') center center no-repeat;
60 | height: 25px;
61 | width: auto;
62 | min-width: 25px;
63 | }
64 |
65 | .editable-inline .editableform-loading {
66 | background-position: left 5px;
67 | }
68 |
69 | .editable-error-block {
70 | max-width: 300px;
71 | margin: 5px 0 0 0;
72 | width: auto;
73 | white-space: normal;
74 | }
75 |
76 | /*add padding for jquery ui*/
77 | .editable-error-block.ui-state-error {
78 | padding: 3px;
79 | }
80 |
81 | .editable-error {
82 | color: red;
83 | }
84 |
85 | /* ---- For specific types ---- */
86 |
87 | .editableform .editable-date {
88 | padding: 0;
89 | margin: 0;
90 | float: left;
91 | }
92 |
93 | /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */
94 | .editable-inline .add-on .icon-th {
95 | margin-top: 3px;
96 | margin-left: 1px;
97 | }
98 |
99 |
100 | /* checklist vertical alignment */
101 | .editable-checklist label input[type="checkbox"],
102 | .editable-checklist label span {
103 | vertical-align: middle;
104 | margin: 0;
105 | }
106 |
107 | .editable-checklist label {
108 | white-space: nowrap;
109 | }
110 |
111 | /* set exact width of textarea to fit buttons toolbar */
112 | .editable-wysihtml5 {
113 | width: 566px;
114 | height: 250px;
115 | }
116 |
117 | /* clear button shown as link in date inputs */
118 | .editable-clear {
119 | clear: both;
120 | font-size: 0.9em;
121 | text-decoration: none;
122 | text-align: right;
123 | }
124 |
125 | /* IOS-style clear button for text inputs */
126 | .editable-clear-x {
127 | background: url('/img/clear.png') center center no-repeat;
128 | display: block;
129 | width: 13px;
130 | height: 13px;
131 | position: absolute;
132 | opacity: 0.6;
133 | z-index: 100;
134 | top: 50%;
135 | right: 6px;
136 | margin-top: -6px;
137 |
138 | }
139 |
140 | .editable-clear-x:hover {
141 | opacity: 1;
142 | }
143 |
144 | .editable-pre-wrapped {
145 | white-space: pre-wrap;
146 | }
147 | .editable-container.editable-popup {
148 | max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
149 | }
150 |
151 | .editable-container.popover {
152 | width: auto; /* without this rule popover does not stretch */
153 | }
154 |
155 | .editable-container.editable-inline {
156 | display: inline-block;
157 | vertical-align: middle;
158 | width: auto;
159 | /* inline-block emulation for IE7*/
160 | zoom: 1;
161 | *display: inline;
162 | }
163 |
164 | .editable-container.ui-widget {
165 | font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */
166 | z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */
167 | }
168 | .editable-click,
169 | a.editable-click,
170 | a.editable-click:hover {
171 | text-decoration: none;
172 | border-bottom: dashed 1px #0088cc;
173 | }
174 |
175 | .editable-click.editable-disabled,
176 | a.editable-click.editable-disabled,
177 | a.editable-click.editable-disabled:hover {
178 | color: #585858;
179 | cursor: default;
180 | border-bottom: none;
181 | }
182 |
183 | .editable-empty, .editable-empty:hover, .editable-empty:focus{
184 | font-style: italic;
185 | color: #DD1144;
186 | /* border-bottom: none; */
187 | text-decoration: none;
188 | }
189 |
190 | .editable-unsaved {
191 | font-weight: bold;
192 | }
193 |
194 | .editable-unsaved:after {
195 | /* content: '*'*/
196 | }
197 |
198 | .editable-bg-transition {
199 | -webkit-transition: background-color 1400ms ease-out;
200 | -moz-transition: background-color 1400ms ease-out;
201 | -o-transition: background-color 1400ms ease-out;
202 | -ms-transition: background-color 1400ms ease-out;
203 | transition: background-color 1400ms ease-out;
204 | }
205 |
206 | /*see https://github.com/vitalets/x-editable/issues/139 */
207 | .form-horizontal .editable
208 | {
209 | padding-top: 5px;
210 | display:inline-block;
211 | }
212 |
213 |
214 | /*!
215 | * Datepicker for Bootstrap
216 | *
217 | * Copyright 2012 Stefan Petre
218 | * Improvements by Andrew Rowls
219 | * Licensed under the Apache License v2.0
220 | * http://www.apache.org/licenses/LICENSE-2.0
221 | *
222 | */
223 | .datepicker {
224 | padding: 4px;
225 | -webkit-border-radius: 4px;
226 | -moz-border-radius: 4px;
227 | border-radius: 4px;
228 | direction: ltr;
229 | /*.dow {
230 | border-top: 1px solid #ddd !important;
231 | }*/
232 |
233 | }
234 | .datepicker-inline {
235 | width: 220px;
236 | }
237 | .datepicker.datepicker-rtl {
238 | direction: rtl;
239 | }
240 | .datepicker.datepicker-rtl table tr td span {
241 | float: right;
242 | }
243 | .datepicker-dropdown {
244 | top: 0;
245 | left: 0;
246 | }
247 | .datepicker-dropdown:before {
248 | content: '';
249 | display: inline-block;
250 | border-left: 7px solid transparent;
251 | border-right: 7px solid transparent;
252 | border-bottom: 7px solid #ccc;
253 | border-bottom-color: rgba(0, 0, 0, 0.2);
254 | position: absolute;
255 | top: -7px;
256 | left: 6px;
257 | }
258 | .datepicker-dropdown:after {
259 | content: '';
260 | display: inline-block;
261 | border-left: 6px solid transparent;
262 | border-right: 6px solid transparent;
263 | border-bottom: 6px solid #ffffff;
264 | position: absolute;
265 | top: -6px;
266 | left: 7px;
267 | }
268 | .datepicker > div {
269 | display: none;
270 | }
271 | .datepicker.days div.datepicker-days {
272 | display: block;
273 | }
274 | .datepicker.months div.datepicker-months {
275 | display: block;
276 | }
277 | .datepicker.years div.datepicker-years {
278 | display: block;
279 | }
280 | .datepicker table {
281 | margin: 0;
282 | }
283 | .datepicker td,
284 | .datepicker th {
285 | text-align: center;
286 | width: 20px;
287 | height: 20px;
288 | -webkit-border-radius: 4px;
289 | -moz-border-radius: 4px;
290 | border-radius: 4px;
291 | border: none;
292 | }
293 | .table-striped .datepicker table tr td,
294 | .table-striped .datepicker table tr th {
295 | background-color: transparent;
296 | }
297 | .datepicker table tr td.day:hover {
298 | background: #eeeeee;
299 | cursor: pointer;
300 | }
301 | .datepicker table tr td.old,
302 | .datepicker table tr td.new {
303 | color: #999999;
304 | }
305 | .datepicker table tr td.disabled,
306 | .datepicker table tr td.disabled:hover {
307 | background: none;
308 | color: #999999;
309 | cursor: default;
310 | }
311 | .datepicker table tr td.today,
312 | .datepicker table tr td.today:hover,
313 | .datepicker table tr td.today.disabled,
314 | .datepicker table tr td.today.disabled:hover {
315 | background-color: #fde19a;
316 | background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
317 | background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
318 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
319 | background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
320 | background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
321 | background-image: linear-gradient(top, #fdd49a, #fdf59a);
322 | background-repeat: repeat-x;
323 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
324 | border-color: #fdf59a #fdf59a #fbed50;
325 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
326 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
327 | color: #000;
328 | }
329 | .datepicker table tr td.today:hover,
330 | .datepicker table tr td.today:hover:hover,
331 | .datepicker table tr td.today.disabled:hover,
332 | .datepicker table tr td.today.disabled:hover:hover,
333 | .datepicker table tr td.today:active,
334 | .datepicker table tr td.today:hover:active,
335 | .datepicker table tr td.today.disabled:active,
336 | .datepicker table tr td.today.disabled:hover:active,
337 | .datepicker table tr td.today.active,
338 | .datepicker table tr td.today:hover.active,
339 | .datepicker table tr td.today.disabled.active,
340 | .datepicker table tr td.today.disabled:hover.active,
341 | .datepicker table tr td.today.disabled,
342 | .datepicker table tr td.today:hover.disabled,
343 | .datepicker table tr td.today.disabled.disabled,
344 | .datepicker table tr td.today.disabled:hover.disabled,
345 | .datepicker table tr td.today[disabled],
346 | .datepicker table tr td.today:hover[disabled],
347 | .datepicker table tr td.today.disabled[disabled],
348 | .datepicker table tr td.today.disabled:hover[disabled] {
349 | background-color: #fdf59a;
350 | }
351 | .datepicker table tr td.today:active,
352 | .datepicker table tr td.today:hover:active,
353 | .datepicker table tr td.today.disabled:active,
354 | .datepicker table tr td.today.disabled:hover:active,
355 | .datepicker table tr td.today.active,
356 | .datepicker table tr td.today:hover.active,
357 | .datepicker table tr td.today.disabled.active,
358 | .datepicker table tr td.today.disabled:hover.active {
359 | background-color: #fbf069 \9;
360 | }
361 | .datepicker table tr td.today:hover:hover {
362 | color: #000;
363 | }
364 | .datepicker table tr td.today.active:hover {
365 | color: #fff;
366 | }
367 | .datepicker table tr td.range,
368 | .datepicker table tr td.range:hover,
369 | .datepicker table tr td.range.disabled,
370 | .datepicker table tr td.range.disabled:hover {
371 | background: #eeeeee;
372 | -webkit-border-radius: 0;
373 | -moz-border-radius: 0;
374 | border-radius: 0;
375 | }
376 | .datepicker table tr td.range.today,
377 | .datepicker table tr td.range.today:hover,
378 | .datepicker table tr td.range.today.disabled,
379 | .datepicker table tr td.range.today.disabled:hover {
380 | background-color: #f3d17a;
381 | background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a);
382 | background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a);
383 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
384 | background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a);
385 | background-image: -o-linear-gradient(top, #f3c17a, #f3e97a);
386 | background-image: linear-gradient(top, #f3c17a, #f3e97a);
387 | background-repeat: repeat-x;
388 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
389 | border-color: #f3e97a #f3e97a #edde34;
390 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
391 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
392 | -webkit-border-radius: 0;
393 | -moz-border-radius: 0;
394 | border-radius: 0;
395 | }
396 | .datepicker table tr td.range.today:hover,
397 | .datepicker table tr td.range.today:hover:hover,
398 | .datepicker table tr td.range.today.disabled:hover,
399 | .datepicker table tr td.range.today.disabled:hover:hover,
400 | .datepicker table tr td.range.today:active,
401 | .datepicker table tr td.range.today:hover:active,
402 | .datepicker table tr td.range.today.disabled:active,
403 | .datepicker table tr td.range.today.disabled:hover:active,
404 | .datepicker table tr td.range.today.active,
405 | .datepicker table tr td.range.today:hover.active,
406 | .datepicker table tr td.range.today.disabled.active,
407 | .datepicker table tr td.range.today.disabled:hover.active,
408 | .datepicker table tr td.range.today.disabled,
409 | .datepicker table tr td.range.today:hover.disabled,
410 | .datepicker table tr td.range.today.disabled.disabled,
411 | .datepicker table tr td.range.today.disabled:hover.disabled,
412 | .datepicker table tr td.range.today[disabled],
413 | .datepicker table tr td.range.today:hover[disabled],
414 | .datepicker table tr td.range.today.disabled[disabled],
415 | .datepicker table tr td.range.today.disabled:hover[disabled] {
416 | background-color: #f3e97a;
417 | }
418 | .datepicker table tr td.range.today:active,
419 | .datepicker table tr td.range.today:hover:active,
420 | .datepicker table tr td.range.today.disabled:active,
421 | .datepicker table tr td.range.today.disabled:hover:active,
422 | .datepicker table tr td.range.today.active,
423 | .datepicker table tr td.range.today:hover.active,
424 | .datepicker table tr td.range.today.disabled.active,
425 | .datepicker table tr td.range.today.disabled:hover.active {
426 | background-color: #efe24b \9;
427 | }
428 | .datepicker table tr td.selected,
429 | .datepicker table tr td.selected:hover,
430 | .datepicker table tr td.selected.disabled,
431 | .datepicker table tr td.selected.disabled:hover {
432 | background-color: #9e9e9e;
433 | background-image: -moz-linear-gradient(top, #b3b3b3, #808080);
434 | background-image: -ms-linear-gradient(top, #b3b3b3, #808080);
435 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
436 | background-image: -webkit-linear-gradient(top, #b3b3b3, #808080);
437 | background-image: -o-linear-gradient(top, #b3b3b3, #808080);
438 | background-image: linear-gradient(top, #b3b3b3, #808080);
439 | background-repeat: repeat-x;
440 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
441 | border-color: #808080 #808080 #595959;
442 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
443 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
444 | color: #fff;
445 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
446 | }
447 | .datepicker table tr td.selected:hover,
448 | .datepicker table tr td.selected:hover:hover,
449 | .datepicker table tr td.selected.disabled:hover,
450 | .datepicker table tr td.selected.disabled:hover:hover,
451 | .datepicker table tr td.selected:active,
452 | .datepicker table tr td.selected:hover:active,
453 | .datepicker table tr td.selected.disabled:active,
454 | .datepicker table tr td.selected.disabled:hover:active,
455 | .datepicker table tr td.selected.active,
456 | .datepicker table tr td.selected:hover.active,
457 | .datepicker table tr td.selected.disabled.active,
458 | .datepicker table tr td.selected.disabled:hover.active,
459 | .datepicker table tr td.selected.disabled,
460 | .datepicker table tr td.selected:hover.disabled,
461 | .datepicker table tr td.selected.disabled.disabled,
462 | .datepicker table tr td.selected.disabled:hover.disabled,
463 | .datepicker table tr td.selected[disabled],
464 | .datepicker table tr td.selected:hover[disabled],
465 | .datepicker table tr td.selected.disabled[disabled],
466 | .datepicker table tr td.selected.disabled:hover[disabled] {
467 | background-color: #808080;
468 | }
469 | .datepicker table tr td.selected:active,
470 | .datepicker table tr td.selected:hover:active,
471 | .datepicker table tr td.selected.disabled:active,
472 | .datepicker table tr td.selected.disabled:hover:active,
473 | .datepicker table tr td.selected.active,
474 | .datepicker table tr td.selected:hover.active,
475 | .datepicker table tr td.selected.disabled.active,
476 | .datepicker table tr td.selected.disabled:hover.active {
477 | background-color: #666666 \9;
478 | }
479 | .datepicker table tr td.active,
480 | .datepicker table tr td.active:hover,
481 | .datepicker table tr td.active.disabled,
482 | .datepicker table tr td.active.disabled:hover {
483 | background-color: #006dcc;
484 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
485 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
486 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
487 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
488 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
489 | background-image: linear-gradient(top, #0088cc, #0044cc);
490 | background-repeat: repeat-x;
491 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
492 | border-color: #0044cc #0044cc #002a80;
493 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
494 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
495 | color: #fff;
496 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
497 | }
498 | .datepicker table tr td.active:hover,
499 | .datepicker table tr td.active:hover:hover,
500 | .datepicker table tr td.active.disabled:hover,
501 | .datepicker table tr td.active.disabled:hover:hover,
502 | .datepicker table tr td.active:active,
503 | .datepicker table tr td.active:hover:active,
504 | .datepicker table tr td.active.disabled:active,
505 | .datepicker table tr td.active.disabled:hover:active,
506 | .datepicker table tr td.active.active,
507 | .datepicker table tr td.active:hover.active,
508 | .datepicker table tr td.active.disabled.active,
509 | .datepicker table tr td.active.disabled:hover.active,
510 | .datepicker table tr td.active.disabled,
511 | .datepicker table tr td.active:hover.disabled,
512 | .datepicker table tr td.active.disabled.disabled,
513 | .datepicker table tr td.active.disabled:hover.disabled,
514 | .datepicker table tr td.active[disabled],
515 | .datepicker table tr td.active:hover[disabled],
516 | .datepicker table tr td.active.disabled[disabled],
517 | .datepicker table tr td.active.disabled:hover[disabled] {
518 | background-color: #0044cc;
519 | }
520 | .datepicker table tr td.active:active,
521 | .datepicker table tr td.active:hover:active,
522 | .datepicker table tr td.active.disabled:active,
523 | .datepicker table tr td.active.disabled:hover:active,
524 | .datepicker table tr td.active.active,
525 | .datepicker table tr td.active:hover.active,
526 | .datepicker table tr td.active.disabled.active,
527 | .datepicker table tr td.active.disabled:hover.active {
528 | background-color: #003399 \9;
529 | }
530 | .datepicker table tr td span {
531 | display: block;
532 | width: 23%;
533 | height: 54px;
534 | line-height: 54px;
535 | float: left;
536 | margin: 1%;
537 | cursor: pointer;
538 | -webkit-border-radius: 4px;
539 | -moz-border-radius: 4px;
540 | border-radius: 4px;
541 | }
542 | .datepicker table tr td span:hover {
543 | background: #eeeeee;
544 | }
545 | .datepicker table tr td span.disabled,
546 | .datepicker table tr td span.disabled:hover {
547 | background: none;
548 | color: #999999;
549 | cursor: default;
550 | }
551 | .datepicker table tr td span.active,
552 | .datepicker table tr td span.active:hover,
553 | .datepicker table tr td span.active.disabled,
554 | .datepicker table tr td span.active.disabled:hover {
555 | background-color: #006dcc;
556 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
557 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
558 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
559 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
560 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
561 | background-image: linear-gradient(top, #0088cc, #0044cc);
562 | background-repeat: repeat-x;
563 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
564 | border-color: #0044cc #0044cc #002a80;
565 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
566 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
567 | color: #fff;
568 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
569 | }
570 | .datepicker table tr td span.active:hover,
571 | .datepicker table tr td span.active:hover:hover,
572 | .datepicker table tr td span.active.disabled:hover,
573 | .datepicker table tr td span.active.disabled:hover:hover,
574 | .datepicker table tr td span.active:active,
575 | .datepicker table tr td span.active:hover:active,
576 | .datepicker table tr td span.active.disabled:active,
577 | .datepicker table tr td span.active.disabled:hover:active,
578 | .datepicker table tr td span.active.active,
579 | .datepicker table tr td span.active:hover.active,
580 | .datepicker table tr td span.active.disabled.active,
581 | .datepicker table tr td span.active.disabled:hover.active,
582 | .datepicker table tr td span.active.disabled,
583 | .datepicker table tr td span.active:hover.disabled,
584 | .datepicker table tr td span.active.disabled.disabled,
585 | .datepicker table tr td span.active.disabled:hover.disabled,
586 | .datepicker table tr td span.active[disabled],
587 | .datepicker table tr td span.active:hover[disabled],
588 | .datepicker table tr td span.active.disabled[disabled],
589 | .datepicker table tr td span.active.disabled:hover[disabled] {
590 | background-color: #0044cc;
591 | }
592 | .datepicker table tr td span.active:active,
593 | .datepicker table tr td span.active:hover:active,
594 | .datepicker table tr td span.active.disabled:active,
595 | .datepicker table tr td span.active.disabled:hover:active,
596 | .datepicker table tr td span.active.active,
597 | .datepicker table tr td span.active:hover.active,
598 | .datepicker table tr td span.active.disabled.active,
599 | .datepicker table tr td span.active.disabled:hover.active {
600 | background-color: #003399 \9;
601 | }
602 | .datepicker table tr td span.old,
603 | .datepicker table tr td span.new {
604 | color: #999999;
605 | }
606 | .datepicker th.datepicker-switch {
607 | width: 145px;
608 | }
609 | .datepicker thead tr:first-child th,
610 | .datepicker tfoot tr th {
611 | cursor: pointer;
612 | }
613 | .datepicker thead tr:first-child th:hover,
614 | .datepicker tfoot tr th:hover {
615 | background: #eeeeee;
616 | }
617 | .datepicker .cw {
618 | font-size: 10px;
619 | width: 12px;
620 | padding: 0 2px 0 5px;
621 | vertical-align: middle;
622 | }
623 | .datepicker thead tr:first-child th.cw {
624 | cursor: default;
625 | background-color: transparent;
626 | }
627 | .input-append.date .add-on i,
628 | .input-prepend.date .add-on i {
629 | display: block;
630 | cursor: pointer;
631 | width: 16px;
632 | height: 16px;
633 | }
634 | .input-daterange input {
635 | text-align: center;
636 | }
637 | .input-daterange input:first-child {
638 | -webkit-border-radius: 3px 0 0 3px;
639 | -moz-border-radius: 3px 0 0 3px;
640 | border-radius: 3px 0 0 3px;
641 | }
642 | .input-daterange input:last-child {
643 | -webkit-border-radius: 0 3px 3px 0;
644 | -moz-border-radius: 0 3px 3px 0;
645 | border-radius: 0 3px 3px 0;
646 | }
647 | .input-daterange .add-on {
648 | display: inline-block;
649 | width: auto;
650 | min-width: 16px;
651 | height: 18px;
652 | padding: 4px 5px;
653 | font-weight: normal;
654 | line-height: 18px;
655 | text-align: center;
656 | text-shadow: 0 1px 0 #ffffff;
657 | vertical-align: middle;
658 | background-color: #eeeeee;
659 | border: 1px solid #ccc;
660 | margin-left: -5px;
661 | margin-right: -5px;
662 | }
--------------------------------------------------------------------------------
/editable.html:
--------------------------------------------------------------------------------
1 |
2 | {{#with settings}}
3 | {{> m_editable_main}}
4 | {{/with}}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | {{displayVal}}
13 |
14 |
15 |
16 |
56 |
57 |
58 |
59 |
60 | {{> m_editable_template
61 | template=template
62 | disabledTemplate=disabledTemplate
63 | disabled=disabled
64 | displayVal=displayVal
65 | editableEmpty=editableEmpty
66 | handle=handle
67 | extraClasses=extraClasses
68 | }}
69 |
70 | {{#unless appendToBody}}
71 | {{>m_editable_popover}}
72 | {{/unless}}
73 |
74 |
75 |
76 |
77 |
78 | {{> m_editable_body_popovers}}
79 |
80 |
81 |
82 |
83 | {{#each popovers}}
84 |
85 | {{> m_editable_popover data}}
86 |
87 | {{/each}}
88 |
--------------------------------------------------------------------------------
/editable.js:
--------------------------------------------------------------------------------
1 | const POSSIBLE_POSITIONS = ['left', 'right', 'top', 'bottom'];
2 | const bodyPopovers = new Mongo.Collection(null);
3 |
4 | Template.m_editable_main.onCreated(function() {
5 | this.Session = new ReactiveDict();
6 | });
7 |
8 | Template.m_editable_main.onDestroyed(function () {
9 | bodyPopovers.remove({ _id: this.view.editableId });
10 | });
11 |
12 | mEditable = {
13 | _types: new Mongo.Collection(null),
14 | getTemplate (type) {
15 | var t = this._types.findOne({_id: type });
16 | if (!t)
17 | throw new Meteor.Error(500, 'Editable type ' + type + ' is not defined.');
18 | return Template[t.template] || null;
19 | },
20 | getVal (type) {
21 | return this._types.findOne({_id: type }).getVal;
22 | },
23 | addType (type) {
24 | type._id = type.type;
25 | delete type.type;
26 |
27 | // allow users to override types
28 | this._types.remove({_id: type._id });
29 |
30 | check(type, {
31 | _id: Match.Where(function (t) {
32 | check(t, String);
33 | return t !== '';
34 | }),
35 | classes: Match.Optional([String]),
36 | getVal: Function,
37 | template: Match.Where(function (t) {
38 | return typeof t === 'object';
39 | })
40 | });
41 |
42 | // store only the template name
43 | if (type.template.viewName) {
44 | type.template = type.template.viewName.replace(/Template\./, '');
45 | } else if (!type.template.kind) {
46 | type.template = type.template.__templateName;
47 | } else {
48 | type.template = type.template.kind.replace(/^Template_/, '');
49 | }
50 |
51 | return this._types.insert(type);
52 | }
53 | };
54 |
55 | Template.m_editable.helpers({ 'settings': function () { return generateSettings(this); } });
56 |
57 | Template.m_editable_main.helpers({
58 | editableId () {
59 | var tmpl = Template.instance();
60 | if (!tmpl.view.editableId)
61 | tmpl.view.editableId = Random.id();
62 | return tmpl.view.editableId;
63 | },
64 | m_editable_template () {
65 | var template = typeof this.template === 'string' ? Template[this.template] : this.template;
66 | return this.disabled ? this.disabledTemplate : template;
67 | },
68 | displayVal () {
69 | var v = valueToText(this.value, this.source) || this.emptyText;
70 | if (typeof this.display === 'function') {
71 | return this.display(v, this.value) || this.emptyText;
72 | }
73 |
74 | if (this.disabled)
75 | return v;
76 | return v || this.emptyText;
77 | },
78 | value () { return valueToText(this.value, this.source) || this.emptyText; },
79 | extraClasses () {
80 | var type = mEditable._types.findOne({ _id: this.type });
81 | if (type && type.classes) {
82 | return type.classes.join(' ');
83 | }
84 | },
85 | editableEmpty () {
86 | var v = valueToText(this.value, this.source);
87 | if (typeof this.display === 'function') {
88 | v = this.display(v, this.value);
89 | }
90 | return !v.toString().trim() ? 'editable-empty' : '';
91 | },
92 | //'loading': function (a,b) {
93 | // return Template.instance().Session.get('loading');
94 | //}
95 | });
96 |
97 | Template.m_editable_popover.helpers({
98 | resetForm () {
99 |
100 | return Session.get('m_editable.resetForm');
101 | },
102 | inputTemplate () { return mEditable.getTemplate(this.type); }
103 | });
104 |
105 | Template.m_editable_main.events({
106 | 'resize .editable-container' (e, tmpl) {
107 | resizePopover(tmpl.getPopover(), this.position);
108 | },
109 | 'click .editable-click' (e, tmpl) {
110 | tmpl.getPopover().trigger(!tmpl.Session.get('popover-visible') ? 'show' : 'hide');
111 | }
112 | });
113 |
114 | function getMainTemplateInstance (tmpl) {
115 | var id = tmpl.$('.popover').parent().data('id');
116 | if (!id)
117 | id = tmpl.$('.popover').parent().find('input.editable-id').val();
118 | return Blaze.getView($('input.editable-id[value="' + id + '"]')[0]).templateInstance();
119 | }
120 |
121 | Template.m_editable_popover.events({
122 | 'click .editable-cancel' (e, popoverTmpl) {
123 | var tmpl = getMainTemplateInstance(popoverTmpl);
124 | tmpl.getPopover().trigger('hide');
125 | },
126 | 'submit .editableform' (e, popoverTmpl) {
127 | e.preventDefault();
128 | var tmpl = getMainTemplateInstance(popoverTmpl),
129 | self = this,
130 | val = mEditable.getVal(self.type)(popoverTmpl.$('.editable-input'));
131 |
132 | if (typeof self.onsubmit === 'function') {
133 | if (self.async) {
134 | tmpl.Session.set('loading', true);
135 | this.onsubmit.call(this, val, () => {
136 | tmpl.getPopover().trigger('hide');
137 | doSavedTransition(tmpl);
138 | });
139 | return;
140 | }
141 | this.onsubmit.call(this, val);
142 | } else {
143 | tmpl.$('.editable-click').text(val);
144 | }
145 | tmpl.getPopover().trigger('hide');
146 | doSavedTransition(tmpl);
147 | },
148 | 'hidden .m_editable-popup' (e, tmpl) {
149 | tmpl = getMainTemplateInstance(tmpl);
150 | tmpl.Session.set('loading', false);
151 |
152 | // hack to reset form
153 | Session.set('m_editable.resetForm', true);
154 | setTimeout(() => {
155 | Session.set('m_editable.resetForm', false);
156 | }, 10);
157 | },
158 | 'shown .m_editable-popup' (e, tmpl) {
159 | tmpl = getMainTemplateInstance(tmpl);
160 | },
161 | 'hide .m_editable-popup' (e, tmpl) {
162 | tmpl = getMainTemplateInstance(tmpl);
163 | if (tmpl.Session.equals('popover-visible', false)) {
164 | e.stopImmediatePropagation();
165 | return;
166 | }
167 |
168 | tmpl.Session.set('popover-visible', false);
169 |
170 | setTimeout(function () {
171 | $(e.target).trigger('hidden');
172 | }, 325); // 325 seems to be the magic number (for my desktop at least) so the user doesn't see the form show up again
173 | },
174 | 'show .m_editable-popup' (e, tmpl) {
175 | tmpl = getMainTemplateInstance(tmpl);
176 | if (tmpl.Session.equals('popover-visible', true)) {
177 | e.stopImmediatePropagation();
178 | return;
179 | }
180 | tmpl.Session.set('popover-visible', true);
181 | setTimeout(function () {
182 | $(e.target).trigger('shown');
183 | }, 0);
184 |
185 | Tracker.flush();
186 | tmpl.getPopover().find('.editable-focus').first().focus();
187 | }
188 | });
189 |
190 |
191 | Template.m_editable_body_popovers.helpers({
192 | 'popovers': function () {
193 | return bodyPopovers.find();
194 | }
195 | });
196 |
197 | Template.m_editable_main.onRendered(function() {
198 | var $popover = this.$('.m_editable-popup');
199 |
200 | this.getPopover = () => {
201 | if (this.data.appendToBody)
202 | return $('#body-editables').find('[data-id="' + this.view.editableId + '"]').find('.m_editable-popup');
203 | return this.$('.m_editable-popup');
204 | };
205 |
206 | this.autorun(() => {
207 | var data = Template.currentData(this.view);
208 | if (data.appendToBody) {
209 | bodyPopovers.upsert({ _id: this.view.editableId }, { _id: this.view.editableId, data: data });
210 | } else {
211 | bodyPopovers.remove({ _id: this.view.editableId });
212 | }
213 | });
214 |
215 | this.autorun(() => {
216 | var loading = this.Session.get('loading');
217 | if (typeof loading === 'undefined')
218 | return;
219 |
220 | if (loading) {
221 | this.$('.editableform').hide();
222 | this.$('.editableform-loading').show();
223 | } else {
224 | this.$('.editableform-loading').hide();
225 | this.$('.editableform').show();
226 | }
227 | });
228 |
229 | this.autorun(() => {
230 | var visible = this.Session.get('popover-visible');
231 | this.Session.get('loading'); // changes the form size, so need to re-calculate location
232 | $popover = this.getPopover();
233 | var settings = this.Session.get('settings');
234 | if (typeof visible === 'undefined') {
235 | return;
236 | }
237 |
238 | if (visible) {
239 | $popover.trigger('show');
240 | $popover.fadeIn();
241 | resizePopover($popover, this.data.position);
242 | } else {
243 | $popover.trigger('hide');
244 | $popover.fadeOut();
245 | }
246 |
247 | });
248 | });
249 |
250 | function resizePopover ($popover, placement) {
251 | let editableClick = $popover.prevAll('.editable-click:first');
252 | if (editableClick.length === 0)
253 | editableClick = $('input.editable-id[value="' + $popover.parent().data('id') + '"]').siblings('.editable-click:first');
254 |
255 | const actualWidth = $popover[0].offsetWidth,
256 | actualHeight = $popover[0].offsetHeight,
257 | pos = $.fn.tooltip.Constructor.prototype.getPosition.call({ $element: editableClick });
258 | const calculatedOffset = $.fn.tooltip.Constructor.prototype.getCalculatedOffset(placement, pos, actualWidth, actualHeight);
259 |
260 | $.fn.tooltip.Constructor.prototype.applyPlacement.call(
261 | _.extend($.fn.tooltip.Constructor.prototype, {
262 | tip: () => $popover,
263 | replaceArrow: () => {}
264 | }), calculatedOffset, placement);
265 | }
266 |
267 | Meteor.startup(() => {
268 | $(document).on('click.m_editable-popover-close', (e) => {
269 | $('.m_editable-popup:visible').each(function () {
270 | var $click, $popover = $(this), id = $popover.parent().data('id');
271 | $click = id ? $('input[value="' + id + '"]').siblings('.editable-click') :
272 | $popover.siblings('.editable-click');
273 |
274 | if ($popover.is(e.target) ||
275 | $popover.has(e.target).length > 0 ||
276 | $click.is(e.target) ||
277 | $click.has(e.target).length > 0)
278 | return;
279 |
280 | $popover.trigger('hide');
281 | });
282 | });
283 | });
284 |
285 | function valueToText(val, source) {
286 | val = val || '';
287 | val = _.isArray(val) ? val : [val];
288 | if (typeof val[0] === 'undefined')
289 | val[0] = '';
290 | if (source && source.length) {
291 | return _.map(val, (v, i) => {
292 | _.each(source, (s) => {
293 | if (s.children) {
294 | _.each(s.children, (s) => {
295 | if (v.toString() === s.value.toString()) {
296 | v = s.text;
297 | }
298 | });
299 | } else if (v.toString() === s.value.toString()) {
300 | v = s.text;
301 | }
302 | });
303 | return v;
304 | }).join(', ');
305 | }
306 |
307 | // if we got this far, return the original value
308 | return val[0].toString() || '';
309 | }
310 |
311 | function generateSettings (settings) {
312 | if (POSSIBLE_POSITIONS.indexOf(settings.position) == -1)
313 | delete settings.position;
314 | if (!mEditable._types.findOne({_id: settings.type }))
315 | delete settings.type;
316 |
317 | if (settings.source)
318 | settings.source = _.map(settings.source, op => (typeof op === 'object' ? op : { value: op, text: op }));
319 |
320 | return _.extend({
321 | appendToBody: false,
322 | template: Template.m_editable_handle_atag,
323 | disabledTemplate: Template.m_editable_handle_disabled,
324 | type: 'text',
325 | emptyText: 'Empty',
326 | async: false,
327 | select2: {},
328 | combodate: {},
329 | showbuttons: true,
330 | value: null,
331 | position: 'left',
332 | title: null,
333 | placeholder: null
334 | }, settings);
335 | }
336 |
337 | function doSavedTransition (tmpl) {
338 | var $e = tmpl.$('.editable-click'),
339 | bgColor = $e.css('background-color');
340 |
341 | $e.css('background-color', '#FFFF80');
342 | setTimeout(() => {
343 | if(bgColor === 'transparent') {
344 | bgColor = '';
345 | }
346 | $e.css('background-color', bgColor);
347 | $e.addClass('editable-bg-transition');
348 | setTimeout(() =>{
349 | $e.removeClass('editable-bg-transition');
350 | }, 1700);
351 | }, 10);
352 | }
--------------------------------------------------------------------------------
/img/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidworkman9/meteor-editable/6385edab2760701b9109d9f5162016b21117ec31/img/clear.png
--------------------------------------------------------------------------------
/img/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidworkman9/meteor-editable/6385edab2760701b9109d9f5162016b21117ec31/img/loading.gif
--------------------------------------------------------------------------------
/inputs/checklist/checklist.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#each source}}
4 |
5 | {{/each}}
6 |
7 |
--------------------------------------------------------------------------------
/inputs/checklist/checklist.js:
--------------------------------------------------------------------------------
1 | mEditable.addType({
2 | type: 'checklist',
3 | template: Template.m_editable_form_checklist,
4 | getVal: function ($inputWrapper) {
5 | return _.map($inputWrapper.find('input[type="checkbox"]:checked'), function (el) {
6 | return el.value;
7 | });
8 | }
9 | });
10 |
11 | Template.m_editable_form_checklist.helpers({
12 | 'valueChecked': function (v) {
13 | v = _.isArray(v) ? v : [v];
14 | return v.indexOf(this.value) !== -1;
15 | }
16 | });
17 |
--------------------------------------------------------------------------------
/inputs/combodate/combodate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/inputs/combodate/combodate.js:
--------------------------------------------------------------------------------
1 | mEditable.addType({
2 | type: 'combodate',
3 | template: Template.m_editable_form_combodate,
4 | getVal: function ($inputWrapper) {
5 | return $inputWrapper.find('.combodate-editable').combodate('getValue');
6 | }
7 | });
8 |
9 | Template.m_editable_form_combodate.events({
10 | 'on-update .combodate-editable': function () {} // just used to make the template data reactive in rendered
11 | });
12 |
13 | Template.m_editable_form_combodate.destroyed = function () { if (this.dep) this.dep.stop(); };
14 | Template.m_editable_form_combodate.rendered = function () {
15 | var self = this;
16 | if (self.dep) self.dep.stop();
17 | self.dep = Deps.autorun(function () {
18 | var $combodate = self.$('.combodate-editable');
19 | $combodate.trigger('on-update');
20 |
21 | var data = self.data;
22 | data.combodate = data.combodate || {};
23 |
24 | data.combodate = _.extend(/* TODO: project defaults */ {}, data.combodate);
25 | $combodate.combodate(data.combodate);
26 | $combodate.combodate('setValue', data.value);
27 | });
28 | };
--------------------------------------------------------------------------------
/inputs/date/date.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/inputs/date/date.js:
--------------------------------------------------------------------------------
1 | mEditable.addType({
2 | type: 'date',
3 | template: Template.m_editable_form_date,
4 | getVal: function ($inputWrapper) {
5 | return $inputWrapper.find('div.editable-date').datepicker('getDate');
6 | }
7 | });
8 |
9 | Template.m_editable_form_date.helpers({
10 | 'value': function () {
11 | var val = this.value;
12 | var rand = Random.id();
13 | Meteor.defer(function () {
14 | var $date = $('input[type="hidden"][value="' + rand + '"]').siblings('div.editable-date');
15 |
16 | // initialize datepicker if it hasn't been already
17 | if ($date.children().length === 0) {
18 | initializeDatepicker($date);
19 | }
20 | if (val instanceof Date)
21 | $date.datepicker('setDate', stripTimeFromDate(val));
22 | });
23 | return rand;
24 | }
25 | });
26 |
27 | Template.m_editable_form_date.events({
28 | 'show': function (e) {
29 | e.stopImmediatePropagation();
30 | },
31 | 'changeDate': function (e) {
32 | if (e.date && !this.showbuttons && e.date.getTime() !== getCurrentValsTime(this.value)) {
33 | $(e.target).closest('form').submit();
34 | }
35 |
36 | function getCurrentValsTime (v) {
37 | if (!v)
38 | return false;
39 | return stripTimeFromDate(v).getTime();
40 | }
41 | }
42 | });
43 |
44 | Template.m_editable_form_date.rendered = function () {
45 | var self = this;
46 | initializeDatepicker(self.$('div.editable-date'))
47 | // for some reason, the click events aren't being registered as inside the popover and causing
48 | // the hide event to be called and events don't fire when registered under Template.events
49 | .click(function (e) { e.stopPropagation(); });
50 | };
51 |
52 | function initializeDatepicker(div) {
53 | return div.datepicker({
54 | weekStart: 0,
55 | startView: 0,
56 | minViewMode: 0,
57 | autoclose: false
58 | });
59 | }
60 |
61 | function stripTimeFromDate(date) {
62 | if (date instanceof Date)
63 | return new Date(date.getFullYear(), date.getMonth(), date.getDate());
64 | }
--------------------------------------------------------------------------------
/inputs/datetime/datetime.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/inputs/datetime/datetime.js:
--------------------------------------------------------------------------------
1 | mEditable.addType({
2 | type: 'datetime',
3 | template: Template.m_editable_form_datetime,
4 | getVal: function ($inputWrapper) {
5 | return $inputWrapper.find('div.editable-date').datetimepicker('getDate');
6 | }
7 | });
8 |
9 | Template.m_editable_form_datetime.helpers({
10 | 'value': function () {
11 | var val = this.value;
12 | var rand = Random.id();
13 | if (val instanceof Date) {
14 | Meteor.defer(function () {
15 | var $date = $('input[type="hidden"][value="' + rand + '"]').siblings('div.editable-date');
16 |
17 | // initialize datetimepicker if it hasn't been already
18 | if ($date.children().length === 0) {
19 | initializeDatetimepicker($date);
20 | }
21 |
22 | $date.datetimepicker('setDate', val);
23 | });
24 | }
25 |
26 | return rand;
27 | }
28 | });
29 |
30 | Template.m_editable_form_datetime.events({
31 | 'show': function (e) {
32 | e.stopImmediatePropagation();
33 | },
34 | 'changeDate': function (e) {
35 | if (!this.showbuttons && e.date.getTime() !== getCurrentValsTime(this.value)) {
36 | $(e.target).closest('form').submit();
37 | }
38 |
39 | function getCurrentValsTime (v) {
40 | if (!v)
41 | return false;
42 | return v.getTime();
43 | }
44 | }
45 | });
46 |
47 | Template.m_editable_form_datetime.rendered = function () {
48 | initializeDatetimepicker(this.$('div.editable-date'));
49 | };
50 |
51 | function initializeDatetimepicker(div) {
52 | return div.datetimepicker({
53 | weekStart: 0,
54 | startView: 0,
55 | minViewMode: 0,
56 | autoclose: false
57 | });
58 | }
59 |
--------------------------------------------------------------------------------
/inputs/radiolist/radiolist.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{#with generateName}}
4 | {{#each source}}
5 |
6 | {{/each}}
7 | {{/with}}
8 |
9 |
--------------------------------------------------------------------------------
/inputs/radiolist/radiolist.js:
--------------------------------------------------------------------------------
1 | mEditable.addType({
2 | type: 'radiolist',
3 | template: Template.m_editable_form_radiolist,
4 | getVal: function ($inputWrapper) {
5 | return $inputWrapper.find('input[type="radio"]:checked').val();
6 | }
7 | });
8 |
9 | Template.m_editable_form_radiolist.helpers({
10 | 'generateName': function () {
11 | return _.extend(this, { _radioListName: 'editable-radiolist-' + Random.id() });
12 | },
13 | 'valueChecked': function (v) {
14 | return v === this.value;
15 | }
16 | });
17 |
18 |
--------------------------------------------------------------------------------
/inputs/select/select.html:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/inputs/select/select.js:
--------------------------------------------------------------------------------
1 | mEditable.addType({
2 | type: 'select',
3 | template: Template.m_editable_form_select,
4 | getVal: function ($inputWrapper) {
5 | return $inputWrapper.find('select').val();
6 | }
7 | });
8 |
9 | Template.m_editable_form_select.helpers({
10 | 'selectedVal': function (v) {
11 | return this.value === v;
12 | }
13 | });
14 |
15 | Template.m_editable_form_select.events({
16 | 'change select': function (e) {
17 | if (!this.showbuttons) {
18 | $(e.target).closest('form').submit();
19 | }
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/inputs/select2/select2.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
--------------------------------------------------------------------------------
/inputs/select2/select2.js:
--------------------------------------------------------------------------------
1 | mEditable.addType({
2 | type: 'select2',
3 | template: Template.m_editable_form_select2,
4 | getVal: function ($inputWrapper) {
5 | return $inputWrapper.find('div').select2('val');
6 | }
7 | });
8 |
9 | Template.m_editable_form_select2.events({
10 | 'on-update .select2-editable': function () {}, // just used to make the template data reactive in rendered
11 | 'change .select2-editable': function (e) {
12 | $(e.target).parents('.editable-container').trigger('resize');
13 | }
14 | });
15 |
16 | Template.m_editable_form_select2.destroyed = function () { if (this.dep) this.dep.stop(); };
17 | Template.m_editable_form_select2.rendered = function () {
18 | var self = this;
19 | if (self.dep) self.dep.stop();
20 | self.dep = Deps.autorun(function () {
21 | var $select2 = self.$('.select2-editable');
22 | $select2.trigger('on-update');
23 |
24 | var data = self.data,
25 | isMultiple = data.select2.tags || data.select2.multiple;
26 | data.select2 = data.select2 || {};
27 |
28 | if (data.placeholder) {
29 | data.select2.placeholder = data.placeholder;
30 | }
31 |
32 | //if not `tags` mode, use source
33 | if(!data.select2.tags && data.source) {
34 | data.select2.data = convertSource(data.source);
35 | }
36 |
37 | data.select2 = _.extend(/* TODO: project defaults */ {}, data.select2);
38 | try {
39 | $select2.select2('destroy');
40 | } catch (e) {}
41 | $select2.select2(data.select2);
42 |
43 | var value = data.value;
44 | if (isMultiple && !_.isArray(data.value))
45 | value = [value];
46 | $select2.select2('val', value);
47 | });
48 | };
49 |
50 | function convertSource (src) {
51 | return _.map(src, function (s) {
52 | if (typeof s.id !== 'undefined') {
53 | return s;
54 | }
55 |
56 | if (s.children) {
57 | return {
58 | text: s.text,
59 | children: _.map(s.children, function (s) {
60 | return {
61 | id: s.value,
62 | text: s.text
63 | };
64 | })
65 | };
66 | } else {
67 | return {
68 | id: s.value,
69 | text: s.text
70 | };
71 | }
72 |
73 | });
74 | }
75 |
76 |
77 |
--------------------------------------------------------------------------------
/inputs/text/text.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/inputs/text/text.js:
--------------------------------------------------------------------------------
1 | var types = [
2 | 'text',
3 | 'password',
4 | 'number',
5 | 'email',
6 | 'url',
7 | 'tel',
8 | 'number',
9 | 'range',
10 | 'time'
11 | ];
12 |
13 | _.each(types, function (t) {
14 | mEditable.addType({
15 | type: t,
16 | template: Template.m_editable_form_text,
17 | getVal: function ($inputWrapper) {
18 | if (t === 'number')
19 | return Number($inputWrapper.find('input').val());
20 | else
21 | return $inputWrapper.find('input').val();
22 | }
23 | });
24 | });
25 |
26 | Template.m_editable_form_text.events({
27 | 'input input[type="range"]': function (e, tmpl) {
28 | tmpl.$('.output').text(tmpl.$(e.target).val());
29 | }
30 | });
31 | Template.m_editable_form_text.helpers({
32 | 'hasOutput': function () { return this.type === 'range'; },
33 | 'formControlClass': function () { return this.type !== 'range' ? 'form-control' : 'input-medium'; }
34 | });
35 |
36 | /*
37 | Template.m_editable_form_text.destroyed = function () { this.Session.destroyAll(); this.Deps.stopAll(); };
38 | Template.m_editable_form_text.created = function () {
39 | var self = this;
40 |
41 | self.Deps = {
42 | _handles: [],
43 | stopAll: function () { _.each(this._handles, function (d) { d.stop(); }); },
44 | autorun: function (f) { this._handles.push(Deps.autorun(f)); }
45 | };
46 |
47 | self._sessId = Random.id();
48 | self.Session = {
49 | destroyAll: function () {
50 | _.each(Object.keys(Session.keys), function (key) {
51 | var sessCheck = new RegExp('-' + self._sessId + '$');
52 | if(sessCheck.test(key)) {
53 | Session.set([key]);
54 | delete Session.keys[key];
55 | }
56 | });
57 | },
58 | set: function (key, val) { return Session.set(key + '-' + self._sessId, val); },
59 | get: function (key) { return Session.get(key + '-' + self._sessId); },
60 | equals: function (key, val) { return Session.equals(key + '-' + self._sessId, val); }
61 | };
62 | };
63 | */
--------------------------------------------------------------------------------
/inputs/textarea/textarea.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/inputs/textarea/textarea.js:
--------------------------------------------------------------------------------
1 | mEditable.addType({
2 | type: 'textarea',
3 | classes: ['editable-pre-wrapped'],
4 | template: Template.m_editable_form_textarea,
5 | getVal: function ($inputWrapper) {
6 | return $inputWrapper.find('textarea').val();
7 | }
8 | });
9 |
10 | Template.m_editable_form_textarea.events({
11 | 'keydown textarea': function (e) {
12 | if (e.ctrlKey && e.which === 13) {
13 | $(e.target).closest('form').submit();
14 | }
15 | }
16 | });
--------------------------------------------------------------------------------
/lib/bootstrap-datetimepicker/bootstrap-datetimepicker.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Datetimepicker for Bootstrap
3 | *
4 | * Copyright 2012 Stefan Petre
5 | * Improvements by Andrew Rowls
6 | * Licensed under the Apache License v2.0
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | */
10 | .datetimepicker {
11 | padding: 4px;
12 | margin-top: 1px;
13 | -webkit-border-radius: 4px;
14 | -moz-border-radius: 4px;
15 | border-radius: 4px;
16 | direction: ltr;
17 | }
18 |
19 | .datetimepicker-inline {
20 | width: 220px;
21 | }
22 |
23 | .datetimepicker.datetimepicker-rtl {
24 | direction: rtl;
25 | }
26 |
27 | .datetimepicker.datetimepicker-rtl table tr td span {
28 | float: right;
29 | }
30 |
31 | .datetimepicker-dropdown, .datetimepicker-dropdown-left {
32 | top: 0;
33 | left: 0;
34 | }
35 |
36 | [class*=" datetimepicker-dropdown"]:before {
37 | content: '';
38 | display: inline-block;
39 | border-left: 7px solid transparent;
40 | border-right: 7px solid transparent;
41 | border-bottom: 7px solid #cccccc;
42 | border-bottom-color: rgba(0, 0, 0, 0.2);
43 | position: absolute;
44 | }
45 |
46 | [class*=" datetimepicker-dropdown"]:after {
47 | content: '';
48 | display: inline-block;
49 | border-left: 6px solid transparent;
50 | border-right: 6px solid transparent;
51 | border-bottom: 6px solid #ffffff;
52 | position: absolute;
53 | }
54 |
55 | [class*=" datetimepicker-dropdown-top"]:before {
56 | content: '';
57 | display: inline-block;
58 | border-left: 7px solid transparent;
59 | border-right: 7px solid transparent;
60 | border-top: 7px solid #cccccc;
61 | border-top-color: rgba(0, 0, 0, 0.2);
62 | border-bottom: 0;
63 | }
64 |
65 | [class*=" datetimepicker-dropdown-top"]:after {
66 | content: '';
67 | display: inline-block;
68 | border-left: 6px solid transparent;
69 | border-right: 6px solid transparent;
70 | border-top: 6px solid #ffffff;
71 | border-bottom: 0;
72 | }
73 |
74 | .datetimepicker-dropdown-bottom-left:before {
75 | top: -7px;
76 | right: 6px;
77 | }
78 |
79 | .datetimepicker-dropdown-bottom-left:after {
80 | top: -6px;
81 | right: 7px;
82 | }
83 |
84 | .datetimepicker-dropdown-bottom-right:before {
85 | top: -7px;
86 | left: 6px;
87 | }
88 |
89 | .datetimepicker-dropdown-bottom-right:after {
90 | top: -6px;
91 | left: 7px;
92 | }
93 |
94 | .datetimepicker-dropdown-top-left:before {
95 | bottom: -7px;
96 | right: 6px;
97 | }
98 |
99 | .datetimepicker-dropdown-top-left:after {
100 | bottom: -6px;
101 | right: 7px;
102 | }
103 |
104 | .datetimepicker-dropdown-top-right:before {
105 | bottom: -7px;
106 | left: 6px;
107 | }
108 |
109 | .datetimepicker-dropdown-top-right:after {
110 | bottom: -6px;
111 | left: 7px;
112 | }
113 |
114 | .datetimepicker > div {
115 | display: none;
116 | }
117 |
118 | .datetimepicker.minutes div.datetimepicker-minutes {
119 | display: block;
120 | }
121 |
122 | .datetimepicker.hours div.datetimepicker-hours {
123 | display: block;
124 | }
125 |
126 | .datetimepicker.days div.datetimepicker-days {
127 | display: block;
128 | }
129 |
130 | .datetimepicker.months div.datetimepicker-months {
131 | display: block;
132 | }
133 |
134 | .datetimepicker.years div.datetimepicker-years {
135 | display: block;
136 | }
137 |
138 | .datetimepicker table {
139 | margin: 0;
140 | }
141 |
142 | .datetimepicker td,
143 | .datetimepicker th {
144 | text-align: center;
145 | width: 20px;
146 | height: 20px;
147 | -webkit-border-radius: 4px;
148 | -moz-border-radius: 4px;
149 | border-radius: 4px;
150 | border: none;
151 | }
152 |
153 | .table-striped .datetimepicker table tr td,
154 | .table-striped .datetimepicker table tr th {
155 | background-color: transparent;
156 | }
157 |
158 | .datetimepicker table tr td.minute:hover {
159 | background: #eeeeee;
160 | cursor: pointer;
161 | }
162 |
163 | .datetimepicker table tr td.hour:hover {
164 | background: #eeeeee;
165 | cursor: pointer;
166 | }
167 |
168 | .datetimepicker table tr td.day:hover {
169 | background: #eeeeee;
170 | cursor: pointer;
171 | }
172 |
173 | .datetimepicker table tr td.old,
174 | .datetimepicker table tr td.new {
175 | color: #999999;
176 | }
177 |
178 | .datetimepicker table tr td.disabled,
179 | .datetimepicker table tr td.disabled:hover {
180 | background: none;
181 | color: #999999;
182 | cursor: default;
183 | }
184 |
185 | .datetimepicker table tr td.today,
186 | .datetimepicker table tr td.today:hover,
187 | .datetimepicker table tr td.today.disabled,
188 | .datetimepicker table tr td.today.disabled:hover {
189 | background-color: #fde19a;
190 | background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
191 | background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
192 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
193 | background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
194 | background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
195 | background-image: linear-gradient(top, #fdd49a, #fdf59a);
196 | background-repeat: repeat-x;
197 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
198 | border-color: #fdf59a #fdf59a #fbed50;
199 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
200 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
201 | }
202 |
203 | .datetimepicker table tr td.today:hover,
204 | .datetimepicker table tr td.today:hover:hover,
205 | .datetimepicker table tr td.today.disabled:hover,
206 | .datetimepicker table tr td.today.disabled:hover:hover,
207 | .datetimepicker table tr td.today:active,
208 | .datetimepicker table tr td.today:hover:active,
209 | .datetimepicker table tr td.today.disabled:active,
210 | .datetimepicker table tr td.today.disabled:hover:active,
211 | .datetimepicker table tr td.today.active,
212 | .datetimepicker table tr td.today:hover.active,
213 | .datetimepicker table tr td.today.disabled.active,
214 | .datetimepicker table tr td.today.disabled:hover.active,
215 | .datetimepicker table tr td.today.disabled,
216 | .datetimepicker table tr td.today:hover.disabled,
217 | .datetimepicker table tr td.today.disabled.disabled,
218 | .datetimepicker table tr td.today.disabled:hover.disabled,
219 | .datetimepicker table tr td.today[disabled],
220 | .datetimepicker table tr td.today:hover[disabled],
221 | .datetimepicker table tr td.today.disabled[disabled],
222 | .datetimepicker table tr td.today.disabled:hover[disabled] {
223 | background-color: #fdf59a;
224 | }
225 |
226 | .datetimepicker table tr td.today:active,
227 | .datetimepicker table tr td.today:hover:active,
228 | .datetimepicker table tr td.today.disabled:active,
229 | .datetimepicker table tr td.today.disabled:hover:active,
230 | .datetimepicker table tr td.today.active,
231 | .datetimepicker table tr td.today:hover.active,
232 | .datetimepicker table tr td.today.disabled.active,
233 | .datetimepicker table tr td.today.disabled:hover.active {
234 | background-color: #fbf069;
235 | }
236 |
237 | .datetimepicker table tr td.active,
238 | .datetimepicker table tr td.active:hover,
239 | .datetimepicker table tr td.active.disabled,
240 | .datetimepicker table tr td.active.disabled:hover {
241 | background-color: #006dcc;
242 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
243 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
244 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
245 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
246 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
247 | background-image: linear-gradient(top, #0088cc, #0044cc);
248 | background-repeat: repeat-x;
249 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
250 | border-color: #0044cc #0044cc #002a80;
251 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
252 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
253 | color: #ffffff;
254 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
255 | }
256 |
257 | .datetimepicker table tr td.active:hover,
258 | .datetimepicker table tr td.active:hover:hover,
259 | .datetimepicker table tr td.active.disabled:hover,
260 | .datetimepicker table tr td.active.disabled:hover:hover,
261 | .datetimepicker table tr td.active:active,
262 | .datetimepicker table tr td.active:hover:active,
263 | .datetimepicker table tr td.active.disabled:active,
264 | .datetimepicker table tr td.active.disabled:hover:active,
265 | .datetimepicker table tr td.active.active,
266 | .datetimepicker table tr td.active:hover.active,
267 | .datetimepicker table tr td.active.disabled.active,
268 | .datetimepicker table tr td.active.disabled:hover.active,
269 | .datetimepicker table tr td.active.disabled,
270 | .datetimepicker table tr td.active:hover.disabled,
271 | .datetimepicker table tr td.active.disabled.disabled,
272 | .datetimepicker table tr td.active.disabled:hover.disabled,
273 | .datetimepicker table tr td.active[disabled],
274 | .datetimepicker table tr td.active:hover[disabled],
275 | .datetimepicker table tr td.active.disabled[disabled],
276 | .datetimepicker table tr td.active.disabled:hover[disabled] {
277 | background-color: #0044cc;
278 | }
279 |
280 | .datetimepicker table tr td.active:active,
281 | .datetimepicker table tr td.active:hover:active,
282 | .datetimepicker table tr td.active.disabled:active,
283 | .datetimepicker table tr td.active.disabled:hover:active,
284 | .datetimepicker table tr td.active.active,
285 | .datetimepicker table tr td.active:hover.active,
286 | .datetimepicker table tr td.active.disabled.active,
287 | .datetimepicker table tr td.active.disabled:hover.active {
288 | background-color: #003399;
289 | }
290 |
291 | .datetimepicker table tr td span {
292 | display: block;
293 | width: 23%;
294 | height: 54px;
295 | line-height: 54px;
296 | float: left;
297 | margin: 1%;
298 | cursor: pointer;
299 | -webkit-border-radius: 4px;
300 | -moz-border-radius: 4px;
301 | border-radius: 4px;
302 | }
303 |
304 | .datetimepicker .datetimepicker-hours span {
305 | height: 26px;
306 | line-height: 26px;
307 | }
308 |
309 | .datetimepicker .datetimepicker-hours table tr td span.hour_am,
310 | .datetimepicker .datetimepicker-hours table tr td span.hour_pm {
311 | width: 14.6%;
312 | }
313 |
314 | .datetimepicker .datetimepicker-hours fieldset legend,
315 | .datetimepicker .datetimepicker-minutes fieldset legend {
316 | margin-bottom: inherit;
317 | line-height: 30px;
318 | }
319 |
320 | .datetimepicker .datetimepicker-minutes span {
321 | height: 26px;
322 | line-height: 26px;
323 | }
324 |
325 | .datetimepicker table tr td span:hover {
326 | background: #eeeeee;
327 | }
328 |
329 | .datetimepicker table tr td span.disabled,
330 | .datetimepicker table tr td span.disabled:hover {
331 | background: none;
332 | color: #999999;
333 | cursor: default;
334 | }
335 |
336 | .datetimepicker table tr td span.active,
337 | .datetimepicker table tr td span.active:hover,
338 | .datetimepicker table tr td span.active.disabled,
339 | .datetimepicker table tr td span.active.disabled:hover {
340 | background-color: #006dcc;
341 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
342 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
343 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
344 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
345 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
346 | background-image: linear-gradient(top, #0088cc, #0044cc);
347 | background-repeat: repeat-x;
348 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
349 | border-color: #0044cc #0044cc #002a80;
350 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
351 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
352 | color: #ffffff;
353 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
354 | }
355 |
356 | .datetimepicker table tr td span.active:hover,
357 | .datetimepicker table tr td span.active:hover:hover,
358 | .datetimepicker table tr td span.active.disabled:hover,
359 | .datetimepicker table tr td span.active.disabled:hover:hover,
360 | .datetimepicker table tr td span.active:active,
361 | .datetimepicker table tr td span.active:hover:active,
362 | .datetimepicker table tr td span.active.disabled:active,
363 | .datetimepicker table tr td span.active.disabled:hover:active,
364 | .datetimepicker table tr td span.active.active,
365 | .datetimepicker table tr td span.active:hover.active,
366 | .datetimepicker table tr td span.active.disabled.active,
367 | .datetimepicker table tr td span.active.disabled:hover.active,
368 | .datetimepicker table tr td span.active.disabled,
369 | .datetimepicker table tr td span.active:hover.disabled,
370 | .datetimepicker table tr td span.active.disabled.disabled,
371 | .datetimepicker table tr td span.active.disabled:hover.disabled,
372 | .datetimepicker table tr td span.active[disabled],
373 | .datetimepicker table tr td span.active:hover[disabled],
374 | .datetimepicker table tr td span.active.disabled[disabled],
375 | .datetimepicker table tr td span.active.disabled:hover[disabled] {
376 | background-color: #0044cc;
377 | }
378 |
379 | .datetimepicker table tr td span.active:active,
380 | .datetimepicker table tr td span.active:hover:active,
381 | .datetimepicker table tr td span.active.disabled:active,
382 | .datetimepicker table tr td span.active.disabled:hover:active,
383 | .datetimepicker table tr td span.active.active,
384 | .datetimepicker table tr td span.active:hover.active,
385 | .datetimepicker table tr td span.active.disabled.active,
386 | .datetimepicker table tr td span.active.disabled:hover.active {
387 | background-color: #003399;
388 | }
389 |
390 | .datetimepicker table tr td span.old {
391 | color: #999999;
392 | }
393 |
394 | .datetimepicker th.switch {
395 | width: 145px;
396 | }
397 |
398 | .datetimepicker thead tr:first-child th,
399 | .datetimepicker tfoot tr:first-child th {
400 | cursor: pointer;
401 | }
402 |
403 | .datetimepicker thead tr:first-child th:hover,
404 | .datetimepicker tfoot tr:first-child th:hover {
405 | background: #eeeeee;
406 | }
407 |
408 | .input-append.date .add-on i,
409 | .input-prepend.date .add-on i,
410 | .input-group.date .input-group-addon span {
411 | cursor: pointer;
412 | width: 14px;
413 | height: 14px;
414 | }
--------------------------------------------------------------------------------
/lib/bootstrap-datetimepicker/bootstrap-datetimepicker.js:
--------------------------------------------------------------------------------
1 | /* =========================================================
2 | * bootstrap-datetimepicker.js
3 | * =========================================================
4 | * Copyright 2012 Stefan Petre
5 | * Improvements by Andrew Rowls
6 | * Improvements by Sébastien Malot
7 | * Improvements by Yun Lai
8 | * Project URL : http://www.malot.fr/bootstrap-datetimepicker
9 | *
10 | * Licensed under the Apache License, Version 2.0 (the "License");
11 | * you may not use this file except in compliance with the License.
12 | * You may obtain a copy of the License at
13 | *
14 | * http://www.apache.org/licenses/LICENSE-2.0
15 | *
16 | * Unless required by applicable law or agreed to in writing, software
17 | * distributed under the License is distributed on an "AS IS" BASIS,
18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 | * See the License for the specific language governing permissions and
20 | * limitations under the License.
21 | * ========================================================= */
22 |
23 | /*
24 | * Improvement by CuGBabyBeaR @ 2013-09-12
25 | *
26 | * Make it work in bootstrap v3
27 | */
28 |
29 | !function ($) {
30 |
31 | function UTCDate() {
32 | return new Date(Date.UTC.apply(Date, arguments));
33 | }
34 |
35 | function UTCToday() {
36 | var today = new Date();
37 | return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), today.getUTCHours(), today.getUTCMinutes(), today.getUTCSeconds(), 0);
38 | }
39 |
40 | // Picker object
41 |
42 | var Datetimepicker = function (element, options) {
43 | var that = this;
44 |
45 | this.element = $(element);
46 |
47 | this.language = options.language || this.element.data('date-language') || "en";
48 | this.language = this.language in dates ? this.language : "en";
49 | this.isRTL = dates[this.language].rtl || false;
50 | this.formatType = options.formatType || this.element.data('format-type') || 'standard';
51 | this.format = DPGlobal.parseFormat(options.format || this.element.data('date-format') || dates[this.language].format || DPGlobal.getDefaultFormat(this.formatType, 'input'), this.formatType);
52 | this.isInline = false;
53 | this.isVisible = false;
54 | this.isInput = this.element.is('input');
55 |
56 | this.bootcssVer = this.isInput ? (this.element.is('.form-control') ? 3 : 2) : ( this.bootcssVer = this.element.is('.input-group') ? 3 : 2 );
57 |
58 | this.component = this.element.is('.date') ? ( this.bootcssVer == 3 ? this.element.find('.input-group-addon .glyphicon-th, .input-group-addon .glyphicon-time, .input-group-addon .glyphicon-calendar').parent() : this.element.find('.add-on .icon-th, .add-on .icon-time, .add-on .icon-calendar').parent()) : false;
59 | this.componentReset = this.element.is('.date') ? ( this.bootcssVer == 3 ? this.element.find('.input-group-addon .glyphicon-remove').parent() : this.element.find('.add-on .icon-remove').parent()) : false;
60 | this.hasInput = this.component && this.element.find('input').length;
61 | if (this.component && this.component.length === 0) {
62 | this.component = false;
63 | }
64 | this.linkField = options.linkField || this.element.data('link-field') || false;
65 | this.linkFormat = DPGlobal.parseFormat(options.linkFormat || this.element.data('link-format') || DPGlobal.getDefaultFormat(this.formatType, 'link'), this.formatType);
66 | this.minuteStep = options.minuteStep || this.element.data('minute-step') || 5;
67 | this.pickerPosition = options.pickerPosition || this.element.data('picker-position') || 'bottom-right';
68 | this.showMeridian = options.showMeridian || this.element.data('show-meridian') || false;
69 | this.initialDate = options.initialDate || new Date();
70 |
71 | this._attachEvents();
72 |
73 | this.formatViewType = "datetime";
74 | if ('formatViewType' in options) {
75 | this.formatViewType = options.formatViewType;
76 | } else if ('formatViewType' in this.element.data()) {
77 | this.formatViewType = this.element.data('formatViewType');
78 | }
79 |
80 | this.minView = 0;
81 | if ('minView' in options) {
82 | this.minView = options.minView;
83 | } else if ('minView' in this.element.data()) {
84 | this.minView = this.element.data('min-view');
85 | }
86 | this.minView = DPGlobal.convertViewMode(this.minView);
87 |
88 | this.maxView = DPGlobal.modes.length - 1;
89 | if ('maxView' in options) {
90 | this.maxView = options.maxView;
91 | } else if ('maxView' in this.element.data()) {
92 | this.maxView = this.element.data('max-view');
93 | }
94 | this.maxView = DPGlobal.convertViewMode(this.maxView);
95 |
96 | this.wheelViewModeNavigation = false;
97 | if ('wheelViewModeNavigation' in options) {
98 | this.wheelViewModeNavigation = options.wheelViewModeNavigation;
99 | } else if ('wheelViewModeNavigation' in this.element.data()) {
100 | this.wheelViewModeNavigation = this.element.data('view-mode-wheel-navigation');
101 | }
102 |
103 | this.wheelViewModeNavigationInverseDirection = false;
104 |
105 | if ('wheelViewModeNavigationInverseDirection' in options) {
106 | this.wheelViewModeNavigationInverseDirection = options.wheelViewModeNavigationInverseDirection;
107 | } else if ('wheelViewModeNavigationInverseDirection' in this.element.data()) {
108 | this.wheelViewModeNavigationInverseDirection = this.element.data('view-mode-wheel-navigation-inverse-dir');
109 | }
110 |
111 | this.wheelViewModeNavigationDelay = 100;
112 | if ('wheelViewModeNavigationDelay' in options) {
113 | this.wheelViewModeNavigationDelay = options.wheelViewModeNavigationDelay;
114 | } else if ('wheelViewModeNavigationDelay' in this.element.data()) {
115 | this.wheelViewModeNavigationDelay = this.element.data('view-mode-wheel-navigation-delay');
116 | }
117 |
118 | this.startViewMode = 2;
119 | if ('startView' in options) {
120 | this.startViewMode = options.startView;
121 | } else if ('startView' in this.element.data()) {
122 | this.startViewMode = this.element.data('start-view');
123 | }
124 | this.startViewMode = DPGlobal.convertViewMode(this.startViewMode);
125 | this.viewMode = this.startViewMode;
126 |
127 | this.viewSelect = this.minView;
128 | if ('viewSelect' in options) {
129 | this.viewSelect = options.viewSelect;
130 | } else if ('viewSelect' in this.element.data()) {
131 | this.viewSelect = this.element.data('view-select');
132 | }
133 | this.viewSelect = DPGlobal.convertViewMode(this.viewSelect);
134 |
135 | this.forceParse = true;
136 | if ('forceParse' in options) {
137 | this.forceParse = options.forceParse;
138 | } else if ('dateForceParse' in this.element.data()) {
139 | this.forceParse = this.element.data('date-force-parse');
140 | }
141 |
142 | this.picker = $((this.bootcssVer == 3) ? DPGlobal.templateV3 : DPGlobal.template)
143 | .appendTo(this.isInline ? this.element : 'body')
144 | .on({
145 | click: $.proxy(this.click, this),
146 | mousedown: $.proxy(this.mousedown, this)
147 | });
148 |
149 | if (this.wheelViewModeNavigation) {
150 | if ($.fn.mousewheel) {
151 | this.picker.on({mousewheel: $.proxy(this.mousewheel, this)});
152 | } else {
153 | console.log("Mouse Wheel event is not supported. Please include the jQuery Mouse Wheel plugin before enabling this option");
154 | }
155 | }
156 |
157 | if (this.isInline) {
158 | this.picker.addClass('datetimepicker-inline');
159 | } else {
160 | this.picker.addClass('datetimepicker-dropdown-' + this.pickerPosition + ' dropdown-menu');
161 | }
162 | if (this.isRTL) {
163 | this.picker.addClass('datetimepicker-rtl');
164 | if (this.bootcssVer == 3) {
165 | this.picker.find('.prev span, .next span')
166 | .toggleClass('glyphicon-arrow-left glyphicon-arrow-right');
167 | } else {
168 | this.picker.find('.prev i, .next i')
169 | .toggleClass('icon-arrow-left icon-arrow-right');
170 | }
171 | ;
172 |
173 | }
174 | $(document).on('mousedown', function (e) {
175 | // Clicked outside the datetimepicker, hide it
176 | if ($(e.target).closest('.datetimepicker').length === 0) {
177 | that.hide();
178 | }
179 | });
180 |
181 | this.autoclose = false;
182 | if ('autoclose' in options) {
183 | this.autoclose = options.autoclose;
184 | } else if ('dateAutoclose' in this.element.data()) {
185 | this.autoclose = this.element.data('date-autoclose');
186 | }
187 |
188 | this.keyboardNavigation = true;
189 | if ('keyboardNavigation' in options) {
190 | this.keyboardNavigation = options.keyboardNavigation;
191 | } else if ('dateKeyboardNavigation' in this.element.data()) {
192 | this.keyboardNavigation = this.element.data('date-keyboard-navigation');
193 | }
194 |
195 | this.todayBtn = (options.todayBtn || this.element.data('date-today-btn') || false);
196 | this.todayHighlight = (options.todayHighlight || this.element.data('date-today-highlight') || false);
197 |
198 | this.weekStart = ((options.weekStart || this.element.data('date-weekstart') || dates[this.language].weekStart || 0) % 7);
199 | this.weekEnd = ((this.weekStart + 6) % 7);
200 | this.startDate = -Infinity;
201 | this.endDate = Infinity;
202 | this.daysOfWeekDisabled = [];
203 | this.setStartDate(options.startDate || this.element.data('date-startdate'));
204 | this.setEndDate(options.endDate || this.element.data('date-enddate'));
205 | this.setDaysOfWeekDisabled(options.daysOfWeekDisabled || this.element.data('date-days-of-week-disabled'));
206 | this.fillDow();
207 | this.fillMonths();
208 | this.update();
209 | this.showMode();
210 |
211 | if (this.isInline) {
212 | this.show();
213 | }
214 | };
215 |
216 | Datetimepicker.prototype = {
217 | constructor: Datetimepicker,
218 |
219 | _events: [],
220 | _attachEvents: function () {
221 | this._detachEvents();
222 | if (this.isInput) { // single input
223 | this._events = [
224 | [this.element, {
225 | focus: $.proxy(this.show, this),
226 | keyup: $.proxy(this.update, this),
227 | keydown: $.proxy(this.keydown, this)
228 | }]
229 | ];
230 | }
231 | else if (this.component && this.hasInput) { // component: input + button
232 | this._events = [
233 | // For components that are not readonly, allow keyboard nav
234 | [this.element.find('input'), {
235 | focus: $.proxy(this.show, this),
236 | keyup: $.proxy(this.update, this),
237 | keydown: $.proxy(this.keydown, this)
238 | }],
239 | [this.component, {
240 | click: $.proxy(this.show, this)
241 | }]
242 | ];
243 | if (this.componentReset) {
244 | this._events.push([
245 | this.componentReset,
246 | {click: $.proxy(this.reset, this)}
247 | ]);
248 | }
249 | }
250 | else if (this.element.is('div')) { // inline datetimepicker
251 | this.isInline = true;
252 | }
253 | else {
254 | this._events = [
255 | [this.element, {
256 | click: $.proxy(this.show, this)
257 | }]
258 | ];
259 | }
260 | for (var i = 0, el, ev; i < this._events.length; i++) {
261 | el = this._events[i][0];
262 | ev = this._events[i][1];
263 | el.on(ev);
264 | }
265 | },
266 |
267 | _detachEvents: function () {
268 | for (var i = 0, el, ev; i < this._events.length; i++) {
269 | el = this._events[i][0];
270 | ev = this._events[i][1];
271 | el.off(ev);
272 | }
273 | this._events = [];
274 | },
275 |
276 | show: function (e) {
277 | this.picker.show();
278 | this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
279 | if (this.forceParse) {
280 | this.update();
281 | }
282 | this.place();
283 | $(window).on('resize', $.proxy(this.place, this));
284 | if (e) {
285 | e.stopPropagation();
286 | e.preventDefault();
287 | }
288 | this.isVisible = true;
289 | this.element.trigger({
290 | type: 'show',
291 | date: this.date
292 | });
293 | },
294 |
295 | hide: function (e) {
296 | if (!this.isVisible) return;
297 | if (this.isInline) return;
298 | this.picker.hide();
299 | $(window).off('resize', this.place);
300 | this.viewMode = this.startViewMode;
301 | this.showMode();
302 | if (!this.isInput) {
303 | $(document).off('mousedown', this.hide);
304 | }
305 |
306 | if (
307 | this.forceParse &&
308 | (
309 | this.isInput && this.element.val() ||
310 | this.hasInput && this.element.find('input').val()
311 | )
312 | )
313 | this.setValue();
314 | this.isVisible = false;
315 | this.element.trigger({
316 | type: 'hide',
317 | date: this.date
318 | });
319 | },
320 |
321 | remove: function () {
322 | this._detachEvents();
323 | this.picker.remove();
324 | delete this.picker;
325 | delete this.element.data().datetimepicker;
326 | },
327 |
328 | getDate: function () {
329 | var d = this.getUTCDate();
330 | return new Date(d.getTime() + (d.getTimezoneOffset() * 60000));
331 | },
332 |
333 | getUTCDate: function () {
334 | return this.date;
335 | },
336 |
337 | setDate: function (d) {
338 | this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset() * 60000)));
339 | },
340 |
341 | setUTCDate: function (d) {
342 | if (d >= this.startDate && d <= this.endDate) {
343 | this.date = d;
344 | this.setValue();
345 | this.viewDate = this.date;
346 | this.fill();
347 | } else {
348 | this.element.trigger({
349 | type: 'outOfRange',
350 | date: d,
351 | startDate: this.startDate,
352 | endDate: this.endDate
353 | });
354 | }
355 | },
356 |
357 | setFormat: function (format) {
358 | this.format = DPGlobal.parseFormat(format, this.formatType);
359 | var element;
360 | if (this.isInput) {
361 | element = this.element;
362 | } else if (this.component) {
363 | element = this.element.find('input');
364 | }
365 | if (element && element.val()) {
366 | this.setValue();
367 | }
368 | },
369 |
370 | setValue: function () {
371 | var formatted = this.getFormattedDate();
372 | if (!this.isInput) {
373 | if (this.component) {
374 | this.element.find('input').val(formatted);
375 | }
376 | this.element.data('date', formatted);
377 | } else {
378 | this.element.val(formatted);
379 | }
380 | if (this.linkField) {
381 | $('#' + this.linkField).val(this.getFormattedDate(this.linkFormat));
382 | }
383 | },
384 |
385 | getFormattedDate: function (format) {
386 | if (format == undefined) format = this.format;
387 | return DPGlobal.formatDate(this.date, format, this.language, this.formatType);
388 | },
389 |
390 | setStartDate: function (startDate) {
391 | this.startDate = startDate || -Infinity;
392 | if (this.startDate !== -Infinity) {
393 | this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language, this.formatType);
394 | }
395 | this.update();
396 | this.updateNavArrows();
397 | },
398 |
399 | setEndDate: function (endDate) {
400 | this.endDate = endDate || Infinity;
401 | if (this.endDate !== Infinity) {
402 | this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language, this.formatType);
403 | }
404 | this.update();
405 | this.updateNavArrows();
406 | },
407 |
408 | setDaysOfWeekDisabled: function (daysOfWeekDisabled) {
409 | this.daysOfWeekDisabled = daysOfWeekDisabled || [];
410 | if (!$.isArray(this.daysOfWeekDisabled)) {
411 | this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
412 | }
413 | this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) {
414 | return parseInt(d, 10);
415 | });
416 | this.update();
417 | this.updateNavArrows();
418 | },
419 |
420 | place: function () {
421 | if (this.isInline) return;
422 |
423 | var index_highest = 0;
424 | $('div').each(function () {
425 | var index_current = parseInt($(this).css("zIndex"), 10);
426 | if (index_current > index_highest) {
427 | index_highest = index_current;
428 | }
429 | });
430 | var zIndex = index_highest + 10;
431 |
432 | var offset, top, left;
433 | if (this.component) {
434 | offset = this.component.offset();
435 | left = offset.left;
436 | if (this.pickerPosition == 'bottom-left' || this.pickerPosition == 'top-left') {
437 | left += this.component.outerWidth() - this.picker.outerWidth();
438 | }
439 | } else {
440 | offset = this.element.offset();
441 | left = offset.left;
442 | }
443 | if (this.pickerPosition == 'top-left' || this.pickerPosition == 'top-right') {
444 | top = offset.top - this.picker.outerHeight();
445 | } else {
446 | top = offset.top + this.height;
447 | }
448 | this.picker.css({
449 | top: top,
450 | left: left,
451 | zIndex: zIndex
452 | });
453 | },
454 |
455 | update: function () {
456 | var date, fromArgs = false;
457 | if (arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) {
458 | date = arguments[0];
459 | fromArgs = true;
460 | } else {
461 | date = this.element.data('date') || (this.isInput ? this.element.val() : this.element.find('input').val()) || this.initialDate;
462 | if (typeof date == 'string' || date instanceof String) {
463 | date = date.replace(/^\s+|\s+$/g,'');
464 | }
465 | }
466 |
467 | if (!date) {
468 | date = new Date();
469 | fromArgs = false;
470 | }
471 |
472 | this.date = DPGlobal.parseDate(date, this.format, this.language, this.formatType);
473 |
474 | if (fromArgs) this.setValue();
475 |
476 | if (this.date < this.startDate) {
477 | this.viewDate = new Date(this.startDate);
478 | } else if (this.date > this.endDate) {
479 | this.viewDate = new Date(this.endDate);
480 | } else {
481 | this.viewDate = new Date(this.date);
482 | }
483 | this.fill();
484 | },
485 |
486 | fillDow: function () {
487 | var dowCnt = this.weekStart,
488 | html = '';
489 | while (dowCnt < this.weekStart + 7) {
490 | html += '' + dates[this.language].daysMin[(dowCnt++) % 7] + ' | ';
491 | }
492 | html += '
';
493 | this.picker.find('.datetimepicker-days thead').append(html);
494 | },
495 |
496 | fillMonths: function () {
497 | var html = '',
498 | i = 0;
499 | while (i < 12) {
500 | html += '' + dates[this.language].monthsShort[i++] + '';
501 | }
502 | this.picker.find('.datetimepicker-months td').html(html);
503 | },
504 |
505 | fill: function () {
506 | if (this.date == null || this.viewDate == null) {
507 | return;
508 | }
509 | var d = new Date(this.viewDate),
510 | year = d.getUTCFullYear(),
511 | month = d.getUTCMonth(),
512 | dayMonth = d.getUTCDate(),
513 | hours = d.getUTCHours(),
514 | minutes = d.getUTCMinutes(),
515 | startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
516 | startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
517 | endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
518 | endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
519 | currentDate = (new UTCDate(this.date.getUTCFullYear(), this.date.getUTCMonth(), this.date.getUTCDate())).valueOf(),
520 | today = new Date();
521 | this.picker.find('.datetimepicker-days thead th:eq(1)')
522 | .text(dates[this.language].months[month] + ' ' + year);
523 | if (this.formatViewType == "time") {
524 | var hourConverted = hours % 12 ? hours % 12 : 12;
525 | var hoursDisplay = (hourConverted < 10 ? '0' : '') + hourConverted;
526 | var minutesDisplay = (minutes < 10 ? '0' : '') + minutes;
527 | var meridianDisplay = dates[this.language].meridiem[hours < 12 ? 0 : 1];
528 | this.picker.find('.datetimepicker-hours thead th:eq(1)')
529 | .text(hoursDisplay + ':' + minutesDisplay + ' ' + meridianDisplay.toUpperCase());
530 | this.picker.find('.datetimepicker-minutes thead th:eq(1)')
531 | .text(hoursDisplay + ':' + minutesDisplay + ' ' + meridianDisplay.toUpperCase());
532 | } else {
533 | this.picker.find('.datetimepicker-hours thead th:eq(1)')
534 | .text(dayMonth + ' ' + dates[this.language].months[month] + ' ' + year);
535 | this.picker.find('.datetimepicker-minutes thead th:eq(1)')
536 | .text(dayMonth + ' ' + dates[this.language].months[month] + ' ' + year);
537 | }
538 | this.picker.find('tfoot th.today')
539 | .text(dates[this.language].today)
540 | .toggle(this.todayBtn !== false);
541 | this.updateNavArrows();
542 | this.fillMonths();
543 | /*var prevMonth = UTCDate(year, month, 0,0,0,0,0);
544 | prevMonth.setUTCDate(prevMonth.getDate() - (prevMonth.getUTCDay() - this.weekStart + 7)%7);*/
545 | var prevMonth = UTCDate(year, month - 1, 28, 0, 0, 0, 0),
546 | day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
547 | prevMonth.setUTCDate(day);
548 | prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7) % 7);
549 | var nextMonth = new Date(prevMonth);
550 | nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
551 | nextMonth = nextMonth.valueOf();
552 | var html = [];
553 | var clsName;
554 | while (prevMonth.valueOf() < nextMonth) {
555 | if (prevMonth.getUTCDay() == this.weekStart) {
556 | html.push('');
557 | }
558 | clsName = '';
559 | if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
560 | clsName += ' old';
561 | } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
562 | clsName += ' new';
563 | }
564 | // Compare internal UTC date with local today, not UTC today
565 | if (this.todayHighlight &&
566 | prevMonth.getUTCFullYear() == today.getFullYear() &&
567 | prevMonth.getUTCMonth() == today.getMonth() &&
568 | prevMonth.getUTCDate() == today.getDate()) {
569 | clsName += ' today';
570 | }
571 | if (prevMonth.valueOf() == currentDate) {
572 | clsName += ' active';
573 | }
574 | if ((prevMonth.valueOf() + 86400000) <= this.startDate || prevMonth.valueOf() > this.endDate ||
575 | $.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) {
576 | clsName += ' disabled';
577 | }
578 | html.push('' + prevMonth.getUTCDate() + ' | ');
579 | if (prevMonth.getUTCDay() == this.weekEnd) {
580 | html.push('
');
581 | }
582 | prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
583 | }
584 | this.picker.find('.datetimepicker-days tbody').empty().append(html.join(''));
585 |
586 | html = [];
587 | var txt = '', meridian = '', meridianOld = '';
588 | for (var i = 0; i < 24; i++) {
589 | var actual = UTCDate(year, month, dayMonth, i);
590 | clsName = '';
591 | // We want the previous hour for the startDate
592 | if ((actual.valueOf() + 3600000) <= this.startDate || actual.valueOf() > this.endDate) {
593 | clsName += ' disabled';
594 | } else if (hours == i) {
595 | clsName += ' active';
596 | }
597 | if (this.showMeridian && dates[this.language].meridiem.length == 2) {
598 | meridian = (i < 12 ? dates[this.language].meridiem[0] : dates[this.language].meridiem[1]);
599 | if (meridian != meridianOld) {
600 | if (meridianOld != '') {
601 | html.push('');
602 | }
603 | html.push('');
610 | }
611 | } else {
612 | txt = i + ':00';
613 | html.push('' + txt + '');
614 | }
615 | }
616 | this.picker.find('.datetimepicker-hours td').html(html.join(''));
617 |
618 | html = [];
619 | txt = '', meridian = '', meridianOld = '';
620 | for (var i = 0; i < 60; i += this.minuteStep) {
621 | var actual = UTCDate(year, month, dayMonth, hours, i, 0);
622 | clsName = '';
623 | if (actual.valueOf() < this.startDate || actual.valueOf() > this.endDate) {
624 | clsName += ' disabled';
625 | } else if (Math.floor(minutes / this.minuteStep) == Math.floor(i / this.minuteStep)) {
626 | clsName += ' active';
627 | }
628 | if (this.showMeridian && dates[this.language].meridiem.length == 2) {
629 | meridian = (hours < 12 ? dates[this.language].meridiem[0] : dates[this.language].meridiem[1]);
630 | if (meridian != meridianOld) {
631 | if (meridianOld != '') {
632 | html.push('');
633 | }
634 | html.push('');
642 | }
643 | } else {
644 | txt = i + ':00';
645 | //html.push(''+txt+'');
646 | html.push('' + hours + ':' + (i < 10 ? '0' + i : i) + '');
647 | }
648 | }
649 | this.picker.find('.datetimepicker-minutes td').html(html.join(''));
650 |
651 | var currentYear = this.date.getUTCFullYear();
652 | var months = this.picker.find('.datetimepicker-months')
653 | .find('th:eq(1)')
654 | .text(year)
655 | .end()
656 | .find('span').removeClass('active');
657 | if (currentYear == year) {
658 | months.eq(this.date.getUTCMonth()).addClass('active');
659 | }
660 | if (year < startYear || year > endYear) {
661 | months.addClass('disabled');
662 | }
663 | if (year == startYear) {
664 | months.slice(0, startMonth).addClass('disabled');
665 | }
666 | if (year == endYear) {
667 | months.slice(endMonth + 1).addClass('disabled');
668 | }
669 |
670 | html = '';
671 | year = parseInt(year / 10, 10) * 10;
672 | var yearCont = this.picker.find('.datetimepicker-years')
673 | .find('th:eq(1)')
674 | .text(year + '-' + (year + 9))
675 | .end()
676 | .find('td');
677 | year -= 1;
678 | for (var i = -1; i < 11; i++) {
679 | html += '' + year + '';
680 | year += 1;
681 | }
682 | yearCont.html(html);
683 | this.place();
684 | },
685 |
686 | updateNavArrows: function () {
687 | var d = new Date(this.viewDate),
688 | year = d.getUTCFullYear(),
689 | month = d.getUTCMonth(),
690 | day = d.getUTCDate(),
691 | hour = d.getUTCHours();
692 | switch (this.viewMode) {
693 | case 0:
694 | if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()
695 | && month <= this.startDate.getUTCMonth()
696 | && day <= this.startDate.getUTCDate()
697 | && hour <= this.startDate.getUTCHours()) {
698 | this.picker.find('.prev').css({visibility: 'hidden'});
699 | } else {
700 | this.picker.find('.prev').css({visibility: 'visible'});
701 | }
702 | if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()
703 | && month >= this.endDate.getUTCMonth()
704 | && day >= this.endDate.getUTCDate()
705 | && hour >= this.endDate.getUTCHours()) {
706 | this.picker.find('.next').css({visibility: 'hidden'});
707 | } else {
708 | this.picker.find('.next').css({visibility: 'visible'});
709 | }
710 | break;
711 | case 1:
712 | if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()
713 | && month <= this.startDate.getUTCMonth()
714 | && day <= this.startDate.getUTCDate()) {
715 | this.picker.find('.prev').css({visibility: 'hidden'});
716 | } else {
717 | this.picker.find('.prev').css({visibility: 'visible'});
718 | }
719 | if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()
720 | && month >= this.endDate.getUTCMonth()
721 | && day >= this.endDate.getUTCDate()) {
722 | this.picker.find('.next').css({visibility: 'hidden'});
723 | } else {
724 | this.picker.find('.next').css({visibility: 'visible'});
725 | }
726 | break;
727 | case 2:
728 | if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()
729 | && month <= this.startDate.getUTCMonth()) {
730 | this.picker.find('.prev').css({visibility: 'hidden'});
731 | } else {
732 | this.picker.find('.prev').css({visibility: 'visible'});
733 | }
734 | if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()
735 | && month >= this.endDate.getUTCMonth()) {
736 | this.picker.find('.next').css({visibility: 'hidden'});
737 | } else {
738 | this.picker.find('.next').css({visibility: 'visible'});
739 | }
740 | break;
741 | case 3:
742 | case 4:
743 | if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
744 | this.picker.find('.prev').css({visibility: 'hidden'});
745 | } else {
746 | this.picker.find('.prev').css({visibility: 'visible'});
747 | }
748 | if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
749 | this.picker.find('.next').css({visibility: 'hidden'});
750 | } else {
751 | this.picker.find('.next').css({visibility: 'visible'});
752 | }
753 | break;
754 | }
755 | },
756 |
757 | mousewheel: function (e) {
758 |
759 | e.preventDefault();
760 | e.stopPropagation();
761 |
762 | if (this.wheelPause) {
763 | return;
764 | }
765 |
766 | this.wheelPause = true;
767 |
768 | var originalEvent = e.originalEvent;
769 |
770 | var delta = originalEvent.wheelDelta;
771 |
772 | var mode = delta > 0 ? 1 : (delta === 0) ? 0 : -1;
773 |
774 | if (this.wheelViewModeNavigationInverseDirection) {
775 | mode = -mode;
776 | }
777 |
778 | this.showMode(mode);
779 |
780 | setTimeout($.proxy(function () {
781 |
782 | this.wheelPause = false
783 |
784 | }, this), this.wheelViewModeNavigationDelay);
785 |
786 | },
787 |
788 | click: function (e) {
789 | e.stopPropagation();
790 | e.preventDefault();
791 | var target = $(e.target).closest('span, td, th, legend');
792 | if (target.length == 1) {
793 | if (target.is('.disabled')) {
794 | this.element.trigger({
795 | type: 'outOfRange',
796 | date: this.viewDate,
797 | startDate: this.startDate,
798 | endDate: this.endDate
799 | });
800 | return;
801 | }
802 | switch (target[0].nodeName.toLowerCase()) {
803 | case 'th':
804 | switch (target[0].className) {
805 | case 'switch':
806 | this.showMode(1);
807 | break;
808 | case 'prev':
809 | case 'next':
810 | var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1);
811 | switch (this.viewMode) {
812 | case 0:
813 | this.viewDate = this.moveHour(this.viewDate, dir);
814 | break;
815 | case 1:
816 | this.viewDate = this.moveDate(this.viewDate, dir);
817 | break;
818 | case 2:
819 | this.viewDate = this.moveMonth(this.viewDate, dir);
820 | break;
821 | case 3:
822 | case 4:
823 | this.viewDate = this.moveYear(this.viewDate, dir);
824 | break;
825 | }
826 | this.fill();
827 | break;
828 | case 'today':
829 | var date = new Date();
830 | date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), 0);
831 |
832 | // Respect startDate and endDate.
833 | if (date < this.startDate) date = this.startDate;
834 | else if (date > this.endDate) date = this.endDate;
835 |
836 | this.viewMode = this.startViewMode;
837 | this.showMode(0);
838 | this._setDate(date);
839 | this.fill();
840 | if (this.autoclose) {
841 | this.hide();
842 | }
843 | break;
844 | }
845 | break;
846 | case 'span':
847 | if (!target.is('.disabled')) {
848 | var year = this.viewDate.getUTCFullYear(),
849 | month = this.viewDate.getUTCMonth(),
850 | day = this.viewDate.getUTCDate(),
851 | hours = this.viewDate.getUTCHours(),
852 | minutes = this.viewDate.getUTCMinutes(),
853 | seconds = this.viewDate.getUTCSeconds();
854 |
855 | if (target.is('.month')) {
856 | this.viewDate.setUTCDate(1);
857 | month = target.parent().find('span').index(target);
858 | day = this.viewDate.getUTCDate();
859 | this.viewDate.setUTCMonth(month);
860 | this.element.trigger({
861 | type: 'changeMonth',
862 | date: this.viewDate
863 | });
864 | if (this.viewSelect >= 3) {
865 | this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
866 | }
867 | } else if (target.is('.year')) {
868 | this.viewDate.setUTCDate(1);
869 | year = parseInt(target.text(), 10) || 0;
870 | this.viewDate.setUTCFullYear(year);
871 | this.element.trigger({
872 | type: 'changeYear',
873 | date: this.viewDate
874 | });
875 | if (this.viewSelect >= 4) {
876 | this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
877 | }
878 | } else if (target.is('.hour')) {
879 | hours = parseInt(target.text(), 10) || 0;
880 | if (target.hasClass('hour_am') || target.hasClass('hour_pm')) {
881 | if (hours == 12 && target.hasClass('hour_am')) {
882 | hours = 0;
883 | } else if (hours != 12 && target.hasClass('hour_pm')) {
884 | hours += 12;
885 | }
886 | }
887 | this.viewDate.setUTCHours(hours);
888 | this.element.trigger({
889 | type: 'changeHour',
890 | date: this.viewDate
891 | });
892 | if (this.viewSelect >= 1) {
893 | this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
894 | }
895 | } else if (target.is('.minute')) {
896 | minutes = parseInt(target.text().substr(target.text().indexOf(':') + 1), 10) || 0;
897 | this.viewDate.setUTCMinutes(minutes);
898 | this.element.trigger({
899 | type: 'changeMinute',
900 | date: this.viewDate
901 | });
902 | if (this.viewSelect >= 0) {
903 | this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
904 | }
905 | }
906 | if (this.viewMode != 0) {
907 | var oldViewMode = this.viewMode;
908 | this.showMode(-1);
909 | this.fill();
910 | if (oldViewMode == this.viewMode && this.autoclose) {
911 | this.hide();
912 | }
913 | } else {
914 | this.fill();
915 | if (this.autoclose) {
916 | this.hide();
917 | }
918 | }
919 | }
920 | break;
921 | case 'td':
922 | if (target.is('.day') && !target.is('.disabled')) {
923 | var day = parseInt(target.text(), 10) || 1;
924 | var year = this.viewDate.getUTCFullYear(),
925 | month = this.viewDate.getUTCMonth(),
926 | hours = this.viewDate.getUTCHours(),
927 | minutes = this.viewDate.getUTCMinutes(),
928 | seconds = this.viewDate.getUTCSeconds();
929 | if (target.is('.old')) {
930 | if (month === 0) {
931 | month = 11;
932 | year -= 1;
933 | } else {
934 | month -= 1;
935 | }
936 | } else if (target.is('.new')) {
937 | if (month == 11) {
938 | month = 0;
939 | year += 1;
940 | } else {
941 | month += 1;
942 | }
943 | }
944 | this.viewDate.setUTCFullYear(year);
945 | this.viewDate.setUTCMonth(month, day);
946 | this.element.trigger({
947 | type: 'changeDay',
948 | date: this.viewDate
949 | });
950 | if (this.viewSelect >= 2) {
951 | this._setDate(UTCDate(year, month, day, hours, minutes, seconds, 0));
952 | }
953 | }
954 | var oldViewMode = this.viewMode;
955 | this.showMode(-1);
956 | this.fill();
957 | if (oldViewMode == this.viewMode && this.autoclose) {
958 | this.hide();
959 | }
960 | break;
961 | }
962 | }
963 | },
964 |
965 | _setDate: function (date, which) {
966 | if (!which || which == 'date')
967 | this.date = date;
968 | if (!which || which == 'view')
969 | this.viewDate = date;
970 | this.fill();
971 | this.setValue();
972 | var element;
973 | if (this.isInput) {
974 | element = this.element;
975 | } else if (this.component) {
976 | element = this.element.find('input');
977 | }
978 | if (element) {
979 | element.change();
980 | if (this.autoclose && (!which || which == 'date')) {
981 | //this.hide();
982 | }
983 | }
984 | this.element.trigger({
985 | type: 'changeDate',
986 | date: this.date
987 | });
988 | },
989 |
990 | moveMinute: function (date, dir) {
991 | if (!dir) return date;
992 | var new_date = new Date(date.valueOf());
993 | //dir = dir > 0 ? 1 : -1;
994 | new_date.setUTCMinutes(new_date.getUTCMinutes() + (dir * this.minuteStep));
995 | return new_date;
996 | },
997 |
998 | moveHour: function (date, dir) {
999 | if (!dir) return date;
1000 | var new_date = new Date(date.valueOf());
1001 | //dir = dir > 0 ? 1 : -1;
1002 | new_date.setUTCHours(new_date.getUTCHours() + dir);
1003 | return new_date;
1004 | },
1005 |
1006 | moveDate: function (date, dir) {
1007 | if (!dir) return date;
1008 | var new_date = new Date(date.valueOf());
1009 | //dir = dir > 0 ? 1 : -1;
1010 | new_date.setUTCDate(new_date.getUTCDate() + dir);
1011 | return new_date;
1012 | },
1013 |
1014 | moveMonth: function (date, dir) {
1015 | if (!dir) return date;
1016 | var new_date = new Date(date.valueOf()),
1017 | day = new_date.getUTCDate(),
1018 | month = new_date.getUTCMonth(),
1019 | mag = Math.abs(dir),
1020 | new_month, test;
1021 | dir = dir > 0 ? 1 : -1;
1022 | if (mag == 1) {
1023 | test = dir == -1
1024 | // If going back one month, make sure month is not current month
1025 | // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
1026 | ? function () {
1027 | return new_date.getUTCMonth() == month;
1028 | }
1029 | // If going forward one month, make sure month is as expected
1030 | // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
1031 | : function () {
1032 | return new_date.getUTCMonth() != new_month;
1033 | };
1034 | new_month = month + dir;
1035 | new_date.setUTCMonth(new_month);
1036 | // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
1037 | if (new_month < 0 || new_month > 11)
1038 | new_month = (new_month + 12) % 12;
1039 | } else {
1040 | // For magnitudes >1, move one month at a time...
1041 | for (var i = 0; i < mag; i++)
1042 | // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
1043 | new_date = this.moveMonth(new_date, dir);
1044 | // ...then reset the day, keeping it in the new month
1045 | new_month = new_date.getUTCMonth();
1046 | new_date.setUTCDate(day);
1047 | test = function () {
1048 | return new_month != new_date.getUTCMonth();
1049 | };
1050 | }
1051 | // Common date-resetting loop -- if date is beyond end of month, make it
1052 | // end of month
1053 | while (test()) {
1054 | new_date.setUTCDate(--day);
1055 | new_date.setUTCMonth(new_month);
1056 | }
1057 | return new_date;
1058 | },
1059 |
1060 | moveYear: function (date, dir) {
1061 | return this.moveMonth(date, dir * 12);
1062 | },
1063 |
1064 | dateWithinRange: function (date) {
1065 | return date >= this.startDate && date <= this.endDate;
1066 | },
1067 |
1068 | keydown: function (e) {
1069 | if (this.picker.is(':not(:visible)')) {
1070 | if (e.keyCode == 27) // allow escape to hide and re-show picker
1071 | this.show();
1072 | return;
1073 | }
1074 | var dateChanged = false,
1075 | dir, day, month,
1076 | newDate, newViewDate;
1077 | switch (e.keyCode) {
1078 | case 27: // escape
1079 | this.hide();
1080 | e.preventDefault();
1081 | break;
1082 | case 37: // left
1083 | case 39: // right
1084 | if (!this.keyboardNavigation) break;
1085 | dir = e.keyCode == 37 ? -1 : 1;
1086 | viewMode = this.viewMode;
1087 | if (e.ctrlKey) {
1088 | viewMode += 2;
1089 | } else if (e.shiftKey) {
1090 | viewMode += 1;
1091 | }
1092 | if (viewMode == 4) {
1093 | newDate = this.moveYear(this.date, dir);
1094 | newViewDate = this.moveYear(this.viewDate, dir);
1095 | } else if (viewMode == 3) {
1096 | newDate = this.moveMonth(this.date, dir);
1097 | newViewDate = this.moveMonth(this.viewDate, dir);
1098 | } else if (viewMode == 2) {
1099 | newDate = this.moveDate(this.date, dir);
1100 | newViewDate = this.moveDate(this.viewDate, dir);
1101 | } else if (viewMode == 1) {
1102 | newDate = this.moveHour(this.date, dir);
1103 | newViewDate = this.moveHour(this.viewDate, dir);
1104 | } else if (viewMode == 0) {
1105 | newDate = this.moveMinute(this.date, dir);
1106 | newViewDate = this.moveMinute(this.viewDate, dir);
1107 | }
1108 | if (this.dateWithinRange(newDate)) {
1109 | this.date = newDate;
1110 | this.viewDate = newViewDate;
1111 | this.setValue();
1112 | this.update();
1113 | e.preventDefault();
1114 | dateChanged = true;
1115 | }
1116 | break;
1117 | case 38: // up
1118 | case 40: // down
1119 | if (!this.keyboardNavigation) break;
1120 | dir = e.keyCode == 38 ? -1 : 1;
1121 | viewMode = this.viewMode;
1122 | if (e.ctrlKey) {
1123 | viewMode += 2;
1124 | } else if (e.shiftKey) {
1125 | viewMode += 1;
1126 | }
1127 | if (viewMode == 4) {
1128 | newDate = this.moveYear(this.date, dir);
1129 | newViewDate = this.moveYear(this.viewDate, dir);
1130 | } else if (viewMode == 3) {
1131 | newDate = this.moveMonth(this.date, dir);
1132 | newViewDate = this.moveMonth(this.viewDate, dir);
1133 | } else if (viewMode == 2) {
1134 | newDate = this.moveDate(this.date, dir * 7);
1135 | newViewDate = this.moveDate(this.viewDate, dir * 7);
1136 | } else if (viewMode == 1) {
1137 | if (this.showMeridian) {
1138 | newDate = this.moveHour(this.date, dir * 6);
1139 | newViewDate = this.moveHour(this.viewDate, dir * 6);
1140 | } else {
1141 | newDate = this.moveHour(this.date, dir * 4);
1142 | newViewDate = this.moveHour(this.viewDate, dir * 4);
1143 | }
1144 | } else if (viewMode == 0) {
1145 | newDate = this.moveMinute(this.date, dir * 4);
1146 | newViewDate = this.moveMinute(this.viewDate, dir * 4);
1147 | }
1148 | if (this.dateWithinRange(newDate)) {
1149 | this.date = newDate;
1150 | this.viewDate = newViewDate;
1151 | this.setValue();
1152 | this.update();
1153 | e.preventDefault();
1154 | dateChanged = true;
1155 | }
1156 | break;
1157 | case 13: // enter
1158 | if (this.viewMode != 0) {
1159 | var oldViewMode = this.viewMode;
1160 | this.showMode(-1);
1161 | this.fill();
1162 | if (oldViewMode == this.viewMode && this.autoclose) {
1163 | this.hide();
1164 | }
1165 | } else {
1166 | this.fill();
1167 | if (this.autoclose) {
1168 | this.hide();
1169 | }
1170 | }
1171 | e.preventDefault();
1172 | break;
1173 | case 9: // tab
1174 | this.hide();
1175 | break;
1176 | }
1177 | if (dateChanged) {
1178 | var element;
1179 | if (this.isInput) {
1180 | element = this.element;
1181 | } else if (this.component) {
1182 | element = this.element.find('input');
1183 | }
1184 | if (element) {
1185 | element.change();
1186 | }
1187 | this.element.trigger({
1188 | type: 'changeDate',
1189 | date: this.date
1190 | });
1191 | }
1192 | },
1193 |
1194 | showMode: function (dir) {
1195 | if (dir) {
1196 | var newViewMode = Math.max(0, Math.min(DPGlobal.modes.length - 1, this.viewMode + dir));
1197 | if (newViewMode >= this.minView && newViewMode <= this.maxView) {
1198 | this.element.trigger({
1199 | type: 'changeMode',
1200 | date: this.viewDate,
1201 | oldViewMode: this.viewMode,
1202 | newViewMode: newViewMode
1203 | });
1204 |
1205 | this.viewMode = newViewMode;
1206 | }
1207 | }
1208 | /*
1209 | vitalets: fixing bug of very special conditions:
1210 | jquery 1.7.1 + webkit + show inline datetimepicker in bootstrap popover.
1211 | Method show() does not set display css correctly and datetimepicker is not shown.
1212 | Changed to .css('display', 'block') solve the problem.
1213 | See https://github.com/vitalets/x-editable/issues/37
1214 |
1215 | In jquery 1.7.2+ everything works fine.
1216 | */
1217 | //this.picker.find('>div').hide().filter('.datetimepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
1218 | this.picker.find('>div').hide().filter('.datetimepicker-' + DPGlobal.modes[this.viewMode].clsName).css('display', 'block');
1219 | this.updateNavArrows();
1220 | },
1221 |
1222 | reset: function (e) {
1223 | this._setDate(null, 'date');
1224 | }
1225 | };
1226 |
1227 | $.fn.datetimepicker = function (option) {
1228 | var args = Array.apply(null, arguments);
1229 | args.shift();
1230 | var internal_return;
1231 | this.each(function () {
1232 | var $this = $(this),
1233 | data = $this.data('datetimepicker'),
1234 | options = typeof option == 'object' && option;
1235 | if (!data) {
1236 | $this.data('datetimepicker', (data = new Datetimepicker(this, $.extend({}, $.fn.datetimepicker.defaults, options))));
1237 | }
1238 | if (typeof option == 'string' && typeof data[option] == 'function') {
1239 | internal_return = data[option].apply(data, args);
1240 | if (internal_return !== undefined) {
1241 | return false;
1242 | }
1243 | }
1244 | });
1245 | if (internal_return !== undefined)
1246 | return internal_return;
1247 | else
1248 | return this;
1249 | };
1250 |
1251 | $.fn.datetimepicker.defaults = {
1252 | };
1253 | $.fn.datetimepicker.Constructor = Datetimepicker;
1254 | var dates = $.fn.datetimepicker.dates = {
1255 | en: {
1256 | days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
1257 | daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
1258 | daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
1259 | months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
1260 | monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
1261 | meridiem: ["am", "pm"],
1262 | suffix: ["st", "nd", "rd", "th"],
1263 | today: "Today"
1264 | }
1265 | };
1266 |
1267 | var DPGlobal = {
1268 | modes: [
1269 | {
1270 | clsName: 'minutes',
1271 | navFnc: 'Hours',
1272 | navStep: 1
1273 | },
1274 | {
1275 | clsName: 'hours',
1276 | navFnc: 'Date',
1277 | navStep: 1
1278 | },
1279 | {
1280 | clsName: 'days',
1281 | navFnc: 'Month',
1282 | navStep: 1
1283 | },
1284 | {
1285 | clsName: 'months',
1286 | navFnc: 'FullYear',
1287 | navStep: 1
1288 | },
1289 | {
1290 | clsName: 'years',
1291 | navFnc: 'FullYear',
1292 | navStep: 10
1293 | }
1294 | ],
1295 | isLeapYear: function (year) {
1296 | return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
1297 | },
1298 | getDaysInMonth: function (year, month) {
1299 | return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
1300 | },
1301 | getDefaultFormat: function (type, field) {
1302 | if (type == "standard") {
1303 | if (field == 'input')
1304 | return 'yyyy-mm-dd hh:ii';
1305 | else
1306 | return 'yyyy-mm-dd hh:ii:ss';
1307 | } else if (type == "php") {
1308 | if (field == 'input')
1309 | return 'Y-m-d H:i';
1310 | else
1311 | return 'Y-m-d H:i:s';
1312 | } else {
1313 | throw new Error("Invalid format type.");
1314 | }
1315 | },
1316 | validParts: function (type) {
1317 | if (type == "standard") {
1318 | return /hh?|HH?|p|P|ii?|ss?|dd?|DD?|mm?|MM?|yy(?:yy)?/g;
1319 | } else if (type == "php") {
1320 | return /[dDjlNwzFmMnStyYaABgGhHis]/g;
1321 | } else {
1322 | throw new Error("Invalid format type.");
1323 | }
1324 | },
1325 | nonpunctuation: /[^ -\/:-@\[-`{-~\t\n\rTZ]+/g,
1326 | parseFormat: function (format, type) {
1327 | // IE treats \0 as a string end in inputs (truncating the value),
1328 | // so it's a bad format delimiter, anyway
1329 | var separators = format.replace(this.validParts(type), '\0').split('\0'),
1330 | parts = format.match(this.validParts(type));
1331 | if (!separators || !separators.length || !parts || parts.length == 0) {
1332 | throw new Error("Invalid date format.");
1333 | }
1334 | return {separators: separators, parts: parts};
1335 | },
1336 | parseDate: function (date, format, language, type) {
1337 | if (date instanceof Date) {
1338 | var dateUTC = new Date(date.valueOf() - date.getTimezoneOffset() * 60000);
1339 | dateUTC.setMilliseconds(0);
1340 | return dateUTC;
1341 | }
1342 | if (/^\d{4}\-\d{1,2}\-\d{1,2}$/.test(date)) {
1343 | format = this.parseFormat('yyyy-mm-dd', type);
1344 | }
1345 | if (/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}$/.test(date)) {
1346 | format = this.parseFormat('yyyy-mm-dd hh:ii', type);
1347 | }
1348 | if (/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}\:\d{1,2}[Z]{0,1}$/.test(date)) {
1349 | format = this.parseFormat('yyyy-mm-dd hh:ii:ss', type);
1350 | }
1351 | if (/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(date)) {
1352 | var part_re = /([-+]\d+)([dmwy])/,
1353 | parts = date.match(/([-+]\d+)([dmwy])/g),
1354 | part, dir;
1355 | date = new Date();
1356 | for (var i = 0; i < parts.length; i++) {
1357 | part = part_re.exec(parts[i]);
1358 | dir = parseInt(part[1]);
1359 | switch (part[2]) {
1360 | case 'd':
1361 | date.setUTCDate(date.getUTCDate() + dir);
1362 | break;
1363 | case 'm':
1364 | date = Datetimepicker.prototype.moveMonth.call(Datetimepicker.prototype, date, dir);
1365 | break;
1366 | case 'w':
1367 | date.setUTCDate(date.getUTCDate() + dir * 7);
1368 | break;
1369 | case 'y':
1370 | date = Datetimepicker.prototype.moveYear.call(Datetimepicker.prototype, date, dir);
1371 | break;
1372 | }
1373 | }
1374 | return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), 0);
1375 | }
1376 | var parts = date && date.match(this.nonpunctuation) || [],
1377 | date = new Date(0, 0, 0, 0, 0, 0, 0),
1378 | parsed = {},
1379 | setters_order = ['hh', 'h', 'ii', 'i', 'ss', 's', 'yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'D', 'DD', 'd', 'dd', 'H', 'HH', 'p', 'P'],
1380 | setters_map = {
1381 | hh: function (d, v) {
1382 | return d.setUTCHours(v);
1383 | },
1384 | h: function (d, v) {
1385 | return d.setUTCHours(v);
1386 | },
1387 | HH: function (d, v) {
1388 | return d.setUTCHours(v == 12 ? 0 : v);
1389 | },
1390 | H: function (d, v) {
1391 | return d.setUTCHours(v == 12 ? 0 : v);
1392 | },
1393 | ii: function (d, v) {
1394 | return d.setUTCMinutes(v);
1395 | },
1396 | i: function (d, v) {
1397 | return d.setUTCMinutes(v);
1398 | },
1399 | ss: function (d, v) {
1400 | return d.setUTCSeconds(v);
1401 | },
1402 | s: function (d, v) {
1403 | return d.setUTCSeconds(v);
1404 | },
1405 | yyyy: function (d, v) {
1406 | return d.setUTCFullYear(v);
1407 | },
1408 | yy: function (d, v) {
1409 | return d.setUTCFullYear(2000 + v);
1410 | },
1411 | m: function (d, v) {
1412 | v -= 1;
1413 | while (v < 0) v += 12;
1414 | v %= 12;
1415 | d.setUTCMonth(v);
1416 | while (d.getUTCMonth() != v)
1417 | d.setUTCDate(d.getUTCDate() - 1);
1418 | return d;
1419 | },
1420 | d: function (d, v) {
1421 | return d.setUTCDate(v);
1422 | },
1423 | p: function (d, v) {
1424 | return d.setUTCHours(v == 1 ? d.getUTCHours() + 12 : d.getUTCHours());
1425 | }
1426 | },
1427 | val, filtered, part;
1428 | setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
1429 | setters_map['dd'] = setters_map['d'];
1430 | setters_map['P'] = setters_map['p'];
1431 | date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
1432 | if (parts.length == format.parts.length) {
1433 | for (var i = 0, cnt = format.parts.length; i < cnt; i++) {
1434 | val = parseInt(parts[i], 10);
1435 | part = format.parts[i];
1436 | if (isNaN(val)) {
1437 | switch (part) {
1438 | case 'MM':
1439 | filtered = $(dates[language].months).filter(function () {
1440 | var m = this.slice(0, parts[i].length),
1441 | p = parts[i].slice(0, m.length);
1442 | return m == p;
1443 | });
1444 | val = $.inArray(filtered[0], dates[language].months) + 1;
1445 | break;
1446 | case 'M':
1447 | filtered = $(dates[language].monthsShort).filter(function () {
1448 | var m = this.slice(0, parts[i].length),
1449 | p = parts[i].slice(0, m.length);
1450 | return m == p;
1451 | });
1452 | val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
1453 | break;
1454 | case 'p':
1455 | case 'P':
1456 | val = $.inArray(parts[i].toLowerCase(), dates[language].meridiem);
1457 | break;
1458 | }
1459 | }
1460 | parsed[part] = val;
1461 | }
1462 | for (var i = 0, s; i < setters_order.length; i++) {
1463 | s = setters_order[i];
1464 | if (s in parsed && !isNaN(parsed[s]))
1465 | setters_map[s](date, parsed[s])
1466 | }
1467 | }
1468 | return date;
1469 | },
1470 | formatDate: function (date, format, language, type) {
1471 | if (date == null) {
1472 | return '';
1473 | }
1474 | var val;
1475 | if (type == 'standard') {
1476 | val = {
1477 | // year
1478 | yy: date.getUTCFullYear().toString().substring(2),
1479 | yyyy: date.getUTCFullYear(),
1480 | // month
1481 | m: date.getUTCMonth() + 1,
1482 | M: dates[language].monthsShort[date.getUTCMonth()],
1483 | MM: dates[language].months[date.getUTCMonth()],
1484 | // day
1485 | d: date.getUTCDate(),
1486 | D: dates[language].daysShort[date.getUTCDay()],
1487 | DD: dates[language].days[date.getUTCDay()],
1488 | p: (dates[language].meridiem.length == 2 ? dates[language].meridiem[date.getUTCHours() < 12 ? 0 : 1] : ''),
1489 | // hour
1490 | h: date.getUTCHours(),
1491 | // minute
1492 | i: date.getUTCMinutes(),
1493 | // second
1494 | s: date.getUTCSeconds()
1495 | };
1496 |
1497 | if (dates[language].meridiem.length == 2) {
1498 | val.H = (val.h % 12 == 0 ? 12 : val.h % 12);
1499 | }
1500 | else {
1501 | val.H = val.h;
1502 | }
1503 | val.HH = (val.H < 10 ? '0' : '') + val.H;
1504 | val.P = val.p.toUpperCase();
1505 | val.hh = (val.h < 10 ? '0' : '') + val.h;
1506 | val.ii = (val.i < 10 ? '0' : '') + val.i;
1507 | val.ss = (val.s < 10 ? '0' : '') + val.s;
1508 | val.dd = (val.d < 10 ? '0' : '') + val.d;
1509 | val.mm = (val.m < 10 ? '0' : '') + val.m;
1510 | } else if (type == 'php') {
1511 | // php format
1512 | val = {
1513 | // year
1514 | y: date.getUTCFullYear().toString().substring(2),
1515 | Y: date.getUTCFullYear(),
1516 | // month
1517 | F: dates[language].months[date.getUTCMonth()],
1518 | M: dates[language].monthsShort[date.getUTCMonth()],
1519 | n: date.getUTCMonth() + 1,
1520 | t: DPGlobal.getDaysInMonth(date.getUTCFullYear(), date.getUTCMonth()),
1521 | // day
1522 | j: date.getUTCDate(),
1523 | l: dates[language].days[date.getUTCDay()],
1524 | D: dates[language].daysShort[date.getUTCDay()],
1525 | w: date.getUTCDay(), // 0 -> 6
1526 | N: (date.getUTCDay() == 0 ? 7 : date.getUTCDay()), // 1 -> 7
1527 | S: (date.getUTCDate() % 10 <= dates[language].suffix.length ? dates[language].suffix[date.getUTCDate() % 10 - 1] : ''),
1528 | // hour
1529 | a: (dates[language].meridiem.length == 2 ? dates[language].meridiem[date.getUTCHours() < 12 ? 0 : 1] : ''),
1530 | g: (date.getUTCHours() % 12 == 0 ? 12 : date.getUTCHours() % 12),
1531 | G: date.getUTCHours(),
1532 | // minute
1533 | i: date.getUTCMinutes(),
1534 | // second
1535 | s: date.getUTCSeconds()
1536 | };
1537 | val.m = (val.n < 10 ? '0' : '') + val.n;
1538 | val.d = (val.j < 10 ? '0' : '') + val.j;
1539 | val.A = val.a.toString().toUpperCase();
1540 | val.h = (val.g < 10 ? '0' : '') + val.g;
1541 | val.H = (val.G < 10 ? '0' : '') + val.G;
1542 | val.i = (val.i < 10 ? '0' : '') + val.i;
1543 | val.s = (val.s < 10 ? '0' : '') + val.s;
1544 | } else {
1545 | throw new Error("Invalid format type.");
1546 | }
1547 | var date = [],
1548 | seps = $.extend([], format.separators);
1549 | for (var i = 0, cnt = format.parts.length; i < cnt; i++) {
1550 | if (seps.length) {
1551 | date.push(seps.shift());
1552 | }
1553 | date.push(val[format.parts[i]]);
1554 | }
1555 | if (seps.length) {
1556 | date.push(seps.shift());
1557 | }
1558 | return date.join('');
1559 | },
1560 | convertViewMode: function (viewMode) {
1561 | switch (viewMode) {
1562 | case 4:
1563 | case 'decade':
1564 | viewMode = 4;
1565 | break;
1566 | case 3:
1567 | case 'year':
1568 | viewMode = 3;
1569 | break;
1570 | case 2:
1571 | case 'month':
1572 | viewMode = 2;
1573 | break;
1574 | case 1:
1575 | case 'day':
1576 | viewMode = 1;
1577 | break;
1578 | case 0:
1579 | case 'hour':
1580 | viewMode = 0;
1581 | break;
1582 | }
1583 |
1584 | return viewMode;
1585 | },
1586 | headTemplate: '' +
1587 | '' +
1588 | ' | ' +
1589 | ' | ' +
1590 | ' | ' +
1591 | '
' +
1592 | '',
1593 | headTemplateV3: '' +
1594 | '' +
1595 | ' | ' +
1596 | ' | ' +
1597 | ' | ' +
1598 | '
' +
1599 | '',
1600 | contTemplate: ' |
',
1601 | footTemplate: ' |
'
1602 | };
1603 | DPGlobal.template = '' +
1604 | '
' +
1605 | '
' +
1606 | DPGlobal.headTemplate +
1607 | DPGlobal.contTemplate +
1608 | DPGlobal.footTemplate +
1609 | '
' +
1610 | '
' +
1611 | '
' +
1612 | '
' +
1613 | DPGlobal.headTemplate +
1614 | DPGlobal.contTemplate +
1615 | DPGlobal.footTemplate +
1616 | '
' +
1617 | '
' +
1618 | '
' +
1619 | '
' +
1620 | DPGlobal.headTemplate +
1621 | '' +
1622 | DPGlobal.footTemplate +
1623 | '
' +
1624 | '
' +
1625 | '
' +
1626 | '
' +
1627 | DPGlobal.headTemplate +
1628 | DPGlobal.contTemplate +
1629 | DPGlobal.footTemplate +
1630 | '
' +
1631 | '
' +
1632 | '
' +
1633 | '
' +
1634 | DPGlobal.headTemplate +
1635 | DPGlobal.contTemplate +
1636 | DPGlobal.footTemplate +
1637 | '
' +
1638 | '
' +
1639 | '
';
1640 | DPGlobal.templateV3 = '' +
1641 | '
' +
1642 | '
' +
1643 | DPGlobal.headTemplateV3 +
1644 | DPGlobal.contTemplate +
1645 | DPGlobal.footTemplate +
1646 | '
' +
1647 | '
' +
1648 | '
' +
1649 | '
' +
1650 | DPGlobal.headTemplateV3 +
1651 | DPGlobal.contTemplate +
1652 | DPGlobal.footTemplate +
1653 | '
' +
1654 | '
' +
1655 | '
' +
1656 | '
' +
1657 | DPGlobal.headTemplateV3 +
1658 | '' +
1659 | DPGlobal.footTemplate +
1660 | '
' +
1661 | '
' +
1662 | '
' +
1663 | '
' +
1664 | DPGlobal.headTemplateV3 +
1665 | DPGlobal.contTemplate +
1666 | DPGlobal.footTemplate +
1667 | '
' +
1668 | '
' +
1669 | '
' +
1670 | '
' +
1671 | DPGlobal.headTemplateV3 +
1672 | DPGlobal.contTemplate +
1673 | DPGlobal.footTemplate +
1674 | '
' +
1675 | '
' +
1676 | '
';
1677 | $.fn.datetimepicker.DPGlobal = DPGlobal;
1678 |
1679 | /* DATETIMEPICKER NO CONFLICT
1680 | * =================== */
1681 |
1682 | $.fn.datetimepicker.noConflict = function () {
1683 | $.fn.datetimepicker = old;
1684 | return this;
1685 | };
1686 |
1687 | /* DATETIMEPICKER DATA-API
1688 | * ================== */
1689 |
1690 | $(document).on(
1691 | 'focus.datetimepicker.data-api click.datetimepicker.data-api',
1692 | '[data-provide="datetimepicker"]',
1693 | function (e) {
1694 | var $this = $(this);
1695 | if ($this.data('datetimepicker')) return;
1696 | e.preventDefault();
1697 | // component click requires us to explicitly show it
1698 | $this.datetimepicker('show');
1699 | }
1700 | );
1701 | $(function () {
1702 | $('[data-provide="datetimepicker-inline"]').datetimepicker();
1703 | });
1704 |
1705 | }(window.jQuery);
--------------------------------------------------------------------------------
/lib/combodate/combodate.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Combodate - 1.0.7
3 | * Dropdown date and time picker.
4 | * Converts text input into dropdowns to pick day, month, year, hour, minute and second.
5 | * Uses momentjs as datetime library http://momentjs.com.
6 | * For i18n include corresponding file from https://github.com/timrwood/moment/tree/master/lang
7 | *
8 | * Confusion at noon and midnight - see http://en.wikipedia.org/wiki/12-hour_clock#Confusion_at_noon_and_midnight
9 | * In combodate:
10 | * 12:00 pm --> 12:00 (24-h format, midday)
11 | * 12:00 am --> 00:00 (24-h format, midnight, start of day)
12 | *
13 | * Differs from momentjs parse rules:
14 | * 00:00 pm, 12:00 pm --> 12:00 (24-h format, day not change)
15 | * 00:00 am, 12:00 am --> 00:00 (24-h format, day not change)
16 | *
17 | *
18 | * Author: Vitaliy Potapov
19 | * Project page: http://github.com/vitalets/combodate
20 | * Copyright (c) 2012 Vitaliy Potapov. Released under MIT License.
21 | **/
22 | (function ($) {
23 |
24 | var Combodate = function (element, options) {
25 | this.$element = $(element);
26 | if(!this.$element.is('input')) {
27 | $.error('Combodate should be applied to INPUT element');
28 | return;
29 | }
30 | this.options = $.extend({}, $.fn.combodate.defaults, options, this.$element.data());
31 | this.init();
32 | };
33 |
34 | Combodate.prototype = {
35 | constructor: Combodate,
36 | init: function () {
37 | this.map = {
38 | //key regexp moment.method
39 | day: ['D', 'date'],
40 | month: ['M', 'month'],
41 | year: ['Y', 'year'],
42 | hour: ['[Hh]', 'hours'],
43 | minute: ['m', 'minutes'],
44 | second: ['s', 'seconds'],
45 | ampm: ['[Aa]', '']
46 | };
47 |
48 | this.$widget = $('').html(this.getTemplate());
49 |
50 | this.initCombos();
51 |
52 | //update original input on change
53 | this.$widget.on('change', 'select', $.proxy(function(e) {
54 | this.$element.val(this.getValue()).change();
55 | // update days count if month or year changes
56 | if (this.options.smartDays) {
57 | if ($(e.target).is('.month') || $(e.target).is('.year')) {
58 | this.fillCombo('day');
59 | }
60 | }
61 | }, this));
62 |
63 | this.$widget.find('select').css('width', 'auto');
64 |
65 | // hide original input and insert widget
66 | this.$element.hide().after(this.$widget);
67 |
68 | // set initial value
69 | this.setValue(this.$element.val() || this.options.value);
70 | },
71 |
72 | /*
73 | Replace tokens in template with