├── .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 | 6 | 7 | 10 | 11 | 14 | 15 | 57 | 58 | 75 | 76 | 77 |
78 | {{> m_editable_body_popovers}} 79 |
80 | 81 | 82 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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('
' + meridian.toUpperCase() + ''); 604 | } 605 | meridianOld = meridian; 606 | txt = (i % 12 ? i % 12 : 12); 607 | html.push('' + txt + ''); 608 | if (i == 23) { 609 | 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('
' + meridian.toUpperCase() + ''); 635 | } 636 | meridianOld = meridian; 637 | txt = (hours % 12 ? hours % 12 : 12); 638 | //html.push(''+txt+''); 639 | html.push('' + txt + ':' + (i < 10 ? '0' + i : i) + ''); 640 | if (i == 59) { 641 | 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 '); 97 | }); 98 | 99 | return tpl; 100 | }, 101 | 102 | /* 103 | Initialize combos that presents in template 104 | */ 105 | initCombos: function() { 106 | for (var k in this.map) { 107 | var $c = this.$widget.find('.'+k); 108 | // set properties like this.$day, this.$month etc. 109 | this['$'+k] = $c.length ? $c : null; 110 | // fill with items 111 | this.fillCombo(k); 112 | } 113 | }, 114 | 115 | /* 116 | Fill combo with items 117 | */ 118 | fillCombo: function(k) { 119 | var $combo = this['$'+k]; 120 | if (!$combo) { 121 | return; 122 | } 123 | 124 | // define method name to fill items, e.g `fillDays` 125 | var f = 'fill' + k.charAt(0).toUpperCase() + k.slice(1); 126 | var items = this[f](); 127 | var value = $combo.val(); 128 | 129 | $combo.empty(); 130 | for(var i=0; i'+items[i][1]+''); 132 | } 133 | 134 | $combo.val(value); 135 | }, 136 | 137 | /* 138 | Initialize items of combos. Handles `firstItem` option 139 | */ 140 | fillCommon: function(key) { 141 | var values = [], 142 | relTime; 143 | 144 | if(this.options.firstItem === 'name') { 145 | //need both to support moment ver < 2 and >= 2 146 | relTime = moment.relativeTime || moment.langData()._relativeTime; 147 | var header = typeof relTime[key] === 'function' ? relTime[key](1, true, key, false) : relTime[key]; 148 | //take last entry (see momentjs lang files structure) 149 | header = header.split(' ').reverse()[0]; 150 | values.push(['', header]); 151 | } else if(this.options.firstItem === 'empty') { 152 | values.push(['', '']); 153 | } 154 | return values; 155 | }, 156 | 157 | 158 | /* 159 | fill day 160 | */ 161 | fillDay: function() { 162 | var items = this.fillCommon('d'), name, i, 163 | twoDigit = this.options.template.indexOf('DD') !== -1, 164 | daysCount = 31; 165 | 166 | // detect days count (depends on month and year) 167 | // originally https://github.com/vitalets/combodate/pull/7 168 | if (this.options.smartDays && this.$month && this.$year) { 169 | var month = parseInt(this.$month.val(), 10); 170 | var year = parseInt(this.$year.val(), 10); 171 | 172 | if (!isNaN(month) && !isNaN(year)) { 173 | daysCount = moment([year, month]).daysInMonth(); 174 | } 175 | } 176 | 177 | for (i = 1; i <= daysCount; i++) { 178 | name = twoDigit ? this.leadZero(i) : i; 179 | items.push([i, name]); 180 | } 181 | return items; 182 | }, 183 | 184 | /* 185 | fill month 186 | */ 187 | fillMonth: function() { 188 | var items = this.fillCommon('M'), name, i, 189 | longNames = this.options.template.indexOf('MMMM') !== -1, 190 | shortNames = this.options.template.indexOf('MMM') !== -1, 191 | twoDigit = this.options.template.indexOf('MM') !== -1; 192 | 193 | for(i=0; i<=11; i++) { 194 | if(longNames) { 195 | //see https://github.com/timrwood/momentjs.com/pull/36 196 | name = moment().date(1).month(i).format('MMMM'); 197 | } else if(shortNames) { 198 | name = moment().date(1).month(i).format('MMM'); 199 | } else if(twoDigit) { 200 | name = this.leadZero(i+1); 201 | } else { 202 | name = i+1; 203 | } 204 | items.push([i, name]); 205 | } 206 | return items; 207 | }, 208 | 209 | /* 210 | fill year 211 | */ 212 | fillYear: function() { 213 | var items = [], name, i, 214 | longNames = this.options.template.indexOf('YYYY') !== -1; 215 | 216 | for(i=this.options.maxYear; i>=this.options.minYear; i--) { 217 | name = longNames ? i : (i+'').substring(2); 218 | items[this.options.yearDescending ? 'push' : 'unshift']([i, name]); 219 | } 220 | 221 | items = this.fillCommon('y').concat(items); 222 | 223 | return items; 224 | }, 225 | 226 | /* 227 | fill hour 228 | */ 229 | fillHour: function() { 230 | var items = this.fillCommon('h'), name, i, 231 | h12 = this.options.template.indexOf('h') !== -1, 232 | h24 = this.options.template.indexOf('H') !== -1, 233 | twoDigit = this.options.template.toLowerCase().indexOf('hh') !== -1, 234 | min = h12 ? 1 : 0, 235 | max = h12 ? 12 : 23; 236 | 237 | for(i=min; i<=max; i++) { 238 | name = twoDigit ? this.leadZero(i) : i; 239 | items.push([i, name]); 240 | } 241 | return items; 242 | }, 243 | 244 | /* 245 | fill minute 246 | */ 247 | fillMinute: function() { 248 | var items = this.fillCommon('m'), name, i, 249 | twoDigit = this.options.template.indexOf('mm') !== -1; 250 | 251 | for(i=0; i<=59; i+= this.options.minuteStep) { 252 | name = twoDigit ? this.leadZero(i) : i; 253 | items.push([i, name]); 254 | } 255 | return items; 256 | }, 257 | 258 | /* 259 | fill second 260 | */ 261 | fillSecond: function() { 262 | var items = this.fillCommon('s'), name, i, 263 | twoDigit = this.options.template.indexOf('ss') !== -1; 264 | 265 | for(i=0; i<=59; i+= this.options.secondStep) { 266 | name = twoDigit ? this.leadZero(i) : i; 267 | items.push([i, name]); 268 | } 269 | return items; 270 | }, 271 | 272 | /* 273 | fill ampm 274 | */ 275 | fillAmpm: function() { 276 | var ampmL = this.options.template.indexOf('a') !== -1, 277 | ampmU = this.options.template.indexOf('A') !== -1, 278 | items = [ 279 | ['am', ampmL ? 'am' : 'AM'], 280 | ['pm', ampmL ? 'pm' : 'PM'] 281 | ]; 282 | return items; 283 | }, 284 | 285 | /* 286 | Returns current date value from combos. 287 | If format not specified - `options.format` used. 288 | If format = `null` - Moment object returned. 289 | */ 290 | getValue: function(format) { 291 | var dt, values = {}, 292 | that = this, 293 | notSelected = false; 294 | 295 | //getting selected values 296 | $.each(this.map, function(k, v) { 297 | if(k === 'ampm') { 298 | return; 299 | } 300 | var def = k === 'day' ? 1 : 0; 301 | 302 | values[k] = that['$'+k] ? parseInt(that['$'+k].val(), 10) : def; 303 | 304 | if(isNaN(values[k])) { 305 | notSelected = true; 306 | return false; 307 | } 308 | }); 309 | 310 | //if at least one visible combo not selected - return empty string 311 | if(notSelected) { 312 | return ''; 313 | } 314 | 315 | //convert hours 12h --> 24h 316 | if(this.$ampm) { 317 | //12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day) 318 | if(values.hour === 12) { 319 | values.hour = this.$ampm.val() === 'am' ? 0 : 12; 320 | } else { 321 | values.hour = this.$ampm.val() === 'am' ? values.hour : values.hour+12; 322 | } 323 | } 324 | 325 | dt = moment([values.year, values.month, values.day, values.hour, values.minute, values.second]); 326 | 327 | //highlight invalid date 328 | this.highlight(dt); 329 | 330 | format = format === undefined ? this.options.format : format; 331 | if(format === null) { 332 | return dt.isValid() ? dt : null; 333 | } else { 334 | return dt.isValid() ? dt.format(format) : ''; 335 | } 336 | }, 337 | 338 | setValue: function(value) { 339 | if(!value) { 340 | return; 341 | } 342 | 343 | // parse in strict mode (third param `true`) 344 | var dt = typeof value === 'string' ? moment(value, this.options.format, true) : moment(value), 345 | that = this, 346 | values = {}; 347 | 348 | //function to find nearest value in select options 349 | function getNearest($select, value) { 350 | var delta = {}; 351 | $select.children('option').each(function(i, opt){ 352 | var optValue = $(opt).attr('value'), 353 | distance; 354 | 355 | if(optValue === '') return; 356 | distance = Math.abs(optValue - value); 357 | if(typeof delta.distance === 'undefined' || distance < delta.distance) { 358 | delta = {value: optValue, distance: distance}; 359 | } 360 | }); 361 | return delta.value; 362 | } 363 | 364 | if(dt.isValid()) { 365 | //read values from date object 366 | $.each(this.map, function(k, v) { 367 | if(k === 'ampm') { 368 | return; 369 | } 370 | values[k] = dt[v[1]](); 371 | }); 372 | 373 | if(this.$ampm) { 374 | //12:00 pm --> 12:00 (24-h format, midday), 12:00 am --> 00:00 (24-h format, midnight, start of day) 375 | if(values.hour >= 12) { 376 | values.ampm = 'pm'; 377 | if(values.hour > 12) { 378 | values.hour -= 12; 379 | } 380 | } else { 381 | values.ampm = 'am'; 382 | if(values.hour === 0) { 383 | values.hour = 12; 384 | } 385 | } 386 | } 387 | 388 | $.each(values, function(k, v) { 389 | //call val() for each existing combo, e.g. this.$hour.val() 390 | if(that['$'+k]) { 391 | 392 | if(k === 'minute' && that.options.minuteStep > 1 && that.options.roundTime) { 393 | v = getNearest(that['$'+k], v); 394 | } 395 | 396 | if(k === 'second' && that.options.secondStep > 1 && that.options.roundTime) { 397 | v = getNearest(that['$'+k], v); 398 | } 399 | 400 | that['$'+k].val(v); 401 | } 402 | }); 403 | 404 | // update days count 405 | if (this.options.smartDays) { 406 | this.fillCombo('day'); 407 | } 408 | 409 | this.$element.val(dt.format(this.options.format)).change(); 410 | } 411 | }, 412 | 413 | /* 414 | highlight combos if date is invalid 415 | */ 416 | highlight: function(dt) { 417 | if(!dt.isValid()) { 418 | if(this.options.errorClass) { 419 | this.$widget.addClass(this.options.errorClass); 420 | } else { 421 | //store original border color 422 | if(!this.borderColor) { 423 | this.borderColor = this.$widget.find('select').css('border-color'); 424 | } 425 | this.$widget.find('select').css('border-color', 'red'); 426 | } 427 | } else { 428 | if(this.options.errorClass) { 429 | this.$widget.removeClass(this.options.errorClass); 430 | } else { 431 | this.$widget.find('select').css('border-color', this.borderColor); 432 | } 433 | } 434 | }, 435 | 436 | leadZero: function(v) { 437 | return v <= 9 ? '0' + v : v; 438 | }, 439 | 440 | destroy: function() { 441 | this.$widget.remove(); 442 | this.$element.removeData('combodate').show(); 443 | } 444 | 445 | //todo: clear method 446 | }; 447 | 448 | $.fn.combodate = function ( option ) { 449 | var d, args = Array.apply(null, arguments); 450 | args.shift(); 451 | 452 | //getValue returns date as string / object (not jQuery object) 453 | if(option === 'getValue' && this.length && (d = this.eq(0).data('combodate'))) { 454 | return d.getValue.apply(d, args); 455 | } 456 | 457 | return this.each(function () { 458 | var $this = $(this), 459 | data = $this.data('combodate'), 460 | options = typeof option == 'object' && option; 461 | if (!data) { 462 | $this.data('combodate', (data = new Combodate(this, options))); 463 | } 464 | if (typeof option == 'string' && typeof data[option] == 'function') { 465 | data[option].apply(data, args); 466 | } 467 | }); 468 | }; 469 | 470 | $.fn.combodate.defaults = { 471 | //in this format value stored in original input 472 | format: 'DD-MM-YYYY HH:mm', 473 | //in this format items in dropdowns are displayed 474 | template: 'D / MMM / YYYY H : mm', 475 | //initial value, can be `new Date()` 476 | value: null, 477 | minYear: 1970, 478 | maxYear: 2015, 479 | yearDescending: true, 480 | minuteStep: 5, 481 | secondStep: 1, 482 | firstItem: 'empty', //'name', 'empty', 'none' 483 | errorClass: null, 484 | customClass: '', 485 | roundTime: true, // whether to round minutes and seconds if step > 1 486 | smartDays: false // whether days in combo depend on selected month: 31, 30, 28 487 | }; 488 | 489 | }(window.jQuery)); 490 | -------------------------------------------------------------------------------- /lib/select2/select2.css: -------------------------------------------------------------------------------- 1 | /* 2 | Version: 3.5.1 Timestamp: Tue Jul 22 18:58:56 EDT 2014 3 | */ 4 | .select2-container { 5 | margin: 0; 6 | position: relative; 7 | display: inline-block; 8 | /* inline-block for ie7 */ 9 | zoom: 1; 10 | *display: inline; 11 | vertical-align: middle; 12 | } 13 | 14 | .select2-container, 15 | .select2-drop, 16 | .select2-search, 17 | .select2-search input { 18 | /* 19 | Force border-box so that % widths fit the parent 20 | container without overlap because of margin/padding. 21 | More Info : http://www.quirksmode.org/css/box.html 22 | */ 23 | -webkit-box-sizing: border-box; /* webkit */ 24 | -moz-box-sizing: border-box; /* firefox */ 25 | box-sizing: border-box; /* css3 */ 26 | } 27 | 28 | .select2-container .select2-choice { 29 | display: block; 30 | height: 26px; 31 | padding: 0 0 0 8px; 32 | overflow: hidden; 33 | position: relative; 34 | 35 | border: 1px solid #aaa; 36 | white-space: nowrap; 37 | line-height: 26px; 38 | color: #444; 39 | text-decoration: none; 40 | 41 | border-radius: 4px; 42 | 43 | background-clip: padding-box; 44 | 45 | -webkit-touch-callout: none; 46 | -webkit-user-select: none; 47 | -moz-user-select: none; 48 | -ms-user-select: none; 49 | user-select: none; 50 | 51 | background-color: #fff; 52 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff)); 53 | background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%); 54 | background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%); 55 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0); 56 | background-image: linear-gradient(to top, #eee 0%, #fff 50%); 57 | } 58 | 59 | html[dir="rtl"] .select2-container .select2-choice { 60 | padding: 0 8px 0 0; 61 | } 62 | 63 | .select2-container.select2-drop-above .select2-choice { 64 | border-bottom-color: #aaa; 65 | 66 | border-radius: 0 0 4px 4px; 67 | 68 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff)); 69 | background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%); 70 | background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%); 71 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); 72 | background-image: linear-gradient(to bottom, #eee 0%, #fff 90%); 73 | } 74 | 75 | .select2-container.select2-allowclear .select2-choice .select2-chosen { 76 | margin-right: 42px; 77 | } 78 | 79 | .select2-container .select2-choice > .select2-chosen { 80 | margin-right: 26px; 81 | display: block; 82 | overflow: hidden; 83 | 84 | white-space: nowrap; 85 | 86 | text-overflow: ellipsis; 87 | float: none; 88 | width: auto; 89 | } 90 | 91 | html[dir="rtl"] .select2-container .select2-choice > .select2-chosen { 92 | margin-left: 26px; 93 | margin-right: 0; 94 | } 95 | 96 | .select2-container .select2-choice abbr { 97 | display: none; 98 | width: 12px; 99 | height: 12px; 100 | position: absolute; 101 | right: 24px; 102 | top: 8px; 103 | 104 | font-size: 1px; 105 | text-decoration: none; 106 | 107 | border: 0; 108 | background: url('select2.png') right top no-repeat; 109 | cursor: pointer; 110 | outline: 0; 111 | } 112 | 113 | .select2-container.select2-allowclear .select2-choice abbr { 114 | display: inline-block; 115 | } 116 | 117 | .select2-container .select2-choice abbr:hover { 118 | background-position: right -11px; 119 | cursor: pointer; 120 | } 121 | 122 | .select2-drop-mask { 123 | border: 0; 124 | margin: 0; 125 | padding: 0; 126 | position: fixed; 127 | left: 0; 128 | top: 0; 129 | min-height: 100%; 130 | min-width: 100%; 131 | height: auto; 132 | width: auto; 133 | opacity: 0; 134 | z-index: 9998; 135 | /* styles required for IE to work */ 136 | background-color: #fff; 137 | filter: alpha(opacity=0); 138 | } 139 | 140 | .select2-drop { 141 | width: 100%; 142 | margin-top: -1px; 143 | position: absolute; 144 | z-index: 9999; 145 | top: 100%; 146 | 147 | background: #fff; 148 | color: #000; 149 | border: 1px solid #aaa; 150 | border-top: 0; 151 | 152 | border-radius: 0 0 4px 4px; 153 | 154 | -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); 155 | box-shadow: 0 4px 5px rgba(0, 0, 0, .15); 156 | } 157 | 158 | .select2-drop.select2-drop-above { 159 | margin-top: 1px; 160 | border-top: 1px solid #aaa; 161 | border-bottom: 0; 162 | 163 | border-radius: 4px 4px 0 0; 164 | 165 | -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); 166 | box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); 167 | } 168 | 169 | .select2-drop-active { 170 | border: 1px solid #5897fb; 171 | border-top: none; 172 | } 173 | 174 | .select2-drop.select2-drop-above.select2-drop-active { 175 | border-top: 1px solid #5897fb; 176 | } 177 | 178 | .select2-drop-auto-width { 179 | border-top: 1px solid #aaa; 180 | width: auto; 181 | } 182 | 183 | .select2-drop-auto-width .select2-search { 184 | padding-top: 4px; 185 | } 186 | 187 | .select2-container .select2-choice .select2-arrow { 188 | display: inline-block; 189 | width: 18px; 190 | height: 100%; 191 | position: absolute; 192 | right: 0; 193 | top: 0; 194 | 195 | border-left: 1px solid #aaa; 196 | border-radius: 0 4px 4px 0; 197 | 198 | background-clip: padding-box; 199 | 200 | background: #ccc; 201 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); 202 | background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); 203 | background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); 204 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0); 205 | background-image: linear-gradient(to top, #ccc 0%, #eee 60%); 206 | } 207 | 208 | html[dir="rtl"] .select2-container .select2-choice .select2-arrow { 209 | left: 0; 210 | right: auto; 211 | 212 | border-left: none; 213 | border-right: 1px solid #aaa; 214 | border-radius: 4px 0 0 4px; 215 | } 216 | 217 | .select2-container .select2-choice .select2-arrow b { 218 | display: block; 219 | width: 100%; 220 | height: 100%; 221 | background: url('select2.png') no-repeat 0 1px; 222 | } 223 | 224 | html[dir="rtl"] .select2-container .select2-choice .select2-arrow b { 225 | background-position: 2px 1px; 226 | } 227 | 228 | .select2-search { 229 | display: inline-block; 230 | width: 100%; 231 | min-height: 26px; 232 | margin: 0; 233 | padding-left: 4px; 234 | padding-right: 4px; 235 | 236 | position: relative; 237 | z-index: 10000; 238 | 239 | white-space: nowrap; 240 | } 241 | 242 | .select2-search input { 243 | width: 100%; 244 | height: auto !important; 245 | min-height: 26px; 246 | padding: 4px 20px 4px 5px; 247 | margin: 0; 248 | 249 | outline: 0; 250 | font-family: sans-serif; 251 | font-size: 1em; 252 | 253 | border: 1px solid #aaa; 254 | border-radius: 0; 255 | 256 | -webkit-box-shadow: none; 257 | box-shadow: none; 258 | 259 | background: #fff url('select2.png') no-repeat 100% -22px; 260 | background: url('select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); 261 | background: url('select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); 262 | background: url('select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); 263 | background: url('select2.png') no-repeat 100% -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; 264 | } 265 | 266 | html[dir="rtl"] .select2-search input { 267 | padding: 4px 5px 4px 20px; 268 | 269 | background: #fff url('select2.png') no-repeat -37px -22px; 270 | background: url('select2.png') no-repeat -37px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); 271 | background: url('select2.png') no-repeat -37px -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); 272 | background: url('select2.png') no-repeat -37px -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); 273 | background: url('select2.png') no-repeat -37px -22px, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; 274 | } 275 | 276 | .select2-drop.select2-drop-above .select2-search input { 277 | margin-top: 4px; 278 | } 279 | 280 | .select2-search input.select2-active { 281 | background: #fff url('select2-spinner.gif') no-repeat 100%; 282 | background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); 283 | background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); 284 | background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); 285 | background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(to bottom, #fff 85%, #eee 99%) 0 0; 286 | } 287 | 288 | .select2-container-active .select2-choice, 289 | .select2-container-active .select2-choices { 290 | border: 1px solid #5897fb; 291 | outline: none; 292 | 293 | -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); 294 | box-shadow: 0 0 5px rgba(0, 0, 0, .3); 295 | } 296 | 297 | .select2-dropdown-open .select2-choice { 298 | border-bottom-color: transparent; 299 | -webkit-box-shadow: 0 1px 0 #fff inset; 300 | box-shadow: 0 1px 0 #fff inset; 301 | 302 | border-bottom-left-radius: 0; 303 | border-bottom-right-radius: 0; 304 | 305 | background-color: #eee; 306 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee)); 307 | background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%); 308 | background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%); 309 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); 310 | background-image: linear-gradient(to top, #fff 0%, #eee 50%); 311 | } 312 | 313 | .select2-dropdown-open.select2-drop-above .select2-choice, 314 | .select2-dropdown-open.select2-drop-above .select2-choices { 315 | border: 1px solid #5897fb; 316 | border-top-color: transparent; 317 | 318 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee)); 319 | background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%); 320 | background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%); 321 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); 322 | background-image: linear-gradient(to bottom, #fff 0%, #eee 50%); 323 | } 324 | 325 | .select2-dropdown-open .select2-choice .select2-arrow { 326 | background: transparent; 327 | border-left: none; 328 | filter: none; 329 | } 330 | html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow { 331 | border-right: none; 332 | } 333 | 334 | .select2-dropdown-open .select2-choice .select2-arrow b { 335 | background-position: -18px 1px; 336 | } 337 | 338 | html[dir="rtl"] .select2-dropdown-open .select2-choice .select2-arrow b { 339 | background-position: -16px 1px; 340 | } 341 | 342 | .select2-hidden-accessible { 343 | border: 0; 344 | clip: rect(0 0 0 0); 345 | height: 1px; 346 | margin: -1px; 347 | overflow: hidden; 348 | padding: 0; 349 | position: absolute; 350 | width: 1px; 351 | } 352 | 353 | /* results */ 354 | .select2-results { 355 | max-height: 200px; 356 | padding: 0 0 0 4px; 357 | margin: 4px 4px 4px 0; 358 | position: relative; 359 | overflow-x: hidden; 360 | overflow-y: auto; 361 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 362 | } 363 | 364 | html[dir="rtl"] .select2-results { 365 | padding: 0 4px 0 0; 366 | margin: 4px 0 4px 4px; 367 | } 368 | 369 | .select2-results ul.select2-result-sub { 370 | margin: 0; 371 | padding-left: 0; 372 | } 373 | 374 | .select2-results li { 375 | list-style: none; 376 | display: list-item; 377 | background-image: none; 378 | } 379 | 380 | .select2-results li.select2-result-with-children > .select2-result-label { 381 | font-weight: bold; 382 | } 383 | 384 | .select2-results .select2-result-label { 385 | padding: 3px 7px 4px; 386 | margin: 0; 387 | cursor: pointer; 388 | 389 | min-height: 1em; 390 | 391 | -webkit-touch-callout: none; 392 | -webkit-user-select: none; 393 | -moz-user-select: none; 394 | -ms-user-select: none; 395 | user-select: none; 396 | } 397 | 398 | .select2-results-dept-1 .select2-result-label { padding-left: 20px } 399 | .select2-results-dept-2 .select2-result-label { padding-left: 40px } 400 | .select2-results-dept-3 .select2-result-label { padding-left: 60px } 401 | .select2-results-dept-4 .select2-result-label { padding-left: 80px } 402 | .select2-results-dept-5 .select2-result-label { padding-left: 100px } 403 | .select2-results-dept-6 .select2-result-label { padding-left: 110px } 404 | .select2-results-dept-7 .select2-result-label { padding-left: 120px } 405 | 406 | .select2-results .select2-highlighted { 407 | background: #3875d7; 408 | color: #fff; 409 | } 410 | 411 | .select2-results li em { 412 | background: #feffde; 413 | font-style: normal; 414 | } 415 | 416 | .select2-results .select2-highlighted em { 417 | background: transparent; 418 | } 419 | 420 | .select2-results .select2-highlighted ul { 421 | background: #fff; 422 | color: #000; 423 | } 424 | 425 | .select2-results .select2-no-results, 426 | .select2-results .select2-searching, 427 | .select2-results .select2-ajax-error, 428 | .select2-results .select2-selection-limit { 429 | background: #f4f4f4; 430 | display: list-item; 431 | padding-left: 5px; 432 | } 433 | 434 | /* 435 | disabled look for disabled choices in the results dropdown 436 | */ 437 | .select2-results .select2-disabled.select2-highlighted { 438 | color: #666; 439 | background: #f4f4f4; 440 | display: list-item; 441 | cursor: default; 442 | } 443 | .select2-results .select2-disabled { 444 | background: #f4f4f4; 445 | display: list-item; 446 | cursor: default; 447 | } 448 | 449 | .select2-results .select2-selected { 450 | display: none; 451 | } 452 | 453 | .select2-more-results.select2-active { 454 | background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%; 455 | } 456 | 457 | .select2-results .select2-ajax-error { 458 | background: rgba(255, 50, 50, .2); 459 | } 460 | 461 | .select2-more-results { 462 | background: #f4f4f4; 463 | display: list-item; 464 | } 465 | 466 | /* disabled styles */ 467 | 468 | .select2-container.select2-container-disabled .select2-choice { 469 | background-color: #f4f4f4; 470 | background-image: none; 471 | border: 1px solid #ddd; 472 | cursor: default; 473 | } 474 | 475 | .select2-container.select2-container-disabled .select2-choice .select2-arrow { 476 | background-color: #f4f4f4; 477 | background-image: none; 478 | border-left: 0; 479 | } 480 | 481 | .select2-container.select2-container-disabled .select2-choice abbr { 482 | display: none; 483 | } 484 | 485 | 486 | /* multiselect */ 487 | 488 | .select2-container-multi .select2-choices { 489 | height: auto !important; 490 | height: 1%; 491 | margin: 0; 492 | padding: 0 5px 0 0; 493 | position: relative; 494 | 495 | border: 1px solid #aaa; 496 | cursor: text; 497 | overflow: hidden; 498 | 499 | background-color: #fff; 500 | background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff)); 501 | background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%); 502 | background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%); 503 | background-image: linear-gradient(to bottom, #eee 1%, #fff 15%); 504 | } 505 | 506 | html[dir="rtl"] .select2-container-multi .select2-choices { 507 | padding: 0 0 0 5px; 508 | } 509 | 510 | .select2-locked { 511 | padding: 3px 5px 3px 5px !important; 512 | } 513 | 514 | .select2-container-multi .select2-choices { 515 | min-height: 26px; 516 | } 517 | 518 | .select2-container-multi.select2-container-active .select2-choices { 519 | border: 1px solid #5897fb; 520 | outline: none; 521 | 522 | -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); 523 | box-shadow: 0 0 5px rgba(0, 0, 0, .3); 524 | } 525 | .select2-container-multi .select2-choices li { 526 | float: left; 527 | list-style: none; 528 | } 529 | html[dir="rtl"] .select2-container-multi .select2-choices li 530 | { 531 | float: right; 532 | } 533 | .select2-container-multi .select2-choices .select2-search-field { 534 | margin: 0; 535 | padding: 0; 536 | white-space: nowrap; 537 | } 538 | 539 | .select2-container-multi .select2-choices .select2-search-field input { 540 | padding: 5px; 541 | margin: 1px 0; 542 | 543 | font-family: sans-serif; 544 | font-size: 100%; 545 | color: #666; 546 | outline: 0; 547 | border: 0; 548 | -webkit-box-shadow: none; 549 | box-shadow: none; 550 | background: transparent !important; 551 | } 552 | 553 | .select2-container-multi .select2-choices .select2-search-field input.select2-active { 554 | background: #fff url('select2-spinner.gif') no-repeat 100% !important; 555 | } 556 | 557 | .select2-default { 558 | color: #999 !important; 559 | } 560 | 561 | .select2-container-multi .select2-choices .select2-search-choice { 562 | padding: 3px 5px 3px 18px; 563 | margin: 3px 0 3px 5px; 564 | position: relative; 565 | 566 | line-height: 13px; 567 | color: #333; 568 | cursor: default; 569 | border: 1px solid #aaaaaa; 570 | 571 | border-radius: 3px; 572 | 573 | -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); 574 | box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); 575 | 576 | background-clip: padding-box; 577 | 578 | -webkit-touch-callout: none; 579 | -webkit-user-select: none; 580 | -moz-user-select: none; 581 | -ms-user-select: none; 582 | user-select: none; 583 | 584 | background-color: #e4e4e4; 585 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0); 586 | background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee)); 587 | background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); 588 | background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); 589 | background-image: linear-gradient(to top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); 590 | } 591 | html[dir="rtl"] .select2-container-multi .select2-choices .select2-search-choice 592 | { 593 | margin: 3px 5px 3px 0; 594 | padding: 3px 18px 3px 5px; 595 | } 596 | .select2-container-multi .select2-choices .select2-search-choice .select2-chosen { 597 | cursor: default; 598 | } 599 | .select2-container-multi .select2-choices .select2-search-choice-focus { 600 | background: #d4d4d4; 601 | } 602 | 603 | .select2-search-choice-close { 604 | display: block; 605 | width: 12px; 606 | height: 13px; 607 | position: absolute; 608 | right: 3px; 609 | top: 4px; 610 | 611 | font-size: 1px; 612 | outline: none; 613 | background: url('select2.png') right top no-repeat; 614 | } 615 | html[dir="rtl"] .select2-search-choice-close { 616 | right: auto; 617 | left: 3px; 618 | } 619 | 620 | .select2-container-multi .select2-search-choice-close { 621 | left: 3px; 622 | } 623 | 624 | html[dir="rtl"] .select2-container-multi .select2-search-choice-close { 625 | left: auto; 626 | right: 2px; 627 | } 628 | 629 | .select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { 630 | background-position: right -11px; 631 | } 632 | .select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { 633 | background-position: right -11px; 634 | } 635 | 636 | /* disabled styles */ 637 | .select2-container-multi.select2-container-disabled .select2-choices { 638 | background-color: #f4f4f4; 639 | background-image: none; 640 | border: 1px solid #ddd; 641 | cursor: default; 642 | } 643 | 644 | .select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { 645 | padding: 3px 5px 3px 5px; 646 | border: 1px solid #ddd; 647 | background-image: none; 648 | background-color: #f4f4f4; 649 | } 650 | 651 | .select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; 652 | background: none; 653 | } 654 | /* end multiselect */ 655 | 656 | 657 | .select2-result-selectable .select2-match, 658 | .select2-result-unselectable .select2-match { 659 | text-decoration: underline; 660 | } 661 | 662 | .select2-offscreen, .select2-offscreen:focus { 663 | clip: rect(0 0 0 0) !important; 664 | width: 1px !important; 665 | height: 1px !important; 666 | border: 0 !important; 667 | margin: 0 !important; 668 | padding: 0 !important; 669 | overflow: hidden !important; 670 | position: absolute !important; 671 | outline: 0 !important; 672 | left: 0px !important; 673 | top: 0px !important; 674 | } 675 | 676 | .select2-display-none { 677 | display: none; 678 | } 679 | 680 | .select2-measure-scrollbar { 681 | position: absolute; 682 | top: -10000px; 683 | left: -10000px; 684 | width: 100px; 685 | height: 100px; 686 | overflow: scroll; 687 | } 688 | 689 | /* Retina-ize icons */ 690 | 691 | @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 2dppx) { 692 | .select2-search input, 693 | .select2-search-choice-close, 694 | .select2-container .select2-choice abbr, 695 | .select2-container .select2-choice .select2-arrow b { 696 | background-image: url('select2x2.png') !important; 697 | background-repeat: no-repeat !important; 698 | background-size: 60px 40px !important; 699 | } 700 | 701 | .select2-search input { 702 | background-position: 100% -21px !important; 703 | } 704 | } 705 | -------------------------------------------------------------------------------- /lib/select2/select2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidworkman9/meteor-editable/6385edab2760701b9109d9f5162016b21117ec31/lib/select2/select2.png -------------------------------------------------------------------------------- /lib/select2/select2x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidworkman9/meteor-editable/6385edab2760701b9109d9f5162016b21117ec31/lib/select2/select2x2.png -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | summary: "Meteor-Editable - in-place edit package influenced by x-editable", 3 | version: "0.2.0", 4 | git: "https://github.com/davidworkman9/meteor-editable.git", 5 | name: "workman:meteor-editable" 6 | }); 7 | 8 | Package.on_use(function (api) { 9 | var fs = Npm.require('fs'); 10 | api.use([ 11 | 'check', 12 | 'ecmascript', 13 | 'reactive-dict', 14 | 'mongo', 15 | 'meteor-platform', 16 | 'templating', 17 | 'underscore' 18 | ], 'client'); 19 | 20 | if(api.versionsFrom) { 21 | api.versionsFrom('METEOR@1.3'); 22 | } 23 | 24 | // libs 25 | api.addFiles([ 26 | 'lib/select2/select2.js', 27 | 'lib/select2/select2.css', 28 | 29 | 'lib/bootstrap-datetimepicker/bootstrap-datetimepicker.css', 30 | 'lib/bootstrap-datetimepicker/bootstrap-datetimepicker.js', 31 | 32 | 'lib/combodate/combodate.js' 33 | ], 'client'); 34 | 35 | api.addFiles([ 36 | 'lib/select2/select2.png', 37 | 'lib/select2/select2x2.png' 38 | ], 'client', { isAsset: true }); 39 | 40 | // main files 41 | api.addFiles([ 42 | 'bootstrap-editable.css', 43 | 'editable.html', 44 | 'editable.js' 45 | ], 'client'); 46 | 47 | // input types 48 | api.addFiles([ 49 | 'inputs/text/text.html', 50 | 'inputs/text/text.js', 51 | 52 | 'inputs/select/select.html', 53 | 'inputs/select/select.js', 54 | 55 | 'inputs/select2/select2.html', 56 | 'inputs/select2/select2.js', 57 | 58 | 'inputs/date/date.html', 59 | 'inputs/date/date.js', 60 | 61 | 'inputs/datetime/datetime.html', 62 | 'inputs/datetime/datetime.js', 63 | 64 | 'inputs/checklist/checklist.html', 65 | 'inputs/checklist/checklist.js', 66 | 67 | 'inputs/radiolist/radiolist.html', 68 | 'inputs/radiolist/radiolist.js', 69 | 70 | 'inputs/combodate/combodate.html', 71 | 'inputs/combodate/combodate.js', 72 | 73 | 'inputs/textarea/textarea.html', 74 | 'inputs/textarea/textarea.js' 75 | ], 'client'); 76 | 77 | api.export('mEditable'); 78 | }); 79 | -------------------------------------------------------------------------------- /smart.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meteor-editable", 3 | "description": "in-place edit package influenced by x-editable", 4 | "homepage": "http://meteor-editable.meteor.com/", 5 | "author": "Dave Workman ", 6 | "version": "0.1.3", 7 | "git": "https://github.com/davidworkman9/meteor-editable.git", 8 | "packages": { } 9 | } 10 | -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | [ 4 | "application-configuration", 5 | "1.0.1" 6 | ], 7 | [ 8 | "autoupdate", 9 | "1.0.6" 10 | ], 11 | [ 12 | "binary-heap", 13 | "1.0.0" 14 | ], 15 | [ 16 | "blaze", 17 | "2.0.0" 18 | ], 19 | [ 20 | "blaze-tools", 21 | "1.0.0" 22 | ], 23 | [ 24 | "callback-hook", 25 | "1.0.0" 26 | ], 27 | [ 28 | "check", 29 | "1.0.0" 30 | ], 31 | [ 32 | "ddp", 33 | "1.0.8" 34 | ], 35 | [ 36 | "deps", 37 | "1.0.3" 38 | ], 39 | [ 40 | "ejson", 41 | "1.0.1" 42 | ], 43 | [ 44 | "follower-livedata", 45 | "1.0.1" 46 | ], 47 | [ 48 | "geojson-utils", 49 | "1.0.0" 50 | ], 51 | [ 52 | "html-tools", 53 | "1.0.0" 54 | ], 55 | [ 56 | "htmljs", 57 | "1.0.0" 58 | ], 59 | [ 60 | "id-map", 61 | "1.0.0" 62 | ], 63 | [ 64 | "jquery", 65 | "1.0.0" 66 | ], 67 | [ 68 | "json", 69 | "1.0.0" 70 | ], 71 | [ 72 | "livedata", 73 | "1.0.9" 74 | ], 75 | [ 76 | "logging", 77 | "1.0.2" 78 | ], 79 | [ 80 | "meteor", 81 | "1.0.3" 82 | ], 83 | [ 84 | "meteor-platform", 85 | "1.0.2" 86 | ], 87 | [ 88 | "minifiers", 89 | "1.0.2" 90 | ], 91 | [ 92 | "minimongo", 93 | "1.0.2" 94 | ], 95 | [ 96 | "mongo", 97 | "1.0.4" 98 | ], 99 | [ 100 | "observe-sequence", 101 | "1.0.2" 102 | ], 103 | [ 104 | "ordered-dict", 105 | "1.0.0" 106 | ], 107 | [ 108 | "random", 109 | "1.0.0" 110 | ], 111 | [ 112 | "reactive-dict", 113 | "1.0.2" 114 | ], 115 | [ 116 | "reactive-var", 117 | "1.0.1" 118 | ], 119 | [ 120 | "reload", 121 | "1.0.1" 122 | ], 123 | [ 124 | "retry", 125 | "1.0.0" 126 | ], 127 | [ 128 | "routepolicy", 129 | "1.0.0" 130 | ], 131 | [ 132 | "session", 133 | "1.0.1" 134 | ], 135 | [ 136 | "spacebars", 137 | "1.0.1" 138 | ], 139 | [ 140 | "spacebars-compiler", 141 | "1.0.2" 142 | ], 143 | [ 144 | "templating", 145 | "1.0.5" 146 | ], 147 | [ 148 | "tracker", 149 | "1.0.2" 150 | ], 151 | [ 152 | "ui", 153 | "1.0.2" 154 | ], 155 | [ 156 | "underscore", 157 | "1.0.0" 158 | ], 159 | [ 160 | "webapp", 161 | "1.0.3" 162 | ] 163 | ], 164 | "pluginDependencies": [], 165 | "toolVersion": "meteor-tool@1.0.28", 166 | "format": "1.0" 167 | } --------------------------------------------------------------------------------