├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── demo.html
├── dist
├── main.js
├── style.css
└── style.js
├── package.json
├── src
├── datetime.js
├── main.css
├── main.js
├── md-datetime.html
├── md-timepicker.html
└── timepicker.js
└── webpack.config.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | "ecmaVersion": 6,
4 | "sourceType": "module"
5 | },
6 | "env": {
7 | "browser": true,
8 | "commonjs": true,
9 | "es6": true
10 | },
11 | "globals": {
12 | "angular": true,
13 | "moment": true
14 | },
15 | "extends": "eslint:recommended",
16 | "rules": {
17 | "no-console": 0,
18 | "no-debugger": 0,
19 |
20 | "prefer-template": 1,
21 | "constructor-super": 2,
22 | "no-shadow": 2,
23 | "no-use-before-define": 2,
24 | "no-else-return": 2,
25 | "no-unused-expressions": [2, { "allowShortCircuit": true }],
26 | "no-unused-vars": [2, {"args": "after-used", "varsIgnorePattern": "^_", "argsIgnorePattern": "^_"}],
27 | "no-const-assign": 2,
28 | "no-dupe-class-members": 2,
29 | "no-this-before-super": 2,
30 |
31 | "arrow-spacing": 2,
32 | "brace-style": [2, "1tbs", { "allowSingleLine": true }],
33 | "curly": 2,
34 | "key-spacing": 2,
35 | "eol-last": 2,
36 | "object-curly-spacing": [2, "always"],
37 | "quote-props": [2, "as-needed"],
38 | "padded-blocks": [2, "never"],
39 | "semi": [2, "always"],
40 | "space-in-parens": [2, "never"],
41 | "space-infix-ops": 2,
42 | "object-shorthand": [2, "always"],
43 | "no-var": 2,
44 | "no-extra-parens": 2,
45 | "no-multi-spaces": 2,
46 | "no-mixed-spaces-and-tabs": 2,
47 | "no-multiple-empty-lines": [2, { "max": 2 }],
48 | "no-negated-condition": 2,
49 | "no-trailing-spaces": 2,
50 | "no-underscore-dangle": 2
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | node_modules
28 |
29 | # Optional npm cache directory
30 | .npm
31 |
32 | # Optional REPL history
33 | .node_repl_history
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Po Chen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # md-datetime
2 |
3 | [](https://badge.fury.io/js/md-datetime)
4 |
5 | Angular material datetime picker
6 |
7 | see [live demo](https://rawgit.com/princemaple/md-datetime/master/demo.html)
8 |
9 | ```html
10 |
11 | ```
12 |
13 | Simply use it as other input widgets
14 |
--------------------------------------------------------------------------------
/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | md-datetime demo
6 |
7 |
8 |
12 |
13 |
14 |
15 | Angular Material Datetime Picker
16 |
17 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
43 |
44 | Fork me on GitHub
45 |
46 |
47 |
--------------------------------------------------------------------------------
/dist/main.js:
--------------------------------------------------------------------------------
1 | !function(e){function t(n){if(i[n])return i[n].exports;var r=i[n]={exports:{},id:n,loaded:!1};return e[n].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t,i){"use strict";angular.module("mdDatetime",["ngMaterial"]),i(4),i(3)},function(e,t){e.exports=' Reset to NOW '},function(e,t){e.exports=' '},function(e,t,i){"use strict";angular.module("mdDatetime").component("mdDatetime",{require:{modelCtrl:"ngModel"},template:i(1),controller:["$attrs",function(e){var t=this;this.$onInit=function(){t.modelCtrl.$render=function(){t.datetime=moment(t.modelCtrl.$modelValue),t.updateParams(!0)}},this.updateDate=function(){var e=moment(t.params.date);t.datetime.year(e.year()),t.datetime.month(e.month()),t.datetime.date(e.date()),t.updateParams()},this.updateTime=function(){t.datetime.hour(t.params.time.hour),t.datetime.minute(t.params.time.minute),t.updateParams()},this.updateParams=function(e){t.params={date:t.datetime.toDate(),time:{hour:t.datetime.hour(),minute:t.datetime.minute()}},e||t.modelCtrl.$setViewValue(t.datetime.toISOString())},this.canReset=!("noReset"in e),this.reset=function(){t.datetime=moment(),t.updateParams()}}],controllerAs:"DT"})},function(e,t,i){"use strict";var n=function(){function e(e,t){var i=[],n=!0,r=!1,o=void 0;try{for(var m,a=e[Symbol.iterator]();!(n=(m=a.next()).done)&&(i.push(m.value),!t||i.length!==t);n=!0);}catch(u){r=!0,o=u}finally{try{!n&&a["return"]&&a["return"]()}finally{if(r)throw o}}return i}return function(t,i){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,i);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}();angular.module("mdDatetime").component("mdTimepicker",{template:i(2),bindings:{mode:"@"},require:{modelCtrl:"ngModel"},controller:["$scope","$window",function(e,t){var i=this;this.$onInit=function(){i.modelCtrl.$render=function(){i.viewValue=moment(i.modelCtrl.$modelValue).format("HH:mm");var e=i.modelCtrl.$modelValue,t=e.hour,n=e.minute;i.hours.forEach(function(e){e.selected=e.realValue==t}),i.minutes.forEach(function(e,t){e.selected=(Math.floor(n/5)+11)%12==t})},angular.element(t).on("click",function(){i.picking=!1,e.$digest()})},this.keepPicking=function(e){e.stopPropagation()},this.outerHours=["1","2","3","4","5","6","7","8","9","10","11","12"],this.innerHours=["13","14","15","16","17","18","19","20","21","22","23","00"],this.minutes=["05","10","15","20","25","30","35","40","45","50","55","00"];var r=function(e,t){return function(i,n){var r=30*n+30;return{type:e,viewValue:i,realValue:parseInt(i,10),style:{transform:"rotate("+r+"deg) translate(0, -"+t+"px) rotate(-"+r+"deg)"}}}};this.outerHours=this.outerHours.map(r("hour",80)),this.innerHours=this.innerHours.map(r("hour",55)),this.ampm="ampm"==this.mode,this.ampm&&(this.innerHours=[]),this.hours=this.outerHours.concat(this.innerHours),this.minutes=this.minutes.map(r("minute",80)),this.togglePicking=function(e){return i.picking?i.picking=!1:(i.picking=!0,i.pickHour(),void i.keepPicking(e))},this.pickHour=function(){i.pickingMinute=!1,i.pickingHour=!0},this.pickMinute=function(){i.pickingHour=!1,i.pickingMinute=!0},this.selectHour=function(e){i.modelCtrl.$setViewValue({hour:e.realValue,minute:i.modelCtrl.$modelValue.minute}),i.outerHours.forEach(function(e){e.selected=!1}),i.innerHours.forEach(function(e){e.selected=!1}),e.selected=!0,i.pickMinute()},this.selectMinute=function(e){i.modelCtrl.$setViewValue({hour:i.modelCtrl.$modelValue.hour,minute:e.realValue}),i.minutes.forEach(function(e){e.selected=!1}),e.selected=!0,i.picking=!1},this.timePattern=/^[0-2]?[0-9]:[0-5][0-9]$/,this.parse=function(){if(i.viewValue){var e=i.viewValue.split(":"),t=n(e,2),r=t[0],o=t[1];i.modelCtrl.$setViewValue({hour:r,minute:o})}},this.time={hour:function(){return moment(i.modelCtrl.$modelValue).format("HH")},minute:function(){return moment(i.modelCtrl.$modelValue).format("mm")}}}],controllerAs:"T"})}]);
--------------------------------------------------------------------------------
/dist/style.css:
--------------------------------------------------------------------------------
1 | .md-datetime-picker-reset{vertical-align:middle}.md-timepicker-widget{position:relative;display:inline-block;outline:none}.md-timepicker-widget .md-errors-spacer{display:none}.md-timepicker-widget .md-datepicker-triangle-button{top:6px}.md-timepicker-popup{position:absolute;top:0;left:0;background:#eee;width:240px;height:288px;overflow:hidden;z-index:99}.md-timepicker-popup.ng-enter{-webkit-transition:-webkit-transform .1s ease-out;transition:-webkit-transform .1s ease-out;transition:transform .1s ease-out;transition:transform .1s ease-out,-webkit-transform .1s ease-out;-webkit-transform:translate(-50%,-50%) scale(.8) translate(50%,50%);transform:translate(-50%,-50%) scale(.8) translate(50%,50%)}.md-timepicker-popup.ng-enter-active{-webkit-transform:scale(1);transform:scale(1)}.md-timepicker-time{text-align:center;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center}.md-timepicker-time-hour,.md-timepicker-time-minute{font-size:32px;cursor:pointer;outline:none}.md-timepicker-time-hour.selected,.md-timepicker-time-minute.selected{font-weight:600;color:#fff}.md-timepicker-clock{position:absolute;left:0;top:64px;background-color:#ddd;width:200px;height:200px;border-radius:50%;margin:12px 20px}.md-timepicker-clock.ng-leave{-webkit-transition:all .3s ease-out;transition:all .3s ease-out;z-index:99;-webkit-transform:scale(1);transform:scale(1);opacity:1}.md-timepicker-clock.ng-leave-active{-webkit-transform:scale(1.2);transform:scale(1.2);opacity:0}.md-timepicker-clock-hour,.md-timepicker-clock-minute,.md-timepicker-hour-number,.md-timepicker-minute-number{position:absolute;top:50%;left:50%}.md-timepicker-clock-hour,.md-timepicker-clock-minute{cursor:pointer}.md-timepicker-hour-number,.md-timepicker-minute-number{-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)}.md-timepicker-hour-number:hover:after,.md-timepicker-minute-number:hover:after,.selected>.md-timepicker-hour-number:after,.selected>.md-timepicker-minute-number:after{content:"";position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);border:14px solid #ccc;border-radius:50%;z-index:-1}.selected>.md-timepicker-hour-number:after,.selected>.md-timepicker-minute-number:after{border:14px solid #aaa}
--------------------------------------------------------------------------------
/dist/style.js:
--------------------------------------------------------------------------------
1 | !function(r){function t(o){if(e[o])return e[o].exports;var n=e[o]={exports:{},id:o,loaded:!1};return r[o].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var e={};return t.m=r,t.c=e,t.p="",t(0)}([function(r,t){}]);
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "md-datetime",
3 | "version": "0.2.1",
4 | "description": "Angular material datetime picker",
5 | "main": "dist/main.js",
6 | "scripts": {
7 | "dev": "webpack --progress -w",
8 | "dist": "webpack -p",
9 | "test": "echo \"Error: no test specified\" && exit 1"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/princemaple/md-datetime.git"
14 | },
15 | "keywords": [
16 | "angular",
17 | "material",
18 | "datetime",
19 | "picker"
20 | ],
21 | "author": "Po Chen",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/princemaple/md-datetime/issues"
25 | },
26 | "homepage": "https://github.com/princemaple/md-datetime#readme",
27 | "dependencies": {
28 | "angular": "^1.6.3",
29 | "angular-material": "^1.1.3",
30 | "moment": "^2.18.1"
31 | },
32 | "devDependencies": {
33 | "autoprefixer": "^7.1.1",
34 | "babel-core": "^6.24.1",
35 | "babel-loader": "^7.0.0",
36 | "babel-preset-es2015": "^6.24.1",
37 | "css-loader": "^0.28.2",
38 | "eslint": "^3.18.0",
39 | "eslint-loader": "^1.7.0",
40 | "extract-text-webpack-plugin": "^2.0.0",
41 | "html-loader": "^0.4.5",
42 | "ng-annotate-loader": "^0.6.0",
43 | "postcss-import": "^10.0.0",
44 | "postcss-loader": "^2.0.3",
45 | "postcss-nested": "^2.0.2",
46 | "postcss-simple-vars": "^4.0.0",
47 | "style-loader": "^0.18.0",
48 | "webpack": "^2.5.1"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/datetime.js:
--------------------------------------------------------------------------------
1 | angular.module('mdDatetime')
2 | .component('mdDatetime', {
3 | require: {
4 | modelCtrl: 'ngModel'
5 | },
6 | template: require('html!./md-datetime.html'),
7 | controller($attrs) {
8 | this.$onInit = () => {
9 | this.modelCtrl.$render = () => {
10 | this.datetime = moment(this.modelCtrl.$modelValue);
11 | this.updateParams(true);
12 | };
13 | };
14 |
15 | this.updateDate = () => {
16 | let newDate = moment(this.params.date);
17 |
18 | this.datetime.year(newDate.year());
19 | this.datetime.month(newDate.month());
20 | this.datetime.date(newDate.date());
21 |
22 | this.updateParams();
23 | };
24 |
25 | this.updateTime = () => {
26 | this.datetime.hour(this.params.time.hour);
27 | this.datetime.minute(this.params.time.minute);
28 |
29 | this.updateParams();
30 | };
31 |
32 | this.updateParams = (init) => {
33 | this.params = {
34 | date: this.datetime.toDate(),
35 | time: {
36 | hour: this.datetime.hour(),
37 | minute: this.datetime.minute()
38 | }
39 | };
40 |
41 | if (init) { return; }
42 | this.modelCtrl.$setViewValue(this.datetime.toISOString());
43 | };
44 |
45 | this.canReset = !('noReset' in $attrs);
46 |
47 | this.reset = () => {
48 | this.datetime = moment();
49 | this.updateParams();
50 | };
51 | },
52 | controllerAs: 'DT'
53 | });
54 |
--------------------------------------------------------------------------------
/src/main.css:
--------------------------------------------------------------------------------
1 | .md-datetime-picker-reset {
2 | vertical-align: middle;
3 | }
4 |
5 | .md-timepicker-widget {
6 | position: relative;
7 | display: inline-block;
8 | outline: none;
9 |
10 | .md-errors-spacer {
11 | display: none;
12 | }
13 |
14 | .md-datepicker-triangle-button {
15 | top: 6px;
16 | }
17 | }
18 |
19 | .md-timepicker-popup {
20 | position: absolute;
21 | top: 0;
22 | left: 0;
23 | background: #eee;
24 | width: 240px;
25 | height: 288px;
26 | overflow: hidden;
27 | z-index: 99;
28 |
29 | &.ng-enter {
30 | transition: transform 0.1s ease-out;
31 | }
32 |
33 | &.ng-enter {
34 | transform: translate(-50%, -50%) scale(0.8) translate(50%, 50%);
35 | }
36 |
37 | &.ng-enter-active {
38 | transform: scale(1);
39 | }
40 | }
41 |
42 | .md-timepicker-time {
43 | text-align: center;
44 | flex-direction: row;
45 | justify-content: center;
46 | align-items: center;
47 | }
48 |
49 | .md-timepicker-time-hour,
50 | .md-timepicker-time-minute {
51 | font-size: 32px;
52 | cursor: pointer;
53 | outline: none;
54 |
55 | &.selected {
56 | font-weight: 600;
57 | color: #fff;
58 | }
59 | }
60 |
61 | .md-timepicker-clock {
62 | position: absolute;
63 | left: 0;
64 | top: 64px;
65 | background-color: #ddd;
66 | width: 200px;
67 | height: 200px;
68 | border-radius: 50%;
69 | margin: 12px 20px;
70 |
71 | &.ng-leave {
72 | transition: all .3s ease-out;
73 | z-index: 99;
74 | }
75 |
76 | &.ng-leave {
77 | transform: scale(1);
78 | opacity: 1;
79 | }
80 |
81 | &.ng-leave-active {
82 | transform: scale(1.2);
83 | opacity: 0;
84 | }
85 | }
86 |
87 | .md-timepicker-clock-hour,
88 | .md-timepicker-clock-minute,
89 | .md-timepicker-hour-number,
90 | .md-timepicker-minute-number {
91 | position: absolute;
92 | top: 50%;
93 | left: 50%;
94 | }
95 |
96 | .md-timepicker-clock-hour,
97 | .md-timepicker-clock-minute {
98 | cursor: pointer;
99 | }
100 |
101 | .md-timepicker-hour-number,
102 | .md-timepicker-minute-number {
103 | transform: translate(-50%, -50%);
104 |
105 | .selected > &::after,
106 | &:hover::after {
107 | content: "";
108 | position: absolute;
109 | top: 50%;
110 | left: 50%;
111 | transform: translate(-50%, -50%);
112 | border: 14px solid #ccc;
113 | border-radius: 50%;
114 | z-index: -1;
115 | }
116 |
117 | .selected > &::after {
118 | border: 14px solid #aaa;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | angular.module('mdDatetime', ['ngMaterial']);
2 |
3 | require('./timepicker');
4 | require('./datetime');
5 |
--------------------------------------------------------------------------------
/src/md-datetime.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 | Reset to NOW
11 |
12 |
--------------------------------------------------------------------------------
/src/md-timepicker.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
10 |
11 |
50 |
--------------------------------------------------------------------------------
/src/timepicker.js:
--------------------------------------------------------------------------------
1 | angular.module('mdDatetime')
2 | .component('mdTimepicker', {
3 | template: require('html!./md-timepicker.html'),
4 | bindings: { mode: '@' },
5 | require: {
6 | modelCtrl: 'ngModel'
7 | },
8 | controller($scope, $window) {
9 | this.$onInit = () => {
10 | this.modelCtrl.$render = () => {
11 | this.viewValue = moment(this.modelCtrl.$modelValue).format('HH:mm');
12 |
13 | let { hour, minute } = this.modelCtrl.$modelValue;
14 |
15 | this.hours.forEach(h => { h.selected = h.realValue == hour; });
16 | this.minutes.forEach((m, index) => { m.selected = (Math.floor(minute / 5) + 11) % 12 == index; });
17 | };
18 |
19 | angular.element($window).on('click', () => {
20 | this.picking = false;
21 | $scope.$digest();
22 | });
23 | };
24 |
25 | this.keepPicking = (event) => { event.stopPropagation(); };
26 |
27 | this.outerHours = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'];
28 | this.innerHours = ['13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '00'];
29 | this.minutes = ['05', '10', '15', '20', '25', '30', '35', '40', '45', '50', '55', '00'];
30 |
31 | let processClockNumber = (type, size) => {
32 | return (viewValue, index) => {
33 | let deg = index * 30 + 30;
34 |
35 | return {
36 | type,
37 | viewValue,
38 | realValue: parseInt(viewValue, 10),
39 | style: {
40 | transform: `rotate(${deg}deg) translate(0, -${size}px) rotate(-${deg}deg)`
41 | }
42 | };
43 | };
44 | };
45 |
46 | this.outerHours = this.outerHours.map(processClockNumber('hour', 80));
47 | this.innerHours = this.innerHours.map(processClockNumber('hour', 55));
48 |
49 | this.ampm = this.mode == 'ampm';
50 | if (this.ampm) { this.innerHours = []; }
51 |
52 | this.hours = this.outerHours.concat(this.innerHours);
53 | this.minutes = this.minutes.map(processClockNumber('minute', 80));
54 |
55 | this.togglePicking = (event) => {
56 | if (this.picking) { return this.picking = false; }
57 |
58 | this.picking = true;
59 | this.pickHour();
60 |
61 | this.keepPicking(event);
62 | };
63 |
64 | this.pickHour = () => {
65 | this.pickingMinute = false;
66 | this.pickingHour = true;
67 | };
68 |
69 | this.pickMinute = () => {
70 | this.pickingHour = false;
71 | this.pickingMinute = true;
72 | };
73 |
74 | this.selectHour = (hour) => {
75 | this.modelCtrl.$setViewValue({
76 | hour: hour.realValue,
77 | minute: this.modelCtrl.$modelValue.minute
78 | });
79 |
80 | this.outerHours.forEach(h => { h.selected = false; });
81 | this.innerHours.forEach(h => { h.selected = false; });
82 | hour.selected = true;
83 |
84 | this.pickMinute();
85 | };
86 |
87 | this.selectMinute = (minute) => {
88 | this.modelCtrl.$setViewValue({
89 | hour: this.modelCtrl.$modelValue.hour,
90 | minute: minute.realValue
91 | });
92 |
93 | this.minutes.forEach(m => { m.selected = false; });
94 | minute.selected = true;
95 |
96 | this.picking = false;
97 | };
98 |
99 | this.timePattern = /^[0-2]?[0-9]:[0-5][0-9]$/;
100 |
101 | this.parse = () => {
102 | if (!this.viewValue) { return; }
103 |
104 | let [hour, minute] = this.viewValue.split(':');
105 |
106 | this.modelCtrl.$setViewValue({ hour, minute });
107 | };
108 |
109 | this.time = {
110 | hour: () => moment(this.modelCtrl.$modelValue).format('HH'),
111 | minute: () => moment(this.modelCtrl.$modelValue).format('mm')
112 | };
113 | },
114 | controllerAs: 'T'
115 | });
116 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | let path = require('path');
4 |
5 | let autoprefixer = require('autoprefixer');
6 | let cssImport = require('postcss-import');
7 | let cssNested = require('postcss-nested');
8 | let cssVars = require('postcss-simple-vars');
9 |
10 | let ExtractTextPlugin = require('extract-text-webpack-plugin');
11 | let ExtractCSS = new ExtractTextPlugin(1, 'style.css');
12 |
13 | module.exports = {
14 | context: path.resolve(__dirname, 'src'),
15 | entry: {
16 | main: './main.js',
17 | style: './main.css'
18 | },
19 | output: {
20 | path: path.resolve(__dirname, 'dist'),
21 | filename: '[name].js'
22 | },
23 | module: {
24 | preLoaders: [
25 | { test: /\.js$/, loader: 'eslint-loader' }
26 | ],
27 | loaders: [
28 | {
29 | test: /\.js$/,
30 | loaders: ['ng-annotate', 'babel?presets[]=es2015']
31 | },
32 | {
33 | test: /\.css$/,
34 | loader: ExtractCSS.extract('style', 'css!postcss')
35 | }
36 | ]
37 | },
38 | eslint: {
39 | fix: true,
40 | configFile: './.eslintrc',
41 | emitWarning: true,
42 | emitError: true,
43 | failOnWarning: false,
44 | failOnError: true
45 | },
46 | postcss: (webpack) => [
47 | cssImport({ addDependencyTo: webpack }),
48 | cssNested(),
49 | cssVars(),
50 | autoprefixer
51 | ],
52 | plugins: [ExtractCSS],
53 | watchOptions: {
54 | poll: true,
55 | aggregateTimeout: 1000
56 | }
57 | };
58 |
--------------------------------------------------------------------------------