@@ 5690-6218 (lines=529) @@ | ||
5687 | templateUrl: 'uib/template/timepicker/timepicker.html' |
|
5688 | }) |
|
5689 | ||
5690 | .controller('UibTimepickerController', ['$scope', '$element', '$attrs', '$parse', '$log', '$locale', 'uibTimepickerConfig', function($scope, $element, $attrs, $parse, $log, $locale, timepickerConfig) { |
|
5691 | var selected = new Date(), |
|
5692 | watchers = [], |
|
5693 | ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl |
|
5694 | meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS, |
|
5695 | padHours = angular.isDefined($attrs.padHours) ? $scope.$parent.$eval($attrs.padHours) : true; |
|
5696 | ||
5697 | $scope.tabindex = angular.isDefined($attrs.tabindex) ? $attrs.tabindex : 0; |
|
5698 | $element.removeAttr('tabindex'); |
|
5699 | ||
5700 | this.init = function(ngModelCtrl_, inputs) { |
|
5701 | ngModelCtrl = ngModelCtrl_; |
|
5702 | ngModelCtrl.$render = this.render; |
|
5703 | ||
5704 | ngModelCtrl.$formatters.unshift(function(modelValue) { |
|
5705 | return modelValue ? new Date(modelValue) : null; |
|
5706 | }); |
|
5707 | ||
5708 | var hoursInputEl = inputs.eq(0), |
|
5709 | minutesInputEl = inputs.eq(1), |
|
5710 | secondsInputEl = inputs.eq(2); |
|
5711 | ||
5712 | var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel; |
|
5713 | ||
5714 | if (mousewheel) { |
|
5715 | this.setupMousewheelEvents(hoursInputEl, minutesInputEl, secondsInputEl); |
|
5716 | } |
|
5717 | ||
5718 | var arrowkeys = angular.isDefined($attrs.arrowkeys) ? $scope.$parent.$eval($attrs.arrowkeys) : timepickerConfig.arrowkeys; |
|
5719 | if (arrowkeys) { |
|
5720 | this.setupArrowkeyEvents(hoursInputEl, minutesInputEl, secondsInputEl); |
|
5721 | } |
|
5722 | ||
5723 | $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput; |
|
5724 | this.setupInputEvents(hoursInputEl, minutesInputEl, secondsInputEl); |
|
5725 | }; |
|
5726 | ||
5727 | var hourStep = timepickerConfig.hourStep; |
|
5728 | if ($attrs.hourStep) { |
|
5729 | watchers.push($scope.$parent.$watch($parse($attrs.hourStep), function(value) { |
|
5730 | hourStep = +value; |
|
5731 | })); |
|
5732 | } |
|
5733 | ||
5734 | var minuteStep = timepickerConfig.minuteStep; |
|
5735 | if ($attrs.minuteStep) { |
|
5736 | watchers.push($scope.$parent.$watch($parse($attrs.minuteStep), function(value) { |
|
5737 | minuteStep = +value; |
|
5738 | })); |
|
5739 | } |
|
5740 | ||
5741 | var min; |
|
5742 | watchers.push($scope.$parent.$watch($parse($attrs.min), function(value) { |
|
5743 | var dt = new Date(value); |
|
5744 | min = isNaN(dt) ? undefined : dt; |
|
5745 | })); |
|
5746 | ||
5747 | var max; |
|
5748 | watchers.push($scope.$parent.$watch($parse($attrs.max), function(value) { |
|
5749 | var dt = new Date(value); |
|
5750 | max = isNaN(dt) ? undefined : dt; |
|
5751 | })); |
|
5752 | ||
5753 | var disabled = false; |
|
5754 | if ($attrs.ngDisabled) { |
|
5755 | watchers.push($scope.$parent.$watch($parse($attrs.ngDisabled), function(value) { |
|
5756 | disabled = value; |
|
5757 | })); |
|
5758 | } |
|
5759 | ||
5760 | $scope.noIncrementHours = function() { |
|
5761 | var incrementedSelected = addMinutes(selected, hourStep * 60); |
|
5762 | return disabled || incrementedSelected > max || |
|
5763 | incrementedSelected < selected && incrementedSelected < min; |
|
5764 | }; |
|
5765 | ||
5766 | $scope.noDecrementHours = function() { |
|
5767 | var decrementedSelected = addMinutes(selected, -hourStep * 60); |
|
5768 | return disabled || decrementedSelected < min || |
|
5769 | decrementedSelected > selected && decrementedSelected > max; |
|
5770 | }; |
|
5771 | ||
5772 | $scope.noIncrementMinutes = function() { |
|
5773 | var incrementedSelected = addMinutes(selected, minuteStep); |
|
5774 | return disabled || incrementedSelected > max || |
|
5775 | incrementedSelected < selected && incrementedSelected < min; |
|
5776 | }; |
|
5777 | ||
5778 | $scope.noDecrementMinutes = function() { |
|
5779 | var decrementedSelected = addMinutes(selected, -minuteStep); |
|
5780 | return disabled || decrementedSelected < min || |
|
5781 | decrementedSelected > selected && decrementedSelected > max; |
|
5782 | }; |
|
5783 | ||
5784 | $scope.noIncrementSeconds = function() { |
|
5785 | var incrementedSelected = addSeconds(selected, secondStep); |
|
5786 | return disabled || incrementedSelected > max || |
|
5787 | incrementedSelected < selected && incrementedSelected < min; |
|
5788 | }; |
|
5789 | ||
5790 | $scope.noDecrementSeconds = function() { |
|
5791 | var decrementedSelected = addSeconds(selected, -secondStep); |
|
5792 | return disabled || decrementedSelected < min || |
|
5793 | decrementedSelected > selected && decrementedSelected > max; |
|
5794 | }; |
|
5795 | ||
5796 | $scope.noToggleMeridian = function() { |
|
5797 | if (selected.getHours() < 12) { |
|
5798 | return disabled || addMinutes(selected, 12 * 60) > max; |
|
5799 | } |
|
5800 | ||
5801 | return disabled || addMinutes(selected, -12 * 60) < min; |
|
5802 | }; |
|
5803 | ||
5804 | var secondStep = timepickerConfig.secondStep; |
|
5805 | if ($attrs.secondStep) { |
|
5806 | watchers.push($scope.$parent.$watch($parse($attrs.secondStep), function(value) { |
|
5807 | secondStep = +value; |
|
5808 | })); |
|
5809 | } |
|
5810 | ||
5811 | $scope.showSeconds = timepickerConfig.showSeconds; |
|
5812 | if ($attrs.showSeconds) { |
|
5813 | watchers.push($scope.$parent.$watch($parse($attrs.showSeconds), function(value) { |
|
5814 | $scope.showSeconds = !!value; |
|
5815 | })); |
|
5816 | } |
|
5817 | ||
5818 | // 12H / 24H mode |
|
5819 | $scope.showMeridian = timepickerConfig.showMeridian; |
|
5820 | if ($attrs.showMeridian) { |
|
5821 | watchers.push($scope.$parent.$watch($parse($attrs.showMeridian), function(value) { |
|
5822 | $scope.showMeridian = !!value; |
|
5823 | ||
5824 | if (ngModelCtrl.$error.time) { |
|
5825 | // Evaluate from template |
|
5826 | var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate(); |
|
5827 | if (angular.isDefined(hours) && angular.isDefined(minutes)) { |
|
5828 | selected.setHours(hours); |
|
5829 | refresh(); |
|
5830 | } |
|
5831 | } else { |
|
5832 | updateTemplate(); |
|
5833 | } |
|
5834 | })); |
|
5835 | } |
|
5836 | ||
5837 | // Get $scope.hours in 24H mode if valid |
|
5838 | function getHoursFromTemplate() { |
|
5839 | var hours = +$scope.hours; |
|
5840 | var valid = $scope.showMeridian ? hours > 0 && hours < 13 : |
|
5841 | hours >= 0 && hours < 24; |
|
5842 | if (!valid || $scope.hours === '') { |
|
5843 | return undefined; |
|
5844 | } |
|
5845 | ||
5846 | if ($scope.showMeridian) { |
|
5847 | if (hours === 12) { |
|
5848 | hours = 0; |
|
5849 | } |
|
5850 | if ($scope.meridian === meridians[1]) { |
|
5851 | hours = hours + 12; |
|
5852 | } |
|
5853 | } |
|
5854 | return hours; |
|
5855 | } |
|
5856 | ||
5857 | function getMinutesFromTemplate() { |
|
5858 | var minutes = +$scope.minutes; |
|
5859 | var valid = minutes >= 0 && minutes < 60; |
|
5860 | if (!valid || $scope.minutes === '') { |
|
5861 | return undefined; |
|
5862 | } |
|
5863 | return minutes; |
|
5864 | } |
|
5865 | ||
5866 | function getSecondsFromTemplate() { |
|
5867 | var seconds = +$scope.seconds; |
|
5868 | return seconds >= 0 && seconds < 60 ? seconds : undefined; |
|
5869 | } |
|
5870 | ||
5871 | function pad(value, noPad) { |
|
5872 | if (value === null) { |
|
5873 | return ''; |
|
5874 | } |
|
5875 | ||
5876 | return angular.isDefined(value) && value.toString().length < 2 && !noPad ? |
|
5877 | '0' + value : value.toString(); |
|
5878 | } |
|
5879 | ||
5880 | // Respond on mousewheel spin |
|
5881 | this.setupMousewheelEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) { |
|
5882 | var isScrollingUp = function(e) { |
|
5883 | if (e.originalEvent) { |
|
5884 | e = e.originalEvent; |
|
5885 | } |
|
5886 | //pick correct delta variable depending on event |
|
5887 | var delta = e.wheelDelta ? e.wheelDelta : -e.deltaY; |
|
5888 | return e.detail || delta > 0; |
|
5889 | }; |
|
5890 | ||
5891 | hoursInputEl.bind('mousewheel wheel', function(e) { |
|
5892 | if (!disabled) { |
|
5893 | $scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours()); |
|
5894 | } |
|
5895 | e.preventDefault(); |
|
5896 | }); |
|
5897 | ||
5898 | minutesInputEl.bind('mousewheel wheel', function(e) { |
|
5899 | if (!disabled) { |
|
5900 | $scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes()); |
|
5901 | } |
|
5902 | e.preventDefault(); |
|
5903 | }); |
|
5904 | ||
5905 | secondsInputEl.bind('mousewheel wheel', function(e) { |
|
5906 | if (!disabled) { |
|
5907 | $scope.$apply(isScrollingUp(e) ? $scope.incrementSeconds() : $scope.decrementSeconds()); |
|
5908 | } |
|
5909 | e.preventDefault(); |
|
5910 | }); |
|
5911 | }; |
|
5912 | ||
5913 | // Respond on up/down arrowkeys |
|
5914 | this.setupArrowkeyEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) { |
|
5915 | hoursInputEl.bind('keydown', function(e) { |
|
5916 | if (!disabled) { |
|
5917 | if (e.which === 38) { // up |
|
5918 | e.preventDefault(); |
|
5919 | $scope.incrementHours(); |
|
5920 | $scope.$apply(); |
|
5921 | } else if (e.which === 40) { // down |
|
5922 | e.preventDefault(); |
|
5923 | $scope.decrementHours(); |
|
5924 | $scope.$apply(); |
|
5925 | } |
|
5926 | } |
|
5927 | }); |
|
5928 | ||
5929 | minutesInputEl.bind('keydown', function(e) { |
|
5930 | if (!disabled) { |
|
5931 | if (e.which === 38) { // up |
|
5932 | e.preventDefault(); |
|
5933 | $scope.incrementMinutes(); |
|
5934 | $scope.$apply(); |
|
5935 | } else if (e.which === 40) { // down |
|
5936 | e.preventDefault(); |
|
5937 | $scope.decrementMinutes(); |
|
5938 | $scope.$apply(); |
|
5939 | } |
|
5940 | } |
|
5941 | }); |
|
5942 | ||
5943 | secondsInputEl.bind('keydown', function(e) { |
|
5944 | if (!disabled) { |
|
5945 | if (e.which === 38) { // up |
|
5946 | e.preventDefault(); |
|
5947 | $scope.incrementSeconds(); |
|
5948 | $scope.$apply(); |
|
5949 | } else if (e.which === 40) { // down |
|
5950 | e.preventDefault(); |
|
5951 | $scope.decrementSeconds(); |
|
5952 | $scope.$apply(); |
|
5953 | } |
|
5954 | } |
|
5955 | }); |
|
5956 | }; |
|
5957 | ||
5958 | this.setupInputEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) { |
|
5959 | if ($scope.readonlyInput) { |
|
5960 | $scope.updateHours = angular.noop; |
|
5961 | $scope.updateMinutes = angular.noop; |
|
5962 | $scope.updateSeconds = angular.noop; |
|
5963 | return; |
|
5964 | } |
|
5965 | ||
5966 | var invalidate = function(invalidHours, invalidMinutes, invalidSeconds) { |
|
5967 | ngModelCtrl.$setViewValue(null); |
|
5968 | ngModelCtrl.$setValidity('time', false); |
|
5969 | if (angular.isDefined(invalidHours)) { |
|
5970 | $scope.invalidHours = invalidHours; |
|
5971 | } |
|
5972 | ||
5973 | if (angular.isDefined(invalidMinutes)) { |
|
5974 | $scope.invalidMinutes = invalidMinutes; |
|
5975 | } |
|
5976 | ||
5977 | if (angular.isDefined(invalidSeconds)) { |
|
5978 | $scope.invalidSeconds = invalidSeconds; |
|
5979 | } |
|
5980 | }; |
|
5981 | ||
5982 | $scope.updateHours = function() { |
|
5983 | var hours = getHoursFromTemplate(), |
|
5984 | minutes = getMinutesFromTemplate(); |
|
5985 | ||
5986 | ngModelCtrl.$setDirty(); |
|
5987 | ||
5988 | if (angular.isDefined(hours) && angular.isDefined(minutes)) { |
|
5989 | selected.setHours(hours); |
|
5990 | selected.setMinutes(minutes); |
|
5991 | if (selected < min || selected > max) { |
|
5992 | invalidate(true); |
|
5993 | } else { |
|
5994 | refresh('h'); |
|
5995 | } |
|
5996 | } else { |
|
5997 | invalidate(true); |
|
5998 | } |
|
5999 | }; |
|
6000 | ||
6001 | hoursInputEl.bind('blur', function(e) { |
|
6002 | ngModelCtrl.$setTouched(); |
|
6003 | if (modelIsEmpty()) { |
|
6004 | makeValid(); |
|
6005 | } else if ($scope.hours === null || $scope.hours === '') { |
|
6006 | invalidate(true); |
|
6007 | } else if (!$scope.invalidHours && $scope.hours < 10) { |
|
6008 | $scope.$apply(function() { |
|
6009 | $scope.hours = pad($scope.hours, !padHours); |
|
6010 | }); |
|
6011 | } |
|
6012 | }); |
|
6013 | ||
6014 | $scope.updateMinutes = function() { |
|
6015 | var minutes = getMinutesFromTemplate(), |
|
6016 | hours = getHoursFromTemplate(); |
|
6017 | ||
6018 | ngModelCtrl.$setDirty(); |
|
6019 | ||
6020 | if (angular.isDefined(minutes) && angular.isDefined(hours)) { |
|
6021 | selected.setHours(hours); |
|
6022 | selected.setMinutes(minutes); |
|
6023 | if (selected < min || selected > max) { |
|
6024 | invalidate(undefined, true); |
|
6025 | } else { |
|
6026 | refresh('m'); |
|
6027 | } |
|
6028 | } else { |
|
6029 | invalidate(undefined, true); |
|
6030 | } |
|
6031 | }; |
|
6032 | ||
6033 | minutesInputEl.bind('blur', function(e) { |
|
6034 | ngModelCtrl.$setTouched(); |
|
6035 | if (modelIsEmpty()) { |
|
6036 | makeValid(); |
|
6037 | } else if ($scope.minutes === null) { |
|
6038 | invalidate(undefined, true); |
|
6039 | } else if (!$scope.invalidMinutes && $scope.minutes < 10) { |
|
6040 | $scope.$apply(function() { |
|
6041 | $scope.minutes = pad($scope.minutes); |
|
6042 | }); |
|
6043 | } |
|
6044 | }); |
|
6045 | ||
6046 | $scope.updateSeconds = function() { |
|
6047 | var seconds = getSecondsFromTemplate(); |
|
6048 | ||
6049 | ngModelCtrl.$setDirty(); |
|
6050 | ||
6051 | if (angular.isDefined(seconds)) { |
|
6052 | selected.setSeconds(seconds); |
|
6053 | refresh('s'); |
|
6054 | } else { |
|
6055 | invalidate(undefined, undefined, true); |
|
6056 | } |
|
6057 | }; |
|
6058 | ||
6059 | secondsInputEl.bind('blur', function(e) { |
|
6060 | if (modelIsEmpty()) { |
|
6061 | makeValid(); |
|
6062 | } else if (!$scope.invalidSeconds && $scope.seconds < 10) { |
|
6063 | $scope.$apply( function() { |
|
6064 | $scope.seconds = pad($scope.seconds); |
|
6065 | }); |
|
6066 | } |
|
6067 | }); |
|
6068 | ||
6069 | }; |
|
6070 | ||
6071 | this.render = function() { |
|
6072 | var date = ngModelCtrl.$viewValue; |
|
6073 | ||
6074 | if (isNaN(date)) { |
|
6075 | ngModelCtrl.$setValidity('time', false); |
|
6076 | $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); |
|
6077 | } else { |
|
6078 | if (date) { |
|
6079 | selected = date; |
|
6080 | } |
|
6081 | ||
6082 | if (selected < min || selected > max) { |
|
6083 | ngModelCtrl.$setValidity('time', false); |
|
6084 | $scope.invalidHours = true; |
|
6085 | $scope.invalidMinutes = true; |
|
6086 | } else { |
|
6087 | makeValid(); |
|
6088 | } |
|
6089 | updateTemplate(); |
|
6090 | } |
|
6091 | }; |
|
6092 | ||
6093 | // Call internally when we know that model is valid. |
|
6094 | function refresh(keyboardChange) { |
|
6095 | makeValid(); |
|
6096 | ngModelCtrl.$setViewValue(new Date(selected)); |
|
6097 | updateTemplate(keyboardChange); |
|
6098 | } |
|
6099 | ||
6100 | function makeValid() { |
|
6101 | ngModelCtrl.$setValidity('time', true); |
|
6102 | $scope.invalidHours = false; |
|
6103 | $scope.invalidMinutes = false; |
|
6104 | $scope.invalidSeconds = false; |
|
6105 | } |
|
6106 | ||
6107 | function updateTemplate(keyboardChange) { |
|
6108 | if (!ngModelCtrl.$modelValue) { |
|
6109 | $scope.hours = null; |
|
6110 | $scope.minutes = null; |
|
6111 | $scope.seconds = null; |
|
6112 | $scope.meridian = meridians[0]; |
|
6113 | } else { |
|
6114 | var hours = selected.getHours(), |
|
6115 | minutes = selected.getMinutes(), |
|
6116 | seconds = selected.getSeconds(); |
|
6117 | ||
6118 | if ($scope.showMeridian) { |
|
6119 | hours = hours === 0 || hours === 12 ? 12 : hours % 12; // Convert 24 to 12 hour system |
|
6120 | } |
|
6121 | ||
6122 | $scope.hours = keyboardChange === 'h' ? hours : pad(hours, !padHours); |
|
6123 | if (keyboardChange !== 'm') { |
|
6124 | $scope.minutes = pad(minutes); |
|
6125 | } |
|
6126 | $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1]; |
|
6127 | ||
6128 | if (keyboardChange !== 's') { |
|
6129 | $scope.seconds = pad(seconds); |
|
6130 | } |
|
6131 | $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1]; |
|
6132 | } |
|
6133 | } |
|
6134 | ||
6135 | function addSecondsToSelected(seconds) { |
|
6136 | selected = addSeconds(selected, seconds); |
|
6137 | refresh(); |
|
6138 | } |
|
6139 | ||
6140 | function addMinutes(selected, minutes) { |
|
6141 | return addSeconds(selected, minutes*60); |
|
6142 | } |
|
6143 | ||
6144 | function addSeconds(date, seconds) { |
|
6145 | var dt = new Date(date.getTime() + seconds * 1000); |
|
6146 | var newDate = new Date(date); |
|
6147 | newDate.setHours(dt.getHours(), dt.getMinutes(), dt.getSeconds()); |
|
6148 | return newDate; |
|
6149 | } |
|
6150 | ||
6151 | function modelIsEmpty() { |
|
6152 | return ($scope.hours === null || $scope.hours === '') && |
|
6153 | ($scope.minutes === null || $scope.minutes === '') && |
|
6154 | (!$scope.showSeconds || $scope.showSeconds && ($scope.seconds === null || $scope.seconds === '')); |
|
6155 | } |
|
6156 | ||
6157 | $scope.showSpinners = angular.isDefined($attrs.showSpinners) ? |
|
6158 | $scope.$parent.$eval($attrs.showSpinners) : timepickerConfig.showSpinners; |
|
6159 | ||
6160 | $scope.incrementHours = function() { |
|
6161 | if (!$scope.noIncrementHours()) { |
|
6162 | addSecondsToSelected(hourStep * 60 * 60); |
|
6163 | } |
|
6164 | }; |
|
6165 | ||
6166 | $scope.decrementHours = function() { |
|
6167 | if (!$scope.noDecrementHours()) { |
|
6168 | addSecondsToSelected(-hourStep * 60 * 60); |
|
6169 | } |
|
6170 | }; |
|
6171 | ||
6172 | $scope.incrementMinutes = function() { |
|
6173 | if (!$scope.noIncrementMinutes()) { |
|
6174 | addSecondsToSelected(minuteStep * 60); |
|
6175 | } |
|
6176 | }; |
|
6177 | ||
6178 | $scope.decrementMinutes = function() { |
|
6179 | if (!$scope.noDecrementMinutes()) { |
|
6180 | addSecondsToSelected(-minuteStep * 60); |
|
6181 | } |
|
6182 | }; |
|
6183 | ||
6184 | $scope.incrementSeconds = function() { |
|
6185 | if (!$scope.noIncrementSeconds()) { |
|
6186 | addSecondsToSelected(secondStep); |
|
6187 | } |
|
6188 | }; |
|
6189 | ||
6190 | $scope.decrementSeconds = function() { |
|
6191 | if (!$scope.noDecrementSeconds()) { |
|
6192 | addSecondsToSelected(-secondStep); |
|
6193 | } |
|
6194 | }; |
|
6195 | ||
6196 | $scope.toggleMeridian = function() { |
|
6197 | var minutes = getMinutesFromTemplate(), |
|
6198 | hours = getHoursFromTemplate(); |
|
6199 | ||
6200 | if (!$scope.noToggleMeridian()) { |
|
6201 | if (angular.isDefined(minutes) && angular.isDefined(hours)) { |
|
6202 | addSecondsToSelected(12 * 60 * (selected.getHours() < 12 ? 60 : -60)); |
|
6203 | } else { |
|
6204 | $scope.meridian = $scope.meridian === meridians[0] ? meridians[1] : meridians[0]; |
|
6205 | } |
|
6206 | } |
|
6207 | }; |
|
6208 | ||
6209 | $scope.blur = function() { |
|
6210 | ngModelCtrl.$setTouched(); |
|
6211 | }; |
|
6212 | ||
6213 | $scope.$on('$destroy', function() { |
|
6214 | while (watchers.length) { |
|
6215 | watchers.shift()(); |
|
6216 | } |
|
6217 | }); |
|
6218 | }]) |
|
6219 | ||
6220 | .directive('uibTimepicker', ['uibTimepickerConfig', function(uibTimepickerConfig) { |
|
6221 | return { |
@@ 5689-6217 (lines=529) @@ | ||
5686 | templateUrl: 'uib/template/timepicker/timepicker.html' |
|
5687 | }) |
|
5688 | ||
5689 | .controller('UibTimepickerController', ['$scope', '$element', '$attrs', '$parse', '$log', '$locale', 'uibTimepickerConfig', function($scope, $element, $attrs, $parse, $log, $locale, timepickerConfig) { |
|
5690 | var selected = new Date(), |
|
5691 | watchers = [], |
|
5692 | ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl |
|
5693 | meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS, |
|
5694 | padHours = angular.isDefined($attrs.padHours) ? $scope.$parent.$eval($attrs.padHours) : true; |
|
5695 | ||
5696 | $scope.tabindex = angular.isDefined($attrs.tabindex) ? $attrs.tabindex : 0; |
|
5697 | $element.removeAttr('tabindex'); |
|
5698 | ||
5699 | this.init = function(ngModelCtrl_, inputs) { |
|
5700 | ngModelCtrl = ngModelCtrl_; |
|
5701 | ngModelCtrl.$render = this.render; |
|
5702 | ||
5703 | ngModelCtrl.$formatters.unshift(function(modelValue) { |
|
5704 | return modelValue ? new Date(modelValue) : null; |
|
5705 | }); |
|
5706 | ||
5707 | var hoursInputEl = inputs.eq(0), |
|
5708 | minutesInputEl = inputs.eq(1), |
|
5709 | secondsInputEl = inputs.eq(2); |
|
5710 | ||
5711 | var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel; |
|
5712 | ||
5713 | if (mousewheel) { |
|
5714 | this.setupMousewheelEvents(hoursInputEl, minutesInputEl, secondsInputEl); |
|
5715 | } |
|
5716 | ||
5717 | var arrowkeys = angular.isDefined($attrs.arrowkeys) ? $scope.$parent.$eval($attrs.arrowkeys) : timepickerConfig.arrowkeys; |
|
5718 | if (arrowkeys) { |
|
5719 | this.setupArrowkeyEvents(hoursInputEl, minutesInputEl, secondsInputEl); |
|
5720 | } |
|
5721 | ||
5722 | $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput; |
|
5723 | this.setupInputEvents(hoursInputEl, minutesInputEl, secondsInputEl); |
|
5724 | }; |
|
5725 | ||
5726 | var hourStep = timepickerConfig.hourStep; |
|
5727 | if ($attrs.hourStep) { |
|
5728 | watchers.push($scope.$parent.$watch($parse($attrs.hourStep), function(value) { |
|
5729 | hourStep = +value; |
|
5730 | })); |
|
5731 | } |
|
5732 | ||
5733 | var minuteStep = timepickerConfig.minuteStep; |
|
5734 | if ($attrs.minuteStep) { |
|
5735 | watchers.push($scope.$parent.$watch($parse($attrs.minuteStep), function(value) { |
|
5736 | minuteStep = +value; |
|
5737 | })); |
|
5738 | } |
|
5739 | ||
5740 | var min; |
|
5741 | watchers.push($scope.$parent.$watch($parse($attrs.min), function(value) { |
|
5742 | var dt = new Date(value); |
|
5743 | min = isNaN(dt) ? undefined : dt; |
|
5744 | })); |
|
5745 | ||
5746 | var max; |
|
5747 | watchers.push($scope.$parent.$watch($parse($attrs.max), function(value) { |
|
5748 | var dt = new Date(value); |
|
5749 | max = isNaN(dt) ? undefined : dt; |
|
5750 | })); |
|
5751 | ||
5752 | var disabled = false; |
|
5753 | if ($attrs.ngDisabled) { |
|
5754 | watchers.push($scope.$parent.$watch($parse($attrs.ngDisabled), function(value) { |
|
5755 | disabled = value; |
|
5756 | })); |
|
5757 | } |
|
5758 | ||
5759 | $scope.noIncrementHours = function() { |
|
5760 | var incrementedSelected = addMinutes(selected, hourStep * 60); |
|
5761 | return disabled || incrementedSelected > max || |
|
5762 | incrementedSelected < selected && incrementedSelected < min; |
|
5763 | }; |
|
5764 | ||
5765 | $scope.noDecrementHours = function() { |
|
5766 | var decrementedSelected = addMinutes(selected, -hourStep * 60); |
|
5767 | return disabled || decrementedSelected < min || |
|
5768 | decrementedSelected > selected && decrementedSelected > max; |
|
5769 | }; |
|
5770 | ||
5771 | $scope.noIncrementMinutes = function() { |
|
5772 | var incrementedSelected = addMinutes(selected, minuteStep); |
|
5773 | return disabled || incrementedSelected > max || |
|
5774 | incrementedSelected < selected && incrementedSelected < min; |
|
5775 | }; |
|
5776 | ||
5777 | $scope.noDecrementMinutes = function() { |
|
5778 | var decrementedSelected = addMinutes(selected, -minuteStep); |
|
5779 | return disabled || decrementedSelected < min || |
|
5780 | decrementedSelected > selected && decrementedSelected > max; |
|
5781 | }; |
|
5782 | ||
5783 | $scope.noIncrementSeconds = function() { |
|
5784 | var incrementedSelected = addSeconds(selected, secondStep); |
|
5785 | return disabled || incrementedSelected > max || |
|
5786 | incrementedSelected < selected && incrementedSelected < min; |
|
5787 | }; |
|
5788 | ||
5789 | $scope.noDecrementSeconds = function() { |
|
5790 | var decrementedSelected = addSeconds(selected, -secondStep); |
|
5791 | return disabled || decrementedSelected < min || |
|
5792 | decrementedSelected > selected && decrementedSelected > max; |
|
5793 | }; |
|
5794 | ||
5795 | $scope.noToggleMeridian = function() { |
|
5796 | if (selected.getHours() < 12) { |
|
5797 | return disabled || addMinutes(selected, 12 * 60) > max; |
|
5798 | } |
|
5799 | ||
5800 | return disabled || addMinutes(selected, -12 * 60) < min; |
|
5801 | }; |
|
5802 | ||
5803 | var secondStep = timepickerConfig.secondStep; |
|
5804 | if ($attrs.secondStep) { |
|
5805 | watchers.push($scope.$parent.$watch($parse($attrs.secondStep), function(value) { |
|
5806 | secondStep = +value; |
|
5807 | })); |
|
5808 | } |
|
5809 | ||
5810 | $scope.showSeconds = timepickerConfig.showSeconds; |
|
5811 | if ($attrs.showSeconds) { |
|
5812 | watchers.push($scope.$parent.$watch($parse($attrs.showSeconds), function(value) { |
|
5813 | $scope.showSeconds = !!value; |
|
5814 | })); |
|
5815 | } |
|
5816 | ||
5817 | // 12H / 24H mode |
|
5818 | $scope.showMeridian = timepickerConfig.showMeridian; |
|
5819 | if ($attrs.showMeridian) { |
|
5820 | watchers.push($scope.$parent.$watch($parse($attrs.showMeridian), function(value) { |
|
5821 | $scope.showMeridian = !!value; |
|
5822 | ||
5823 | if (ngModelCtrl.$error.time) { |
|
5824 | // Evaluate from template |
|
5825 | var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate(); |
|
5826 | if (angular.isDefined(hours) && angular.isDefined(minutes)) { |
|
5827 | selected.setHours(hours); |
|
5828 | refresh(); |
|
5829 | } |
|
5830 | } else { |
|
5831 | updateTemplate(); |
|
5832 | } |
|
5833 | })); |
|
5834 | } |
|
5835 | ||
5836 | // Get $scope.hours in 24H mode if valid |
|
5837 | function getHoursFromTemplate() { |
|
5838 | var hours = +$scope.hours; |
|
5839 | var valid = $scope.showMeridian ? hours > 0 && hours < 13 : |
|
5840 | hours >= 0 && hours < 24; |
|
5841 | if (!valid || $scope.hours === '') { |
|
5842 | return undefined; |
|
5843 | } |
|
5844 | ||
5845 | if ($scope.showMeridian) { |
|
5846 | if (hours === 12) { |
|
5847 | hours = 0; |
|
5848 | } |
|
5849 | if ($scope.meridian === meridians[1]) { |
|
5850 | hours = hours + 12; |
|
5851 | } |
|
5852 | } |
|
5853 | return hours; |
|
5854 | } |
|
5855 | ||
5856 | function getMinutesFromTemplate() { |
|
5857 | var minutes = +$scope.minutes; |
|
5858 | var valid = minutes >= 0 && minutes < 60; |
|
5859 | if (!valid || $scope.minutes === '') { |
|
5860 | return undefined; |
|
5861 | } |
|
5862 | return minutes; |
|
5863 | } |
|
5864 | ||
5865 | function getSecondsFromTemplate() { |
|
5866 | var seconds = +$scope.seconds; |
|
5867 | return seconds >= 0 && seconds < 60 ? seconds : undefined; |
|
5868 | } |
|
5869 | ||
5870 | function pad(value, noPad) { |
|
5871 | if (value === null) { |
|
5872 | return ''; |
|
5873 | } |
|
5874 | ||
5875 | return angular.isDefined(value) && value.toString().length < 2 && !noPad ? |
|
5876 | '0' + value : value.toString(); |
|
5877 | } |
|
5878 | ||
5879 | // Respond on mousewheel spin |
|
5880 | this.setupMousewheelEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) { |
|
5881 | var isScrollingUp = function(e) { |
|
5882 | if (e.originalEvent) { |
|
5883 | e = e.originalEvent; |
|
5884 | } |
|
5885 | //pick correct delta variable depending on event |
|
5886 | var delta = e.wheelDelta ? e.wheelDelta : -e.deltaY; |
|
5887 | return e.detail || delta > 0; |
|
5888 | }; |
|
5889 | ||
5890 | hoursInputEl.bind('mousewheel wheel', function(e) { |
|
5891 | if (!disabled) { |
|
5892 | $scope.$apply(isScrollingUp(e) ? $scope.incrementHours() : $scope.decrementHours()); |
|
5893 | } |
|
5894 | e.preventDefault(); |
|
5895 | }); |
|
5896 | ||
5897 | minutesInputEl.bind('mousewheel wheel', function(e) { |
|
5898 | if (!disabled) { |
|
5899 | $scope.$apply(isScrollingUp(e) ? $scope.incrementMinutes() : $scope.decrementMinutes()); |
|
5900 | } |
|
5901 | e.preventDefault(); |
|
5902 | }); |
|
5903 | ||
5904 | secondsInputEl.bind('mousewheel wheel', function(e) { |
|
5905 | if (!disabled) { |
|
5906 | $scope.$apply(isScrollingUp(e) ? $scope.incrementSeconds() : $scope.decrementSeconds()); |
|
5907 | } |
|
5908 | e.preventDefault(); |
|
5909 | }); |
|
5910 | }; |
|
5911 | ||
5912 | // Respond on up/down arrowkeys |
|
5913 | this.setupArrowkeyEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) { |
|
5914 | hoursInputEl.bind('keydown', function(e) { |
|
5915 | if (!disabled) { |
|
5916 | if (e.which === 38) { // up |
|
5917 | e.preventDefault(); |
|
5918 | $scope.incrementHours(); |
|
5919 | $scope.$apply(); |
|
5920 | } else if (e.which === 40) { // down |
|
5921 | e.preventDefault(); |
|
5922 | $scope.decrementHours(); |
|
5923 | $scope.$apply(); |
|
5924 | } |
|
5925 | } |
|
5926 | }); |
|
5927 | ||
5928 | minutesInputEl.bind('keydown', function(e) { |
|
5929 | if (!disabled) { |
|
5930 | if (e.which === 38) { // up |
|
5931 | e.preventDefault(); |
|
5932 | $scope.incrementMinutes(); |
|
5933 | $scope.$apply(); |
|
5934 | } else if (e.which === 40) { // down |
|
5935 | e.preventDefault(); |
|
5936 | $scope.decrementMinutes(); |
|
5937 | $scope.$apply(); |
|
5938 | } |
|
5939 | } |
|
5940 | }); |
|
5941 | ||
5942 | secondsInputEl.bind('keydown', function(e) { |
|
5943 | if (!disabled) { |
|
5944 | if (e.which === 38) { // up |
|
5945 | e.preventDefault(); |
|
5946 | $scope.incrementSeconds(); |
|
5947 | $scope.$apply(); |
|
5948 | } else if (e.which === 40) { // down |
|
5949 | e.preventDefault(); |
|
5950 | $scope.decrementSeconds(); |
|
5951 | $scope.$apply(); |
|
5952 | } |
|
5953 | } |
|
5954 | }); |
|
5955 | }; |
|
5956 | ||
5957 | this.setupInputEvents = function(hoursInputEl, minutesInputEl, secondsInputEl) { |
|
5958 | if ($scope.readonlyInput) { |
|
5959 | $scope.updateHours = angular.noop; |
|
5960 | $scope.updateMinutes = angular.noop; |
|
5961 | $scope.updateSeconds = angular.noop; |
|
5962 | return; |
|
5963 | } |
|
5964 | ||
5965 | var invalidate = function(invalidHours, invalidMinutes, invalidSeconds) { |
|
5966 | ngModelCtrl.$setViewValue(null); |
|
5967 | ngModelCtrl.$setValidity('time', false); |
|
5968 | if (angular.isDefined(invalidHours)) { |
|
5969 | $scope.invalidHours = invalidHours; |
|
5970 | } |
|
5971 | ||
5972 | if (angular.isDefined(invalidMinutes)) { |
|
5973 | $scope.invalidMinutes = invalidMinutes; |
|
5974 | } |
|
5975 | ||
5976 | if (angular.isDefined(invalidSeconds)) { |
|
5977 | $scope.invalidSeconds = invalidSeconds; |
|
5978 | } |
|
5979 | }; |
|
5980 | ||
5981 | $scope.updateHours = function() { |
|
5982 | var hours = getHoursFromTemplate(), |
|
5983 | minutes = getMinutesFromTemplate(); |
|
5984 | ||
5985 | ngModelCtrl.$setDirty(); |
|
5986 | ||
5987 | if (angular.isDefined(hours) && angular.isDefined(minutes)) { |
|
5988 | selected.setHours(hours); |
|
5989 | selected.setMinutes(minutes); |
|
5990 | if (selected < min || selected > max) { |
|
5991 | invalidate(true); |
|
5992 | } else { |
|
5993 | refresh('h'); |
|
5994 | } |
|
5995 | } else { |
|
5996 | invalidate(true); |
|
5997 | } |
|
5998 | }; |
|
5999 | ||
6000 | hoursInputEl.bind('blur', function(e) { |
|
6001 | ngModelCtrl.$setTouched(); |
|
6002 | if (modelIsEmpty()) { |
|
6003 | makeValid(); |
|
6004 | } else if ($scope.hours === null || $scope.hours === '') { |
|
6005 | invalidate(true); |
|
6006 | } else if (!$scope.invalidHours && $scope.hours < 10) { |
|
6007 | $scope.$apply(function() { |
|
6008 | $scope.hours = pad($scope.hours, !padHours); |
|
6009 | }); |
|
6010 | } |
|
6011 | }); |
|
6012 | ||
6013 | $scope.updateMinutes = function() { |
|
6014 | var minutes = getMinutesFromTemplate(), |
|
6015 | hours = getHoursFromTemplate(); |
|
6016 | ||
6017 | ngModelCtrl.$setDirty(); |
|
6018 | ||
6019 | if (angular.isDefined(minutes) && angular.isDefined(hours)) { |
|
6020 | selected.setHours(hours); |
|
6021 | selected.setMinutes(minutes); |
|
6022 | if (selected < min || selected > max) { |
|
6023 | invalidate(undefined, true); |
|
6024 | } else { |
|
6025 | refresh('m'); |
|
6026 | } |
|
6027 | } else { |
|
6028 | invalidate(undefined, true); |
|
6029 | } |
|
6030 | }; |
|
6031 | ||
6032 | minutesInputEl.bind('blur', function(e) { |
|
6033 | ngModelCtrl.$setTouched(); |
|
6034 | if (modelIsEmpty()) { |
|
6035 | makeValid(); |
|
6036 | } else if ($scope.minutes === null) { |
|
6037 | invalidate(undefined, true); |
|
6038 | } else if (!$scope.invalidMinutes && $scope.minutes < 10) { |
|
6039 | $scope.$apply(function() { |
|
6040 | $scope.minutes = pad($scope.minutes); |
|
6041 | }); |
|
6042 | } |
|
6043 | }); |
|
6044 | ||
6045 | $scope.updateSeconds = function() { |
|
6046 | var seconds = getSecondsFromTemplate(); |
|
6047 | ||
6048 | ngModelCtrl.$setDirty(); |
|
6049 | ||
6050 | if (angular.isDefined(seconds)) { |
|
6051 | selected.setSeconds(seconds); |
|
6052 | refresh('s'); |
|
6053 | } else { |
|
6054 | invalidate(undefined, undefined, true); |
|
6055 | } |
|
6056 | }; |
|
6057 | ||
6058 | secondsInputEl.bind('blur', function(e) { |
|
6059 | if (modelIsEmpty()) { |
|
6060 | makeValid(); |
|
6061 | } else if (!$scope.invalidSeconds && $scope.seconds < 10) { |
|
6062 | $scope.$apply( function() { |
|
6063 | $scope.seconds = pad($scope.seconds); |
|
6064 | }); |
|
6065 | } |
|
6066 | }); |
|
6067 | ||
6068 | }; |
|
6069 | ||
6070 | this.render = function() { |
|
6071 | var date = ngModelCtrl.$viewValue; |
|
6072 | ||
6073 | if (isNaN(date)) { |
|
6074 | ngModelCtrl.$setValidity('time', false); |
|
6075 | $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.'); |
|
6076 | } else { |
|
6077 | if (date) { |
|
6078 | selected = date; |
|
6079 | } |
|
6080 | ||
6081 | if (selected < min || selected > max) { |
|
6082 | ngModelCtrl.$setValidity('time', false); |
|
6083 | $scope.invalidHours = true; |
|
6084 | $scope.invalidMinutes = true; |
|
6085 | } else { |
|
6086 | makeValid(); |
|
6087 | } |
|
6088 | updateTemplate(); |
|
6089 | } |
|
6090 | }; |
|
6091 | ||
6092 | // Call internally when we know that model is valid. |
|
6093 | function refresh(keyboardChange) { |
|
6094 | makeValid(); |
|
6095 | ngModelCtrl.$setViewValue(new Date(selected)); |
|
6096 | updateTemplate(keyboardChange); |
|
6097 | } |
|
6098 | ||
6099 | function makeValid() { |
|
6100 | ngModelCtrl.$setValidity('time', true); |
|
6101 | $scope.invalidHours = false; |
|
6102 | $scope.invalidMinutes = false; |
|
6103 | $scope.invalidSeconds = false; |
|
6104 | } |
|
6105 | ||
6106 | function updateTemplate(keyboardChange) { |
|
6107 | if (!ngModelCtrl.$modelValue) { |
|
6108 | $scope.hours = null; |
|
6109 | $scope.minutes = null; |
|
6110 | $scope.seconds = null; |
|
6111 | $scope.meridian = meridians[0]; |
|
6112 | } else { |
|
6113 | var hours = selected.getHours(), |
|
6114 | minutes = selected.getMinutes(), |
|
6115 | seconds = selected.getSeconds(); |
|
6116 | ||
6117 | if ($scope.showMeridian) { |
|
6118 | hours = hours === 0 || hours === 12 ? 12 : hours % 12; // Convert 24 to 12 hour system |
|
6119 | } |
|
6120 | ||
6121 | $scope.hours = keyboardChange === 'h' ? hours : pad(hours, !padHours); |
|
6122 | if (keyboardChange !== 'm') { |
|
6123 | $scope.minutes = pad(minutes); |
|
6124 | } |
|
6125 | $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1]; |
|
6126 | ||
6127 | if (keyboardChange !== 's') { |
|
6128 | $scope.seconds = pad(seconds); |
|
6129 | } |
|
6130 | $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1]; |
|
6131 | } |
|
6132 | } |
|
6133 | ||
6134 | function addSecondsToSelected(seconds) { |
|
6135 | selected = addSeconds(selected, seconds); |
|
6136 | refresh(); |
|
6137 | } |
|
6138 | ||
6139 | function addMinutes(selected, minutes) { |
|
6140 | return addSeconds(selected, minutes*60); |
|
6141 | } |
|
6142 | ||
6143 | function addSeconds(date, seconds) { |
|
6144 | var dt = new Date(date.getTime() + seconds * 1000); |
|
6145 | var newDate = new Date(date); |
|
6146 | newDate.setHours(dt.getHours(), dt.getMinutes(), dt.getSeconds()); |
|
6147 | return newDate; |
|
6148 | } |
|
6149 | ||
6150 | function modelIsEmpty() { |
|
6151 | return ($scope.hours === null || $scope.hours === '') && |
|
6152 | ($scope.minutes === null || $scope.minutes === '') && |
|
6153 | (!$scope.showSeconds || $scope.showSeconds && ($scope.seconds === null || $scope.seconds === '')); |
|
6154 | } |
|
6155 | ||
6156 | $scope.showSpinners = angular.isDefined($attrs.showSpinners) ? |
|
6157 | $scope.$parent.$eval($attrs.showSpinners) : timepickerConfig.showSpinners; |
|
6158 | ||
6159 | $scope.incrementHours = function() { |
|
6160 | if (!$scope.noIncrementHours()) { |
|
6161 | addSecondsToSelected(hourStep * 60 * 60); |
|
6162 | } |
|
6163 | }; |
|
6164 | ||
6165 | $scope.decrementHours = function() { |
|
6166 | if (!$scope.noDecrementHours()) { |
|
6167 | addSecondsToSelected(-hourStep * 60 * 60); |
|
6168 | } |
|
6169 | }; |
|
6170 | ||
6171 | $scope.incrementMinutes = function() { |
|
6172 | if (!$scope.noIncrementMinutes()) { |
|
6173 | addSecondsToSelected(minuteStep * 60); |
|
6174 | } |
|
6175 | }; |
|
6176 | ||
6177 | $scope.decrementMinutes = function() { |
|
6178 | if (!$scope.noDecrementMinutes()) { |
|
6179 | addSecondsToSelected(-minuteStep * 60); |
|
6180 | } |
|
6181 | }; |
|
6182 | ||
6183 | $scope.incrementSeconds = function() { |
|
6184 | if (!$scope.noIncrementSeconds()) { |
|
6185 | addSecondsToSelected(secondStep); |
|
6186 | } |
|
6187 | }; |
|
6188 | ||
6189 | $scope.decrementSeconds = function() { |
|
6190 | if (!$scope.noDecrementSeconds()) { |
|
6191 | addSecondsToSelected(-secondStep); |
|
6192 | } |
|
6193 | }; |
|
6194 | ||
6195 | $scope.toggleMeridian = function() { |
|
6196 | var minutes = getMinutesFromTemplate(), |
|
6197 | hours = getHoursFromTemplate(); |
|
6198 | ||
6199 | if (!$scope.noToggleMeridian()) { |
|
6200 | if (angular.isDefined(minutes) && angular.isDefined(hours)) { |
|
6201 | addSecondsToSelected(12 * 60 * (selected.getHours() < 12 ? 60 : -60)); |
|
6202 | } else { |
|
6203 | $scope.meridian = $scope.meridian === meridians[0] ? meridians[1] : meridians[0]; |
|
6204 | } |
|
6205 | } |
|
6206 | }; |
|
6207 | ||
6208 | $scope.blur = function() { |
|
6209 | ngModelCtrl.$setTouched(); |
|
6210 | }; |
|
6211 | ||
6212 | $scope.$on('$destroy', function() { |
|
6213 | while (watchers.length) { |
|
6214 | watchers.shift()(); |
|
6215 | } |
|
6216 | }); |
|
6217 | }]) |
|
6218 | ||
6219 | .directive('uibTimepicker', ['uibTimepickerConfig', function(uibTimepickerConfig) { |
|
6220 | return { |