tags if they are specified in the 'unformatted array' 310 | for (var i=0; i0) { 412 | this.indent_level--; 413 | } 414 | } 415 | } 416 | return this; 417 | } 418 | 419 | /*_____________________--------------------_____________________*/ 420 | 421 | multi_parser = new Parser(); //wrapping functions Parser 422 | multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values 423 | 424 | while (true) { 425 | var t = multi_parser.get_token(); 426 | multi_parser.token_text = t[0]; 427 | multi_parser.token_type = t[1]; 428 | 429 | if (multi_parser.token_type === 'TK_EOF') { 430 | break; 431 | } 432 | 433 | switch (multi_parser.token_type) { 434 | case 'TK_TAG_START': 435 | multi_parser.print_newline(false, multi_parser.output); 436 | multi_parser.print_token(multi_parser.token_text); 437 | multi_parser.indent(); 438 | multi_parser.current_mode = 'CONTENT'; 439 | break; 440 | case 'TK_TAG_STYLE': 441 | case 'TK_TAG_SCRIPT': 442 | multi_parser.print_newline(false, multi_parser.output); 443 | multi_parser.print_token(multi_parser.token_text); 444 | multi_parser.current_mode = 'CONTENT'; 445 | break; 446 | case 'TK_TAG_END': 447 | //Print new line only if the tag has no content and has child 448 | if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') { 449 | var tag_name = multi_parser.token_text.match(/\w+/)[0]; 450 | var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length - 1].match(/<\s*(\w+)/); 451 | if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name) 452 | multi_parser.print_newline(true, multi_parser.output); 453 | } 454 | multi_parser.print_token(multi_parser.token_text); 455 | multi_parser.current_mode = 'CONTENT'; 456 | break; 457 | case 'TK_TAG_SINGLE': 458 | multi_parser.print_newline(false, multi_parser.output); 459 | multi_parser.print_token(multi_parser.token_text); 460 | multi_parser.current_mode = 'CONTENT'; 461 | break; 462 | case 'TK_CONTENT': 463 | if (multi_parser.token_text !== '') { 464 | multi_parser.print_token(multi_parser.token_text); 465 | } 466 | multi_parser.current_mode = 'TAG'; 467 | break; 468 | case 'TK_STYLE': 469 | case 'TK_SCRIPT': 470 | if (multi_parser.token_text !== '') { 471 | multi_parser.output.push('\n'); 472 | var text = multi_parser.token_text; 473 | if (multi_parser.token_type == 'TK_SCRIPT') { 474 | var _beautifier = typeof js_beautify == 'function' && js_beautify; 475 | } else if (multi_parser.token_type == 'TK_STYLE') { 476 | var _beautifier = typeof css_beautify == 'function' && css_beautify; 477 | } 478 | 479 | if (options.indent_scripts == "keep") { 480 | var script_indent_level = 0; 481 | } else if (options.indent_scripts == "separate") { 482 | var script_indent_level = -multi_parser.indent_level; 483 | } else { 484 | var script_indent_level = 1; 485 | } 486 | 487 | var indentation = multi_parser.get_full_indent(script_indent_level); 488 | if (_beautifier) { 489 | // call the Beautifier if avaliable 490 | text = _beautifier(text.replace(/^\s*/, indentation), options); 491 | } else { 492 | // simply indent the string otherwise 493 | var white = text.match(/^\s*/)[0]; 494 | var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1; 495 | var reindent = multi_parser.get_full_indent(script_indent_level - _level); 496 | text = text.replace(/^\s*/, indentation) 497 | .replace(/\r\n|\r|\n/g, '\n' + reindent) 498 | .replace(/\s*$/, ''); 499 | } 500 | if (text) { 501 | multi_parser.print_token(text); 502 | multi_parser.print_newline(true, multi_parser.output); 503 | } 504 | } 505 | multi_parser.current_mode = 'TAG'; 506 | break; 507 | } 508 | multi_parser.last_token = multi_parser.token_type; 509 | multi_parser.last_text = multi_parser.token_text; 510 | } 511 | return multi_parser.output.join(''); 512 | } -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | var esbuild = require('esbuild'); 2 | 3 | esbuild.build({ 4 | entryPoints: ['./js/angular-material-datetimepicker.js'], 5 | minify: true, 6 | outdir: 'dist', 7 | sourcemap: true, 8 | outExtension: { '.js': '.min.js' }, 9 | }).catch(function(err) {process.exit(1);}); 10 | 11 | esbuild.build({ 12 | entryPoints: ['./css/material-datetimepicker.css'], 13 | minify: true, 14 | outdir: 'dist', 15 | outExtension: { '.css': '.min.css' }, 16 | }).catch(function(err) {process.exit(1);}); 17 | -------------------------------------------------------------------------------- /css/material-datetimepicker.css: -------------------------------------------------------------------------------- 1 | md-dialog.dtp { 2 | font-size: 14px; 3 | line-height: 1.42857143; 4 | color: #333; 5 | background-color: #fff; 6 | max-height: none; 7 | min-width: 300px; 8 | width: 300px; 9 | } 10 | 11 | .noselect { 12 | -webkit-user-select: none; 13 | -moz-user-select: none; 14 | -ms-user-select: none; 15 | user-select: none; 16 | } 17 | 18 | .dtp *:focus { 19 | outline: none !important; 20 | } 21 | 22 | .dtp table { 23 | border-spacing: 0; 24 | border-collapse: collapse; 25 | width: 100%; 26 | } 27 | 28 | .dtp .table > tbody > tr > td, 29 | .dtp .table > tbody > tr > th, 30 | .dtp .table > tfoot > tr > td, 31 | .dtp .table > tfoot > tr > th, 32 | .dtp .table > thead > tr > td, 33 | .dtp .table > thead > tr > th { 34 | padding: 8px; 35 | line-height: 1.42857143; 36 | vertical-align: top; 37 | border-top: 1px solid #ddd; 38 | } 39 | 40 | .dtp, .dtp * { 41 | box-sizing: border-box !important; 42 | } 43 | 44 | .dtp > .dtp-content { 45 | max-width: 300px; 46 | max-height: 500px; 47 | } 48 | 49 | .dtp > .dtp-content > .dtp-date-view > header.dtp-header { 50 | background: #689F38; 51 | color: #fff; 52 | text-align: center; 53 | } 54 | 55 | .dtp div.dtp-date, .dtp div.dtp-time { 56 | background: #8BC34A; 57 | text-align: center; 58 | color: #fff; 59 | padding: 10px; 60 | } 61 | 62 | .dtp div.dtp-date > div { 63 | padding: 0; 64 | margin: 0; 65 | } 66 | 67 | .dtp div.dtp-actual-month { 68 | font-size: 1.5em; 69 | cursor: pointer; 70 | } 71 | 72 | md-menu-content.dtp-month-list { 73 | background-color: #ffffff; 74 | } 75 | 76 | .dtp div.dtp-actual-num { 77 | font-size: 2em; 78 | line-height: 0.9; 79 | } 80 | 81 | .dtp div.dtp-actual-maxtime { 82 | font-size: 2em; 83 | line-height: 0.9; 84 | color: #DCEDC8; 85 | } 86 | 87 | .dtp div.dtp-actual-maxtime span.selected { 88 | color: #fff; 89 | } 90 | 91 | .dtp div.dtp-actual-year { 92 | font-size: 1.6em; 93 | color: #DCEDC8; 94 | cursor: pointer; 95 | } 96 | 97 | md-menu-content.dtp-year-list { 98 | background-color: #ffffff; 99 | } 100 | 101 | .dtp div.dtp-month-btn { 102 | font-size: 1.4em; 103 | line-height: 30px; 104 | cursor: pointer; 105 | } 106 | 107 | .dtp div.dtp-month-btn-prev { 108 | text-align: right; 109 | } 110 | 111 | .dtp div.dtp-month-btn-next { 112 | text-align: left; 113 | } 114 | 115 | .dtp div.dtp-year-btn { 116 | font-size: 1.4em; 117 | line-height: 30px; 118 | cursor: pointer; 119 | color: #DCEDC8; 120 | } 121 | 122 | .dtp div.dtp-year-btn-prev { 123 | text-align: right; 124 | } 125 | 126 | 127 | .dtp div.dtp-year-btn-next { 128 | text-align: left; 129 | } 130 | 131 | .dtp div.dtp-picker { 132 | padding: 10px 10px 0 10px; 133 | text-align: center; 134 | 135 | /* Prevent dialog resizing when switcing between date/time */ 136 | overflow: hidden; 137 | } 138 | 139 | .dtp div.dtp-picker-month, .dtp div.dtp-actual-time { 140 | font-size: 1em; 141 | font-weight: 500; 142 | text-align: center; 143 | } 144 | 145 | .dtp div.dtp-actual-time.p60 span.selected { 146 | color: #689F38; 147 | } 148 | 149 | .dtp .dtp-close { 150 | position: absolute; 151 | top: 0; 152 | right: 5px; 153 | font-size: 16px; 154 | } 155 | 156 | .dtp .dtp-close > a { 157 | color: #fff; 158 | text-decoration: none; 159 | } 160 | 161 | .dtp .dtp-close > a > i { 162 | font-size: 1em; 163 | } 164 | 165 | .dtp table.dtp-picker-days { 166 | margin: 0; 167 | min-height: 260px; 168 | } 169 | 170 | .dtp md-virtual-repeat-container.months { 171 | height: 260px; 172 | } 173 | 174 | .dtp table.dtp-picker-days, .dtp table.dtp-picker-days tr, .dtp table.dtp-picker-days tr > td { 175 | border: none; 176 | } 177 | 178 | .dtp table.dtp-picker-days tr > td { 179 | font-size: 12px; 180 | text-align: center; 181 | padding: 0; 182 | } 183 | 184 | .dtp table.dtp-picker-days tr > td > span.dtp-select-day { 185 | color: #BDBDBD !important; 186 | } 187 | 188 | .dtp table.dtp-picker-days tr > td, .dtp table.dtp-picker-days tr > td > .dtp-select-day { 189 | width: 36px; 190 | height: 36px; 191 | } 192 | 193 | .dtp table.dtp-picker-days tr > td > .dtp-select-day { 194 | display: inline-block; 195 | } 196 | 197 | .dtp table.dtp-picker-days tr > td > .dtp-select-day, .dtp .dtp-picker-time > a { 198 | color: #212121; 199 | text-decoration: none; 200 | padding: 10px; 201 | border-radius: 50% !important; 202 | } 203 | 204 | .dtp table.dtp-picker-days tr > td > a.selected { 205 | background: #8BC34A; 206 | color: #fff; 207 | } 208 | 209 | .dtp table.dtp-picker-days tr > td > a.selected.hilite { 210 | padding: 6px; 211 | font-size: 16px; 212 | font-weight: 500; 213 | background: #8BC34A; 214 | color: #fff; 215 | } 216 | 217 | .dtp table.dtp-picker-days tr > td > a.hilite:not(.selected) { 218 | padding: 6px; 219 | font-size: 16px; 220 | font-weight: 500; 221 | color: #8BC34A; 222 | } 223 | 224 | .dtp table.dtp-picker-days tr > td > a:hover:not(.selected) { 225 | background: #dddddd; 226 | } 227 | 228 | .dtp table.dtp-picker-days tr > th { 229 | color: #757575; 230 | text-align: center; 231 | font-weight: 700; 232 | padding: 2px 3px; 233 | width: 38px; 234 | height: 28px; 235 | } 236 | 237 | .dtp .p10 > a { 238 | color: #689F38; 239 | text-decoration: none; 240 | } 241 | 242 | .dtp .p10 { 243 | width: 10%; 244 | display: inline-block; 245 | } 246 | 247 | .dtp .p20 { 248 | width: 20%; 249 | display: inline-block; 250 | } 251 | 252 | .dtp .p60 { 253 | width: 60%; 254 | display: inline-block; 255 | } 256 | 257 | .dtp .p80 { 258 | width: 80%; 259 | display: inline-block; 260 | } 261 | 262 | .dtp div.dtp-picker-datetime { 263 | padding-bottom: 25px; 264 | } 265 | 266 | .dtp span.dtp-actual-meridien { 267 | font-size: 0.6em; 268 | } 269 | 270 | .dtp div.dtp-actual-meridien { 271 | height: 20px; 272 | } 273 | 274 | .dtp a.dtp-meridien-am, .dtp a.dtp-meridien-pm { 275 | position: relative; 276 | color: #212121; 277 | font-weight: 500; 278 | padding: 7px 5px; 279 | border-radius: 50% !important; 280 | text-decoration: none; 281 | background: #eee; 282 | font-size: 10px; 283 | } 284 | 285 | .dtp .dtp-actual-meridien a.selected { 286 | background: #689F38; 287 | color: #fff; 288 | } 289 | 290 | .dtp .dtp-picker-time > a { 291 | display: block; 292 | line-height: 23px; 293 | padding: 3px 3px 3px 3px; 294 | } 295 | 296 | .dtp .dtp-picker-time { 297 | position: absolute; 298 | width: 30px; 299 | height: 30px; 300 | font-size: 1.1em; 301 | border-radius: 50%; 302 | cursor: pointer; 303 | text-align: center !important; 304 | } 305 | 306 | .dtp .dtp-picker-time > a.dtp-select-hour.selected { 307 | background: #689F38; 308 | color: #fff; 309 | } 310 | 311 | .dtp .dtp-picker-time > a.dtp-select-hour.disabled, .dtp .dtp-picker-time > a.dtp-select-minute.disabled { 312 | color: #757575; 313 | } 314 | 315 | .dtp .dtp-picker-time > a.dtp-select-minute.selected { 316 | background: #8BC34A; 317 | color: #fff; 318 | } 319 | 320 | .dtp div.dtp-picker-clock { 321 | margin: 10px 20px 0 20px; 322 | padding: 10px; 323 | border-radius: 50% !important; 324 | background: #eee; 325 | direction: ltr; 326 | cursor: default; 327 | } 328 | 329 | .dtp-clock-center { 330 | width: 15px; 331 | height: 15px; 332 | background: #757575; 333 | border-radius: 50%; 334 | position: absolute; 335 | z-index: 50; 336 | } 337 | 338 | .dtp .dtp-hand, .dtp .dtp-hour-hand { 339 | position: absolute; 340 | width: 4px; 341 | margin-left: -2px; 342 | background: #BDBDBD; 343 | -moz-transform: rotate(0deg); 344 | -ms-transform: rotate(0deg); 345 | -webkit-transform: rotate(0deg); 346 | transform: rotate(0deg); 347 | -moz-transform-origin: bottom; 348 | -ms-transform-origin: bottom; 349 | -webkit-transform-origin: bottom; 350 | transform-origin: bottom; 351 | z-index: 1; 352 | } 353 | 354 | .dtp .dtp-minute-hand { 355 | width: 2px; 356 | margin-left: -1px; 357 | } 358 | 359 | .dtp .dtp-second-hand { 360 | width: 1px; 361 | margin-left: -1px; 362 | } 363 | 364 | .dtp .dtp-hand.on { 365 | background: #8BC34A; 366 | } 367 | 368 | .dtp .dtp-buttons { 369 | padding-bottom: 10px; 370 | text-align: right; 371 | } 372 | 373 | .dtp.hidden, .dtp .hidden { 374 | display: none; 375 | } 376 | 377 | .dtp .invisible { 378 | visibility: hidden; 379 | } 380 | 381 | .dtp .left { 382 | float: left; 383 | } 384 | 385 | .dtp .right { 386 | float: right; 387 | } 388 | 389 | .dtp .clearfix { 390 | clear: both; 391 | } 392 | 393 | .dtp .center { 394 | text-align: center; 395 | } 396 | 397 | [dir=rtl] .dtp div.dtp-year-btn-next, [dir=rtl] .dtp div.dtp-month-btn-next, 398 | [dir=rtl] .dtp div.dtp-year-btn-prev, [dir=rtl] .dtp div.dtp-month-btn-prev { 399 | -ms-transform: rotate(180deg); 400 | -webkit-transform: rotate(180deg); 401 | transform: rotate(180deg); 402 | } 403 | 404 | .dtp-btn-today, .dtp-btn-ok, .dtp-btn-cancel { 405 | min-width: 70px; 406 | } 407 | 408 | .dtp-clear { 409 | position: absolute; 410 | top: 0; 411 | right: -10px; 412 | } 413 | 414 | /* Remove IE clear button */ 415 | .dtp-no-msclear::-ms-clear { 416 | display: none; 417 | width : 0; 418 | height: 0; 419 | } 420 | 421 | .dtp-btn-calendar { 422 | position: absolute; 423 | top: -3px; 424 | left: -10px; 425 | } 426 | 427 | .dtp-input { 428 | margin-left: 30px; 429 | max-width: calc(100% - 30px); 430 | } 431 | -------------------------------------------------------------------------------- /dist/angular-material-datetimepicker.min.js: -------------------------------------------------------------------------------- 1 | (function(){"use strict";function P(o){var N="ngMaterialDatePicker",G="data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gICAgPHBhdGggZD0iTTExLjk5IDJDNi40NyAyIDIgNi40OCAyIDEyczQuNDcgMTAgOS45OSAxMEMxNy41MiAyMiAyMiAxNy41MiAyMiAxMlMxNy41MiAyIDExLjk5IDJ6TTEyIDIwYy00LjQyIDAtOC0zLjU4LTgtOHMzLjU4LTggOC04IDggMy41OCA4IDgtMy41OCA4LTggOHoiLz4gICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPiAgICA8cGF0aCBkPSJNMTIuNSA3SDExdjZsNS4yNSAzLjE1Ljc1LTEuMjMtNC41LTIuNjd6Ii8+PC9zdmc+",Q="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTkgM2gtMVYxaC0ydjJIOFYxSDZ2Mkg1Yy0xLjExIDAtMS45OS45LTEuOTkgMkwzIDE5YzAgMS4xLjg5IDIgMiAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJ6bTAgMTZINVY4aDE0djExek03IDEwaDV2NUg3eiIvPjwvc3ZnPg==",M={DATE:0,HOUR:1,MINUTE:2},V=function(i,n){return i=angular.element(i),"getComputedStyle"in window?window.getComputedStyle(i[0])[n]:i.css(n)},H=` `;angular.module(N,["ngMaterial"]).factory("mdcDefaultParams",function(){var i={date:!0,time:!0,minutes:!0,seconds:!1,format:"YYYY-MM-DD",minDate:null,maxDate:null,currentDate:null,lang:window.navigator.userLanguage||window.navigator.language||"en",weekStart:0,shortTime:!1,cancelText:"Cancel",okText:"OK",amText:"AM",pmText:"PM",todayBtn:!0,todayText:"Today",disableDates:[],weekDays:!1,disableParentScroll:!1,autoOk:!1,editInput:!1,clickOutsideToClose:!1,minuteSteps:5,showIcon:!1,showClear:!0,template:H,templateUrl:"",targetEvent:null,openFrom:null,closeTo:null,dayOfWeekLen:1,hasBackdrop:!0};return function(n){if(n)for(var a in n)i.hasOwnProperty(a)&&n.hasOwnProperty(a)&&(i[a]=n[a]);return i}}).directive("mdcDatetimePicker",["$mdDialog","$timeout","$compile","$parse",function(i,n,a,r){return{restrict:"A",require:"ngModel",scope:{currentDate:"=ngModel",ngModelOptions:"=",ngChange:"&",time:"=",date:"=",minutes:"=",seconds:"=",minDate:"=",maxDate:"=",disableDates:"=",weekDays:"=",shortTime:"=",weekStart:"=",format:"@",cancelText:"@",okText:"@",lang:"@",amText:"@",pmText:"@",showTodaysDate:"@",todayBtn:"=",todayText:"@",disableParentScroll:"=",autoOk:"=",editInput:"=",clickOutsideToClose:"=",minuteSteps:"=",showIcon:"=",showClear:"=",templateUrl:"@",dayOfWeekLen:"=",hasBackdrop:"="},link:function(t,s,f,e){var d=!1;t.format||(t.date&&t.time&&t.seconds?t.format="YYYY-MM-DD HH:mm:ss":t.date&&t.time?t.format="YYYY-MM-DD HH:mm":t.date?t.format="YYYY-MM-DD":t.format="HH:mm");var S=null;t.showTodaysDate!==void 0&&t.showTodaysDate!=="false"&&(S=o()),angular.isString(t.currentDate)&&t.currentDate!==""&&(t.currentDate=o(t.currentDate,t.format));var c;if(e){var u={"*":"$inherit",debounce:500};angular.version.major===1&&angular.version.minor>5?(e.$options=e.$options.createChild(u),e.$options.getOption("timezone")&&(c=e.$options.getOption("timezone"))):(t.ngModelOptions&&t.ngModelOptions.timezone&&(u.timezone=t.ngModelOptions.timezone),e.$options=u,e.$options.timezone&&(c=e.$options.timezone)),(c==="utc"||c==="UTC")&&(c=0),e.$formatters.push(function(D){if(!(typeof D>"u")){var p=o(D);return p.isValid()?p.format(t.format):""}}),e.$parsers.push(function(D){if(!(typeof D>"u")){var p=o(D,t.format);return c!==void 0&&p.utcOffset(c,p._tzm===void 0),t.minDate&&e.$setValidity("min",!p.isBefore(t.minDate)),t.maxDate&&e.$setValidity("max",!p.isAfter(t.maxDate)),e.$setValidity("format",o(D,t.format,!0).isValid()),p.isValid()?p._isUTC?p:p.toDate():""}})}function v(D){if(D.preventDefault(),s.blur(),s.parent().removeClass("md-input-focused"),!d){d=!0;var p={};for(var T in f)t.hasOwnProperty(T)&&!angular.isUndefined(t[T])&&(p[T]=t[T]);p.currentDate=t.currentDate,p.showTodaysDate=S;var l={controller:C,controllerAs:"picker",locals:{options:p},openFrom:s,closeTo:s,parent:angular.element(document.body),bindToController:!0,clickOutsideToClose:p.clickOutsideToClose||!1,disableParentScroll:p.disableParentScroll||!1,hasBackdrop:p.hasBackdrop===void 0?!0:p.hasBackdrop,skipHide:!0,multiple:!0};p.templateUrl?l.templateUrl=p.templateUrl:l.template=H,i.show(l).then(function(m){c!==void 0&&m.utcOffset(c,!0),t.currentDate=m&&!m._isUTC?m.toDate():m,e.$setValidity("format",!0),e.$setViewValue(t.currentDate),e.$setDirty(),d=!1,o(t.currentDate).isSame(p.currentDate)||n(t.ngChange,0),s.parent().removeClass("md-input-focused")},function(){d=!1,s.parent().removeClass("md-input-focused")})}}if(t.editInput||(t.showIcon?s.on("click",v):s.on("focus",v)),t.showIcon){s.addClass("dtp-no-msclear dtp-input");var b=' ',y="";(t.showClear===void 0||t.showClear)&&(y=" '),s.after(a(b+y)(t)),t.openCalendarDiag=function(D){v(D)},t.clear=function(){e.$setViewValue(null),t.currentDate=null,e.$render(),n(function(){t.ngChange(),s[0].focus()},0,!1)}}}}}]).factory("mdcDateTimeDialog",["$mdDialog","$q",function(i,n){var a={show:function(r){var t=n.defer();r.showTodaysDate!==void 0&&r.showTodaysDate!=="false"&&(r.showTodaysDate=o());var s={controller:C,controllerAs:"picker",locals:{options:r},parent:angular.element(document.body),bindToController:!0,clickOutsideToClose:r.clickOutsideToClose||!1,disableParentScroll:r.disableParentScroll||!1,skipHide:!0,multiple:!0,hasBackdrop:r.hasBackdrop===void 0?!0:r.hasBackdrop,targetEvent:r.targetEvent,openFrom:r.openFrom,closeTo:r.closeTo};return r.templateUrl?s.templateUrl=r.templateUrl:s.template=H,i.show(s).then(function(f){t.resolve(f&&!f._isUTC?f.toDate():f)},function(){t.reject()}),t.promise}};return a}]);var C=function(i,n){this.currentView=M.DATE,this._dialog=i,this._attachedEvents=[],this.VIEWS=M,this.params=angular.copy(n()),this.meridien="AM"};return C.$inject=["$mdDialog","mdcDefaultParams"],C.prototype={$onInit:function(){this.params=angular.extend(this.params,this.options),this.timeMode=this.params.time&&!this.params.date,this.dateMode=this.params.date,this.initDates(),this.start()},currentNearestMinute:function(){var i=this.params.minuteSteps;(i<1||i>59)&&(i=1);var n=this.currentDate||o(),a=i*Math.round(n.minute()/i);a>=60&&(a=60-i);var r;return this.params.seconds?(r=n.second(),r>=60&&(r=60-1)):r=0,o(n).minutes(a).seconds(r).millisecond(0)},initDates:function(){var i=this,n=function(a,r){var t=null;if(angular.isDefined(a)&&a!==null&&a!=="")if(angular.isString(a))typeof i.params.format<"u"&&i.params.format!==null?t=o(a,i.params.format).locale(i.params.lang):t=o(a).locale(i.params.lang);else if(typeof a=="number")t=o(a).locale(i.params.lang);else if(angular.isDate(a)){var s=a.getTime();t=o(s,"x").locale(i.params.lang)}else o.isMoment(a)&&(a.isValid()?t=a:t=r);else t=r;return t};this.currentDate=n(this.params.currentDate,o()),this.currentDate=this.currentNearestMinute(),this.minDate=n(this.params.minDate),this.maxDate=n(this.params.maxDate),this.disableDates=this.params.disableDates.map(function(a){return o(a).format("MMMM Do YYYY")}),this.selectDate(this.currentDate),this.weekDays=this.params.weekDays},initDate:function(){this.currentView=M.DATE},initHours:function(){this.currentView=M.HOUR},initMinutes:function(){this.currentView=M.MINUTE},initSeconds:function(){this.currentView=M.SECOND},isAfterMinDate:function(i,n,a){var r=!0;if(typeof this.minDate<"u"&&this.minDate!==null){var t=o(this.minDate),s=o(i);!n&&!a&&(t.hour(0),t.minute(0),s.hour(0),s.minute(0)),t.second(0),s.second(0),t.millisecond(0),s.millisecond(0),a||(s.minute(0),t.minute(0)),r=parseInt(s.format("X"))>=parseInt(t.format("X"))}return r},isBeforeMaxDate:function(i,n,a){var r=!0;if(typeof this.maxDate<"u"&&this.maxDate!==null){var t=o(this.maxDate),s=o(i);!n&&!a&&(t.hour(0),t.minute(0),s.hour(0),s.minute(0)),t.second(0),s.second(0),t.millisecond(0),s.millisecond(0),a||(s.minute(0),t.minute(0)),r=parseInt(s.format("X"))<=parseInt(t.format("X"))}return r},isInDisableDates:function(i){var n=i.format("MMMM Do YYYY");return!(this.disableDates.indexOf(n)>-1)},isWeekDay:function(i){return this.weekDays?i.isoWeekday()<=5:!0},selectDate:function(i){i&&(this.currentDate=o(i),this.isAfterMinDate(this.currentDate,!0,!0)||(this.currentDate=o(this.minDate)),this.isBeforeMaxDate(this.currentDate,!0,!0)||(this.currentDate=o(this.maxDate)),this.currentDate.locale(this.params.lang),this.calendarStart=o(this.currentDate),this.meridien=this.currentDate.hour()>=12?"PM":"AM")},isPM:function(){return this.meridien==="PM"},incrementMonth:function(i){(i===1&&this.isNextMonthVisible()||i===-1&&this.isPreviousMonthVisible())&&this.selectDate(this.currentDate.add(i,"month"))},incrementYear:function(i){(i===1&&this.isNextYearVisible()||i===-1&&this.isPreviousYearVisible())&&this.selectDate(this.currentDate.add(i,"year"))},openMenu:function(i,n){i.open(n)},monthsAvailable:function(){for(var i=[],n=o(this.currentDate),a=0;a<12;a++){var r=n.month(a);this.isAfterMinDate(r.endOf("month"))&&this.isBeforeMaxDate(r.startOf("month"))&&i.push(r.format("MMMM"))}return i},selectMonth:function(i){this.selectDate(this.currentDate.month(i))},yearsAvailable:function(){var i,n,a,r,t=[],s=this.currentDate.year();typeof this.minDate<"u"&&this.minDate!==null&&(i=o(this.minDate).year()),typeof this.maxDate<"u"&&this.maxDate!==null&&(n=o(this.maxDate).year()),n&&i?(a=n-i,r=i):i?(a=115,r=i):n?(a=30,r=n-a):(a=60,r=s-a/2);for(var f=0;f<=a;f++)t.push(r+f);return t},selectYear:function(i){this.selectDate(this.currentDate.year(i))},isPreviousMonthVisible:function(){return this.calendarStart&&this.isAfterMinDate(o(this.calendarStart).startOf("month"),!1,!1)},isNextMonthVisible:function(){return this.calendarStart&&this.isBeforeMaxDate(o(this.calendarStart).endOf("month"),!1,!1)},isPreviousYearVisible:function(){return this.calendarStart&&this.isAfterMinDate(o(this.calendarStart).startOf("year"),!1,!1)},isNextYearVisible:function(){return this.calendarStart&&this.isBeforeMaxDate(o(this.calendarStart).endOf("year"),!1,!1)},isHourAvailable:function(i){var n=o(this.currentDate);return this.params.shortTime?n.hour(this.convertHours(i)).minute(0).second(0):n.hour(i).minute(0).second(0),this.isAfterMinDate(n,!0,!1)&&this.isBeforeMaxDate(n,!0,!1)},isMinuteAvailable:function(i){var n=o(this.currentDate);n.minute(i).second(0);var a=this.params.minuteSteps;if(a>1&&5%a!==0){var r=n.minute(),t=a*Math.round(r/a);if(t>=60&&(t=60-a),t!==r)return!1}return this.isAfterMinDate(n,!0,!0)&&this.isBeforeMaxDate(n,!0,!0)},isSecondAvailable:function(i){return!0},start:function(){this.currentView=M.DATE,this.params.date?this.initDate():this.params.time&&this.initHours()},today:function(){var i=this.params.minuteSteps,n=o(),a=i*Math.round(n.minute()/i);a>=60&&(a=60-i);var r;this.params.seconds?(r=n.second(),r>=60&&(r=60-1)):r=0,this.selectDate(o(n).minutes(a).seconds(r).millisecond(0))},ok:function(){switch(this.currentView){case M.DATE:this.params.time===!0?this.initHours():this.hide(!0);break;case M.HOUR:this.params.minutes===!0?this.initMinutes():this.hide(!0);break;case M.MINUTE:this.params.seconds===!0?this.initSeconds():this.hide(!0);break;case M.SECOND:this.hide(!0);break}},cancel:function(){if(this.params.time)switch(this.currentView){case M.DATE:this.hide();break;case M.HOUR:this.params.date?this.initDate():this.hide();break;case M.MINUTE:this.initHours();break;case M.SECOND:this.initMinutes();break}else this.hide()},selectMonthBefore:function(){this.calendarStart.subtract(1,"months")},selectMonthAfter:function(){this.calendarStart.add(1,"months")},selectYearBefore:function(){this.calendarStart.subtract(1,"years")},selectYearAfter:function(){this.calendarStart.add(1,"years")},selectAM:function(){(this.isHourAvailable(0)||this.isHourAvailable(12))&&(this.currentDate.hour()>=12&&this.selectDate(this.currentDate.subtract(12,"hours")),this.isHourAvailable(this.currentDate.hour())||this.selectDate(this.currentDate.hour(this.minDate.hour())),this.isMinuteAvailable(this.currentDate.minute())||this.selectDate(this.currentDate.minute(this.minDate.minute())))},selectPM:function(){(this.isHourAvailable(12)||this.isHourAvailable(24))&&(this.currentDate.hour()<12&&this.selectDate(this.currentDate.add(12,"hours")),this.isHourAvailable(this.currentDate.hour())||this.selectDate(this.currentDate.hour(this.maxDate.hour())),this.isMinuteAvailable(this.currentDate.minute())||this.selectDate(this.currentDate.minute(this.maxDate.minute())))},convertHours:function(i){var n=i;return i<12&&this.isPM()&&(n+=12),n},hide:function(i){i?this._dialog.hide(this.currentDate):this._dialog.cancel()}},angular.module(N).directive("mdcDatetimePickerCalendar",[function(){for(var i=1920,n=new Date().getFullYear()+30,a=(n-i+1)*12,r=[],t=0;t6&&(u=0),c.push(u.toString());if(e.week=c,!d.maxDate&&!d.minDate)e.months=r;else{var v=d.minDate?s(d.minDate):0,b=d.maxDate?s(d.maxDate)+1:a;e.months=r.slice(v,b)}e.topIndex=s(d.currentDate)-e.months[0]},angular.version.major===1&&angular.version.minor<5&&this.$onInit(),e.getItemAtIndex=function(c){var u=(c+1)%12||12,v=i+Math.floor(c/12),b=o(d.currentDate).year(v).month(u);return S(b)},f.$watch(function(){return d.currentDate?d.currentDate.format("YYYY-MM"):""},function(c,u){if(c!=u){var v=o(c,"YYYY-MM"),b=d.minDate?s(d.minDate):0,y=s(v,b);e.topIndex!=y&&(e.topIndex=y)}});var S=function(c){var u={};if(c!==null){u.name=c.format("MMMM YYYY");var v=o(c).locale(d.params.lang).startOf("month").hour(c.hour()).minute(c.minute()),b=v.format("d");u.days=[];for(var y=v.date();y<=v.daysInMonth();y++){if(y===v.date()){var D=e.week.indexOf(b.toString());if(D>0)for(var p=0;p {{picker.currentNearestMinute().format("dddd")}}{{picker.params.shortTime?picker.currentDate.format("A"):" "}}◄ {{picker.currentDate.format("MMM")|uppercase}}{{itemMonth}} ►{{picker.currentDate.format("DD")}}◄ {{picker.currentDate.format("YYYY")}}{{itemYear}} ►{{picker.currentNearestMinute().format(picker.params.shortTime ? "hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}} {{picker.currentNearestMinute().format(picker.params.shortTime ? "hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}:{{picker.currentNearestMinute().format("ss")}} {{picker.currentDate.format("A")}} {{picker.currentNearestMinute().format(picker.params.shortTime?"hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}{{picker.currentNearestMinute().format(picker.params.shortTime?"hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}:{{picker.currentNearestMinute().format("ss")}}{{::picker.params.todayText}} {{::picker.params.cancelText}} {{::picker.params.okText}} '}}]).directive("mdcDatetimePickerCalendarMonth",["$compile",function(i){var n=function(a,r){var t=angular.element(a[0].querySelector("tbody")),s=r.cal,f=r.month,e=[];f.days.forEach(function(d,S){e.push(""),d.forEach(function(c,u){if(e.push(" ")}),t.html(e.join("")),i(t)(r)};return{scope:{idx:"="},require:"^mdcDatetimePickerCalendar",restrict:"AE",template:'"),c)if(s.isInRange(c)){var v="month['days']["+S+"]["+u+"]";e.push(''),e.push(c.format("D")),e.push("")}else e.push(''),e.push(c.format("D")),e.push("");e.push(" ")}),e.push("{{month.name}}',link:function(a,r,t,s){a.cal=s,a.month=s.getItemAtIndex(parseInt(a.idx)),n(r,a),a.$watch(function(){return a.idx},function(f,e){f!=e&&(a.month=s.getItemAtIndex(parseInt(a.idx)),n(r,a))})}}}]),angular.module(N).directive("mdcDtpNoclick",function(){return{link:function(i,n){n.on("click",function(a){a.preventDefault()}),n.on("dragstart",function(a){a.preventDefault()})}}}),angular.module(N).directive("mdcDatetimePickerClock",["$timeout",function(i){var n='';return{restrict:"E",template:n,link:function(a,r,t){var s=t.mode==="minutes",f=t.mode==="seconds",e=a.picker,d=document.querySelector("md-dialog.dtp"),S=function(l,m){var h=0;if(l=l>=360?0:l,l!==0){var g=s||f?60:12;h=Math.round(g/360*l)}if(s){var I=e.params.minuteSteps;(I<1||I>59)&&(I=1);var w=I*Math.round(h/I);if(w>=60&&(w=60-I),!a.pointAvailable({value:h}))return;e.currentDate.minute(w)}else if(f){if(h>=60&&(h=0),!a.pointAvailable({value:h}))return;e.currentDate.second(h)}else{if(h===12&&(h=0),e.params.shortTime||(e.meridien=m>84?"AM":"PM"),e.isPM()&&(h+=12),!a.pointAvailable({value:h}))return;e.currentDate.hour(h)}},c="ontouchstart"in window,u={POINTER_DOWN:c?"touchstart":"mousedown",POINTER_UP:c?"touchend":"mouseup",POINTER_MOVE:c?"touchmove":"mousemove"},v=function(l){l.preventDefault();var m=l.currentTarget.closest("div"),h=m.getClientRects()[0];c&&(l=l.changedTouches[0]);var g=m.offsetWidth/2-(l.pageX-h.left),I=l.pageY-h.top-m.offsetHeight/2,w=Math.sqrt(Math.pow(g,2)+Math.pow(I,2)),x=Math.round(Math.atan2(g,I)*(180/Math.PI));i(function(){S(x+180,w)})};r.on(u.POINTER_DOWN,function(){r.on(u.POINTER_MOVE,v)}),r.on(u.POINTER_UP,function(){r.off(u.POINTER_MOVE)}),a.$on("$destroy",function(){r.off(u.POINTER_MOVE,v)});var b=function(){var l=angular.element(r[0].querySelector(".dtp-picker-clock")),m=angular.element(d.querySelector(".dtp-picker")),h=d.querySelector(".dtp-content").offsetWidth,g=parseInt(V(m,"paddingLeft").replace("px",""))||0,I=parseInt(V(m,"paddingRight").replace("px",""))||0,w=parseInt(V(m,"paddingTop").replace("px",""))||0,x=parseInt(V(l,"marginLeft").replace("px",""))||0,K=parseInt(V(l,"marginRight").replace("px",""))||0,Y=parseInt(V(l,"marginTop").replace("px",""))||0,$=h-(x+K+g+I);l.css("width",$+"px");for(var k=$/2,U=k/1.2,W=[],A=0;A<12;++A){var ee=U*Math.sin(Math.PI*2*(A/12)),te=U*Math.cos(Math.PI*2*(A/12)),B=k+ee+g/2-(g+x),j=k-te-Y/2-(w+Y),E={left:B,top:j,value:s||f?A*5:A,style:{"margin-left":B+"px","margin-top":j+"px"}};s||f?E.display=E.value<10?"0"+E.value:E.value:e.params.shortTime?E.display=A===0?12:A:E.display=A,W.push(E)}if(a.points=W,!e.params.shortTime&&!s&&!f){for(var R=[],z=k/1.8,O=12;O<24;++O){var ae=z*Math.sin(Math.PI*2*(O/12)),ie=z*Math.cos(Math.PI*2*(O/12)),q=k+ae+g/2-(g+x),Z=k-ie-Y/2-(w+Y);R.push({left:q,top:Z,value:O,display:O,style:{"margin-left":q+"px","margin-top":Z+"px"}})}a.points24=R}a.mode=t.mode,p(),l.css("height",$+"px");var L=r[0].querySelector(".dtp-clock-center"),re=L.offsetWidth/2||7.5,ne=L.offsetHeight/2||7.5,_=k/(e.params.shortTime?1.8:2.3),X=k/1.4,F=k;angular.element(r[0].querySelector(".dtp-hour-hand")).css({left:k+x*1.5+"px",height:_+"px",marginTop:k-_-g+"px"}).addClass(!s&&!f?"on":""),angular.element(r[0].querySelector(".dtp-minute-hand")).css({left:k+x*1.5+"px",height:X+"px",marginTop:k-X-g+"px"}).addClass(s?"on":""),angular.element(r[0].querySelector(".dtp-second-hand")).css({left:k+x*1.5+"px",height:F+"px",marginTop:k-F-g+"px"}).addClass(f?"on":""),angular.element(L).css({left:k+g+x-re+"px",marginTop:k-x/2-ne+"px"}),y()},y=function(){var l=e.currentNearestMinute(),m=l.hour(),h=l.minute(),g=l.second();D(angular.element(r[0].querySelector(".dtp-hour-hand")),30*m),D(angular.element(r[0].querySelector(".dtp-minute-hand")),6*h),D(angular.element(r[0].querySelector(".dtp-second-hand")),6*g)},D=function(l,m){angular.element(l).css({WebkitTransform:"rotate("+m+"deg)","-moz-transform":"rotate("+m+"deg)","-ms-transform":"rotate("+m+"deg)",transform:"rotate("+m+"deg)"})},p=function(){var l=e.currentNearestMinute(),m=e.params.shortTime?12:24;s?a.currentValue=l.minute():f?a.currentValue=l.second():a.currentValue=l.hour()%m};a.$watch(function(){var l=e.currentNearestMinute();return l?l.format("HH:mm:ss"):""},function(){p(),y()}),a.setTime=function(l){!s&&!f?(l===a.currentValue&&!e.params.autoOk&&e.ok(),e.params.shortTime?e.currentDate.hour(e.isPM()?l+12:l):(e.currentDate.hour(l),l>=12?e.meridien="PM":e.meridien="AM"),e.params.autoOk&&e.ok()):f?(l===a.currentValue&&e.ok(),e.currentDate.second(l)):(l===a.currentValue&&!e.params.seconds&&e.ok(),e.currentDate.minute(l),e.params.seconds?e.params.autoOk&&e.ok():e.currentDate.second(0))},a.pointAvailable=function(l){return s?e.isMinuteAvailable(l.value):f?e.isSecondAvailable(l.value):e.isHourAvailable(l.value)};var T=a.$watch(function(){return r[0].querySelectorAll("div").length},function(){b(),T()})}}}]),N}var J=window&&window.process&&window.process.type;typeof define=="function"&&define.amd?define(["moment"],P):typeof module<"u"&&module&&module.exports&&typeof require=="function"&&!J?module.exports=P(require("moment")):P((typeof global<"u"?global:window).moment)})(); 2 | //# sourceMappingURL=angular-material-datetimepicker.min.js.map 3 | -------------------------------------------------------------------------------- /dist/material-datetimepicker.min.css: -------------------------------------------------------------------------------- 1 | md-dialog.dtp{font-size:14px;line-height:1.42857143;color:#333;background-color:#fff;max-height:none;min-width:300px;width:300px}.noselect{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.dtp *:focus{outline:none!important}.dtp table{border-spacing:0;border-collapse:collapse;width:100%}.dtp .table>tbody>tr>td,.dtp .table>tbody>tr>th,.dtp .table>tfoot>tr>td,.dtp .table>tfoot>tr>th,.dtp .table>thead>tr>td,.dtp .table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.dtp,.dtp *{box-sizing:border-box!important}.dtp>.dtp-content{max-width:300px;max-height:500px}.dtp>.dtp-content>.dtp-date-view>header.dtp-header{background:#689F38;color:#fff;text-align:center}.dtp div.dtp-date,.dtp div.dtp-time{background:#8BC34A;text-align:center;color:#fff;padding:10px}.dtp div.dtp-date>div{padding:0;margin:0}.dtp div.dtp-actual-month{font-size:1.5em;cursor:pointer}md-menu-content.dtp-month-list{background-color:#fff}.dtp div.dtp-actual-num{font-size:2em;line-height:.9}.dtp div.dtp-actual-maxtime{font-size:2em;line-height:.9;color:#dcedc8}.dtp div.dtp-actual-maxtime span.selected{color:#fff}.dtp div.dtp-actual-year{font-size:1.6em;color:#dcedc8;cursor:pointer}md-menu-content.dtp-year-list{background-color:#fff}.dtp div.dtp-month-btn{font-size:1.4em;line-height:30px;cursor:pointer}.dtp div.dtp-month-btn-prev{text-align:right}.dtp div.dtp-month-btn-next{text-align:left}.dtp div.dtp-year-btn{font-size:1.4em;line-height:30px;cursor:pointer;color:#dcedc8}.dtp div.dtp-year-btn-prev{text-align:right}.dtp div.dtp-year-btn-next{text-align:left}.dtp div.dtp-picker{padding:10px 10px 0;text-align:center;overflow:hidden}.dtp div.dtp-picker-month,.dtp div.dtp-actual-time{font-size:1em;font-weight:500;text-align:center}.dtp div.dtp-actual-time.p60 span.selected{color:#689f38}.dtp .dtp-close{position:absolute;top:0;right:5px;font-size:16px}.dtp .dtp-close>a{color:#fff;text-decoration:none}.dtp .dtp-close>a>i{font-size:1em}.dtp table.dtp-picker-days{margin:0;min-height:260px}.dtp md-virtual-repeat-container.months{height:260px}.dtp table.dtp-picker-days,.dtp table.dtp-picker-days tr,.dtp table.dtp-picker-days tr>td{border:none}.dtp table.dtp-picker-days tr>td{font-size:12px;text-align:center;padding:0}.dtp table.dtp-picker-days tr>td>span.dtp-select-day{color:#bdbdbd!important}.dtp table.dtp-picker-days tr>td,.dtp table.dtp-picker-days tr>td>.dtp-select-day{width:36px;height:36px}.dtp table.dtp-picker-days tr>td>.dtp-select-day{display:inline-block}.dtp table.dtp-picker-days tr>td>.dtp-select-day,.dtp .dtp-picker-time>a{color:#212121;text-decoration:none;padding:10px;border-radius:50%!important}.dtp table.dtp-picker-days tr>td>a.selected{background:#8BC34A;color:#fff}.dtp table.dtp-picker-days tr>td>a.selected.hilite{padding:6px;font-size:16px;font-weight:500;background:#8BC34A;color:#fff}.dtp table.dtp-picker-days tr>td>a.hilite:not(.selected){padding:6px;font-size:16px;font-weight:500;color:#8bc34a}.dtp table.dtp-picker-days tr>td>a:hover:not(.selected){background:#dddddd}.dtp table.dtp-picker-days tr>th{color:#757575;text-align:center;font-weight:700;padding:2px 3px;width:38px;height:28px}.dtp .p10>a{color:#689f38;text-decoration:none}.dtp .p10{width:10%;display:inline-block}.dtp .p20{width:20%;display:inline-block}.dtp .p60{width:60%;display:inline-block}.dtp .p80{width:80%;display:inline-block}.dtp div.dtp-picker-datetime{padding-bottom:25px}.dtp span.dtp-actual-meridien{font-size:.6em}.dtp div.dtp-actual-meridien{height:20px}.dtp a.dtp-meridien-am,.dtp a.dtp-meridien-pm{position:relative;color:#212121;font-weight:500;padding:7px 5px;border-radius:50%!important;text-decoration:none;background:#eee;font-size:10px}.dtp .dtp-actual-meridien a.selected{background:#689F38;color:#fff}.dtp .dtp-picker-time>a{display:block;line-height:23px;padding:3px}.dtp .dtp-picker-time{position:absolute;width:30px;height:30px;font-size:1.1em;border-radius:50%;cursor:pointer;text-align:center!important}.dtp .dtp-picker-time>a.dtp-select-hour.selected{background:#689F38;color:#fff}.dtp .dtp-picker-time>a.dtp-select-hour.disabled,.dtp .dtp-picker-time>a.dtp-select-minute.disabled{color:#757575}.dtp .dtp-picker-time>a.dtp-select-minute.selected{background:#8BC34A;color:#fff}.dtp div.dtp-picker-clock{margin:10px 20px 0;padding:10px;border-radius:50%!important;background:#eee;direction:ltr;cursor:default}.dtp-clock-center{width:15px;height:15px;background:#757575;border-radius:50%;position:absolute;z-index:50}.dtp .dtp-hand,.dtp .dtp-hour-hand{position:absolute;width:4px;margin-left:-2px;background:#BDBDBD;-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-webkit-transform:rotate(0deg);transform:rotate(0);-moz-transform-origin:bottom;-ms-transform-origin:bottom;-webkit-transform-origin:bottom;transform-origin:bottom;z-index:1}.dtp .dtp-minute-hand{width:2px;margin-left:-1px}.dtp .dtp-second-hand{width:1px;margin-left:-1px}.dtp .dtp-hand.on{background:#8BC34A}.dtp .dtp-buttons{padding-bottom:10px;text-align:right}.dtp.hidden,.dtp .hidden{display:none}.dtp .invisible{visibility:hidden}.dtp .left{float:left}.dtp .right{float:right}.dtp .clearfix{clear:both}.dtp .center{text-align:center}[dir=rtl] .dtp div.dtp-year-btn-next,[dir=rtl] .dtp div.dtp-month-btn-next,[dir=rtl] .dtp div.dtp-year-btn-prev,[dir=rtl] .dtp div.dtp-month-btn-prev{-ms-transform:rotate(180deg);-webkit-transform:rotate(180deg);transform:rotate(180deg)}.dtp-btn-today,.dtp-btn-ok,.dtp-btn-cancel{min-width:70px}.dtp-clear{position:absolute;top:0;right:-10px}.dtp-no-msclear::-ms-clear{display:none;width:0;height:0}.dtp-btn-calendar{position:absolute;top:-3px;left:-10px}.dtp-input{margin-left:30px;max-width:calc(100% - 30px)} 2 | -------------------------------------------------------------------------------- /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beenote/angular-material-datetimepicker/c8b97d36da220a0c5ed69896fb902fd80ed0760f/favicon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
{{cal.toDay(day)}} Angular-Material DateTimePicker 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |35 | 294 | 295 | -------------------------------------------------------------------------------- /js/angular-material-datetimepicker.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | function ngMaterialDatePicker(moment) { 5 | var moduleName = "ngMaterialDatePicker"; 6 | var mdAccesTime = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4gICAgPHBhdGggZD0iTTExLjk5IDJDNi40NyAyIDIgNi40OCAyIDEyczQuNDcgMTAgOS45OSAxMEMxNy41MiAyMiAyMiAxNy41MiAyMiAxMlMxNy41MiAyIDExLjk5IDJ6TTEyIDIwYy00LjQyIDAtOC0zLjU4LTgtOHMzLjU4LTggOC04IDggMy41OCA4IDgtMy41OCA4LTggOHoiLz4gICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPiAgICA8cGF0aCBkPSJNMTIuNSA3SDExdjZsNS4yNSAzLjE1Ljc1LTEuMjMtNC41LTIuNjd6Ii8+PC9zdmc+'; 7 | var mdCalendar = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTkgM2gtMVYxaC0ydjJIOFYxSDZ2Mkg1Yy0xLjExIDAtMS45OS45LTEuOTkgMkwzIDE5YzAgMS4xLjg5IDIgMiAyaDE0YzEuMSAwIDItLjkgMi0yVjVjMC0xLjEtLjktMi0yLTJ6bTAgMTZINVY4aDE0djExek03IDEwaDV2NUg3eiIvPjwvc3ZnPg=='; 8 | var VIEW_STATES = {DATE: 0, HOUR: 1, MINUTE: 2}; 9 | 10 | var css = function (el, name) { 11 | el = angular.element(el); 12 | return ('getComputedStyle' in window) ? window.getComputedStyle(el[0])[name] : el.css(name); 13 | }; 14 | 15 | var template = 16 | '36 |38 | 39 |Angular Material DateTimePicker
37 |40 | 293 |41 | 51 | 50 |52 | 292 |53 | INSTRUCTION 54 |
55 | 56 |57 |65 | 66 |58 | 59 | 62 | 63 | 64 |67 |77 | 78 |68 | 69 | 74 | 75 | 76 |79 |92 | 93 |80 |90 | 91 |81 | 82 | 87 | 88 | {{timez.toDate()}} 89 |94 |104 | 105 |95 | 96 | 101 | 102 | 103 |106 |119 | 120 |107 |117 | 118 |108 | 109 | 114 | 115 | moment: {{timeutc._isAMomentObject}} 116 |121 |131 | 132 |122 | 123 | 128 | 129 | 130 |133 |142 | 143 |134 | 135 | 139 | 140 | 141 |144 |153 | 154 | 173 | 174 | 191 | 192 |145 | 146 | 150 | 151 | 152 |193 |202 | 203 |194 | 195 | 199 | 200 | 201 |204 |213 | 214 |205 | 206 | 210 | 211 | 212 |215 |222 | 223 |216 | 217 | 219 | 220 | 221 |224 |231 | 232 |225 | 226 | 228 | 229 | 230 |233 |251 | 252 |234 |249 | 250 |235 | 236 | 240 | 241 |242 | 243 | 247 | 248 |253 |261 | 262 |254 | 255 | 258 | 259 | 260 |263 |270 | 271 |264 | 265 | 267 | 268 | 269 |272 |279 | 280 |273 | 274 | 276 | 277 | 278 |281 |290 | 291 |282 |288 | 289 |mdcDateTimeDialog Service
283 |284 | Display Picker 285 | 286 |Date: {{selectedDateTime|date:'medium'}}
287 |' + 17 | ' '; 91 | 92 | angular.module(moduleName, ['ngMaterial']) 93 | .factory('mdcDefaultParams', function () { 94 | var default_params = { 95 | date: true, 96 | time: true, 97 | minutes: true, 98 | seconds: false, 99 | format: 'YYYY-MM-DD', 100 | minDate: null, 101 | maxDate: null, 102 | currentDate: null, 103 | lang: window.navigator.userLanguage || window.navigator.language || 'en', 104 | weekStart: 0, 105 | shortTime: false, 106 | cancelText: 'Cancel', 107 | okText: 'OK', 108 | amText: 'AM', 109 | pmText: 'PM', 110 | todayBtn: true, 111 | todayText: 'Today', 112 | disableDates: [], 113 | weekDays: false, 114 | disableParentScroll: false, 115 | autoOk: false, 116 | editInput: false, 117 | clickOutsideToClose: false, 118 | minuteSteps: 5, 119 | showIcon: false, 120 | showClear: true, 121 | template: template, 122 | templateUrl: '', 123 | targetEvent: null, 124 | openFrom: null, 125 | closeTo: null, 126 | dayOfWeekLen: 1, 127 | hasBackdrop: true, 128 | }; 129 | 130 | return function (params) { 131 | if (params) { 132 | for (var i in params) { 133 | if (default_params.hasOwnProperty(i) && params.hasOwnProperty(i)) default_params[i] = params[i]; 134 | } 135 | } 136 | return default_params; 137 | }; 138 | }) 139 | .directive('mdcDatetimePicker', ['$mdDialog', '$timeout', '$compile', '$parse', 140 | function ($mdDialog, $timeout, $compile, $parse) { 141 | return { 142 | restrict: 'A', 143 | require: 'ngModel', 144 | scope: { 145 | currentDate: '=ngModel', 146 | ngModelOptions: '=', 147 | ngChange: '&', 148 | time: '=', 149 | date: '=', 150 | minutes: '=', 151 | seconds: '=', 152 | minDate: '=', 153 | maxDate: '=', 154 | disableDates: '=', 155 | weekDays: '=', 156 | shortTime: '=', 157 | weekStart: '=', 158 | format: '@', 159 | cancelText: '@', 160 | okText: '@', 161 | lang: '@', 162 | amText: '@', 163 | pmText: '@', 164 | showTodaysDate: '@', 165 | todayBtn: '=', 166 | todayText: '@', 167 | disableParentScroll: '=', 168 | autoOk: '=', 169 | editInput: '=', 170 | clickOutsideToClose: '=', 171 | minuteSteps: '=', 172 | showIcon: '=', 173 | showClear: '=', 174 | templateUrl: '@', 175 | dayOfWeekLen: '=', 176 | hasBackdrop: '=' 177 | }, 178 | link: function (scope, element, attrs, ngModel) { 179 | var isOn = false; 180 | if (!scope.format) { 181 | if (scope.date && scope.time && scope.seconds) scope.format = 'YYYY-MM-DD HH:mm:ss'; 182 | else if (scope.date && scope.time) scope.format = 'YYYY-MM-DD HH:mm'; 183 | else if (scope.date) scope.format = 'YYYY-MM-DD'; 184 | else scope.format = 'HH:mm'; 185 | } 186 | 187 | var dateOfTheDay = null; 188 | if (scope.showTodaysDate !== undefined && scope.showTodaysDate !== "false") { 189 | dateOfTheDay = moment(); 190 | } 191 | 192 | if (angular.isString(scope.currentDate) && scope.currentDate !== '') { 193 | scope.currentDate = moment(scope.currentDate, scope.format); 194 | } 195 | 196 | var offset; 197 | if (ngModel) { 198 | var ngModelOptions = {'*': '$inherit', debounce: 500}; 199 | if (angular.version.major === 1 && angular.version.minor > 5) { 200 | ngModel.$options = ngModel.$options.createChild(ngModelOptions); 201 | if (ngModel.$options.getOption('timezone')) offset = ngModel.$options.getOption('timezone'); 202 | } else { 203 | if (scope.ngModelOptions && scope.ngModelOptions.timezone) ngModelOptions.timezone = scope.ngModelOptions.timezone; 204 | ngModel.$options = ngModelOptions; 205 | if (ngModel.$options.timezone) offset = ngModel.$options.timezone; 206 | } 207 | if (offset==='utc' || offset==='UTC') offset = 0; 208 | 209 | ngModel.$formatters.push(function (value) { 210 | if (typeof value === 'undefined') return; 211 | var m = moment(value); 212 | return m.isValid() ? m.format(scope.format) : ''; 213 | }); 214 | 215 | ngModel.$parsers.push(function (value) { 216 | if (typeof value === 'undefined') return; 217 | 218 | var m = moment(value, scope.format); 219 | if (offset !== undefined) m.utcOffset(offset, m._tzm === undefined); 220 | if (scope.minDate) ngModel.$setValidity('min', !m.isBefore(scope.minDate)); 221 | if (scope.maxDate) ngModel.$setValidity('max', !m.isAfter(scope.maxDate)); 222 | ngModel.$setValidity('format', moment(value, scope.format, true).isValid()); 223 | 224 | return m.isValid() ? (m._isUTC ? m : m.toDate()) : ''; 225 | }); 226 | 227 | } 228 | 229 | function openCalendar(e) { 230 | e.preventDefault(); 231 | element.blur(); 232 | element.parent().removeClass('md-input-focused'); 233 | if (isOn) { 234 | return; 235 | } 236 | isOn = true; 237 | var options = {}; 238 | for (var i in attrs) { 239 | if (scope.hasOwnProperty(i) && !angular.isUndefined(scope[i])) { 240 | options[i] = scope[i]; 241 | } 242 | } 243 | options.currentDate = scope.currentDate; 244 | options.showTodaysDate = dateOfTheDay; 245 | 246 | var dialogOptions = { 247 | controller: PluginController, 248 | controllerAs: 'picker', 249 | locals: {options: options}, 250 | openFrom: element, 251 | closeTo: element, 252 | parent: angular.element(document.body), 253 | bindToController: true, 254 | clickOutsideToClose: options.clickOutsideToClose || false, 255 | disableParentScroll: options.disableParentScroll || false, 256 | hasBackdrop: options.hasBackdrop === undefined ? true : options.hasBackdrop, 257 | skipHide: true, 258 | multiple: true, 259 | }; 260 | 261 | if (!options.templateUrl) dialogOptions.template = template; 262 | else dialogOptions.templateUrl = options.templateUrl; 263 | 264 | $mdDialog.show(dialogOptions).then(function(v) { 265 | 266 | if (offset !== undefined) v.utcOffset(offset, true); 267 | 268 | scope.currentDate = v && !v._isUTC ? v.toDate() : v; 269 | ngModel.$setValidity('format', true); 270 | ngModel.$setViewValue(scope.currentDate); 271 | ngModel.$setDirty(); 272 | isOn = false; 273 | 274 | if (!moment(scope.currentDate).isSame(options.currentDate)) { 275 | $timeout(scope.ngChange, 0); 276 | } 277 | 278 | element.parent().removeClass('md-input-focused'); 279 | }, function () { 280 | isOn = false; 281 | element.parent().removeClass('md-input-focused'); 282 | }); 283 | } 284 | 285 | if (!scope.editInput) { 286 | if (scope.showIcon) { 287 | element.on('click', openCalendar); 288 | } else { 289 | element.on('focus', openCalendar); 290 | } 291 | } 292 | 293 | if (scope.showIcon) { 294 | element.addClass('dtp-no-msclear dtp-input'); 295 | var calendarButton = 296 | ' ', clearButton = ''; 302 | 303 | if (scope.showClear === undefined || scope.showClear) { 304 | clearButton = ' '; 307 | } 308 | 309 | element.after($compile(calendarButton + clearButton)(scope)); 310 | 311 | scope.openCalendarDiag = function(e) { 312 | openCalendar(e); 313 | }; 314 | 315 | scope.clear = function() { 316 | ngModel.$setViewValue(null); 317 | scope.currentDate = null; 318 | ngModel.$render(); 319 | $timeout(function() { 320 | scope.ngChange(); 321 | element[0].focus(); 322 | }, 0, false); 323 | }; 324 | } 325 | } 326 | }; 327 | }]) 328 | // Returns a service that opens a dialog when the attribute shown is called 329 | .factory('mdcDateTimeDialog', ["$mdDialog", "$q", function ($mdDialog, $q) { 330 | var service = { 331 | show: function (options) { 332 | var deferred = $q.defer(); 333 | 334 | if (options.showTodaysDate !== undefined && options.showTodaysDate !== "false") options.showTodaysDate = moment(); 335 | 336 | var dialogOptions = { 337 | controller: PluginController, 338 | controllerAs: 'picker', 339 | locals: {options: options}, 340 | parent: angular.element(document.body), 341 | bindToController: true, 342 | clickOutsideToClose: options.clickOutsideToClose || false, 343 | disableParentScroll: options.disableParentScroll || false, 344 | skipHide: true, 345 | multiple: true, 346 | hasBackdrop: options.hasBackdrop === undefined ? true : options.hasBackdrop, 347 | targetEvent: options.targetEvent, 348 | openFrom: options.openFrom, 349 | closeTo: options.closeTo, 350 | }; 351 | 352 | if (!options.templateUrl) dialogOptions.template = template; 353 | else dialogOptions.templateUrl = options.templateUrl; 354 | 355 | $mdDialog.show(dialogOptions).then(function (v) { 356 | deferred.resolve(v && !v._isUTC ? v.toDate() : v); 357 | }, function () { 358 | deferred.reject(); 359 | }); 360 | return deferred.promise; 361 | } 362 | }; 363 | 364 | return service; 365 | }]) 366 | ; 367 | 368 | var PluginController = function ($mdDialog, mdcDefaultParams) { 369 | this.currentView = VIEW_STATES.DATE; 370 | this._dialog = $mdDialog; 371 | 372 | this._attachedEvents = []; 373 | this.VIEWS = VIEW_STATES; 374 | this.params = angular.copy(mdcDefaultParams()); 375 | this.meridien = 'AM'; 376 | }; 377 | 378 | PluginController.$inject = ['$mdDialog', 'mdcDefaultParams']; 379 | PluginController.prototype = { 380 | $onInit: function () { 381 | this.params = angular.extend(this.params, this.options); 382 | this.timeMode = this.params.time && !this.params.date; 383 | this.dateMode = this.params.date; 384 | this.initDates(); 385 | this.start(); 386 | }, 387 | currentNearestMinute: function () { 388 | var nearestMin = this.params.minuteSteps; 389 | if (nearestMin < 1 || nearestMin > 59) nearestMin = 1; 390 | 391 | var date = this.currentDate || moment(); 392 | var minutes = (nearestMin * Math.round(date.minute() / nearestMin)); 393 | if (minutes >= 60) minutes = 60 - nearestMin; 394 | 395 | var seconds; 396 | if (this.params.seconds) { 397 | seconds = date.second(); 398 | if (seconds >= 60) seconds = 60 - 1; 399 | } else seconds = 0; 400 | 401 | return moment(date).minutes(minutes).seconds(seconds).millisecond(0); 402 | }, 403 | initDates: function () { 404 | var that = this; 405 | var _dateParam = function (input, fallback) { 406 | var ret = null; 407 | if (angular.isDefined(input) && input !== null && input !== '') { 408 | if (angular.isString(input)) { 409 | if (typeof(that.params.format) !== 'undefined' && that.params.format !== null) { 410 | ret = moment(input, that.params.format).locale(that.params.lang); 411 | } 412 | else { 413 | ret = moment(input).locale(that.params.lang); 414 | } 415 | } else if (typeof input === 'number') { 416 | ret = moment(input).locale(that.params.lang); 417 | } else { 418 | if (angular.isDate(input)) { 419 | var x = input.getTime(); 420 | ret = moment(x, "x").locale(that.params.lang); 421 | } else if (moment.isMoment(input)) { 422 | if (input.isValid()) ret = input; 423 | else ret = fallback; 424 | } 425 | } 426 | } else { 427 | ret = fallback; 428 | } 429 | return ret; 430 | }; 431 | 432 | this.currentDate = _dateParam(this.params.currentDate, moment()); 433 | this.currentDate = this.currentNearestMinute(); 434 | this.minDate = _dateParam(this.params.minDate); 435 | this.maxDate = _dateParam(this.params.maxDate); 436 | this.disableDates = this.params.disableDates.map(function (x) { 437 | return moment(x).format('MMMM Do YYYY'); 438 | }); 439 | this.selectDate(this.currentDate); 440 | this.weekDays = this.params.weekDays; 441 | }, 442 | initDate: function () { 443 | this.currentView = VIEW_STATES.DATE; 444 | }, 445 | initHours: function () { 446 | this.currentView = VIEW_STATES.HOUR; 447 | }, 448 | initMinutes: function () { 449 | this.currentView = VIEW_STATES.MINUTE; 450 | }, 451 | initSeconds: function () { 452 | this.currentView = VIEW_STATES.SECOND; 453 | }, 454 | isAfterMinDate: function (date, checkHour, checkMinute) { 455 | var _return = true; 456 | 457 | if (typeof(this.minDate) !== 'undefined' && this.minDate !== null) { 458 | var _minDate = moment(this.minDate); 459 | var _date = moment(date); 460 | 461 | if (!checkHour && !checkMinute) { 462 | _minDate.hour(0); 463 | _minDate.minute(0); 464 | 465 | _date.hour(0); 466 | _date.minute(0); 467 | } 468 | 469 | _minDate.second(0); 470 | _date.second(0); 471 | _minDate.millisecond(0); 472 | _date.millisecond(0); 473 | 474 | if (!checkMinute) { 475 | _date.minute(0); 476 | _minDate.minute(0); 477 | 478 | _return = (parseInt(_date.format("X")) >= parseInt(_minDate.format("X"))); 479 | } 480 | else { 481 | _return = (parseInt(_date.format("X")) >= parseInt(_minDate.format("X"))); 482 | } 483 | } 484 | 485 | return _return; 486 | }, 487 | isBeforeMaxDate: function (date, checkTime, checkMinute) { 488 | var _return = true; 489 | 490 | if (typeof(this.maxDate) !== 'undefined' && this.maxDate !== null) { 491 | var _maxDate = moment(this.maxDate); 492 | var _date = moment(date); 493 | 494 | if (!checkTime && !checkMinute) { 495 | _maxDate.hour(0); 496 | _maxDate.minute(0); 497 | 498 | _date.hour(0); 499 | _date.minute(0); 500 | } 501 | 502 | _maxDate.second(0); 503 | _date.second(0); 504 | _maxDate.millisecond(0); 505 | _date.millisecond(0); 506 | 507 | if (!checkMinute) { 508 | _date.minute(0); 509 | _maxDate.minute(0); 510 | 511 | _return = (parseInt(_date.format("X")) <= parseInt(_maxDate.format("X"))); 512 | } 513 | else { 514 | _return = (parseInt(_date.format("X")) <= parseInt(_maxDate.format("X"))); 515 | } 516 | } 517 | 518 | return _return; 519 | }, 520 | isInDisableDates: function (date) { 521 | var dut = date.format('MMMM Do YYYY'); 522 | if (this.disableDates.indexOf(dut) > -1) { 523 | return false; 524 | } 525 | return true; 526 | }, 527 | isWeekDay: function(date) { 528 | if (this.weekDays) { 529 | if (date.isoWeekday() <= 5) { 530 | return true; 531 | } 532 | return false; 533 | } 534 | return true; 535 | }, 536 | selectDate: function (date) { 537 | if (date) { 538 | this.currentDate = moment(date); 539 | if (!this.isAfterMinDate(this.currentDate, true, true)) { 540 | this.currentDate = moment(this.minDate); 541 | } 542 | 543 | if (!this.isBeforeMaxDate(this.currentDate, true, true)) { 544 | this.currentDate = moment(this.maxDate); 545 | } 546 | this.currentDate.locale(this.params.lang); 547 | this.calendarStart = moment(this.currentDate); 548 | this.meridien = this.currentDate.hour() >= 12 ? 'PM' : 'AM'; 549 | } 550 | }, 551 | isPM: function () { 552 | return this.meridien === 'PM'; 553 | }, 554 | incrementMonth: function (amount) { 555 | if ((amount === 1 && this.isNextMonthVisible()) || (amount === -1 && this.isPreviousMonthVisible())) { 556 | this.selectDate(this.currentDate.add(amount, 'month')); 557 | } 558 | }, 559 | incrementYear: function (amount) { 560 | if ((amount === 1 && this.isNextYearVisible()) || (amount === -1 && this.isPreviousYearVisible())) { 561 | this.selectDate(this.currentDate.add(amount, 'year')); 562 | } 563 | }, 564 | openMenu: function ($mdMenu, ev) { 565 | $mdMenu.open(ev); 566 | }, 567 | monthsAvailable: function () { 568 | var monthsArr = [], _date = moment(this.currentDate); 569 | 570 | for (var m = 0; m < 12; m++) { 571 | var curMonth = _date.month(m); 572 | if (this.isAfterMinDate(curMonth.endOf('month')) && this.isBeforeMaxDate(curMonth.startOf('month'))) { 573 | monthsArr.push(curMonth.format('MMMM')); 574 | } 575 | } 576 | return monthsArr; 577 | }, 578 | selectMonth: function (month) { 579 | this.selectDate(this.currentDate.month(month)); 580 | }, 581 | yearsAvailable: function () { 582 | var _minDate, _maxDate, len, startYear, yearsArr = [], 583 | _date = this.currentDate.year(); 584 | 585 | if (typeof(this.minDate) !== 'undefined' && this.minDate !== null) { 586 | _minDate = moment(this.minDate).year(); 587 | } 588 | if (typeof(this.maxDate) !== 'undefined' && this.maxDate !== null) { 589 | _maxDate = moment(this.maxDate).year(); 590 | } 591 | 592 | if (_maxDate && _minDate) { 593 | len = _maxDate - _minDate; 594 | startYear = _minDate; 595 | } else if (_minDate) { 596 | len = 115; 597 | startYear = _minDate; 598 | } else if (_maxDate) { 599 | len = 30; 600 | startYear = _maxDate - len; 601 | } else { 602 | len = 60; 603 | startYear = _date - len/2; 604 | } 605 | 606 | for (var i=0; i <= len; i++) { 607 | yearsArr.push(startYear+i); 608 | } 609 | return yearsArr; 610 | }, 611 | selectYear: function (year) { 612 | this.selectDate(this.currentDate.year(year)); 613 | }, 614 | isPreviousMonthVisible: function () { 615 | return this.calendarStart && this.isAfterMinDate(moment(this.calendarStart).startOf('month'), false, false); 616 | }, 617 | isNextMonthVisible: function () { 618 | return this.calendarStart && this.isBeforeMaxDate(moment(this.calendarStart).endOf('month'), false, false); 619 | }, 620 | isPreviousYearVisible: function () { 621 | return this.calendarStart && this.isAfterMinDate(moment(this.calendarStart).startOf('year'), false, false); 622 | }, 623 | isNextYearVisible: function () { 624 | return this.calendarStart && this.isBeforeMaxDate(moment(this.calendarStart).endOf('year'), false, false); 625 | }, 626 | isHourAvailable: function (hour) { 627 | var _date = moment(this.currentDate); 628 | if (this.params.shortTime) { 629 | _date.hour(this.convertHours(hour)).minute(0).second(0); 630 | } else { 631 | _date.hour(hour).minute(0).second(0); 632 | } 633 | return this.isAfterMinDate(_date, true, false) && this.isBeforeMaxDate(_date, true, false); 634 | }, 635 | isMinuteAvailable: function (minute) { 636 | var _date = moment(this.currentDate); 637 | _date.minute(minute).second(0); 638 | 639 | var nearestMin = this.params.minuteSteps; 640 | if (nearestMin > 1 && 5 % nearestMin !== 0){ 641 | var _curmin = _date.minute(); 642 | var minutes = (nearestMin * Math.round(_curmin / nearestMin)); 643 | if (minutes >= 60) minutes = 60 - nearestMin; 644 | if (minutes !== _curmin) return false; 645 | } 646 | 647 | return this.isAfterMinDate(_date, true, true) && this.isBeforeMaxDate(_date, true, true); 648 | }, 649 | isSecondAvailable: function (second) { 650 | return true; 651 | }, 652 | start: function () { 653 | this.currentView = VIEW_STATES.DATE; 654 | if (this.params.date) { 655 | this.initDate(); 656 | } else { 657 | if (this.params.time) { 658 | this.initHours(); 659 | } 660 | } 661 | }, 662 | today: function () { 663 | var nearestMin = this.params.minuteSteps; 664 | var date = moment(); 665 | var minutes = (nearestMin * Math.round(date.minute() / nearestMin)); 666 | if (minutes >= 60) minutes = 60 - nearestMin; 667 | 668 | var seconds; 669 | if (this.params.seconds) { 670 | seconds = date.second(); 671 | if (seconds >= 60) seconds = 60 - 1; 672 | } else seconds = 0; 673 | 674 | this.selectDate(moment(date).minutes(minutes).seconds(seconds).millisecond(0)); 675 | }, 676 | ok: function () { 677 | switch (this.currentView) { 678 | case VIEW_STATES.DATE: 679 | if (this.params.time === true) { 680 | this.initHours(); 681 | } else { 682 | this.hide(true); 683 | } 684 | break; 685 | case VIEW_STATES.HOUR: 686 | if (this.params.minutes === true) { 687 | this.initMinutes(); 688 | } else { 689 | this.hide(true); 690 | } 691 | break; 692 | case VIEW_STATES.MINUTE: 693 | if (this.params.seconds === true) { 694 | this.initSeconds(); 695 | } else { 696 | this.hide(true); 697 | } 698 | break; 699 | case VIEW_STATES.SECOND: 700 | this.hide(true); 701 | break; 702 | } 703 | }, 704 | cancel: function () { 705 | if (this.params.time) { 706 | switch (this.currentView) { 707 | case VIEW_STATES.DATE: 708 | this.hide(); 709 | break; 710 | case VIEW_STATES.HOUR: 711 | if (this.params.date) { 712 | this.initDate(); 713 | } 714 | else { 715 | this.hide(); 716 | } 717 | break; 718 | case VIEW_STATES.MINUTE: 719 | this.initHours(); 720 | break; 721 | case VIEW_STATES.SECOND: 722 | this.initMinutes(); 723 | break; 724 | } 725 | } 726 | else { 727 | this.hide(); 728 | } 729 | }, 730 | selectMonthBefore: function () { 731 | this.calendarStart.subtract(1, 'months'); 732 | }, 733 | selectMonthAfter: function () { 734 | this.calendarStart.add(1, 'months'); 735 | }, 736 | selectYearBefore: function () { 737 | this.calendarStart.subtract(1, 'years'); 738 | }, 739 | selectYearAfter: function () { 740 | this.calendarStart.add(1, 'years'); 741 | }, 742 | selectAM: function () { 743 | if (this.isHourAvailable(0) || this.isHourAvailable(12)) { 744 | if (this.currentDate.hour() >= 12) { 745 | this.selectDate(this.currentDate.subtract(12, 'hours')); 746 | } 747 | if (!this.isHourAvailable(this.currentDate.hour())) { 748 | this.selectDate(this.currentDate.hour(this.minDate.hour())); 749 | } 750 | if (!this.isMinuteAvailable(this.currentDate.minute())) { 751 | this.selectDate(this.currentDate.minute(this.minDate.minute())); 752 | } 753 | } 754 | }, 755 | selectPM: function () { 756 | if (this.isHourAvailable(12) || this.isHourAvailable(24)) { 757 | if (this.currentDate.hour() < 12) { 758 | this.selectDate(this.currentDate.add(12, 'hours')); 759 | } 760 | if (!this.isHourAvailable(this.currentDate.hour())) { 761 | this.selectDate(this.currentDate.hour(this.maxDate.hour())); 762 | } 763 | if (!this.isMinuteAvailable(this.currentDate.minute())) { 764 | this.selectDate(this.currentDate.minute(this.maxDate.minute())); 765 | } 766 | } 767 | }, 768 | convertHours: function (h) { 769 | var _return = h; 770 | if (h < 12 && this.isPM()) _return += 12; 771 | 772 | return _return; 773 | }, 774 | hide: function (okBtn) { 775 | if (okBtn) this._dialog.hide(this.currentDate); 776 | else this._dialog.cancel(); 777 | } 778 | }; 779 | 780 | angular.module(moduleName) 781 | .directive('mdcDatetimePickerCalendar', [ 782 | function () { 783 | 784 | var YEAR_MIN = 1920, 785 | YEAR_MAX = new Date().getFullYear() + 30, 786 | MONTHS_IN_ALL = (YEAR_MAX - YEAR_MIN + 1) * 12, 787 | MONTHS = []; 788 | for (var i = 0; i < MONTHS_IN_ALL; i++) { 789 | MONTHS.push(i); 790 | } 791 | 792 | var currentMonthIndex = function (date, low) { 793 | low = low ? low : 0; 794 | return (((date.year() - YEAR_MIN) * 12) + date.month() - 1) - low; 795 | }; 796 | 797 | return { 798 | restrict: 'E', 799 | scope: { 800 | picker: '=', 801 | date: '=' 802 | }, 803 | bindToController: true, 804 | controllerAs: 'cal', 805 | controller: ['$scope', function ($scope) { 806 | var calendar = this, picker; 807 | 808 | this.$onInit = function () { 809 | picker = this.picker; 810 | 811 | var days = []; 812 | for (var i = picker.params.weekStart; days.length < 7; i++) { 813 | if (i > 6) i = 0; 814 | days.push(i.toString()); 815 | } 816 | calendar.week = days; 817 | 818 | if (!picker.maxDate && !picker.minDate) { 819 | calendar.months = MONTHS; 820 | } else { 821 | var low = picker.minDate ? currentMonthIndex(picker.minDate) : 0; 822 | var high = picker.maxDate ? (currentMonthIndex(picker.maxDate) +1) : MONTHS_IN_ALL; 823 | calendar.months = MONTHS.slice(low, high); 824 | } 825 | 826 | calendar.topIndex = currentMonthIndex(picker.currentDate) - calendar.months[0]; 827 | }; 828 | 829 | if (angular.version.major === 1 && angular.version.minor < 5) this.$onInit(); 830 | 831 | calendar.getItemAtIndex = function (index) { 832 | var month = ((index + 1) % 12) || 12; 833 | var year = YEAR_MIN + Math.floor(index / 12); 834 | var monthObj = moment(picker.currentDate).year(year).month(month); 835 | return generateMonthCalendar(monthObj); 836 | }; 837 | 838 | $scope.$watch(function () { 839 | return picker.currentDate ? picker.currentDate.format('YYYY-MM') : ''; 840 | }, function (val2, val1) { 841 | if (val2 != val1) { 842 | var nDate = moment(val2, 'YYYY-MM'); 843 | var low = picker.minDate ? currentMonthIndex(picker.minDate): 0; 844 | var index = currentMonthIndex(nDate, low); 845 | if (calendar.topIndex != index) { 846 | calendar.topIndex = index; 847 | } 848 | } 849 | }); 850 | 851 | var generateMonthCalendar = function (date) { 852 | var month = {}; 853 | if (date !== null) { 854 | month.name = date.format('MMMM YYYY'); 855 | var startOfMonth = moment(date).locale(picker.params.lang).startOf('month') 856 | .hour(date.hour()) 857 | .minute(date.minute()); 858 | var iNumDay = startOfMonth.format('d'); 859 | month.days = []; 860 | for (var i = startOfMonth.date(); i <= startOfMonth.daysInMonth(); i++) { 861 | if (i === startOfMonth.date()) { 862 | var iWeek = calendar.week.indexOf(iNumDay.toString()); 863 | if (iWeek > 0) { 864 | for (var x = 0; x < iWeek; x++) { 865 | month.days.push(0); 866 | } 867 | } 868 | } 869 | month.days.push(moment(startOfMonth).locale(picker.params.lang).date(i)); 870 | } 871 | 872 | var daysInAWeek = 7, daysTmp = [], slices = Math.ceil(month.days.length / daysInAWeek); 873 | for (var j = 0; j < slices; j++) { 874 | daysTmp.push(month.days.slice(j * daysInAWeek, (j + 1) * daysInAWeek)); 875 | } 876 | month.days = daysTmp; 877 | return month; 878 | } 879 | 880 | }; 881 | 882 | calendar.toDay = function (i) { 883 | return moment(parseInt(i), "d") 884 | .locale(picker.params.lang) 885 | .format("ddd") 886 | .substring(0, picker.params.dayOfWeekLen); 887 | }; 888 | 889 | calendar.isInRange = function (date) { 890 | return picker.isAfterMinDate(moment(date), false, false) && 891 | picker.isBeforeMaxDate(moment(date), false, false) && 892 | picker.isWeekDay(moment(date)) && 893 | picker.isInDisableDates(moment(date)); 894 | }; 895 | 896 | calendar.selectDate = function (date) { 897 | if (date) { 898 | if (calendar.isSelectedDay(date)) { 899 | return picker.ok(); 900 | } 901 | picker.selectDate(moment(date).hour(calendar.date.hour()).minute(calendar.date.minute())); 902 | if (picker.params.autoOk) { 903 | picker.ok(); 904 | } 905 | } 906 | }; 907 | 908 | calendar.isSelectedDay = function (m) { 909 | return m && calendar.date.date() === m.date() && calendar.date.month() === m.month() && calendar.date.year() === m.year(); 910 | }; 911 | 912 | calendar.isDateOfTheDay = function (m) { 913 | var today = calendar.picker.options.showTodaysDate; 914 | if (!today) { 915 | return false; 916 | } 917 | 918 | return m && today.date() === m.date() && today.month() === m.month() && today.year() === m.year(); 919 | }; 920 | }], 921 | template: 922 | '' + 18 | ' ' + 85 | '' + 19 | '' + 84 | '' + 20 | ' ' + 26 | '{{picker.currentNearestMinute().format("dddd")}}' + 21 | '{{picker.params.shortTime?picker.currentDate.format("A"):" "}}' + 22 | '' + 23 | ' ×' + 24 | '' + 25 | '' + 27 | '' + //start time 53 | '' + 28 | '' + 39 | '◄' + 29 | '' + 30 | ' ' + 37 | '{{picker.currentDate.format("MMM")|uppercase}}' + 31 | '' + 32 | ' ' + 36 | '' + 33 | ' ' + 35 | '{{itemMonth}} ' + 34 | '►' + 38 | '{{picker.currentDate.format("DD")}}' + 40 | '' + 41 | ''+ 52 | '◄' + 42 | '' + 43 | ' ' + 50 | '{{picker.currentDate.format("YYYY")}}' + 44 | '' + 45 | ' ' + 49 | '' + 46 | ' ' + 48 | '{{itemYear}} ' + 47 | '►' + 51 | '' + 54 | '' + 60 | '' + 55 | ' {{picker.currentNearestMinute().format(picker.params.shortTime ? "hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}'+ 56 | ' {{picker.currentNearestMinute().format(picker.params.shortTime ? "hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}:{{picker.currentNearestMinute().format("ss")}}'+ 57 | ' {{picker.currentDate.format("A")}}'+ 58 | '' + 59 | '' + 61 | '' + 83 | '' + 62 | ' ' + 63 | '' + 82 | '' + 64 | '' + 78 | '' + 65 | ' {{::picker.params.amText}}' + 66 | '' + 67 | '' + 68 | ' {{picker.currentNearestMinute().format(picker.params.shortTime?"hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}' + 69 | '' + 70 | '' + 71 | ' {{picker.currentNearestMinute().format(picker.params.shortTime?"hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}:{{picker.currentNearestMinute().format("ss")}}' + 72 | '' + 73 | '' + 74 | ' {{::picker.params.pmText}}' + 75 | '' + 76 | ' ' + 77 | '' + 79 | ' ' + 80 | ' ' + 81 | ' ' + 86 | ' ' + 90 | '{{::picker.params.todayText}} ' + 87 | '{{::picker.params.cancelText}} ' + 88 | '{{::picker.params.okText}} ' + 89 | '' + 923 | ' ' 927 | }; 928 | }]) 929 | .directive('mdcDatetimePickerCalendarMonth', ['$compile', 930 | function ($compile) { 931 | var buildCalendarContent = function (element, scope) { 932 | var tbody = angular.element(element[0].querySelector('tbody')); 933 | var calendar = scope.cal, month = scope.month; 934 | 935 | var tbodyHtml = []; 936 | 937 | month.days.forEach(function (weekDays, i) { 938 | tbodyHtml.push('' + 924 | ' ' + 925 | '' + 926 | ''); 939 | weekDays.forEach(function (weekDay, j) { 940 | tbodyHtml.push(' '); 958 | }); 959 | 960 | tbody.html(tbodyHtml.join('')); 961 | $compile(tbody)(scope); 962 | }; 963 | 964 | return { 965 | scope: { 966 | idx: '=' 967 | }, 968 | require: '^mdcDatetimePickerCalendar', 969 | restrict: 'AE', 970 | template: 971 | ''); 941 | if (weekDay) { 942 | if (calendar.isInRange(weekDay)) { 943 | //build a 944 | var scopeRef = 'month[\'days\'][' + i + '][' + j + ']'; 945 | 946 | tbodyHtml.push(''); 947 | tbodyHtml.push(weekDay.format('D')); 948 | tbodyHtml.push(''); 949 | } else { 950 | tbodyHtml.push(''); 951 | tbodyHtml.push(weekDay.format('D')); 952 | tbodyHtml.push(''); 953 | } 954 | } 955 | tbodyHtml.push(' '); 956 | }); 957 | tbodyHtml.push('{{month.name}}' + 972 | '' + 973 | ' ' + 974 | '
', 981 | link: function (scope, element, attrs, calendar) { 982 | scope.cal = calendar; 983 | scope.month = calendar.getItemAtIndex(parseInt(scope.idx)); 984 | buildCalendarContent(element, scope); 985 | scope.$watch(function () { 986 | return scope.idx; 987 | }, function (idx, oldIdx) { 988 | if (idx != oldIdx) { 989 | scope.month = calendar.getItemAtIndex(parseInt(scope.idx)); 990 | buildCalendarContent(element, scope); 991 | } 992 | }); 993 | } 994 | }; 995 | } 996 | ]) 997 | ; 998 | 999 | angular.module(moduleName) 1000 | .directive('mdcDtpNoclick', function () { 1001 | return { 1002 | link: function (scope, el) { 1003 | el.on('click', function (e) { 1004 | e.preventDefault(); 1005 | }); 1006 | el.on('dragstart', function (e) { 1007 | e.preventDefault(); 1008 | }); 1009 | } 1010 | }; 1011 | }); 1012 | angular.module(moduleName) 1013 | .directive('mdcDatetimePickerClock', ['$timeout', 1014 | function ($timeout) { 1015 | 1016 | var template = 1017 | '' + 975 | ' ' + 977 | ' ' + 978 | ' ' + 979 | ' ' + 980 | '{{cal.toDay(day)}} ' + 976 | '' + 1018 | ''; 1031 | 1032 | return { 1033 | restrict: 'E', 1034 | template: template, 1035 | link: function (scope, element, attrs) { 1036 | var minuteMode = attrs.mode === 'minutes'; 1037 | var secondMode = attrs.mode === 'seconds'; 1038 | var picker = scope.picker; 1039 | //banking on the fact that there will only be one at a time 1040 | var componentRoot = document.querySelector('md-dialog.dtp'); 1041 | 1042 | var setTimeDegRay = function(deg, ray) { 1043 | var val = 0; 1044 | deg = deg >= 360 ? 0 : deg; 1045 | if (deg !== 0) { 1046 | var divider = minuteMode||secondMode ? 60 : 12; 1047 | val = Math.round(divider / 360 * deg); 1048 | } 1049 | 1050 | if (minuteMode) { 1051 | var nearestMin = picker.params.minuteSteps; 1052 | if (nearestMin < 1 || nearestMin > 59) nearestMin = 1; 1053 | var minutes = (nearestMin * Math.round(val / nearestMin)); 1054 | if (minutes >= 60) minutes = 60 - nearestMin; 1055 | if (!scope.pointAvailable({value: val})) return; 1056 | picker.currentDate.minute(minutes); 1057 | } else if (!secondMode){ 1058 | if (val === 12) val = 0; 1059 | if (!picker.params.shortTime) picker.meridien = ray > 84 ? 'AM' : 'PM'; 1060 | if (picker.isPM()) val += 12; 1061 | if (!scope.pointAvailable({value: val})) return; 1062 | picker.currentDate.hour(val); 1063 | } else { 1064 | if (val >= 60) val = 0; 1065 | if (!scope.pointAvailable({value: val})) return; 1066 | picker.currentDate.second(val); 1067 | } 1068 | }; 1069 | 1070 | var isTouchSupported = ('ontouchstart' in window) ? true : false, 1071 | EVENTS = { 1072 | POINTER_DOWN : isTouchSupported ? 'touchstart' : 'mousedown', 1073 | POINTER_UP : isTouchSupported ? 'touchend' : 'mouseup', 1074 | POINTER_MOVE : isTouchSupported ? 'touchmove' : 'mousemove' 1075 | }; 1076 | 1077 | var onMoveEvent = function(e) { 1078 | e.preventDefault(); 1079 | 1080 | var closestTarget = e.currentTarget.closest('div'), 1081 | clientRect = closestTarget.getClientRects()[0]; 1082 | 1083 | if (isTouchSupported) e = e.changedTouches[0]; 1084 | 1085 | var x = ((closestTarget.offsetWidth / 2) - (e.pageX - clientRect.left)), 1086 | y = ((e.pageY - clientRect.top) - (closestTarget.offsetHeight / 2)); 1087 | 1088 | var ray = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), 1089 | deg = Math.round((Math.atan2(x, y) * (180 / Math.PI))); 1090 | 1091 | $timeout(function() { 1092 | setTimeDegRay(deg+180, ray); 1093 | }); 1094 | }; 1095 | 1096 | element.on(EVENTS.POINTER_DOWN, function() { 1097 | element.on(EVENTS.POINTER_MOVE, onMoveEvent); 1098 | }); 1099 | 1100 | element.on(EVENTS.POINTER_UP, function() { 1101 | element.off(EVENTS.POINTER_MOVE); 1102 | }); 1103 | 1104 | scope.$on("$destroy", function() { 1105 | element.off(EVENTS.POINTER_MOVE, onMoveEvent); 1106 | }); 1107 | 1108 | var exec = function () { 1109 | var clock = angular.element(element[0].querySelector('.dtp-picker-clock')), 1110 | pickerEl = angular.element(componentRoot.querySelector('.dtp-picker')); 1111 | 1112 | var w = componentRoot.querySelector('.dtp-content').offsetWidth; 1113 | var pL = parseInt(css(pickerEl, 'paddingLeft').replace('px', '')) || 0; 1114 | var pR = parseInt(css(pickerEl, 'paddingRight').replace('px', '')) || 0; 1115 | var pT = parseInt(css(pickerEl, 'paddingTop').replace('px', '')) || 0; 1116 | var mL = parseInt(css(clock, 'marginLeft').replace('px', '')) || 0; 1117 | var mR = parseInt(css(clock, 'marginRight').replace('px', '')) || 0; 1118 | var mT = parseInt(css(clock, 'marginTop').replace('px', '')) || 0; 1119 | 1120 | //set width 1121 | var clockWidth = (w - (mL + mR + pL + pR)); 1122 | clock.css('width', (clockWidth) + 'px'); 1123 | 1124 | var r = (clockWidth / 2); 1125 | var j = r / 1.2; // radius for low number 1126 | 1127 | var points = []; 1128 | 1129 | for (var h = 0; h < 12; ++h) { 1130 | var x = j * Math.sin(Math.PI * 2 * (h / 12)); 1131 | var y = j * Math.cos(Math.PI * 2 * (h / 12)); 1132 | var left = (r + x + pL / 2) - (pL + mL); 1133 | var top = (r - y - mT / 2) - (pT + mT); 1134 | 1135 | var hour = { 1136 | left: left, 1137 | top: top, 1138 | value: (minuteMode||secondMode ? (h * 5) : h), //5 for minute 60/12 1139 | style: {'margin-left': left + 'px', 'margin-top': top + 'px'} 1140 | }; 1141 | 1142 | if (minuteMode || secondMode) { 1143 | hour.display = hour.value < 10 ? ('0' + hour.value) : hour.value; 1144 | } else { 1145 | if (picker.params.shortTime) { 1146 | hour.display = h === 0 ? 12 : h; 1147 | } else { 1148 | hour.display = h; 1149 | } 1150 | } 1151 | 1152 | points.push(hour); 1153 | } 1154 | scope.points = points; 1155 | 1156 | if (!picker.params.shortTime && !minuteMode && !secondMode) { 1157 | var points24 = []; 1158 | 1159 | var j24 = r / 1.8; // radius for high number 1160 | for (var h24 = 12; h24 < 24; ++h24) { 1161 | var x24 = j24 * Math.sin(Math.PI * 2 * (h24 / 12)); 1162 | var y24 = j24 * Math.cos(Math.PI * 2 * (h24 / 12)); 1163 | var left24 = (r + x24 + pL / 2) - (pL + mL); 1164 | var top24 = (r - y24 - mT / 2) - (pT + mT); 1165 | 1166 | points24.push({ 1167 | left: left24, 1168 | top: top24, 1169 | value: h24, 1170 | display: h24, 1171 | style: {'margin-left': left24 + 'px', 'margin-top': top24 + 'px'} 1172 | }); 1173 | } 1174 | scope.points24 = points24; 1175 | } 1176 | 1177 | scope.mode = attrs.mode; 1178 | setCurrentValue(); 1179 | clock.css('height', clockWidth + 'px'); 1180 | 1181 | var clockCenter = element[0].querySelector('.dtp-clock-center'); 1182 | var centerWidth = (clockCenter.offsetWidth / 2) || 7.5; 1183 | var centerHeight = (clockCenter.offsetHeight / 2) || 7.5; 1184 | var _hL = r / (picker.params.shortTime ? 1.8 : 2.3); 1185 | var _mL = r / 1.4; 1186 | var _sL = r; 1187 | 1188 | angular.element(element[0].querySelector('.dtp-hour-hand')).css({ 1189 | left: r + (mL * 1.5) + 'px', 1190 | height: _hL + 'px', 1191 | marginTop: (r - _hL - pL) + 'px' 1192 | }).addClass(!minuteMode && !secondMode ? 'on' : ''); 1193 | 1194 | angular.element(element[0].querySelector('.dtp-minute-hand')).css({ 1195 | left: r + (mL * 1.5) + 'px', 1196 | height: _mL + 'px', 1197 | marginTop: r - _mL - pL + 'px' 1198 | }).addClass(minuteMode ? 'on' : ''); 1199 | 1200 | angular.element(element[0].querySelector('.dtp-second-hand')).css({ 1201 | left: r + (mL * 1.5) + 'px', 1202 | height: _sL + 'px', 1203 | marginTop: r - _sL - pL + 'px' 1204 | }).addClass(secondMode ? 'on' : ''); 1205 | 1206 | angular.element(clockCenter).css({ 1207 | left: r + pL + mL - centerWidth + 'px', 1208 | marginTop: (r - (mL / 2)) - centerHeight + 'px' 1209 | }); 1210 | animateHands(); 1211 | }; 1212 | 1213 | var animateHands = function () { 1214 | var _date = picker.currentNearestMinute(); 1215 | var h = _date.hour(), m = _date.minute(), s = _date.second(); 1216 | 1217 | rotateElement(angular.element(element[0].querySelector('.dtp-hour-hand')), 30 * h); 1218 | rotateElement(angular.element(element[0].querySelector('.dtp-minute-hand')), 6 * m); 1219 | rotateElement(angular.element(element[0].querySelector('.dtp-second-hand')), 6 * s); 1220 | }; 1221 | 1222 | var rotateElement = function (el, deg) { 1223 | angular.element(el).css({ 1224 | WebkitTransform: 'rotate(' + deg + 'deg)', 1225 | '-moz-transform': 'rotate(' + deg + 'deg)', 1226 | '-ms-transform': 'rotate(' + deg + 'deg)', 1227 | 'transform': 'rotate(' + deg + 'deg)' 1228 | }); 1229 | }; 1230 | 1231 | 1232 | var setCurrentValue = function () { 1233 | var date = picker.currentNearestMinute(); 1234 | var nbH = picker.params.shortTime ? 12 : 24; 1235 | if (minuteMode) scope.currentValue = date.minute(); 1236 | else if (secondMode) scope.currentValue = date.second(); 1237 | else scope.currentValue = date.hour() % nbH; 1238 | }; 1239 | 1240 | scope.$watch(function () { 1241 | var tmp = picker.currentNearestMinute(); 1242 | return tmp ? tmp.format('HH:mm:ss') : ''; 1243 | }, function () { 1244 | setCurrentValue(); 1245 | animateHands(); 1246 | }); 1247 | 1248 | scope.setTime = function (val) { 1249 | if (!minuteMode && !secondMode) { 1250 | if (val === scope.currentValue && !picker.params.autoOk) picker.ok(); // double click 1251 | 1252 | if (picker.params.shortTime) { 1253 | picker.currentDate.hour(picker.isPM() ? (val + 12) : val); 1254 | } else { 1255 | picker.currentDate.hour(val); 1256 | if (val >= 12) picker.meridien = 'PM'; 1257 | else picker.meridien = 'AM'; 1258 | } 1259 | 1260 | if (picker.params.autoOk) picker.ok(); // single click 1261 | } else if (!secondMode) { 1262 | if (val === scope.currentValue && !picker.params.seconds) picker.ok(); // double click 1263 | 1264 | picker.currentDate.minute(val); 1265 | if (!picker.params.seconds) { 1266 | picker.currentDate.second(0); 1267 | } else if (picker.params.autoOk) picker.ok(); // single click 1268 | } else { 1269 | if (val === scope.currentValue) picker.ok(); // double click 1270 | picker.currentDate.second(val); 1271 | } 1272 | }; 1273 | 1274 | scope.pointAvailable = function (point) { 1275 | if (minuteMode) return picker.isMinuteAvailable(point.value); 1276 | else if (secondMode) return picker.isSecondAvailable(point.value); 1277 | else return picker.isHourAvailable(point.value); 1278 | }; 1279 | 1280 | var unWatcher = scope.$watch(function () { 1281 | return element[0].querySelectorAll('div').length; 1282 | }, function () { 1283 | exec(); 1284 | unWatcher(); 1285 | }); 1286 | } 1287 | }; 1288 | }]); 1289 | return moduleName; 1290 | } 1291 | 1292 | var isElectron = window && window.process && window.process.type; 1293 | if (typeof define === 'function' && define.amd) { 1294 | define(['moment'], ngMaterialDatePicker); 1295 | } else if (typeof module !== 'undefined' && module && module.exports && (typeof require === 'function') && !isElectron) { 1296 | module.exports = ngMaterialDatePicker(require('moment')); 1297 | } else { 1298 | ngMaterialDatePicker((typeof global !== 'undefined' ? global : window).moment); 1299 | } 1300 | })(); 1301 | -------------------------------------------------------------------------------- /js/demo.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | angular.module('mdDatetimePickerDemo', [ 4 | 'ngMaterialDatePicker', 5 | 'pascalprecht.translate', 6 | 'ngMessages' 7 | ]) 8 | .config(function($translateProvider) { 9 | $translateProvider.translations('en', { 10 | CANCEL: "Cancel", 11 | TODAY: "Today", 12 | INSTRUCTION: "You can double click or double tap to make selections.", 13 | }); 14 | $translateProvider.translations('fr', { 15 | CANCEL: "Annuler", 16 | TODAY: "Aujourd'hui", 17 | INSTRUCTION: "Vous pouvez double-cliquer ou appuyer deux fois pour effectuer des sélections.", 18 | }); 19 | $translateProvider.preferredLanguage('en'); 20 | $translateProvider.useSanitizeValueStrategy('sceParameters'); 21 | }) 22 | .run(['$templateCache', function($templateCache) { 23 | $templateCache.put( 24 | 'customTemplate.html', 25 | '' + 1019 | ' {{point.display}}' + 1020 | ' {{point.display}}' + 1021 | '' + 1022 | '' + 1023 | ' {{point24.display}}' + 1024 | ' {{point24.display}}' + 1025 | '' + 1026 | '' + 1027 | '' + 1028 | '' + 1029 | '' + 1030 | '' + 26 | ' ' 66 | ); 67 | }]) 68 | .controller('DemoCtrl', function ($scope, mdcDateTimeDialog, $translate, mdcDefaultParams) { 69 | $scope.date = moment().startOf('day'); 70 | $scope.dateLang = new Date(); 71 | $scope.time = new Date(); 72 | $scope.timeutc = moment.utc(); 73 | $scope.dateTime = new Date(); 74 | $scope.dateTimeEdit = new Date(); 75 | $scope.timez = moment.utc(); 76 | $scope.timeEdit = new Date(); 77 | 78 | // current date + 1 hour, no minutes, no seconds, no milliseconds 79 | var newDate = new Date(); 80 | newDate.setHours(newDate.getHours() +1, 0, 0, 0); 81 | $scope.dateTimeNoMin = newDate; 82 | 83 | $scope.minDate = moment().subtract(6, 'year'); 84 | $scope.minDateNow = moment(); 85 | $scope.maxDateNow = moment(); 86 | $scope.maxDate = moment().add(6, 'year'); 87 | $scope.dates = [new Date('2018-11-14T00:00:00'), new Date('2018-11-15T00:00:00'), 88 | new Date('2018-11-30T00:00:00'), new Date('2018-12-12T00:00:00'), new Date('2018-12-13T00:00:00'), 89 | new Date('2018-12-31T00:00:00')]; 90 | 91 | $scope.langs = [{'value': 'en', 'label': 'English'},{'value': 'fr', 'label': 'Français'}]; 92 | 93 | $scope.displayDialog = function(event) { 94 | mdcDateTimeDialog.show({ 95 | currentDate: moment().startOf('day'), 96 | maxDate: $scope.maxDate, 97 | showTodaysDate: true, 98 | time: true, 99 | clickOutsideToClose: true, 100 | targetEvent: event, 101 | openFrom: angular.element(document.querySelector('#pickerbutton')), 102 | closeTo: angular.element(document.querySelector('#pickerbutton')) 103 | }).then(function (date) { 104 | $scope.selectedDateTime = date; 105 | console.log('New Date / Time selected:', date); 106 | }, function(){}); 107 | }; 108 | 109 | // Set and change the text direction 110 | $scope.txtdir = document.documentElement.dir || 'ltr'; 111 | $scope.changeDir = function () { 112 | $scope.txtdir = document.documentElement.dir = ($scope.txtdir === 'rtl') ? 'ltr' : 'rtl'; 113 | }; 114 | 115 | $scope.changeLanguage = function() { 116 | $translate.use($scope.selectedLang); 117 | moment.locale($scope.selectedLang); 118 | mdcDefaultParams({ 119 | lang: $scope.selectedLang, 120 | cancelText: $translate.instant('CANCEL'), 121 | todayText: $translate.instant('TODAY') 122 | }); 123 | }; 124 | 125 | $scope.change = function() { 126 | console.log("changed"); 127 | }; 128 | 129 | }) 130 | 131 | .directive('exSourceCode', function () { 132 | return { 133 | template: '' + 27 | ' ' + 60 | '' + 28 | '' + 59 | '' + 29 | '' + 35 | '' + 30 | ' {{picker.currentNearestMinute().format(picker.params.shortTime ? "hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}'+ 31 | ' {{picker.currentNearestMinute().format(picker.params.shortTime ? "hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}:{{picker.currentNearestMinute().format("ss")}}'+ 32 | ' {{picker.currentDate.format("A")}}'+ 33 | '' + 34 | '' + 36 | '' + 58 | '' + 37 | ' ' + 38 | '' + 57 | '' + 39 | '' + 53 | '' + 40 | ' {{picker.params.amText}}' + 41 | '' + 42 | '' + 43 | ' {{picker.currentNearestMinute().format(picker.params.shortTime ? "hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}' + 44 | '' + 45 | '' + 46 | ' {{picker.currentNearestMinute().format(picker.params.shortTime ? "hh":"HH")}}:{{picker.currentNearestMinute().format("mm")}}:{{picker.currentNearestMinute().format("ss")}}' + 47 | '' + 48 | '' + 49 | ' {{picker.params.pmText}}' + 50 | '' + 51 | ' ' + 52 | '' + 54 | ' ' + 55 | ' ' + 56 | ' ' + 61 | ' ' + 65 | '{{picker.params.todayText}} ' + 62 | '{{picker.params.cancelText}} ' + 63 | '{{picker.params.okText}} ' + 64 | '{{title}}
', 134 | scope: {}, 135 | link: function (scope, element, attrs) { 136 | var tmp = angular.element((element.parent()[0]).querySelector(attrs.target || 'md-input-container')); 137 | if (tmp.length) { 138 | scope.title = attrs.title || "Source Code"; 139 | var sourceCode = tmp[0].outerHTML 140 | .replace('ng-model=', 'angularModel=') 141 | .replace('ng-model-options=', 'angularModelOptions=') 142 | .replace('ng-click=', 'angularClick=') 143 | .replace(/ng-[a-z\-]+/g, '') 144 | .replace(/ +/g, ' ') 145 | .replace('angularModel=', 'ng-model=') 146 | .replace('angularModelOptions=', 'ng-model-options=') 147 | .replace('angularClick=', 'ng-click='); 148 | 149 | scope.sourceCode = style_html(sourceCode, { 150 | 'indent_size': 2, 151 | 'indent_char': ' ', 152 | 'max_char': 78, 153 | 'brace_style': 'expand' 154 | }); 155 | } 156 | } 157 | }; 158 | }) 159 | .directive('hljs', function ($timeout) { 160 | return { 161 | link: function (scope, element) { 162 | $timeout(function () { 163 | hljs.highlightBlock(element[0].querySelector('code')); 164 | }, 100); 165 | } 166 | }; 167 | }) 168 | ; 169 | })(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-material-datetimepicker", 3 | "description": "A datetime picker for AngularJS Material", 4 | "version": "1.20.0", 5 | "keywords": [ 6 | "css", 7 | "js", 8 | "mobile-first", 9 | "angular", 10 | "material", 11 | "angular-material", 12 | "responsive", 13 | "front-end", 14 | "web" 15 | ], 16 | "homepage": "https://beenote.github.io/angular-material-datetimepicker/", 17 | "main": "js/angular-material-datetimepicker.js", 18 | "scripts": { 19 | "build": "yarn node build", 20 | "start": "web-dev-server --watch --open" 21 | }, 22 | "dependencies": { 23 | "angular": "^1.8.3", 24 | "angular-animate": "^1.8.3", 25 | "angular-aria": "^1.8.3", 26 | "angular-material": "^1.2.5", 27 | "angular-messages": "^1.8.3", 28 | "moment": "^2.29.4" 29 | }, 30 | "repository": { 31 | "type": "git", 32 | "url": "https://github.com/beenote/angular-material-datetimepicker" 33 | }, 34 | "devDependencies": { 35 | "@web/dev-server": "^0.1.35", 36 | "esbuild": "^0.15.16" 37 | }, 38 | "packageManager": "yarn@3.3.0" 39 | } 40 | --------------------------------------------------------------------------------{{sourceCode}}