diff --git a/README.md b/README.md index a4b9a4c..1deac58 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ +本家からの変更点 +============= +- datepicker要素に ng-modelを設定して、日付選択時にこの値が更新される +- 内部にinputを置くのは変わらないが、日付選択時にinputのvalueは変更されない +- clear-text指定で上部にクリアボタンを表示 +``` + + + +``` + Angular Datepicker ================== ![Angular datepicker calendar](http://i.imgur.com/jKfADtA.png) diff --git a/dist/angular-datepicker.css b/dist/angular-datepicker.css index 4a26ee9..4c5d763 100644 --- a/dist/angular-datepicker.css +++ b/dist/angular-datepicker.css @@ -5,9 +5,9 @@ datepicker a, [datepicker] a, .datepicker a{ datepicker a:hover, [datepicker] a:hover, .datepicker a:hover{ text-decoration:none; } -datepicker select, datepicker select:focus, datepicker select:hover, -.datepicker select, .datepicker select:focus, .datepicker select:hover, -[datepicker] select, [datepicker] select:focus, [datepicker] select:hover{ +datepicker select._720kb-datepicker-calendar-select, +.datepicker select._720kb-datepicker-calendar-select, +[datepicker] select._720kb-datepicker-calendar-select { width:100%; overflow: hidden; background:none; @@ -23,14 +23,13 @@ datepicker, .datepicker, [datepicker], ._720kb-datepicker-calendar-days-header, ._720kb-datepicker-calendar-years-pagination-pages { font-family: Helvetica Neue, Arial, sans-serif; - font-size: 13.5px; + font-size: inherit; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; width: 100%; margin: 0 auto; - float: left; clear: right; position: relative; } @@ -60,13 +59,17 @@ datepicker, .datepicker, [datepicker], text-align: center; font-size: 15px; line-height: 40px; -} -._720kb-datepicker-calendar-header:nth-child(odd) { background: #138EFA; } ._720kb-datepicker-calendar-header:nth-child(even) { background: #7BC6FC; } +._720kb-datepicker-calendar-header-clear { + background: #DDDDDD; +} +._720kb-datepicker-calendar-header-container { + height:40px; +} ._720kb-datepicker-calendar-header-left, ._720kb-datepicker-calendar-header-middle, ._720kb-datepicker-calendar-header-right { @@ -109,9 +112,16 @@ datepicker, .datepicker, [datepicker], -moz-border-radius: 1px; border-radius: 1px; } -._720kb-datepicker-calendar-day:hover, +._720kb-datepicker-calendar-day:hover { + background: #d0e9ff; +} +._720kb-datepicker-calendar-day._720kb-datepicker-today { + background: #777; + color: #fff; +} ._720kb-datepicker-calendar-day._720kb-datepicker-active { - background: rgba(0, 0, 0, 0.03); + background: #138efa; + color: #fff; } ._720kb-datepicker-calendar-header a, ._720kb-datepicker-calendar-header a:hover { text-decoration:none; @@ -144,7 +154,6 @@ datepicker, .datepicker, [datepicker], } ._720kb-datepicker-calendar-years-pagination{ padding:2% 0 0 0; - float:left; clear: right; width: 100%; } diff --git a/dist/angular-datepicker.js b/dist/angular-datepicker.js index 971dbc9..7a504b4 100644 --- a/dist/angular-datepicker.js +++ b/dist/angular-datepicker.js @@ -1,11 +1,14 @@ /*global angular document navigator*/ -(function withAngular(angular, navigator) { +(function withAngular(angular /*, navigator*/) { 'use strict'; var A_DAY_IN_MILLISECONDS = 86400000 , isMobile = (function isMobile() { + // mobile off 動作確認後戻す + return false; + /* if (navigator.userAgent && (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || @@ -17,6 +20,7 @@ return true; } + */ }()) , generateMonthAndYearHeader = function generateMonthAndYearHeader(prevButton, nextButton, preventMobile) { @@ -30,7 +34,7 @@ return [ '
', '
', - '', '', @@ -39,7 +43,7 @@ '
', '
', '
', - '', '', @@ -51,24 +55,27 @@ return [ '
', - '', - '
', - '{{month}} ', - '', - '', - '{{year}}', - '', - '', + '', + '
', + '', + '
', + '{{month}} ', + '', + '', + '{{year}}', + '', + '', + '', + '
', + '
', + '', + nextButton, '', - '
', - '', '
', '
' ]; @@ -78,15 +85,15 @@ return [ '
', '', '', @@ -110,7 +117,7 @@ '', '{{px}}', '', - '', + '', '{{item}}', '', '', @@ -141,16 +148,16 @@ return toReturn.join(''); } - , datepickerDirective = function datepickerDirective($window, $compile, $locale, $filter, $interpolate, $timeout) { + , datepickerDirective = function datepickerDirective($document, $compile, $locale, $filter, $interpolate, $timeout) { - var linkingFunction = function linkingFunction($scope, element, attr) { + var linkingFunction = function linkingFunction($scope, element, attr, ngModelCtrl) { //get child input var selector = attr.selector , thisInput = angular.element(selector ? element[0].querySelector('.' + selector) : element[0].children[0]) , theCalendar - , defaultPrevButton = '' - , defaultNextButton = '' + , defaultPrevButton = '' + , defaultNextButton = '' , prevButton = attr.buttonPrev || defaultPrevButton , nextButton = attr.buttonNext || defaultNextButton , dateFormat = attr.dateFormat @@ -338,18 +345,29 @@ if ($scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day) && $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { - var modelDate = new Date($scope.year + '/' + $scope.monthNumber + '/' + $scope.day); - - if (attr.dateFormat) { - - thisInput.val($filter('date')(modelDate, dateFormat)); + // $scope.watchにひっかかるように、Dateオブジェクトを作り直す(オブジェクトのアドレスを更新) + // and 年月日以外の値を保持して更新する + var modelDate = ngModelCtrl.$viewValue; + + if (modelDate instanceof Date){ + modelDate = new Date(modelDate.getTime()); + modelDate.setYear($scope.year); + modelDate.setMonth($scope.monthNumber - 1); + modelDate.setDate($scope.day); + } else if (typeof modelDate === 'string') { + modelDate = new Date(modelDate); + modelDate.setYear($scope.year); + modelDate.setMonth($scope.monthNumber - 1); + modelDate.setDate($scope.day); } else { + modelDate = new Date($scope.year + '/' + $scope.monthNumber + '/' + $scope.day); + } - thisInput.val(modelDate); + if (attr.dateFormat) { + modelDate = $filter('date')(modelDate, dateFormat); } + ngModelCtrl.$setViewValue(modelDate); - thisInput.triggerHandler('input'); - thisInput.triggerHandler('change');//just to be sure; } else { return false; @@ -390,8 +408,9 @@ } } , showCalendar = function showCalendar() { + $scope.isShowed = true; //lets hide all the latest instances of datepicker - pageDatepickers = $window.document.getElementsByClassName('_720kb-datepicker-calendar'); + pageDatepickers = document.getElementsByClassName('_720kb-datepicker-calendar'); angular.forEach(pageDatepickers, function forEachDatepickerPages(value, key) { if (pageDatepickers[key].classList) { @@ -407,9 +426,9 @@ theCalendar.classList.add('_720kb-datepicker-open'); if (dateFormat) { - date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + date = localDateTimestamp(String(ngModelCtrl.$viewValue).toString(), dateFormat); } else { - date = new Date(thisInput[0].value.toString()); + date = new Date(String(ngModelCtrl.$viewValue).toString()); } $scope.selectedMonth = Number($filter('date')(date, 'MM')); $scope.selectedDay = Number($filter('date')(date, 'dd')); @@ -445,9 +464,9 @@ return false; } if (dateFormat) { - date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + date = localDateTimestamp(ngModelCtrl.$viewValue.toString(), dateFormat); } else { - date = new Date(thisInput[0].value.toString()); + date = new Date(ngModelCtrl.$viewValue.toString()); } $scope.selectedMonth = Number($filter('date')(date, 'MM')); $scope.selectedDay = Number($filter('date')(date, 'dd')); @@ -493,9 +512,7 @@ dateDisabledDates = $scope.$eval(newValue); if (!$scope.isSelectableDate($scope.monthNumber, $scope.year, $scope.day)) { - thisInput.val(''); - thisInput.triggerHandler('input'); - thisInput.triggerHandler('change');//just to be sure; + ngModelCtrl.$setViewValue(null); } } }) @@ -504,9 +521,7 @@ dateEnabledDates = $scope.$eval(newValue); if (!$scope.isSelectableDate($scope.monthNumber, $scope.year, $scope.day)) { - thisInput.val(''); - thisInput.triggerHandler('input'); - thisInput.triggerHandler('change');//just to be sure; + ngModelCtrl.$setViewValue(null); } } }); @@ -615,7 +630,10 @@ }; $scope.selectedMonthHandle = function manageSelectedMonthHandle(selectedMonthNumber) { - + if (selectedMonthNumber === null) { + // iphoneのsafariで初期化時にselectedMonthNumber=nullで呼ばれる + return; + } $scope.monthNumber = Number($filter('date')(new Date(selectedMonthNumber + '/01/2000'), 'MM')); setDaysInMonth($scope.monthNumber, $scope.year); setInputValue(); @@ -653,6 +671,7 @@ }; $scope.hideCalendar = function hideCalendar() { + $scope.isShowed = false; if (theCalendar.classList) { theCalendar.classList.remove('_720kb-datepicker-open'); } else { @@ -716,15 +735,15 @@ thisInput.on('keyup blur', function onTyping() { - if (thisInput[0].value && - thisInput[0].value.length && - thisInput[0].value.length > 0) { + if (ngModelCtrl.$viewValue && + ngModelCtrl.$viewValue.length && + ngModelCtrl.$viewValue.length > 0) { try { if (dateFormat) { - date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + date = localDateTimestamp(ngModelCtrl.$viewValue.toString(), dateFormat); } else { - date = new Date(thisInput[0].value.toString()); + date = new Date(ngModelCtrl.$viewValue.toString()); } if (date.getFullYear() && @@ -879,6 +898,11 @@ return validWeekDay; }; + $scope.clear = function clear() { + ngModelCtrl.$setViewValue(null); + $scope.hideCalendar(); + }; + // respect previously configured interpolation symbols. htmlTemplate = htmlTemplate.replace(/{{/g, $interpolate.startSymbol()).replace(/}}/g, $interpolate.endSymbol()); $scope.dateMonthTitle = $scope.dateMonthTitle || 'Select month'; @@ -942,8 +966,38 @@ //if datepicker-toggle="" is not present or true by default if (checkToggle()) { - thisInput.on('focus click focusin', function onFocusAndClick() { + thisInput.on('click', function onFocusAndClick(event) { + if (event.target.nodeName !== 'INPUT') { + // input以外の場合は無視する + return; + } + if (event.target.type !== 'button') { + // button以外は除く + return; + } + event.stopPropagation(); + isMouseOnInput = true; + + if (!isMouseOn && + !isMouseOnInput && theCalendar || $scope.isShowed) { + + $scope.hideCalendar(); + } else { + + showCalendar(); + } + }); + + thisInput.on('focusin focus', function onFocusAndClick(event) { + if (event.target.nodeName !== 'INPUT') { + // input以外の場合は無視する + return; + } + if (event.target.type === 'button') { + // buttonは除く + return; + } isMouseOnInput = true; if (!isMouseOn && @@ -958,8 +1012,14 @@ } thisInput.on('focusout blur', function onBlurAndFocusOut() { - + // focusout/blurの場合、フォーカス外れた時のevent.targetはINPUT以外の要素 isMouseOnInput = false; + + if (!isMouseOn && + !isMouseOnInput && theCalendar) { + + $scope.hideCalendar(); + } }); //some tricky dirty events to fire if click is outside of the calendar and show/hide calendar when needed angular.element(theCalendar).on('mouseenter', function onMouseEnter() { @@ -977,7 +1037,7 @@ isMouseOn = true; }); - angular.element($window).on('click focus focusin', onClickOnWindow); + $document.on('click focus focusin', onClickOnWindow); //check always if given range of dates is ok if ($scope.dateMinLimit && @@ -1010,11 +1070,12 @@ unregisterDateEnabledDatesWatcher(); thisInput.off('focus click focusout blur'); angular.element(theCalendar).off('mouseenter mouseleave focusin'); - angular.element($window).off('click focus focusin', onClickOnWindow); + $document.off('click focus focusin', onClickOnWindow); }); }; return { + 'require': 'ngModel', 'restrict': 'AEC', 'scope': { 'dateSet': '@', @@ -1033,12 +1094,13 @@ 'datepickerAppendTo': '@', 'datepickerToggle': '@', 'datepickerClass': '@', - 'datepickerShow': '@' + 'datepickerShow': '@', + 'clearText': '@' }, 'link': linkingFunction }; }; angular.module('720kb.datepicker', []) - .directive('datepicker', ['$window', '$compile', '$locale', '$filter', '$interpolate', '$timeout', datepickerDirective]); + .directive('datepicker', ['$document', '$compile', '$locale', '$filter', '$interpolate', '$timeout', datepickerDirective]); }(angular, navigator)); diff --git a/dist/angular-datepicker.min.css b/dist/angular-datepicker.min.css index 5967e84..4b181e2 100644 --- a/dist/angular-datepicker.min.css +++ b/dist/angular-datepicker.min.css @@ -1 +1 @@ -.datepicker a,[datepicker] a,datepicker a{color:inherit;text-decoration:none}.datepicker a:hover,[datepicker] a:hover,datepicker a:hover{text-decoration:none}.datepicker select,.datepicker select:focus,.datepicker select:hover,[datepicker] select,[datepicker] select:focus,[datepicker] select:hover,datepicker select,datepicker select:focus,datepicker select:hover{width:100%;overflow:hidden;background:0 0;color:#fff;background-color:#138efa;border-radius:2px;border:0;margin-top:5px}._720kb-datepicker-calendar-body,._720kb-datepicker-calendar-days-header,._720kb-datepicker-calendar-header,._720kb-datepicker-calendar-years-pagination-pages,.datepicker,[datepicker],datepicker{font-family:Helvetica Neue,Arial,sans-serif;font-size:13.5px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;width:100%;margin:0 auto;float:left;clear:right;position:relative}._720kb-datepicker-calendar{background:#fff;color:#333;position:absolute;z-index:999;min-width:220px;margin:0 auto;width:101%;-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;-moz-box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;visibility:hidden;overflow:hidden;margin-left:-.5%;padding:0 0 2% 0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}._720kb-datepicker-calendar._720kb-datepicker-forced-to-open,._720kb-datepicker-calendar._720kb-datepicker-open{visibility:visible}._720kb-datepicker-calendar-header{text-align:center;font-size:15px;line-height:40px}._720kb-datepicker-calendar-header:nth-child(odd){background:#138efa}._720kb-datepicker-calendar-header:nth-child(even){background:#7bc6fc}._720kb-datepicker-calendar-header-left,._720kb-datepicker-calendar-header-middle,._720kb-datepicker-calendar-header-right{width:15%;float:left}._720kb-datepicker-calendar-header-middle{width:70%}._720kb-datepicker-calendar-header-closed-pagination::after{content:" \25BE"}._720kb-datepicker-calendar-header-opened-pagination::after{content:" \25BE";margin-left:4px;position:relative;bottom:-3px;display:inline-block;-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}._720kb-datepicker-calendar-body{width:96%;margin:2%;text-align:center}._720kb-datepicker-calendar-day{cursor:pointer;font-size:12.5px;width:12.2%;margin:5px 1%;padding:1.5% 0;float:left;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}._720kb-datepicker-calendar-day._720kb-datepicker-active,._720kb-datepicker-calendar-day:hover{background:rgba(0,0,0,.03)}._720kb-datepicker-calendar-header a,._720kb-datepicker-calendar-header a:hover{text-decoration:none;padding:3% 9% 4% 9%;font-size:13.5px;color:rgba(0,0,0,.55);font-weight:700;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}._720kb-datepicker-calendar-header a:hover{color:rgba(0,0,0,.9);background:rgba(255,255,255,.45)}._720kb-datepicker-calendar-month{color:#fff}._720kb-datepicker-calendar-month span{font-size:13px;color:rgba(0,0,0,.4)}._720kb-datepicker-calendar-month a span i{font-style:normal;font-size:15px}._720kb-datepicker-calendar-month a,._720kb-datepicker-calendar-month a:hover{padding:3px;margin-left:1%}._720kb-datepicker-calendar-years-pagination{padding:2% 0 0 0;float:left;clear:right;width:100%}._720kb-datepicker-calendar-years-pagination a,._720kb-datepicker-calendar-years-pagination a:hover{font-size:12px;padding:0 7px;font-weight:400;margin:3px 1% 0 1%;line-height:20px;display:inline-block}._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active{color:rgba(0,0,0,.9);font-weight:500;background:rgba(255,255,255,.45)}._720kb-datepicker-calendar-years-pagination-pages a,._720kb-datepicker-calendar-years-pagination-pages a:hover{padding:5px 10px}._720kb-datepicker-calendar-days-header{max-width:100%;margin:0 auto;padding:0 2% 0 2%;background:rgba(19,142,250,.08);border-bottom:1px solid rgba(0,0,0,.02)}._720kb-datepicker-calendar-days-header div{width:14.18%;font-weight:500;font-size:11.5px;padding:10px 0;float:left;text-align:center;color:rgba(0,0,0,.7)}._720kb-datepicker-calendar-days ._720kb-datepicker-default-button{font-size:18.5px;position:relative;bottom:-.5px}._720kb-datepicker-default-button{padding:0 4.5px}._720kb-datepicker-calendar-header-middle._720kb-datepicker-mobile-item{width:95%;float:none;margin:0 auto}._720kb-datepicker-item-hidden{visibility:hidden}._720kb-datepicker-calendar-day._720kb-datepicker-disabled,._720kb-datepicker-calendar-day._720kb-datepicker-disabled:hover,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled:hover,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled:hover{color:rgba(0,0,0,.2);background:rgba(25,2,0,.02);cursor:default} \ No newline at end of file +.datepicker a,[datepicker] a,datepicker a{color:inherit;text-decoration:none}.datepicker a:hover,[datepicker] a:hover,datepicker a:hover{text-decoration:none}.datepicker select._720kb-datepicker-calendar-select,[datepicker] select._720kb-datepicker-calendar-select,datepicker select._720kb-datepicker-calendar-select{width:100%;overflow:hidden;background:0 0;color:#fff;background-color:#138efa;border-radius:2px;border:0;margin-top:5px}._720kb-datepicker-calendar-body,._720kb-datepicker-calendar-days-header,._720kb-datepicker-calendar-header,._720kb-datepicker-calendar-years-pagination-pages,.datepicker,[datepicker],datepicker{font-family:Helvetica Neue,Arial,sans-serif;font-size:inherit;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;width:100%;margin:0 auto;clear:right;position:relative}._720kb-datepicker-calendar{background:#fff;color:#333;position:absolute;z-index:999;min-width:220px;margin:0 auto;width:101%;-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;-moz-box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;visibility:hidden;overflow:hidden;margin-left:-.5%;padding:0 0 2% 0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}._720kb-datepicker-calendar._720kb-datepicker-forced-to-open,._720kb-datepicker-calendar._720kb-datepicker-open{visibility:visible}._720kb-datepicker-calendar-header{text-align:center;font-size:15px;line-height:40px;background:#138efa}._720kb-datepicker-calendar-header:nth-child(even){background:#7bc6fc}._720kb-datepicker-calendar-header-clear{background:#ddd}._720kb-datepicker-calendar-header-container{height:40px}._720kb-datepicker-calendar-header-left,._720kb-datepicker-calendar-header-middle,._720kb-datepicker-calendar-header-right{width:15%;float:left}._720kb-datepicker-calendar-header-middle{width:70%}._720kb-datepicker-calendar-header-closed-pagination::after{content:" \25BE"}._720kb-datepicker-calendar-header-opened-pagination::after{content:" \25BE";margin-left:4px;position:relative;bottom:-3px;display:inline-block;-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}._720kb-datepicker-calendar-body{width:96%;margin:2%;text-align:center}._720kb-datepicker-calendar-day{cursor:pointer;font-size:12.5px;width:12.2%;margin:5px 1%;padding:1.5% 0;float:left;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}._720kb-datepicker-calendar-day:hover{background:#d0e9ff}._720kb-datepicker-calendar-day._720kb-datepicker-today{background:#777;color:#fff}._720kb-datepicker-calendar-day._720kb-datepicker-active{background:#138efa;color:#fff}._720kb-datepicker-calendar-header a,._720kb-datepicker-calendar-header a:hover{text-decoration:none;padding:3% 9% 4% 9%;font-size:13.5px;color:rgba(0,0,0,.55);font-weight:700;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}._720kb-datepicker-calendar-header a:hover{color:rgba(0,0,0,.9);background:rgba(255,255,255,.45)}._720kb-datepicker-calendar-month{color:#fff}._720kb-datepicker-calendar-month span{font-size:13px;color:rgba(0,0,0,.4)}._720kb-datepicker-calendar-month a span i{font-style:normal;font-size:15px}._720kb-datepicker-calendar-month a,._720kb-datepicker-calendar-month a:hover{padding:3px;margin-left:1%}._720kb-datepicker-calendar-years-pagination{padding:2% 0 0 0;clear:right;width:100%}._720kb-datepicker-calendar-years-pagination a,._720kb-datepicker-calendar-years-pagination a:hover{font-size:12px;padding:0 7px;font-weight:400;margin:3px 1% 0 1%;line-height:20px;display:inline-block}._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active{color:rgba(0,0,0,.9);font-weight:500;background:rgba(255,255,255,.45)}._720kb-datepicker-calendar-years-pagination-pages a,._720kb-datepicker-calendar-years-pagination-pages a:hover{padding:5px 10px}._720kb-datepicker-calendar-days-header{max-width:100%;margin:0 auto;padding:0 2% 0 2%;background:rgba(19,142,250,.08);border-bottom:1px solid rgba(0,0,0,.02)}._720kb-datepicker-calendar-days-header div{width:14.18%;font-weight:500;font-size:11.5px;padding:10px 0;float:left;text-align:center;color:rgba(0,0,0,.7)}._720kb-datepicker-calendar-days ._720kb-datepicker-default-button{font-size:18.5px;position:relative;bottom:-.5px}._720kb-datepicker-default-button{padding:0 4.5px}._720kb-datepicker-calendar-header-middle._720kb-datepicker-mobile-item{width:95%;float:none;margin:0 auto}._720kb-datepicker-item-hidden{visibility:hidden}._720kb-datepicker-calendar-day._720kb-datepicker-disabled,._720kb-datepicker-calendar-day._720kb-datepicker-disabled:hover,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled:hover,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled:hover{color:rgba(0,0,0,.2);background:rgba(25,2,0,.02);cursor:default} \ No newline at end of file diff --git a/dist/angular-datepicker.min.js b/dist/angular-datepicker.min.js index 13c53aa..e44035d 100644 --- a/dist/angular-datepicker.min.js +++ b/dist/angular-datepicker.min.js @@ -4,9 +4,9 @@ * Released by 720kb.net under the MIT license * www.opensource.org/licenses/MIT * - * 2017-06-28 + * 2019-03-05 */ -!function(e,a){"use strict";var t=function(){if(a.userAgent&&(a.userAgent.match(/Android/i)||a.userAgent.match(/webOS/i)||a.userAgent.match(/iPhone/i)||a.userAgent.match(/iPad/i)||a.userAgent.match(/iPod/i)||a.userAgent.match(/BlackBerry/i)||a.userAgent.match(/Windows Phone/i)))return!0}(),n=function(e,a,n){return n&&(t=!1),t?['
','
','","
","
",'
','
','","
","
"]:['
','",'
',"{{month}} ",'',"","{{year}}","","","","
",'
','',a,"","
","
"]},i=function(e,a){return['
','",'
','',e,"",'',a,"","
","
"]},r=function(e,a,t){var r=['
',"
"],d=n(e,a,t),l=i(e,a),c=['
','
',"{{d}}","
","
"],o=['"],s=function(e){r.splice(r.length-1,0,e)};return d.forEach(s),l.forEach(s),c.forEach(s),o.forEach(s),r.join("")},d=function(a,n,i,d,l,c){return{restrict:"AEC",scope:{dateSet:"@",dateMinLimit:"@",dateMaxLimit:"@",dateMonthTitle:"@",dateYearTitle:"@",buttonNextTitle:"@",buttonPrevTitle:"@",dateDisabledDates:"@",dateEnabledDates:"@",dateDisabledWeekdays:"@",dateSetHidden:"@",dateTyper:"@",dateWeekStartDay:"@",datepickerAppendTo:"@",datepickerToggle:"@",datepickerClass:"@",datepickerShow:"@"},link:function(o,s,m){var u,b,h,y=m.selector,p=e.element(y?s[0].querySelector("."+y):s[0].children[0]),g=m.buttonPrev||'',M=m.buttonNext||'',k=m.dateFormat,f=o.$eval(o.dateDisabledDates),D=o.$eval(o.dateEnabledDates),v=o.$eval(o.dateDisabledWeekdays),N=new Date,S=!1,w=!1,x=void 0!==m.datepickerMobile&&"false"!==m.datepickerMobile,Y=i.DATETIME_FORMATS,T=r(g,M,x),_=function(){S||w||!u||o.hideCalendar()},L=function(e,a){var t,n,i,r,d,l=new Date(a,e,0).getDate(),c=new Date(a+"/"+e+"/1").getDay(),s=new Date(a+"/"+e+"/"+l).getDay(),m=[],u=[];for(o.days=[],o.dateWeekStartDay=o.validateWeekDay(o.dateWeekStartDay),d=(o.dateWeekStartDay+6)%7,t=1;t<=l;t+=1)o.days.push(t);if(c===o.dateWeekStartDay)o.prevMonthDays=[];else{for(i=c-o.dateWeekStartDay,c0}),t=a.match(m).filter(function(e){return null!==e.match(/^[a-zA-Z]+$/i)}),l=0;l-1||((t=e.className.split(" ")).push(a),e.className=t.join(" "))},remove:function(e,a){var t,n;if(-1!==e.className.indexOf(a)){for(n=e.className.split(" "),t=0;tNumber(e)&&!o.isSelectableMinYear(e))return;o.paginateYears(e),o.showYearsPagination=!1,c(function(){o.year=Number(e),L(o.monthNumber,o.year)},0)},o.hideCalendar=function(){u.classList?u.classList.remove("_720kb-datepicker-open"):O.remove(u,"_720kb-datepicker-open")},o.setDatepickerDay=function(e){o.isSelectableDay(o.monthNumber,o.year,e)&&o.isSelectableDate(o.monthNumber,o.year,e)&&o.isSelectableMaxDate(o.year+"/"+o.monthNumber+"/"+e)&&o.isSelectableMinDate(o.year+"/"+o.monthNumber+"/"+e)&&(o.day=Number(e),o.selectedDay=o.day,o.selectedMonth=o.monthNumber,o.selectedYear=o.year,H(),m.hasOwnProperty("dateRefocus")&&p[0].focus(),o.hideCalendar())},o.paginateYears=function(e){var a,n=[],i=10,r=10;for(o.paginationYears=[],t&&(i=50,r=50,o.dateMinLimit&&o.dateMaxLimit&&(i=(e=new Date(o.dateMaxLimit).getFullYear())-new Date(o.dateMinLimit).getFullYear(),r=1)),a=i;a>0;a-=1)n.push(Number(e)-a);for(a=0;a0)try{(N=k?E(p[0].value.toString(),k):new Date(p[0].value.toString())).getFullYear()&&!isNaN(N.getDay())&&!isNaN(N.getMonth())&&o.isSelectableDay(N.getMonth(),N.getFullYear(),N.getDay())&&o.isSelectableDate(N.getMonth(),N.getFullYear(),N.getDay())&&o.isSelectableMaxDate(N)&&o.isSelectableMinDate(N)&&o.$apply(function(){o.month=d("date")(N,"MMMM"),o.monthNumber=Number(d("date")(N,"MM")),o.day=Number(d("date")(N,"dd")),4===N.getFullYear().toString().length&&(o.year=Number(d("date")(N,"yyyy"))),L(o.monthNumber,o.year)})}catch(e){return e}}),o.dateMaxLimit&&n&&n.length&&!o.isSelectableMaxYear(Number(n[n.length-1])+1)?o.paginationYearsNextDisabled=!0:o.paginationYearsNextDisabled=!1,o.dateMinLimit&&n&&n.length&&!o.isSelectableMinYear(Number(n[0])-1)?o.paginationYearsPrevDisabled=!0:o.paginationYearsPrevDisabled=!1,o.paginationYears=n},o.isSelectableDay=function(e,a,t){var n=0;if(v&&v.length>0)for(n;n<=v.length;n+=1)if(v[n]===new Date(e+"/"+t+"/"+a).getDay())return!1;return!0},o.isSelectableDate=function(e,a,t){var n=0;if(f&&f.length>0)for(n;n<=f.length;n+=1)if(new Date(f[n]).getTime()===new Date(e+"/"+t+"/"+a).getTime())return!1;if(D){for(n;n<=D.length;n+=1)if(new Date(D[n]).getTime()===new Date(e+"/"+t+"/"+a).getTime())return!0;return!1}return!0},o.isSelectableMinDate=function(e){return!(o.dateMinLimit&&new Date(o.dateMinLimit)&&new Date(e).getTime()new Date(o.dateMaxLimit).getTime())},o.isSelectableMaxYear=function(e){return!(o.dateMaxLimit&&e>new Date(o.dateMaxLimit).getFullYear())},o.isSelectableMinYear=function(e){return!(o.dateMinLimit&&e6)&&(a=0),a},T=T.replace(/{{/g,l.startSymbol()).replace(/}}/g,l.endSymbol()),o.dateMonthTitle=o.dateMonthTitle||"Select month",o.dateYearTitle=o.dateYearTitle||"Select year",o.buttonNextTitle=o.buttonNextTitle||"Next",o.buttonPrevTitle=o.buttonPrevTitle||"Prev",o.month=d("date")(N,"MMMM"),o.monthNumber=Number(d("date")(N,"MM")),o.day=Number(d("date")(N,"dd")),o.dateWeekStartDay=o.validateWeekDay(o.dateWeekStartDay),o.dateMaxLimit?o.year=Number(d("date")(new Date(o.dateMaxLimit),"yyyy")):o.year=Number(d("date")(N,"yyyy")),o.months=Y.MONTH,o.daysInString=[],h=o.dateWeekStartDay;h<=o.dateWeekStartDay+6;h+=1)o.daysInString.push(h%7);o.daysInString=o.daysInString.map(function(e){return d("date")(new Date(new Date("06/08/2014").valueOf()+864e5*e),"EEE")}),o.datepickerAppendTo&&-1!==o.datepickerAppendTo.indexOf(".")?(o.datepickerID="datepicker-id-"+(new Date).getTime()+(Math.floor(6*Math.random())+8),e.element(document.getElementsByClassName(o.datepickerAppendTo.replace(".",""))[0]).append(n(e.element(T))(o,function(a){u=e.element(a)[0]}))):o.datepickerAppendTo&&-1!==o.datepickerAppendTo.indexOf("#")?(o.datepickerID="datepicker-id-"+(new Date).getTime()+(Math.floor(6*Math.random())+8),e.element(document.getElementById(o.datepickerAppendTo.replace("#",""))).append(n(e.element(T))(o,function(a){u=e.element(a)[0]}))):o.datepickerAppendTo&&"body"===o.datepickerAppendTo?(o.datepickerID="datepicker-id-"+((new Date).getTime()+(Math.floor(6*Math.random())+8)),e.element(document).find("body").append(n(e.element(T))(o,function(a){u=e.element(a)[0]}))):(p.after(n(e.element(T))(o)),u=s[0].querySelector("._720kb-datepicker-calendar")),function(){return!o.datepickerToggle||o.$eval(o.datepickerToggle)}()&&p.on("focus click focusin",function(){w=!0,S||w||!u?F():o.hideCalendar()}),p.on("focusout blur",function(){w=!1}),e.element(u).on("mouseenter",function(){S=!0}),e.element(u).on("mouseleave",function(){S=!1}),e.element(u).on("focusin",function(){S=!0}),e.element(a).on("click focus focusin",_),(o.dateMinLimit&&!o.isSelectableMinYear(o.year)||!o.isSelectableMinDate(o.year+"/"+o.monthNumber+"/"+o.day))&&$(),(o.dateMaxLimit&&!o.isSelectableMaxYear(o.year)||!o.isSelectableMaxDate(o.year+"/"+o.monthNumber+"/"+o.day))&&A(),o.paginateYears(o.year),L(o.monthNumber,o.year),o.checkVisibility=j,o.$on("$destroy",function(){I(),C(),B(),G(),z(),R(),p.off("focus click focusout blur"),e.element(u).off("mouseenter mouseleave focusin"),e.element(a).off("click focus focusin",_)})}}};e.module("720kb.datepicker",[]).directive("datepicker",["$window","$compile","$locale","$filter","$interpolate","$timeout",d])}(angular,navigator); +!function(H){"use strict";var B=!1,G=function(e,a,t){var i,n,r=['
',"
"],d=(i=e,n=a,t&&(B=!1),B?['
','
','","
","
",'
','
','","
","
"]:['
','','
','
','',i,"","
",'
',"{{month}} ",'',"","{{year}}","","","","
",'
','',n,"","
","
","
"]),l=['
','",'
','',e,"",'',a,"","
","
"],o=['
','
',"{{d}}","
","
"],c=['"],s=function(e){r.splice(r.length-1,0,e)};return d.forEach(s),l.forEach(s),o.forEach(s),c.forEach(s),r.join("")};H.module("720kb.datepicker",[]).directive("datepicker",["$document","$compile","$locale","$filter","$interpolate","$timeout",function(O,A,F,C,I,j){return{require:"ngModel",restrict:"AEC",scope:{dateSet:"@",dateMinLimit:"@",dateMaxLimit:"@",dateMonthTitle:"@",dateYearTitle:"@",buttonNextTitle:"@",buttonPrevTitle:"@",dateDisabledDates:"@",dateEnabledDates:"@",dateDisabledWeekdays:"@",dateSetHidden:"@",dateTyper:"@",dateWeekStartDay:"@",datepickerAppendTo:"@",datepickerToggle:"@",datepickerClass:"@",datepickerShow:"@",clearText:"@"},link:function(u,e,a,r){var t,i,n,d=a.selector,l=H.element(d?e[0].querySelector("."+d):e[0].children[0]),o=a.buttonPrev||'',c=a.buttonNext||'',s=a.dateFormat,m=u.$eval(u.dateDisabledDates),b=u.$eval(u.dateEnabledDates),y=u.$eval(u.dateDisabledWeekdays),p=new Date,h=!1,g=!1,k=void 0!==a.datepickerMobile&&"false"!==a.datepickerMobile,M=F.DATETIME_FORMATS,f=G(o,c,k),D=function(){h||g||!t||u.hideCalendar()},v=function(e,a){var t,i,n,r,d,l=new Date(a,e,0).getDate(),o=new Date(a+"/"+e+"/1").getDay(),c=new Date(a+"/"+e+"/"+l).getDay(),s=[],m=[];for(u.days=[],u.dateWeekStartDay=u.validateWeekDay(u.dateWeekStartDay),d=(u.dateWeekStartDay+6)%7,t=1;t<=l;t+=1)u.days.push(t);if(o===u.dateWeekStartDay)u.prevMonthDays=[];else{for(n=o-u.dateWeekStartDay,oNumber(e)&&!u.isSelectableMinYear(e))return;u.paginateYears(e),u.showYearsPagination=!1,j(function(){u.year=Number(e),v(u.monthNumber,u.year)},0)},u.hideCalendar=function(){u.isShowed=!1,t.classList?t.classList.remove("_720kb-datepicker-open"):T(t,"_720kb-datepicker-open")},u.setDatepickerDay=function(e){u.isSelectableDay(u.monthNumber,u.year,e)&&u.isSelectableDate(u.monthNumber,u.year,e)&&u.isSelectableMaxDate(u.year+"/"+u.monthNumber+"/"+e)&&u.isSelectableMinDate(u.year+"/"+u.monthNumber+"/"+e)&&(u.day=Number(e),u.selectedDay=u.day,u.selectedMonth=u.monthNumber,u.selectedYear=u.year,x(),a.hasOwnProperty("dateRefocus")&&l[0].focus(),u.hideCalendar())},u.paginateYears=function(e){var a,t=[],i=10,n=10;for(u.paginationYears=[],B&&(n=i=50,u.dateMinLimit&&u.dateMaxLimit&&(i=(e=new Date(u.dateMaxLimit).getFullYear())-new Date(u.dateMinLimit).getFullYear(),n=1)),a=i;0new Date(u.dateMaxLimit).getTime())},u.isSelectableMaxYear=function(e){return!(u.dateMaxLimit&&e>new Date(u.dateMaxLimit).getFullYear())},u.isSelectableMinYear=function(e){return!(u.dateMinLimit&&e', '
', - '', '', @@ -39,7 +43,7 @@ '
', '
', '
', - '', '', @@ -51,24 +55,27 @@ return [ '
', - '', - '
', - '{{month}} ', - '', - '', - '{{year}}', - '', - '', + '', + '
', + '', + '
', + '{{month}} ', + '', + '', + '{{year}}', + '', + '', + '', + '
', + '
', + '', + nextButton, '', - '
', - '', '
', '
' ]; @@ -78,15 +85,15 @@ return [ '
', '', '', @@ -110,7 +117,7 @@ '', '{{px}}', '', - '', + '', '{{item}}', '', '', @@ -141,16 +148,16 @@ return toReturn.join(''); } - , datepickerDirective = function datepickerDirective($window, $compile, $locale, $filter, $interpolate, $timeout) { + , datepickerDirective = function datepickerDirective($document, $compile, $locale, $filter, $interpolate, $timeout) { - var linkingFunction = function linkingFunction($scope, element, attr) { + var linkingFunction = function linkingFunction($scope, element, attr, ngModelCtrl) { //get child input var selector = attr.selector , thisInput = angular.element(selector ? element[0].querySelector('.' + selector) : element[0].children[0]) , theCalendar - , defaultPrevButton = '' - , defaultNextButton = '' + , defaultPrevButton = '' + , defaultNextButton = '' , prevButton = attr.buttonPrev || defaultPrevButton , nextButton = attr.buttonNext || defaultNextButton , dateFormat = attr.dateFormat @@ -338,18 +345,30 @@ if ($scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day) && $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { - var modelDate = new Date($scope.year + '/' + $scope.monthNumber + '/' + $scope.day); - - if (attr.dateFormat) { - - thisInput.val($filter('date')(modelDate, dateFormat)); + // $scope.watchにひっかかるように、Dateオブジェクトを作り直す(オブジェクトのアドレスを更新) + // and 年月日以外の値を保持して更新する + var modelDate = ngModelCtrl.$viewValue; + + if (modelDate instanceof Date){ + modelDate = new Date(modelDate.getTime()); + modelDate.setYear($scope.year); + modelDate.setMonth($scope.monthNumber - 1); + modelDate.setDate($scope.day); + } else if (typeof modelDate === 'string') { + modelDate = new Date(modelDate); + modelDate.setDate(1); // dateが月末だと意図しない動きになるので一度月初にする + modelDate.setYear($scope.year); + modelDate.setMonth($scope.monthNumber - 1); + modelDate.setDate($scope.day); } else { + modelDate = new Date($scope.year + '/' + $scope.monthNumber + '/' + $scope.day); + } - thisInput.val(modelDate); + if (attr.dateFormat) { + modelDate = $filter('date')(modelDate, dateFormat); } + ngModelCtrl.$setViewValue(modelDate); - thisInput.triggerHandler('input'); - thisInput.triggerHandler('change');//just to be sure; } else { return false; @@ -390,8 +409,9 @@ } } , showCalendar = function showCalendar() { + $scope.isShowed = true; //lets hide all the latest instances of datepicker - pageDatepickers = $window.document.getElementsByClassName('_720kb-datepicker-calendar'); + pageDatepickers = document.getElementsByClassName('_720kb-datepicker-calendar'); angular.forEach(pageDatepickers, function forEachDatepickerPages(value, key) { if (pageDatepickers[key].classList) { @@ -407,9 +427,9 @@ theCalendar.classList.add('_720kb-datepicker-open'); if (dateFormat) { - date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + date = localDateTimestamp(String(ngModelCtrl.$viewValue).toString(), dateFormat); } else { - date = new Date(thisInput[0].value.toString()); + date = new Date(String(ngModelCtrl.$viewValue).toString()); } $scope.selectedMonth = Number($filter('date')(date, 'MM')); $scope.selectedDay = Number($filter('date')(date, 'dd')); @@ -445,9 +465,9 @@ return false; } if (dateFormat) { - date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + date = localDateTimestamp(ngModelCtrl.$viewValue.toString(), dateFormat); } else { - date = new Date(thisInput[0].value.toString()); + date = new Date(ngModelCtrl.$viewValue.toString()); } $scope.selectedMonth = Number($filter('date')(date, 'MM')); $scope.selectedDay = Number($filter('date')(date, 'dd')); @@ -493,9 +513,7 @@ dateDisabledDates = $scope.$eval(newValue); if (!$scope.isSelectableDate($scope.monthNumber, $scope.year, $scope.day)) { - thisInput.val(''); - thisInput.triggerHandler('input'); - thisInput.triggerHandler('change');//just to be sure; + ngModelCtrl.$setViewValue(null); } } }) @@ -504,9 +522,7 @@ dateEnabledDates = $scope.$eval(newValue); if (!$scope.isSelectableDate($scope.monthNumber, $scope.year, $scope.day)) { - thisInput.val(''); - thisInput.triggerHandler('input'); - thisInput.triggerHandler('change');//just to be sure; + ngModelCtrl.$setViewValue(null); } } }); @@ -615,7 +631,10 @@ }; $scope.selectedMonthHandle = function manageSelectedMonthHandle(selectedMonthNumber) { - + if (selectedMonthNumber === null) { + // iphoneのsafariで初期化時にselectedMonthNumber=nullで呼ばれる + return; + } $scope.monthNumber = Number($filter('date')(new Date(selectedMonthNumber + '/01/2000'), 'MM')); setDaysInMonth($scope.monthNumber, $scope.year); setInputValue(); @@ -653,6 +672,7 @@ }; $scope.hideCalendar = function hideCalendar() { + $scope.isShowed = false; if (theCalendar.classList) { theCalendar.classList.remove('_720kb-datepicker-open'); } else { @@ -716,15 +736,15 @@ thisInput.on('keyup blur', function onTyping() { - if (thisInput[0].value && - thisInput[0].value.length && - thisInput[0].value.length > 0) { + if (ngModelCtrl.$viewValue && + ngModelCtrl.$viewValue.length && + ngModelCtrl.$viewValue.length > 0) { try { if (dateFormat) { - date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + date = localDateTimestamp(ngModelCtrl.$viewValue.toString(), dateFormat); } else { - date = new Date(thisInput[0].value.toString()); + date = new Date(ngModelCtrl.$viewValue.toString()); } if (date.getFullYear() && @@ -879,6 +899,11 @@ return validWeekDay; }; + $scope.clear = function clear() { + ngModelCtrl.$setViewValue(null); + $scope.hideCalendar(); + }; + // respect previously configured interpolation symbols. htmlTemplate = htmlTemplate.replace(/{{/g, $interpolate.startSymbol()).replace(/}}/g, $interpolate.endSymbol()); $scope.dateMonthTitle = $scope.dateMonthTitle || 'Select month'; @@ -942,8 +967,38 @@ //if datepicker-toggle="" is not present or true by default if (checkToggle()) { - thisInput.on('focus click focusin', function onFocusAndClick() { + thisInput.on('click', function onFocusAndClick(event) { + if (event.target.nodeName !== 'INPUT') { + // input以外の場合は無視する + return; + } + if (event.target.type !== 'button') { + // button以外は除く + return; + } + event.stopPropagation(); + isMouseOnInput = true; + + if (!isMouseOn && + !isMouseOnInput && theCalendar || $scope.isShowed) { + + $scope.hideCalendar(); + } else { + + showCalendar(); + } + }); + + thisInput.on('focusin focus', function onFocusAndClick(event) { + if (event.target.nodeName !== 'INPUT') { + // input以外の場合は無視する + return; + } + if (event.target.type === 'button') { + // buttonは除く + return; + } isMouseOnInput = true; if (!isMouseOn && @@ -958,8 +1013,14 @@ } thisInput.on('focusout blur', function onBlurAndFocusOut() { - + // focusout/blurの場合、フォーカス外れた時のevent.targetはINPUT以外の要素 isMouseOnInput = false; + + if (!isMouseOn && + !isMouseOnInput && theCalendar) { + + $scope.hideCalendar(); + } }); //some tricky dirty events to fire if click is outside of the calendar and show/hide calendar when needed angular.element(theCalendar).on('mouseenter', function onMouseEnter() { @@ -977,7 +1038,7 @@ isMouseOn = true; }); - angular.element($window).on('click focus focusin', onClickOnWindow); + $document.on('click focus focusin', onClickOnWindow); //check always if given range of dates is ok if ($scope.dateMinLimit && @@ -1010,11 +1071,12 @@ unregisterDateEnabledDatesWatcher(); thisInput.off('focus click focusout blur'); angular.element(theCalendar).off('mouseenter mouseleave focusin'); - angular.element($window).off('click focus focusin', onClickOnWindow); + $document.off('click focus focusin', onClickOnWindow); }); }; return { + 'require': 'ngModel', 'restrict': 'AEC', 'scope': { 'dateSet': '@', @@ -1033,12 +1095,13 @@ 'datepickerAppendTo': '@', 'datepickerToggle': '@', 'datepickerClass': '@', - 'datepickerShow': '@' + 'datepickerShow': '@', + 'clearText': '@' }, 'link': linkingFunction }; }; angular.module('720kb.datepicker', []) - .directive('datepicker', ['$window', '$compile', '$locale', '$filter', '$interpolate', '$timeout', datepickerDirective]); + .directive('datepicker', ['$document', '$compile', '$locale', '$filter', '$interpolate', '$timeout', datepickerDirective]); }(angular, navigator));