diff --git a/docs/directives/time.md b/docs/directives/time.md index 14ac2c4..d8fec0d 100644 --- a/docs/directives/time.md +++ b/docs/directives/time.md @@ -1,23 +1,44 @@ Time === -A directive for creating a time input field +A directive for creating a time input field. Time input can use any `ng-` attributes support by text input type. ### Parameters -**mac-time-model** +**ng-model** Type: `String` Assignable angular expression to data-bind to Clearing model by setting it to null or '' will set model back to default value -**mac-time-placeholder** +**name** Type: `String` -Placeholder text of the text input (default --:--) +Property name of the form under which the control is published -**mac-time-disabled** +**required** +Type: `String` +Adds `required` validation error key if the value is not entered. + +**ng-required** +Type: `String` +Adds `required` attribute and `required` validation constraint to + the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + `required` when you want to data-bind to the `required` attribute. + +**ng-pattern** +Type: `String` +Sets `pattern` validation error key if the value does not match the + RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + patterns defined as scope expressions. + +**ng-change** +Type: `String` +Angular expression to be executed when input changes due to user interaction with the input element. + +**ng-disabled** Type: `String` Enable or disable time input + **mac-time-default** Type: `String` If model is undefined, use this as the starting value (default 12:00 PM) diff --git a/docs/html/directives/time.html b/docs/html/directives/time.html index 2d86bee..c8436ff 100644 --- a/docs/html/directives/time.html +++ b/docs/html/directives/time.html @@ -1,7 +1,11 @@

Time

-

A directive for creating a time input field

+

A directive for creating a time input field. Time input can use any ng- attributes support by text input type.

Parameters

-

mac-time-model
Type: String
Assignable angular expression to data-bind to
Clearing model by setting it to null or '' will set model back to default value

-

mac-time-placeholder
Type: String
Placeholder text of the text input (default --:--)

-

mac-time-disabled
Type: String
Enable or disable time input

+

ng-model
Type: String
Assignable angular expression to data-bind to
Clearing model by setting it to null or '' will set model back to default value

+

name
Type: String
Property name of the form under which the control is published

+

required
Type: String
Adds required validation error key if the value is not entered.

+

ng-required
Type: String
Adds required attribute and required validation constraint to
the element when the ngRequired expression evaluates to true. Use ngRequired instead of
required when you want to data-bind to the required attribute.

+

ng-pattern
Type: String
Sets pattern validation error key if the value does not match the
RegExp pattern expression. Expected value is /regexp/ for inline patterns or regexp for
patterns defined as scope expressions.

+

ng-change
Type: String
Angular expression to be executed when input changes due to user interaction with the input element.

+

ng-disabled
Type: String
Enable or disable time input

mac-time-default
Type: String
If model is undefined, use this as the starting value (default 12:00 PM)

diff --git a/docs/index.jade b/docs/index.jade index dd5b111..0cf67d2 100644 --- a/docs/index.jade +++ b/docs/index.jade @@ -314,14 +314,14 @@ block append content h3 Example .docs-example mac-time( - mac-time-id = "input-start-time" - mac-time-model = "myStartTime" + id = "input-start-time" + ng-model = "myStartTime" mac-time-default = "11:59 PM" ) pre.prettyprint. <mac-time - mac-time-id="input-start-time" - mac-time-model="myStartTime" + id="input-start-time" + ng-model="myStartTime" mac-time-default="11:59 PM"> </mac-time> diff --git a/src/directives/time.coffee b/src/directives/time.coffee index 69d6726..dd43dca 100644 --- a/src/directives/time.coffee +++ b/src/directives/time.coffee @@ -2,127 +2,148 @@ @chalk overview @name Time @description -A directive for creating a time input field +A directive for creating a time input field. Time input can use any `ng-` attributes support by text input type. -@param {String} mac-time-model Assignable angular expression to data-bind to +@param {String} ng-model Assignable angular expression to data-bind to Clearing model by setting it to null or '' will set model back to default value -@param {String} mac-time-placeholder Placeholder text of the text input (default --:--) -@param {String} mac-time-disabled Enable or disable time input -@param {String} mac-time-default If model is undefined, use this as the starting value (default 12:00 PM) +@param {String} name Property name of the form under which the control is published +@param {String} required Adds `required` validation error key if the value is not entered. +@param {String} ng-required Adds `required` attribute and `required` validation constraint to + the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + `required` when you want to data-bind to the `required` attribute. +@param {String} ng-pattern Sets `pattern` validation error key if the value does not match the + RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + patterns defined as scope expressions. +@param {String} ng-change Angular expression to be executed when input changes due to user interaction with the input element. +@param {String} ng-disabled Enable or disable time input + +@param {String} mac-time-default If model is undefined, use this as the starting value (default 12:00 PM) ### angular.module("Mac").directive "macTime", [ "$filter" "$timeout" - "util" "keys" - ($filter, $timeout, util, keys) -> - restrict: "E" - scope: - model: "=macTimeModel" - disabled: "=macTimeDisabled" + "util" + ( + $filter + $timeout + keys + util + ) -> + defaults = + default: "12:00 AM" + + restrict: "E" + require: "ngModel" replace: true templateUrl: "template/time.html" + link: ($scope, element, attrs, ngModelCtrl) -> + opts = util.extendAttributes "macTime", defaults, attrs + time = null - compile: (element, attrs) -> - - defaults = - placeholder: "--:--" - default: "12:00 AM" + # Set default placeholder + unless attrs.placeholder + attrs.$set "placeholder", "--:--" - opts = util.extendAttributes "macTime", defaults, attrs + # Validation + timeValidator = (value) -> + if !value or util.timeRegex.exec(value) + ngModelCtrl.$setValidity "time", true - ($scope, element, attrs) -> - $scope.placeholder = opts.placeholder + return value + else + ngModelCtrl.$setValidity "time", false - inputDOM = element[0].getElementsByTagName("input")[0] + return undefined - do initializeTime = -> - currentDate = new Date().toDateString() - time = new Date currentDate + " " + opts.default + ngModelCtrl.$formatters.push timeValidator + ngModelCtrl.$parsers.push timeValidator - if isNaN time.getTime() - time = new Date currentDate + " " + defaults.default + do initializeTime = -> + currentDate = new Date().toDateString() + time = new Date currentDate + " " + opts.default - # - # @name $scope.time - # @description - # Javscript date variable for easier datetime manipulation - # - $scope.time = time + if isNaN time.getTime() + time = new Date currentDate + " " + defaults.default - getSelection = -> - start = inputDOM.selectionStart + getSelection = -> + start = element[0].selectionStart - switch - when 0 <= start < 3 then "hour" - when 3 <= start < 6 then "minute" - when 6 <= start < 9 then "meridian" + switch + when 0 <= start < 3 then "hour" + when 3 <= start < 6 then "minute" + when 6 <= start < 9 then "meridian" - selectRange = (start, end) -> - $timeout -> - inputDOM.setSelectionRange start, end - , 0, false + selectRange = (start, end) -> + $timeout -> + element[0].setSelectionRange start, end + , 0, false - selectHours = -> selectRange 0, 2 - selectMinutes = -> selectRange 3, 5 - selectMeridian = -> selectRange 6, 8 + selectHours = -> selectRange 0, 2 + selectMinutes = -> selectRange 3, 5 + selectMeridian = -> selectRange 6, 8 - selectNextSection = -> - switch getSelection() - when "hour" then selectMinutes() - when "minute", "meridian" then selectMeridian() + selectNextSection = -> + switch getSelection() + when "hour" then selectMinutes() + when "minute", "meridian" then selectMeridian() - selectPreviousSection = -> - switch getSelection() - when "hour", "minute" then selectHours() - when "meridian" then selectMinutes() + selectPreviousSection = -> + switch getSelection() + when "hour", "minute" then selectHours() + when "meridian" then selectMinutes() - setMeridian = (meridian) -> - hours = $scope.time.getHours() + setMeridian = (meridian) -> + hours = time.getHours() - hours -= 12 if hours >= 12 and meridian is "AM" - hours += 12 if hours < 12 and meridian is "PM" + hours -= 12 if hours >= 12 and meridian is "AM" + hours += 12 if hours < 12 and meridian is "PM" - $scope.time.setHours hours + time.setHours hours - toggleMeridian = -> - hours = $scope.time.getHours() + toggleMeridian = -> + hours = time.getHours() + time.setHours (hours + 12) % 24 - $scope.time.setHours (hours + 12) % 24 + incrementHour = (change) -> + time.setHours time.getHours() + change - incrementHour = (change) -> - $scope.time.setHours $scope.time.getHours() + change + incrementMinute = (change) -> + time.setMinutes time.getMinutes() + change - incrementMinute = (change) -> - $scope.time.setMinutes $scope.time.getMinutes() + change + updateInput = -> + displayTime = $filter("date") time.getTime(), "hh:mm a" - updateInput = -> - $scope.model = $filter("date") $scope.time.getTime(), "hh:mm a" + unless displayTime is ngModelCtrl.$viewValue + ngModelCtrl.$setViewValue displayTime + ngModelCtrl.$render() - updateTime = -> - if timeMatch = util.timeRegex.exec $scope.model - hours = +timeMatch[1] - minutes = +timeMatch[2] - meridian = timeMatch[3] + updateTime = -> + if timeMatch = util.timeRegex.exec ngModelCtrl.$modelValue + hours = +timeMatch[1] + minutes = +timeMatch[2] + meridian = timeMatch[3] - hours += 12 if meridian is "PM" and hours isnt 12 - hours = 0 if meridian is "AM" and hours is 12 + hours += 12 if meridian is "PM" and hours isnt 12 + hours = 0 if meridian is "AM" and hours is 12 - $scope.time.setHours hours, minutes + time.setHours hours, minutes - $scope.blurEvent = (event) -> + element.on 'blur', (event) -> + $scope.$apply -> updateInput() - # - # @name $scope.clickEvent - # @description - # Note: The initial click into the input will not update the time because the - # model is empty. The selection by default should be hour. This works - # due to the cursor defaulting to 0,0. - # - $scope.clickEvent = (event) -> + # + # @name Click event + # @description + # Note: The initial click into the input will not update the time because the + # model is empty. The selection by default should be hour. This works + # due to the cursor defaulting to 0,0. + # + element.on 'click', (event) -> + $scope.$apply -> updateTime() updateInput() @@ -131,18 +152,21 @@ angular.module("Mac").directive "macTime", [ when "minute" then selectMinutes() when "meridian" then selectMeridian() - $scope.keydownEvent = (event) -> - key = event.which + element.on 'keydown', (event) -> + key = event.which + + return true unless key in [ + keys.UP + keys.DOWN + keys.LEFT + keys.RIGHT + keys.A + keys.P + ] - event.preventDefault() if key in [ - keys.UP - keys.DOWN - keys.LEFT - keys.RIGHT - keys.A - keys.P - ] + event.preventDefault() + $scope.$apply -> switch key when keys.UP, keys.DOWN change = if key is keys.UP then 1 else -1 @@ -159,7 +183,7 @@ angular.module("Mac").directive "macTime", [ selectMeridian() updateInput() - + when keys.LEFT, keys.RIGHT switch key when keys.LEFT then selectPreviousSection() @@ -179,36 +203,12 @@ angular.module("Mac").directive "macTime", [ selectMeridian() updateInput() - $scope.keyupEvent = (event) -> - key = event.which + element.on 'keyup', (event) -> + key = event.which - unless keys.NUMPAD0 <= key <= keys.NUMPAD9 or keys.ZERO <= key <= keys.NINE - event.preventDefault() + unless keys.NUMPAD0 <= key <= keys.NUMPAD9 or keys.ZERO <= key <= keys.NINE + event.preventDefault() + $scope.$apply -> updateTime() ] - -### -@name Time Input -@description -An internal directive for mac-time input element to add validator -### -angular.module("Mac").directive "macTimeInput", [ - "util" - (util) -> - restrict: "A" - require: "?ngModel" - link: ($scope, element, attrs, ctrl) -> - timeValidator = (value) -> - if !value or util.timeRegex.exec(value) - ctrl.$setValidity "time", true - - return value - else - ctrl.$setValidity "time", false - - return undefined - - ctrl.$formatters.push timeValidator - ctrl.$parsers.push timeValidator -] \ No newline at end of file diff --git a/src/template/time.jade b/src/template/time.jade index df9762f..b24978a 100644 --- a/src/template/time.jade +++ b/src/template/time.jade @@ -1,14 +1,4 @@ -.mac-date-time - i.mac-icons.mac-icon-time - input( - type = "text" - mac-placeholder = "placeholder" - maxlength = "8" - ng-model = "model" - ng-disabled = "disabled" - ng-click = "clickEvent($event)" - ng-blur = "blurEvent($event)" - ng-keydown = "keydownEvent($event)" - ng-keyup = "keyupEvent($event)" - mac-time-input - ) +input.mac-date-time( + type = "text" + maxlength = "8" +) diff --git a/test/e2e/time.html b/test/e2e/time.html index 63eeae2..593944b 100644 --- a/test/e2e/time.html +++ b/test/e2e/time.html @@ -14,7 +14,7 @@ diff --git a/test/e2e/time.spec.coffee b/test/e2e/time.spec.coffee index 4feed85..3ddf5cd 100644 --- a/test/e2e/time.spec.coffee +++ b/test/e2e/time.spec.coffee @@ -5,13 +5,13 @@ describe "Mac Time Input", -> return it "should return true", -> - input = element(By.css(".mac-date-time input")) + input = element(By.css(".mac-date-time")) input.click() expect(input.getAttribute("value")).toEqual "10:55 PM" return it "should change the meridian to AM after pressing the A button", -> - input = element(By.css(".mac-date-time input")) + input = element(By.css(".mac-date-time")) input.click() input.sendKeys "A" input.sendKeys "A" @@ -19,7 +19,7 @@ describe "Mac Time Input", -> return it "should not change the meridian to AM after pressing the P button", -> - input = element(By.css(".mac-date-time input")) + input = element(By.css(".mac-date-time")) input.click() input.sendKeys "P" input.sendKeys "P" @@ -27,14 +27,14 @@ describe "Mac Time Input", -> return it "should change the model after pressing down button", -> - input = element(By.css(".mac-date-time input")) + input = element(By.css(".mac-date-time")) input.click() input.sendKeys protractor.Key.DOWN expect(input.getAttribute("value")).toEqual "09:55 PM" return it "should change the model after pressing up button", -> - input = element(By.css(".mac-date-time input")) + input = element(By.css(".mac-date-time")) input.click() input.sendKeys protractor.Key.UP expect(input.getAttribute("value")).toEqual "11:55 PM" diff --git a/test/unit/time.spec.coffee b/test/unit/time.spec.coffee index 5d5f648..8202364 100644 --- a/test/unit/time.spec.coffee +++ b/test/unit/time.spec.coffee @@ -12,54 +12,46 @@ describe "Mac Time input", -> $rootScope = _$rootScope_ it "should replace with template", -> - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() expect(element.hasClass("mac-date-time")).toBe true it "should use default placeholder", -> - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() - expect($("input", element).prop("placeholder")).toBe "--:--" + expect(element.prop("placeholder")).toBe "--:--" - it "should use default time (12:00AM)", -> + it "should use set default time based on user input", -> $rootScope.model = "" - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() - expectTime = new Date currentDate + " " + "12:00 AM" - scope = $rootScope.$$childHead - expect(scope.time.getTime()).toBe expectTime.getTime() - - it "should use set default time based on user input", -> - $rootScope.model = "" - element = $compile("") $rootScope + element.click() $rootScope.$digest() - expectTime = new Date currentDate + " " + "06:30 PM" - scope = $rootScope.$$childHead - expect(scope.time.getTime()).toBe expectTime.getTime() + expect($rootScope.model).toBe "06:30 PM" it "should update the model with default time", -> $rootScope.model = "" - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() - $rootScope.$$childHead.clickEvent() + element.click() $rootScope.$digest() expect($rootScope.model).toBe "12:00 AM" it "should reset back to default value when clearing model", -> $rootScope.model = "2:30 PM" - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() $rootScope.model = "" $rootScope.$digest() - $rootScope.$$childHead.clickEvent() + element.click() $rootScope.$digest() expect($rootScope.model).toBe "12:00 AM" @@ -81,43 +73,38 @@ describe "Mac Time input", -> it "should update the model correctly", -> $rootScope.model = "" - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() - input = $("input", element) - input.click() - changeInputValue input, "06:25 PM" + element.click() + changeInputValue element, "06:25 PM" expect($rootScope.model).toBe "06:25 PM" it "should reset back to the original time when input is invalid - 1", -> $rootScope.model = "" - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() - input = $("input", element) - - $rootScope.$$childHead.clickEvent() + element.click() $rootScope.$digest() - changeInputValue input, "14:41 AM" - $rootScope.$$childHead.blurEvent() + changeInputValue element, "14:41 AM" + element.trigger 'blur' $rootScope.$digest() expect($rootScope.model).toBe("12:00 AM") it "should reset back to the original time when input is invalid - 2", -> $rootScope.model = "" - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() - input = $("input", element) - - $rootScope.$$childHead.clickEvent() + element.click() $rootScope.$digest() - changeInputValue input, "123" - $rootScope.$$childHead.blurEvent() + changeInputValue element, "123" + element.trigger 'blur' $rootScope.$digest() expect($rootScope.model).toBe("12:00 AM") @@ -131,69 +118,36 @@ describe "Mac Time input", -> $rootScope = _$rootScope_ it "should update the value of the input", -> - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() - input = $("input", element) - expect(input.val()).toBe "" + expect(element.val()).toBe "" $rootScope.model = "02:30 PM" $rootScope.$digest() - expect(input.val()).toBe "02:30 PM" + expect(element.val()).toBe "02:30 PM" it "should clear out text input when clearing model", -> - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() $rootScope.model = "02:30 PM" $rootScope.$digest() - input = $("input", element) - expect(input.val()).toBe "02:30 PM" + expect(element.val()).toBe "02:30 PM" $rootScope.model = "" $rootScope.$digest() - expect(input.val()).toBe "" + expect(element.val()).toBe "" it "should clear out text input when clearing model with null", -> - element = $compile("") $rootScope + element = $compile("") $rootScope $rootScope.$digest() $rootScope.model = "02:30 PM" $rootScope.$digest() - input = $("input", element) - $rootScope.model = null $rootScope.$digest() - expect(input.val()).toBe "" - - describe "disabled", -> - $compile = null - $rootScope = null - - beforeEach inject (_$compile_, _$rootScope_) -> - $compile = _$compile_ - $rootScope = _$rootScope_ - - it "should disable the input", -> - $rootScope.disabled = true - element = $compile("") $rootScope - $rootScope.$digest() - - input = $("input", element) - expect(input.prop("disabled")).toBe true - - it "should disable the input when scope variable changes", -> - $rootScope.disabled = false - element = $compile("") $rootScope - $rootScope.$digest() - - input = $("input", element) - expect(input.prop("disabled")).toBe false - - $rootScope.disabled = true - $rootScope.$digest() - - expect(input.prop("disabled")).toBe true + expect(element.val()).toBe ""