diff --git a/.eslintrc b/.eslintrc index 52d7a45..53eecb8 100644 --- a/.eslintrc +++ b/.eslintrc @@ -22,7 +22,7 @@ "no-plusplus": 2, "no-bitwise": 2, "block-scoped-var": 2, - "consistent-return": 2, + "consistent-return": 1, "curly": [ 2, "all" @@ -32,7 +32,6 @@ "no-caller": 2, "no-div-regex": 2, "no-else-return": 2, - "no-empty-label": 2, "no-eq-null": 2, "no-eval": 2, "no-extend-native": 2, @@ -64,7 +63,6 @@ 2, "outside" ], - "strict": [2, "never"], "strict": 2, "no-catch-shadow": 2, "no-delete-var": 2, @@ -109,10 +107,7 @@ 2, "always" ], - "space-after-keywords": [ - 2, - "always" - ], + "keyword-spacing": 2, "object-curly-spacing": [ 2, "never" @@ -126,7 +121,6 @@ "never" ], "space-infix-ops": 2, - "space-return-throw-case": 2, "space-unary-ops": 2, "one-var": 2, "wrap-regex": 2, @@ -150,7 +144,6 @@ 1, "expression" ], - "no-extra-parens": 1, "func-names": 1, "no-ternary": 0, diff --git a/.gitignore b/.gitignore index c8aea3c..3353a52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ bower_components/ npm-debug.log +**/.idea \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 9883dd8..d3c8000 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -20,7 +20,8 @@ , cssmin = require('./tasks/cssmin')(banner, grunt) , connect = require('./tasks/connect')(grunt) , watch = require('./tasks/watch')(grunt) - , concurrent = require('./tasks/concurrent')(grunt); + , concurrent = require('./tasks/concurrent')(grunt) + , copy = require('./tasks/copy')(grunt); grunt.initConfig({ 'pkg': grunt.file.readJSON('package.json'), @@ -32,7 +33,8 @@ 'cssmin': cssmin, 'connect': connect, 'watch': watch, - 'concurrent': concurrent + 'concurrent': concurrent, + 'copy': copy }); grunt.registerTask('default', [ @@ -48,6 +50,7 @@ grunt.registerTask('prod', [ 'lint', + 'copy:non-minified', 'cssmin', 'uglify' ]); diff --git a/README.md b/README.md index 2c19f3e..a4b9a4c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ Angular Datepicker ================== +![Angular datepicker calendar](http://i.imgur.com/jKfADtA.png) [![Join the chat at https://gitter.im/720kb/angular-datepicker](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/720kb/angular-datepicker?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) @@ -8,17 +9,13 @@ Angular datepicker is an angularjs directive that generates a datepicker calenda The Angularjs Datepicker is developed by [720kb](http://720kb.net). -##Requirements +## Requirements +AngularJS v1.3+ -AngularJS v1.2+ +### Browser support -##Screen -![Angular datepicker calendar](http://i.imgur.com/44ut0ET.png) - -###Browser support - -![Chrome](https://raw.github.com/alrra/browser-logos/master/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/firefox/firefox_48x48.png) | ![IE](https://raw.github.com/alrra/browser-logos/master/internet-explorer/internet-explorer_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/opera/opera_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/safari/safari_48x48.png) +Chrome | Firefox | IE | Opera | Safari --- | --- | --- | --- | --- | ✔ | ✔ | IE9 + | ✔ | ✔ | @@ -40,17 +37,22 @@ To use the directive, include the Angular Datepicker's javascript and css files ``` -##Install +## Installation -###Bower installation +#### Bower ``` $ bower install angularjs-datepicker --save ``` +#### Npm + +``` +$ npm install angularjs-datepicker --save +``` _then load the js files in your html_ -###Add module dependency +### Add module dependency Add the 720kb.datepicker module dependency @@ -60,7 +62,6 @@ angular.module('app', [ ]); ``` - Call the directive wherever you want in your html page ```html @@ -70,62 +71,42 @@ Call the directive wherever you want in your html page ``` > By default the ng-model will show a Javascript Date() Object inside your input, you can use the options below to set your preferred date format to. -##Options -Angular datepicker allows you to use some options via `attribute` data - -####Date format -You can use all the Angularjs `$date` filter date formats (that can be found [here](https://docs.angularjs.org/api/ng/filter/date)) -```html - - - -``` - -####Date limits -You can set date limits using `date-min-limit=""` and `date-max-limit=""` attribute data ( you can use all the accepted date formats by the javascript `new Date()`) - -```html - - - -``` - -####Default date -You can set date to be displayed by default with `date-set=""` attribute data ( you can use all the accepted date formats by the javascript `new Date()`) - -```html - - - - - - - -``` - -####Default date hidden on start -You can set default date to be shown only in calendar and not in input field by using the `date-set-hidden="true"` option. - -```html - - - -``` - -####Date disabled -You can disable specific dates using the **date-disabled-dates=""** attribute and an _Array_ of dates you want to disable. - -```html - - - -``` +## DOC + +Option | Type | Default | Description +------------- | ------------- | ------------- | ------------- +date-set="" | String | false | Set a default date to show and init datepicker + | | | **tip:** _Do not use same scope for ng-model="date" and date-set="{{date}}", this example is wrong._ + | | | **tip:** _If you want to pass a Date Object inside do like this date-set="{{newDateObject.toString()}}"_ + | | | **tip:** _Consider that `date-set="{{myDate}}"` equals to `new Date(attr.dateSet)`, be sure the date you pass inside date-set="" is always in a correct ISO format, or adjust it based on the browser locale to avoid problems with that."._ +date-format="" | String | String(new Date()) | Set the date format you want to use, see the list [here](https://docs.angularjs.org/api/ng/filter/date) + | | | **tip:** _Be always sure to use a recognized format, maybe try first of all to pass it through new Date('...') and see if it's recognized_ +date-min-limit="" | String | false | Set a minimum date limit - you can use all the accepted date formats by the javascript `new Date()` +date-max-limit="" | String | false | Set a maximum date limit - you can use all the accepted date formats by the javascript `new Date()` +date-set-hidden="" | String(Boolean) | false | Set the default date to be shown only in calendar and not in the input field +date-disabled-dates="" | String([Date(), Date(), ...]) | false | Disable specific dates using an _Array_ of dates. +date-enabled-dates="" | String([Date(), Date(), ...]) | false | Enable only the specific dates using an _Array_ of dates. +date-disabled-weekdays="" | String(1, 5, ...]) | false | Disable specific weekdays using an _Array_ of weeks number +date-refocus="" | String(Boolean) | false | Set the datepicker to re-focus the input after selecting a date +date-typer="" | String(Boolean) | false | Set the datepicker to update calendar date when user is typing a date, see validation [tips](#date-validation) +date-week-start-day="" | String(Number) | 0 | Set the first day of the week. Must be an integer between 0 (Sunday) and 6 (Saturday). (e.g. 1 for Monday) +datepicker-class="" | String('class1 class2 class3') | false | Set custom class/es for the datepicker calendar +datepicker-append-to="" | String('#id','.classname', 'body') | false | Append the datepicker to #id or .class element or to body +datepicker-toggle="" | String(Boolean) | true | Set the datepicker to toggle its visibility on focus and blur +| | | **tip:** Best is to use `pointer-events: none;` on your input if you don't want the user to toggle the calendar visibility. +datepicker-show="" | String | false | Trigger the datepicker visibility, if true datepicker is shown if false it is hidden + | | | **tip:** _Do not mix it with datepicker-toggle for a more stable behavior_ +datepicker-mobile="" | String | true | Set to `false` to force override of mobile styles. Especially useful for using desktop-style pagination control in mobile apps. + +## Options +Angular datepicker allows you to use some options via `attribute` data +#### Custom titles -####Custom titles You can set the titles for the month and year selectors with the **date-year-title=""** and **date-month-title=""** data attributes (default to is _"select month"_ and _"select year"_) +```html @@ -133,8 +114,19 @@ You can set the titles for the month and year selectors with the **date-year-tit +``` -####Custom buttons +#### Highlight today day in calendar +To highlight or style the today day in the calendar just use its own CSS class (`._720kb-datepicker-today`) like this: + +```css +._720kb-datepicker-calendar-day._720kb-datepicker-today { + background:red; + color:white; +} +``` + +#### Custom buttons You can customize the calendar navigation buttons content, let's make an example while using [FontAwesome](http://fontawesome.io) ```html @@ -142,8 +134,11 @@ You can customize the calendar navigation buttons content, let's make an example ``` -####Custom buttons titles for arrows + +#### Custom buttons titles for arrows You can also set the titles for the left and right arrows with **button-next-title=""** for the right and **button-prev-title=""** for the left. By default they are labeled _"next"_ and _"prev"_. + +```html @@ -151,49 +146,107 @@ You can also set the titles for the left and right arrows with **button-next-tit +``` -####Input as grandchild +#### Input as grandchild Sometimes you cannot put date input as a first child of datepicker. In this case you may use `selector=""` to point to the CSS class of the input. Below example with using Twitter Bootstrap and FontAwesome ```html
- - + + + +
``` +#### Manually show and hide datepicker +Sometimes you want to (manually/programmatically) show or hide the datepicker, this can be achieved using `datepicker-show` attribute, if `false`, datepicker is hidden, if `true`, datepicker is shown + +```javascript +.controller('TestController', ['$scope', '$interval', function TestController($scope, $interval) { + $scope.visibility = true; + + $interval(function setInterval() { + //toggling manually everytime + $scope.visibility = !$scope.visibility; + }, 3500); + }]); +``` +```html + + + +``` +_tip: you should use this attribute together with `datepicker-toggle="false" , for a better stable behavior of the datepicker_ -####Datepicker visible on load -You have an option to make the datepicker visible when it loads with `visible-on-load` attribute. +#### Input as grandchild +Sometimes you cannot put date input as a first child of datepicker. In this case you may use `selector=""` to point to the CSS class of the input. Below example with using Twitter Bootstrap and FontAwesome ```html - - + +
+ + + + +
``` +### Tips -####Re-focus input after selecting date -Re-focus input after selecting a date with `date-refocus` attribute. +#### Date validation +If you want to validate the input, while user is typing for example, you just have to refer to the `ngModel`. +As long as you use something like: +```html +
+ +
+``` +You can show validation errors simply validating the ngModel, as you would do for any other type of input, for example: +```javascript +.controller('Ctrl', ['$scope', function ($scope) { + var liveDate; + + $scope.$watch('myDate', function (value) { + try { + liveDate = new Date(value); + } catch(e) {} + + if (!liveDate) { + + $scope.error = "This is not a valid date"; + } else { + $scope.error = false; + } + }); +}]); +``` +Then your final html: ```html - - - +
+ +
{{ctrl.error}}
+
``` + ### Example [Live demo](https://720kb.github.io/angular-datepicker) -##Themes :art: +## Themes :art: You can edit the default Css file `angular-datepicker.css` if you want to make a new theme for the datepicker, then just add it to the ```themes``` dir and PR! More about it https://github.com/720kb/angular-datepicker/tree/master/themes. Here is an example of a [Dark Theme](http://codepen.io/45kb/pen/bjslv) made using custom Css. -##Contributing +***_Please note that the example may not be uptodate with the latest angular and/or module version_ + +## Contributing We will be much grateful if you help us making this project to grow up. Feel free to contribute by forking, opening issues, pull requests etc. diff --git a/assets/js/index.js b/assets/js/index.js index e3c0b2f..3835ff7 100644 --- a/assets/js/index.js +++ b/assets/js/index.js @@ -1,4 +1,4 @@ -/*global angular*/ +/*global angular window*/ (function (angular) { 'use strict'; @@ -6,5 +6,16 @@ var app = angular.module('720kb', [ 'ngRoute', '720kb.datepicker' - ]); + ]) + .controller('TestController', ['$scope', '$interval', function TestController($scope, $interval) { + var that = this; + + that.visibility = true; + + $interval(function setInterval() { + //toggle manually everytime + that.visibility = !that.visibility; + window.console.info('Toggling datepicker with interval of 3.5 seconds'); + }, 3500); + }]); }(angular)); diff --git a/bower.json b/bower.json index 981433d..8a5471f 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angularjs-datepicker", - "version": "0.2.12", + "version": "2.1.23", "description": "A datepicker directive for angularjs.", "authors": [ "Filippo Oretti ', + '
', + '', + '
', + '', + '
', + '
', + '', + '
', + '
' + ]; + } + + return [ + '
', + '', + '
', + '{{month}} ', + '', + '', + '{{year}}', + '', + '', + '', + '
', + '', + '
' + ]; + } + , generateYearsPaginationHeader = function generateYearsPaginationHeader(prevButton, nextButton) { + + return [ + '
', + '
', + '', + '{{y}}', + '', + '
', + '', + '
' + ]; + } + , generateDaysColumns = function generateDaysColumns() { + + return [ + '
', + '
', + '{{d}}', + '
', + '
' + ]; + } + , generateDays = function generateDays() { + + return [ + '' + ]; + } + , generateHtmlTemplate = function generateHtmlTemplate(prevButton, nextButton, preventMobile) { + + var toReturn = [ + '
', + '
' + ] + , monthAndYearHeader = generateMonthAndYearHeader(prevButton, nextButton, preventMobile) + , yearsPaginationHeader = generateYearsPaginationHeader(prevButton, nextButton) + , daysColumns = generateDaysColumns() + , days = generateDays() + , iterator = function iterator(aRow) { + + toReturn.splice(toReturn.length - 1, 0, aRow); + }; + + monthAndYearHeader.forEach(iterator); + yearsPaginationHeader.forEach(iterator); + daysColumns.forEach(iterator); + days.forEach(iterator); + + return toReturn.join(''); + } + , datepickerDirective = function datepickerDirective($window, $compile, $locale, $filter, $interpolate, $timeout) { + + var linkingFunction = function linkingFunction($scope, element, attr) { + + //get child input + var selector = attr.selector + , thisInput = angular.element(selector ? element[0].querySelector('.' + selector) : element[0].children[0]) + , theCalendar + , defaultPrevButton = '' + , defaultNextButton = '' + , prevButton = attr.buttonPrev || defaultPrevButton + , nextButton = attr.buttonNext || defaultNextButton + , dateFormat = attr.dateFormat + //, dateMinLimit + //, dateMaxLimit + , dateDisabledDates = $scope.$eval($scope.dateDisabledDates) + , dateEnabledDates = $scope.$eval($scope.dateEnabledDates) + , dateDisabledWeekdays = $scope.$eval($scope.dateDisabledWeekdays) + , date = new Date() + , isMouseOn = false + , isMouseOnInput = false + , preventMobile = typeof attr.datepickerMobile !== 'undefined' && attr.datepickerMobile !== 'false' + , datetime = $locale.DATETIME_FORMATS + , pageDatepickers + , hours24h = 86400000 + , htmlTemplate = generateHtmlTemplate(prevButton, nextButton, preventMobile) + , n + , onClickOnWindow = function onClickOnWindow() { + + if (!isMouseOn && + !isMouseOnInput && theCalendar) { + + $scope.hideCalendar(); + } + } + , setDaysInMonth = function setDaysInMonth(month, year) { + + var i + , limitDate = new Date(year, month, 0).getDate() + , firstDayMonthNumber = new Date(year + '/' + month + '/' + 1).getDay() + , lastDayMonthNumber = new Date(year + '/' + month + '/' + limitDate).getDay() + , prevMonthDays = [] + , nextMonthDays = [] + , howManyNextDays + , howManyPreviousDays + , monthAlias + , dateWeekEndDay; + + $scope.days = []; + $scope.dateWeekStartDay = $scope.validateWeekDay($scope.dateWeekStartDay); + dateWeekEndDay = ($scope.dateWeekStartDay + 6) % 7; + + for (i = 1; i <= limitDate; i += 1) { + + $scope.days.push(i); + } + + //get previous month days if first day in month is not first day in week + if (firstDayMonthNumber === $scope.dateWeekStartDay) { + + //no need for it + $scope.prevMonthDays = []; + } else { + + howManyPreviousDays = firstDayMonthNumber - $scope.dateWeekStartDay; + + if (firstDayMonthNumber < $scope.dateWeekStartDay) { + + howManyPreviousDays += 7; + } + + //get previous month + if (Number(month) === 1) { + + monthAlias = 12; + } else { + + monthAlias = month - 1; + } + //return previous month days + for (i = 1; i <= new Date(year, monthAlias, 0).getDate(); i += 1) { + + prevMonthDays.push(i); + } + //attach previous month days + $scope.prevMonthDays = prevMonthDays.slice(-howManyPreviousDays); + } + + //get next month days if last day in month is not last day in week + if (lastDayMonthNumber === dateWeekEndDay) { + //no need for it + $scope.nextMonthDays = []; + } else { + howManyNextDays = 6 - lastDayMonthNumber + $scope.dateWeekStartDay; + + if (lastDayMonthNumber < $scope.dateWeekStartDay) { + + howManyNextDays -= 7; + } + //get previous month + + //return next month days + for (i = 1; i <= howManyNextDays; i += 1) { + + nextMonthDays.push(i); + } + //attach previous month days + $scope.nextMonthDays = nextMonthDays; + } + } + , resetToMinDate = function resetToMinDate() { + + $scope.month = $filter('date')(new Date($scope.dateMinLimit), 'MMMM'); + $scope.monthNumber = Number($filter('date')(new Date($scope.dateMinLimit), 'MM')); + $scope.day = Number($filter('date')(new Date($scope.dateMinLimit), 'dd')); + $scope.year = Number($filter('date')(new Date($scope.dateMinLimit), 'yyyy')); + + setDaysInMonth($scope.monthNumber, $scope.year); + } + , resetToMaxDate = function resetToMaxDate() { + + $scope.month = $filter('date')(new Date($scope.dateMaxLimit), 'MMMM'); + $scope.monthNumber = Number($filter('date')(new Date($scope.dateMaxLimit), 'MM')); + $scope.day = Number($filter('date')(new Date($scope.dateMaxLimit), 'dd')); + $scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy')); + + setDaysInMonth($scope.monthNumber, $scope.year); + } + , prevYear = function prevYear() { + + $scope.year = Number($scope.year) - 1; + } + , nextYear = function nextYear() { + + $scope.year = Number($scope.year) + 1; + } + , localDateTimestamp = function localDateTimestamp(rawDate, dateFormatDefinition) { + + var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|MMMM|MMM|MM|M|dd?d?|yy?yy?y?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g + ,formatDate,dateSplit, m, d, y, index, el, longName, shortName; + + for (index = 0; index < datetime.MONTH.length; index += 1) { + longName = datetime.MONTH[index]; + shortName = datetime.SHORTMONTH[index]; + + if (rawDate.indexOf(longName) !== -1) { + rawDate = rawDate.replace(longName, index + 1); + break; + } + + if (rawDate.indexOf(shortName) !== -1) { + rawDate = rawDate.replace(shortName, index + 1); + break; + } + } + + dateSplit = rawDate + .split(/\D/) + .filter(function dateSplitFilter(item) { + return item.length > 0; + }); + + formatDate = dateFormatDefinition + .match(formattingTokens) + .filter(function fromatDateFilter(item) { + return item.match(/^[a-zA-Z]+$/i) !== null; + }); + + for (index = 0; index < formatDate.length; index += 1) { + el = formatDate[index]; + + switch (true) { + case el.indexOf('d') !== -1: { + d = dateSplit[index - (formatDate.length - dateSplit.length)]; + break; + } + case el.indexOf('M') !== -1: { + m = dateSplit[index - (formatDate.length - dateSplit.length)]; + break; + } + case el.indexOf('y') !== -1: { + y = dateSplit[index - (formatDate.length - dateSplit.length)]; + break; + } + default: { + break; + } + } + } + + return new Date(y + '/' + m + '/' + d); + } + , setInputValue = function setInputValue() { + + 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)); + } else { + + thisInput.val(modelDate); + } + + thisInput.triggerHandler('input'); + thisInput.triggerHandler('change');//just to be sure; + } else { + + return false; + } + } + , classHelper = { + 'add': function add(ele, klass) { + var classes; + + if (ele.className.indexOf(klass) > -1) { + + return; + } + + classes = ele.className.split(' '); + classes.push(klass); + ele.className = classes.join(' '); + }, + 'remove': function remove(ele, klass) { + var i + , classes; + + if (ele.className.indexOf(klass) === -1) { + + return; + } + + classes = ele.className.split(' '); + for (i = 0; i < classes.length; i += 1) { + + if (classes[i] === klass) { + + classes = classes.slice(0, i).concat(classes.slice(i + 1)); + break; + } + } + ele.className = classes.join(' '); + } + } + , showCalendar = function showCalendar() { + //lets hide all the latest instances of datepicker + pageDatepickers = $window.document.getElementsByClassName('_720kb-datepicker-calendar'); + + angular.forEach(pageDatepickers, function forEachDatepickerPages(value, key) { + if (pageDatepickers[key].classList) { + + pageDatepickers[key].classList.remove('_720kb-datepicker-open'); + } else { + + classHelper.remove(pageDatepickers[key], '_720kb-datepicker-open'); + } + }); + + if (theCalendar.classList) { + + theCalendar.classList.add('_720kb-datepicker-open'); + if (dateFormat) { + date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + } else { + date = new Date(thisInput[0].value.toString()); + } + $scope.selectedMonth = Number($filter('date')(date, 'MM')); + $scope.selectedDay = Number($filter('date')(date, 'dd')); + $scope.selectedYear = Number($filter('date')(date, 'yyyy')); + } else { + + classHelper.add(theCalendar, '_720kb-datepicker-open'); + } + $scope.today = new Date(); + $timeout(function timeoutForYears() { + if ($scope.selectedDay) { + $scope.year = $scope.selectedYear; + $scope.monthNumber = $scope.selectedMonth; + } else { + $scope.year = $scope.today.getFullYear(); + $scope.monthNumber = $scope.today.getMonth() + 1; + } + $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); + setDaysInMonth($scope.monthNumber, $scope.year); + }, 0); + } + , checkToggle = function checkToggle() { + if (!$scope.datepickerToggle) { + + return true; + } + + return $scope.$eval($scope.datepickerToggle); + } + , checkVisibility = function checkVisibility() { + if (!$scope.datepickerShow) { + + return false; + } + if (dateFormat) { + date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + } else { + date = new Date(thisInput[0].value.toString()); + } + $scope.selectedMonth = Number($filter('date')(date, 'MM')); + $scope.selectedDay = Number($filter('date')(date, 'dd')); + $scope.selectedYear = Number($filter('date')(date, 'yyyy')); + return $scope.$eval($scope.datepickerShow); + } + , unregisterDataSetWatcher = $scope.$watch('dateSet', function dateSetWatcher(newValue) { + + if (newValue && !isNaN(Date.parse(newValue))) { + + date = new Date(newValue); + + $scope.month = $filter('date')(date, 'MMMM');//december-November like + $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like + $scope.day = Number($filter('date')(date, 'dd')); //01-31 like + $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like + + setDaysInMonth($scope.monthNumber, $scope.year); + + if ($scope.dateSetHidden !== 'true') { + + setInputValue(); + } + } + }) + , unregisterDateMinLimitWatcher = $scope.$watch('dateMinLimit', function dateMinLimitWatcher(newValue) { + if (newValue) { + resetToMinDate(); + } + }) + , unregisterDateMaxLimitWatcher = $scope.$watch('dateMaxLimit', function dateMaxLimitWatcher(newValue) { + if (newValue) { + resetToMaxDate(); + } + }) + , unregisterDateFormatWatcher = $scope.$watch('dateFormat', function dateFormatWatcher(newValue) { + if (newValue) { + setInputValue(); + } + }) + , unregisterDateDisabledDatesWatcher = $scope.$watch('dateDisabledDates', function dateDisabledDatesWatcher(newValue) { + if (newValue) { + 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; + } + } + }) + , unregisterDateEnabledDatesWatcher = $scope.$watch('dateEnabledDates', function dateEnabledDatesWatcher(newValue) { + if (newValue) { + 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; + } + } + }); + + $scope.nextMonth = function nextMonth() { + + if ($scope.monthNumber === 12) { + + $scope.monthNumber = 1; + //its happy new year + nextYear(); + } else { + + $scope.monthNumber += 1; + } + + //check if max date is ok + if ($scope.dateMaxLimit) { + + if (!$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.days[0])) { + + resetToMaxDate(); + } + } + + //set next month + $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); + //reinit days + setDaysInMonth($scope.monthNumber, $scope.year); + //deactivate selected day + $scope.day = undefined; + }; + + $scope.willPrevMonthBeSelectable = function willPrevMonthBeSelectable() { + var monthNumber = $scope.monthNumber + , year = $scope.year + , prevDay = $filter('date')(new Date(new Date(year + '/' + monthNumber + '/01').getTime() - hours24h), 'dd'); //get last day in previous month + + if (monthNumber === 1) { + + monthNumber = 12; + year = year - 1; + } else { + + monthNumber -= 1; + } + + if ($scope.dateMinLimit) { + if (!$scope.isSelectableMinDate(year + '/' + monthNumber + '/' + prevDay)) { + + return false; + } + } + + return true; + }; + + $scope.willNextMonthBeSelectable = function willNextMonthBeSelectable() { + var monthNumber = $scope.monthNumber + , year = $scope.year; + + if (monthNumber === 12) { + + monthNumber = 1; + year += 1; + } else { + + monthNumber += 1; + } + + if ($scope.dateMaxLimit) { + if (!$scope.isSelectableMaxDate(year + '/' + monthNumber + '/01')) { + + return false; + } + } + + return true; + }; + + $scope.prevMonth = function managePrevMonth() { + + if ($scope.monthNumber === 1) { + + $scope.monthNumber = 12; + //its happy new year + prevYear(); + } else { + + $scope.monthNumber -= 1; + } + //check if min date is ok + if ($scope.dateMinLimit) { + + if (!$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.days[$scope.days.length - 1])) { + + resetToMinDate(); + } + } + //set next month + $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); + //reinit days + setDaysInMonth($scope.monthNumber, $scope.year); + //deactivate selected day + $scope.day = undefined; + }; + + $scope.selectedMonthHandle = function manageSelectedMonthHandle(selectedMonthNumber) { + + $scope.monthNumber = Number($filter('date')(new Date(selectedMonthNumber + '/01/2000'), 'MM')); + setDaysInMonth($scope.monthNumber, $scope.year); + setInputValue(); + }; + + $scope.setNewYear = function setNewYear(year) { + + //deactivate selected day + if (!isMobile) { + $scope.day = undefined; + } + + if ($scope.dateMaxLimit && + $scope.year < Number(year)) { + + if (!$scope.isSelectableMaxYear(year)) { + + return; + } + } else if ($scope.dateMinLimit && + $scope.year > Number(year)) { + + if (!$scope.isSelectableMinYear(year)) { + + return; + } + } + + $scope.paginateYears(year); + $scope.showYearsPagination = false; + $timeout(function timeoutForYears() { + $scope.year = Number(year); + setDaysInMonth($scope.monthNumber, $scope.year); + }, 0); + }; + + $scope.hideCalendar = function hideCalendar() { + if (theCalendar.classList) { + theCalendar.classList.remove('_720kb-datepicker-open'); + } else { + + classHelper.remove(theCalendar, '_720kb-datepicker-open'); + } + }; + + $scope.setDatepickerDay = function setDatepickerDay(day) { + + if ($scope.isSelectableDay($scope.monthNumber, $scope.year, day) && + $scope.isSelectableDate($scope.monthNumber, $scope.year, day) && + $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + day) && + $scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + day)) { + + $scope.day = Number(day); + $scope.selectedDay = $scope.day; + $scope.selectedMonth = $scope.monthNumber; + $scope.selectedYear = $scope.year; + + setInputValue(); + + if (attr.hasOwnProperty('dateRefocus')) { + thisInput[0].focus(); + } + + $scope.hideCalendar(); + } + }; + + $scope.paginateYears = function paginateYears(startingYear) { + var i + , theNewYears = [] + , daysToPrepend = 10 + , daysToAppend = 10; + + $scope.paginationYears = []; + if (isMobile) { + + daysToPrepend = 50; + daysToAppend = 50; + if ( $scope.dateMinLimit && $scope.dateMaxLimit) { + + startingYear = new Date($scope.dateMaxLimit).getFullYear(); + daysToPrepend = startingYear - new Date($scope.dateMinLimit).getFullYear(); + daysToAppend = 1; + } + } + + for (i = daysToPrepend; i > 0; i -= 1) { + + theNewYears.push(Number(startingYear) - i); + } + + for (i = 0; i < daysToAppend; i += 1) { + + theNewYears.push(Number(startingYear) + i); + } + //date typing in input date-typer + if ($scope.dateTyper === 'true') { + + thisInput.on('keyup blur', function onTyping() { + + if (thisInput[0].value && + thisInput[0].value.length && + thisInput[0].value.length > 0) { + + try { + if (dateFormat) { + date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + } else { + date = new Date(thisInput[0].value.toString()); + } + + if (date.getFullYear() && + !isNaN(date.getDay()) && + !isNaN(date.getMonth()) && + $scope.isSelectableDay(date.getMonth(), date.getFullYear(), date.getDay()) && + $scope.isSelectableDate(date.getMonth(), date.getFullYear(), date.getDay()) && + $scope.isSelectableMaxDate(date) && + $scope.isSelectableMinDate(date)) { + + $scope.$apply(function applyTyping() { + + $scope.month = $filter('date')(date, 'MMMM');//december-November like + $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like + $scope.day = Number($filter('date')(date, 'dd')); //01-31 like + + if (date.getFullYear().toString().length === 4) { + $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like + } + setDaysInMonth($scope.monthNumber, $scope.year); + }); + } + } catch (e) { + + return e; + } + } + }); + } + //check range dates + if ($scope.dateMaxLimit && + theNewYears && + theNewYears.length && + !$scope.isSelectableMaxYear(Number(theNewYears[theNewYears.length - 1]) + 1)) { + + $scope.paginationYearsNextDisabled = true; + } else { + + $scope.paginationYearsNextDisabled = false; + } + + if ($scope.dateMinLimit && + theNewYears && + theNewYears.length && + !$scope.isSelectableMinYear(Number(theNewYears[0]) - 1)) { + + $scope.paginationYearsPrevDisabled = true; + } else { + + $scope.paginationYearsPrevDisabled = false; + } + + $scope.paginationYears = theNewYears; + }; + + $scope.isSelectableDay = function isSelectableDay(monthNumber, year, day) { + var i = 0; + + if (dateDisabledWeekdays && dateDisabledWeekdays.length > 0) { + for (i; i <= dateDisabledWeekdays.length; i += 1) { + if (dateDisabledWeekdays[i] === new Date(monthNumber + '/' + day + '/' + year).getDay()) { + return false; + } + } + } + + return true; + }; + + $scope.isSelectableDate = function isSelectableDate(monthNumber, year, day) { + var i = 0; + + if (dateDisabledDates && + dateDisabledDates.length > 0) { + + for (i; i <= dateDisabledDates.length; i += 1) { + + if (new Date(dateDisabledDates[i]).getTime() === new Date(monthNumber + '/' + day + '/' + year).getTime()) { + + return false; + } + } + } + + if (dateEnabledDates) { + + for (i; i <= dateEnabledDates.length; i += 1) { + + if (new Date(dateEnabledDates[i]).getTime() === new Date(monthNumber + '/' + day + '/' + year).getTime()) { + + return true; + } + } + + return false; + } + + return true; + }; + + $scope.isSelectableMinDate = function isSelectableMinDate(aDate) { + //if current date + if (!!$scope.dateMinLimit && + !!new Date($scope.dateMinLimit) && + new Date(aDate).getTime() < new Date($scope.dateMinLimit).getTime()) { + + return false; + } + + return true; + }; + + $scope.isSelectableMaxDate = function isSelectableMaxDate(aDate) { + //if current date + if (!!$scope.dateMaxLimit && + !!new Date($scope.dateMaxLimit) && + new Date(aDate).getTime() > new Date($scope.dateMaxLimit).getTime()) { + + return false; + } + + return true; + }; + + $scope.isSelectableMaxYear = function isSelectableMaxYear(year) { + if (!!$scope.dateMaxLimit && + year > new Date($scope.dateMaxLimit).getFullYear()) { + + return false; + } + + return true; + }; + + $scope.isSelectableMinYear = function isSelectableMinYear(year) { + if (!!$scope.dateMinLimit && + year < new Date($scope.dateMinLimit).getFullYear()) { + + return false; + } + + return true; + }; + + $scope.validateWeekDay = function isValidWeekDay(weekDay) { + var validWeekDay = Number(weekDay, 10); + // making sure that the given option is valid + if (!validWeekDay || validWeekDay < 0 || validWeekDay > 6) { + + validWeekDay = 0; + } + return validWeekDay; + }; + + // respect previously configured interpolation symbols. + htmlTemplate = htmlTemplate.replace(/{{/g, $interpolate.startSymbol()).replace(/}}/g, $interpolate.endSymbol()); + $scope.dateMonthTitle = $scope.dateMonthTitle || 'Select month'; + $scope.dateYearTitle = $scope.dateYearTitle || 'Select year'; + $scope.buttonNextTitle = $scope.buttonNextTitle || 'Next'; + $scope.buttonPrevTitle = $scope.buttonPrevTitle || 'Prev'; + $scope.month = $filter('date')(date, 'MMMM');//december-November like + $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like + $scope.day = Number($filter('date')(date, 'dd')); //01-31 like + $scope.dateWeekStartDay = $scope.validateWeekDay($scope.dateWeekStartDay); + + if ($scope.dateMaxLimit) { + + $scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy'));//2014 like + } else { + + $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like + } + $scope.months = datetime.MONTH; + + $scope.daysInString = []; + for (n = $scope.dateWeekStartDay; n <= $scope.dateWeekStartDay + 6; n += 1) { + + $scope.daysInString.push(n % 7); + } + $scope.daysInString = $scope.daysInString.map(function mappingFunc(el) { + + return $filter('date')(new Date(new Date('06/08/2014').valueOf() + A_DAY_IN_MILLISECONDS * el), 'EEE'); + }); + + //create the calendar holder and append where needed + if ($scope.datepickerAppendTo && + $scope.datepickerAppendTo.indexOf('.') !== -1) { + + $scope.datepickerID = 'datepicker-id-' + new Date().getTime() + (Math.floor(Math.random() * 6) + 8); + angular.element(document.getElementsByClassName($scope.datepickerAppendTo.replace('.', ''))[0]).append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { + + theCalendar = angular.element(el)[0]; + })); + } else if ($scope.datepickerAppendTo && + $scope.datepickerAppendTo.indexOf('#') !== -1) { + + $scope.datepickerID = 'datepicker-id-' + new Date().getTime() + (Math.floor(Math.random() * 6) + 8); + angular.element(document.getElementById($scope.datepickerAppendTo.replace('#', ''))).append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { + + theCalendar = angular.element(el)[0]; + })); + } else if ($scope.datepickerAppendTo && + $scope.datepickerAppendTo === 'body') { + $scope.datepickerID = 'datepicker-id-' + (new Date().getTime() + (Math.floor(Math.random() * 6) + 8)); + angular.element(document).find('body').append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { + + theCalendar = angular.element(el)[0]; + })); + } else { + + thisInput.after($compile(angular.element(htmlTemplate))($scope)); + //get the calendar as element + theCalendar = element[0].querySelector('._720kb-datepicker-calendar'); + } + //if datepicker-toggle="" is not present or true by default + if (checkToggle()) { + + thisInput.on('focus click focusin', function onFocusAndClick() { + + isMouseOnInput = true; + + if (!isMouseOn && + !isMouseOnInput && theCalendar) { + + $scope.hideCalendar(); + } else { + + showCalendar(); + } + }); + } + + thisInput.on('focusout blur', function onBlurAndFocusOut() { + + isMouseOnInput = false; + }); + //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() { + + isMouseOn = true; + }); + + angular.element(theCalendar).on('mouseleave', function onMouseLeave() { + + isMouseOn = false; + }); + + angular.element(theCalendar).on('focusin', function onCalendarFocus() { + + isMouseOn = true; + }); + + angular.element($window).on('click focus focusin', onClickOnWindow); + + //check always if given range of dates is ok + if ($scope.dateMinLimit && + !$scope.isSelectableMinYear($scope.year) || + !$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { + + resetToMinDate(); + } + + if ($scope.dateMaxLimit && + !$scope.isSelectableMaxYear($scope.year) || + !$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { + + resetToMaxDate(); + } + + //datepicker boot start + $scope.paginateYears($scope.year); + + setDaysInMonth($scope.monthNumber, $scope.year); + $scope.checkVisibility = checkVisibility; + + $scope.$on('$destroy', function unregisterListener() { + + unregisterDataSetWatcher(); + unregisterDateMinLimitWatcher(); + unregisterDateMaxLimitWatcher(); + unregisterDateFormatWatcher(); + unregisterDateDisabledDatesWatcher(); + unregisterDateEnabledDatesWatcher(); + thisInput.off('focus click focusout blur'); + angular.element(theCalendar).off('mouseenter mouseleave focusin'); + angular.element($window).off('click focus focusin', onClickOnWindow); + }); + }; + + return { + 'restrict': 'AEC', + 'scope': { + 'dateSet': '@', + 'dateMinLimit': '@', + 'dateMaxLimit': '@', + 'dateMonthTitle': '@', + 'dateYearTitle': '@', + 'buttonNextTitle': '@', + 'buttonPrevTitle': '@', + 'dateDisabledDates': '@', + 'dateEnabledDates': '@', + 'dateDisabledWeekdays': '@', + 'dateSetHidden': '@', + 'dateTyper': '@', + 'dateWeekStartDay': '@', + 'datepickerAppendTo': '@', + 'datepickerToggle': '@', + 'datepickerClass': '@', + 'datepickerShow': '@' + }, + 'link': linkingFunction + }; + }; + + angular.module('720kb.datepicker', []) + .directive('datepicker', ['$window', '$compile', '$locale', '$filter', '$interpolate', '$timeout', datepickerDirective]); +}(angular, navigator)); diff --git a/dist/angular-datepicker.min.css b/dist/angular-datepicker.min.css index acaa6e6..5967e84 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:#138EFA;color:#fff;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;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 0 -.5%;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;padding:0 0 2%;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}._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:" \25F9"}._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%;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;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;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%;background:rgba(19,142,250,.08);border-bottom:1px solid rgba(0,0,0,.02)}._720kb-datepicker-calendar-days-header div{width:13.2%;font-weight:500;font-size:11.5px;padding:10px .5%;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-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,.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 diff --git a/dist/angular-datepicker.min.js b/dist/angular-datepicker.min.js index dd43113..13c53aa 100644 --- a/dist/angular-datepicker.min.js +++ b/dist/angular-datepicker.min.js @@ -1,12 +1,12 @@ /*! - * Angular Datepicker v0.2.12 + * Angular Datepicker v2.1.23 * * Released by 720kb.net under the MIT license * www.opensource.org/licenses/MIT * - * 2015-10-07 + * 2017-06-28 */ -!function(a,b){"use strict";var c=864e5,d=function(){return b.userAgent&&(b.userAgent.match(/Android/i)||b.userAgent.match(/webOS/i)||b.userAgent.match(/iPhone/i)||b.userAgent.match(/iPad/i)||b.userAgent.match(/iPod/i)||b.userAgent.match(/BlackBerry/i)||b.userAgent.match(/Windows Phone/i))?!0:void 0}(),e=function(a,b){return d?['
','
','","
","
",'
','
','","
","
"]:['
','
','',a,"","
",'
',"{{month}} ",'',"","{{year}}","","","","
",'
','',b,"","
","
"]},f=function(a,b){return['
','",'
','',a,"",'',b,"","
","
"]},g=function(){return['
','
',"{{d}}","
","
"]},h=function(){return['"]},i=function(a,b){var c=['
',"
"],d=e(a,b),i=f(a,b),j=g(),k=h(),l=function(a){c.splice(c.length-1,0,a)};return d.forEach(l),i.forEach(l),j.forEach(l),k.forEach(l),c.join("")},j=function(b,e,f,g,h){var j=function(j,k,l){var m,n,o=l.selector,p=a.element(o?k[0].querySelector("."+o):k[0].children[0]),q='',r='',s=l.buttonPrev||q,t=l.buttonNext||r,u=l.dateFormat,v=j.dateDisabledDates,w=new Date,x=g("date")(w,"M"),y=!1,z=!1,A=f.DATETIME_FORMATS,B=i(s,t),C=function(){j.month=g("date")(new Date(j.dateMinLimit),"MMMM"),j.monthNumber=Number(g("date")(new Date(j.dateMinLimit),"MM")),j.day=Number(g("date")(new Date(j.dateMinLimit),"dd")),j.year=Number(g("date")(new Date(j.dateMinLimit),"yyyy"))},D=function(){j.month=g("date")(new Date(j.dateMaxLimit),"MMMM"),j.monthNumber=Number(g("date")(new Date(j.dateMaxLimit),"MM")),j.day=Number(g("date")(new Date(j.dateMaxLimit),"dd")),j.year=Number(g("date")(new Date(j.dateMaxLimit),"yyyy"))},E=function(){j.year=Number(j.year)-1},F=function(){j.year=Number(j.year)+1},G=function(){if(!j.isSelectableMinDate(j.year+"/"+j.monthNumber+"/"+j.day)||!j.isSelectableMaxDate(j.year+"/"+j.monthNumber+"/"+j.day))return!1;var a=new Date(j.year+"/"+j.monthNumber+"/"+j.day);l.dateFormat?p.val(g("date")(a,u)):p.val(a),p.triggerHandler("input"),p.triggerHandler("change")},H={add:function(a,b){var c;a.className.indexOf(b)>-1||(c=a.className.split(" "),c.push(b),a.className=c.join(" "))},remove:function(a,b){var c,d;if(-1!==a.className.indexOf(b)){for(d=a.className.split(" "),c=0;c=c;c+=1)j.days.push(c);if(0===h)j.prevMonthDays=[];else{for(e=h,f=1===Number(a)?12:a-1,c=1;c<=new Date(b,f,0).getDate();c+=1)k.push(c);j.prevMonthDays=k.slice(-e)}if(6>i){for(d=6-i,c=1;d>=c;c+=1)l.push(c);j.nextMonthDays=l}else j.nextMonthDays=[]},K=j.$watch("dateSet",function(a){a&&(w=new Date(a),j.month=g("date")(w,"MMMM"),j.monthNumber=Number(g("date")(w,"MM")),j.day=Number(g("date")(w,"dd")),j.year=Number(g("date")(w,"yyyy")),J(j.monthNumber,j.year),"true"!==j.dateSetHidden&&G())});j.nextMonth=function(){12===j.monthNumber?(j.monthNumber=1,F()):j.monthNumber+=1,j.month=g("date")(new Date(j.year,j.monthNumber-1),"MMMM"),J(j.monthNumber,j.year),j.dateMaxLimit&&x>j.monthNumber&&(j.isSelectableMaxDate(j.year+"/"+j.monthNumber+"/"+j.day)||D()),j.day=void 0},j.prevMonth=function(){1===j.monthNumber?(j.monthNumber=12,E()):j.monthNumber-=1,j.month=g("date")(new Date(j.year,j.monthNumber-1),"MMMM"),J(j.monthNumber,j.year),j.dateMinLimit&&(j.isSelectableMinDate(j.year+"/"+j.monthNumber+"/"+j.day)||C()),j.day=void 0},j.selectedMonthHandle=function(a){j.monthNumber=Number(g("date")(new Date("01 "+a+" 2000"),"MM")),J(j.monthNumber,j.year),G()},j.setNewYear=function(a){if(j.day=void 0,j.dateMaxLimit&&j.yearNumber(a)&&!j.isSelectableMinYear(a))return;j.year=Number(a),J(j.monthNumber,j.year),j.paginateYears(a)},j.hideCalendar=function(){m.classList?m.classList.remove("_720kb-datepicker-open"):H.remove(m,"_720kb-datepicker-open")},j.setDatepickerDay=function(a){j.isSelectableDate(j.monthNumber,j.year,a)&&j.isSelectableMaxDate(j.year+"/"+j.monthNumber+"/"+a)&&j.isSelectableMinDate(j.year+"/"+j.monthNumber+"/"+a)&&(j.day=Number(a),G(),j.hideCalendar())},j.paginateYears=function(a){var b,c=[],e=10,f=10;for(j.paginationYears=[],d&&(e=50,f=50,j.dateMinLimit&&j.dateMaxLimit&&(a=new Date(j.dateMaxLimit).getFullYear(),e=a-new Date(j.dateMinLimit).getFullYear(),f=1)),b=e;b>0;b-=1)c.push(Number(a)-b);for(b=0;f>b;b+=1)c.push(Number(a)+b);j.dateMaxLimit&&c&&c.length&&!j.isSelectableMaxYear(Number(c[c.length-1])+1)?j.paginationYearsNextDisabled=!0:j.paginationYearsNextDisabled=!1,j.dateMinLimit&&c&&c.length&&!j.isSelectableMinYear(Number(c[0])-1)?j.paginationYearsPrevDisabled=!0:j.paginationYearsPrevDisabled=!1,j.paginationYears=c},j.isSelectableDate=function(a,b,c){var d=0;if(v&&v.length>0)for(d;d<=v.length;d+=1)if(new Date(v[d]).getTime()===new Date(a+"/"+c+"/"+b).getTime())return!1;return!0},j.isSelectableMinDate=function(a){return j.dateMinLimit&&new Date(j.dateMinLimit)&&new Date(a).getTime()new Date(j.dateMaxLimit).getTime()?!1:!0},j.isSelectableMaxYear=function(a){return j.dateMaxLimit&&a>new Date(j.dateMaxLimit).getFullYear()?!1:!0},j.isSelectableMinYear=function(a){return j.dateMinLimit&&a','
','","
","",'
','
','","
","
"]:['
','
','',e,"","
",'
',"{{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); //# sourceMappingURL=angular-datepicker.sourcemap.map \ No newline at end of file diff --git a/dist/angular-datepicker.sourcemap.map b/dist/angular-datepicker.sourcemap.map index 66e2c84..bbc30f5 100644 --- a/dist/angular-datepicker.sourcemap.map +++ b/dist/angular-datepicker.sourcemap.map @@ -1 +1 @@ -{"version":3,"file":"angular-datepicker.min.js","sources":["../src/js/angular-datepicker.js"],"names":["angular","navigator","A_DAY_IN_MILLISECONDS","isMobile","userAgent","match","generateMonthAndYearHeader","prevButton","nextButton","generateYearsPaginationHeader","generateDaysColumns","generateDays","generateHtmlTemplate","toReturn","monthAndYearHeader","yearsPaginationHeader","daysColumns","days","iterator","aRow","splice","length","forEach","join","datepickerDirective","$window","$compile","$locale","$filter","$interpolate","linkingFunction","$scope","element","attr","theCalendar","pageDatepickers","selector","thisInput","querySelector","children","defaultPrevButton","defaultNextButton","buttonPrev","buttonNext","dateFormat","dateDisabledDates","date","Date","currentMonthNumber","isMouseOn","isMouseOnInput","datetime","DATETIME_FORMATS","htmlTemplate","resetToMinDate","month","dateMinLimit","monthNumber","Number","day","year","resetToMaxDate","dateMaxLimit","prevYear","nextYear","setInputValue","isSelectableMinDate","isSelectableMaxDate","modelDate","val","triggerHandler","classHelper","add","ele","klass","classes","className","indexOf","split","push","remove","i","slice","concat","showCalendar","document","getElementsByClassName","value","key","classList","setDaysInMonth","howManyNextDays","howManyPreviousDays","monthAlias","limitDate","getDate","firstDayMonthNumber","getDay","lastDayMonthNumber","prevMonthDays","nextMonthDays","unregisterDataSetWatcher","$watch","newValue","dateSetHidden","nextMonth","undefined","prevMonth","selectedMonthHandle","selectedMonth","setNewYear","isSelectableMaxYear","isSelectableMinYear","paginateYears","hideCalendar","setDatepickerDay","isSelectableDate","startingYear","theNewYears","daysToPrepend","daysToAppend","paginationYears","getFullYear","paginationYearsNextDisabled","paginationYearsPrevDisabled","getTime","aDate","replace","startSymbol","endSymbol","dateMonthTitle","dateYearTitle","buttonNextTitle","buttonPrevTitle","months","MONTH","daysInString","map","el","valueOf","after","on","$on","off","hasOwnProperty","restrict","scope","dateSet","link","module","directive"],"mappings":"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"} \ No newline at end of file +{"version":3,"sources":["../src/js/angular-datepicker.js"],"names":["angular","navigator","isMobile","userAgent","match","generateMonthAndYearHeader","prevButton","nextButton","preventMobile","generateYearsPaginationHeader","generateHtmlTemplate","toReturn","monthAndYearHeader","yearsPaginationHeader","daysColumns","days","iterator","aRow","splice","length","forEach","join","datepickerDirective","$window","$compile","$locale","$filter","$interpolate","$timeout","restrict","scope","dateSet","dateMinLimit","dateMaxLimit","dateMonthTitle","dateYearTitle","buttonNextTitle","buttonPrevTitle","dateDisabledDates","dateEnabledDates","dateDisabledWeekdays","dateSetHidden","dateTyper","dateWeekStartDay","datepickerAppendTo","datepickerToggle","datepickerClass","datepickerShow","link","$scope","element","attr","theCalendar","pageDatepickers","n","selector","thisInput","querySelector","children","buttonPrev","buttonNext","dateFormat","$eval","date","Date","isMouseOn","isMouseOnInput","datepickerMobile","datetime","DATETIME_FORMATS","htmlTemplate","onClickOnWindow","hideCalendar","setDaysInMonth","month","year","i","howManyNextDays","howManyPreviousDays","monthAlias","dateWeekEndDay","limitDate","getDate","firstDayMonthNumber","getDay","lastDayMonthNumber","prevMonthDays","nextMonthDays","validateWeekDay","push","Number","slice","resetToMinDate","monthNumber","day","resetToMaxDate","prevYear","nextYear","localDateTimestamp","rawDate","dateFormatDefinition","formatDate","dateSplit","m","d","y","index","el","longName","shortName","formattingTokens","MONTH","SHORTMONTH","indexOf","replace","split","filter","item","setInputValue","isSelectableMinDate","isSelectableMaxDate","modelDate","val","triggerHandler","classHelper","add","ele","klass","classes","className","remove","concat","showCalendar","document","getElementsByClassName","value","key","classList","toString","selectedMonth","selectedDay","selectedYear","today","getFullYear","getMonth","checkVisibility","unregisterDataSetWatcher","$watch","newValue","isNaN","parse","unregisterDateMinLimitWatcher","unregisterDateMaxLimitWatcher","unregisterDateFormatWatcher","unregisterDateDisabledDatesWatcher","isSelectableDate","unregisterDateEnabledDatesWatcher","nextMonth","undefined","willPrevMonthBeSelectable","prevDay","getTime","willNextMonthBeSelectable","prevMonth","selectedMonthHandle","selectedMonthNumber","setNewYear","isSelectableMaxYear","isSelectableMinYear","paginateYears","showYearsPagination","setDatepickerDay","isSelectableDay","hasOwnProperty","focus","startingYear","theNewYears","daysToPrepend","daysToAppend","paginationYears","on","$apply","e","paginationYearsNextDisabled","paginationYearsPrevDisabled","aDate","weekDay","validWeekDay","startSymbol","endSymbol","months","daysInString","map","valueOf","datepickerID","Math","floor","random","append","getElementById","find","after","$on","off","module","directive"],"mappings":"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","file":"angular-datepicker.min.js"} \ No newline at end of file diff --git a/index.html b/index.html index f644bb9..3237ccb 100644 --- a/index.html +++ b/index.html @@ -15,35 +15,42 @@ Angularjs Datepicker - +
-
+
Date 1 is: {{date1}}
Date 2 is: {{date2}} +
- + Date 3 is: {{date3}}
- - + + + diff --git a/index.js b/index.js index 5cba79b..5a0aca4 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,7 @@ (function setUp(module, require) { 'use strict'; - require('./src/js/angular-datepicker'); + require('./dist/angular-datepicker'); module.exports = '720kb.datepicker'; }(module, require)); diff --git a/package.json b/package.json index 4e5c46b..5807bd7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angularjs-datepicker", - "version": "0.2.12", + "version": "2.1.23", "description": "A datepicker directive for angularjs.", "homepage": "http://720kb.github.io/angular-datepicker", "keywords": [ @@ -12,12 +12,11 @@ "input" ], "scripts": { - "precommit": "grunt lint" + "precommit": "grunt lint", + "lint": "grunt lint", + "dist": "grunt prod" }, - "main": [ - "dist/angular-datepicker.min.js", - "dist/angular-datepicker.min.css" - ], + "main": "dist/angular-datepicker.min.js", "repository": { "type": "git", "url": "https://github.com/720kb/angular-datepicker.git" @@ -28,6 +27,7 @@ "grunt": "*", "grunt-concurrent": "*", "grunt-contrib-connect": "*", + "grunt-contrib-copy": "*", "grunt-contrib-csslint": "*", "grunt-contrib-cssmin": "*", "grunt-contrib-uglify": "*", diff --git a/src/css/angular-datepicker.css b/src/css/angular-datepicker.css index 3f0689d..4a26ee9 100644 --- a/src/css/angular-datepicker.css +++ b/src/css/angular-datepicker.css @@ -22,7 +22,7 @@ datepicker, .datepicker, [datepicker], ._720kb-datepicker-calendar-body, ._720kb-datepicker-calendar-days-header, ._720kb-datepicker-calendar-years-pagination-pages { - font-family: Helvetica Neue; + font-family: Helvetica Neue, Arial, sans-serif; font-size: 13.5px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; @@ -53,7 +53,7 @@ datepicker, .datepicker, [datepicker], -moz-border-radius: 3px; border-radius: 3px; } -._720kb-datepicker-calendar._720kb-datepicker-open { +._720kb-datepicker-calendar._720kb-datepicker-open,._720kb-datepicker-calendar._720kb-datepicker-forced-to-open { visibility: visible; } ._720kb-datepicker-calendar-header { @@ -82,9 +82,17 @@ datepicker, .datepicker, [datepicker], } ._720kb-datepicker-calendar-header-opened-pagination::after { - content: " \25F9"; + 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%; @@ -101,7 +109,8 @@ datepicker, .datepicker, [datepicker], -moz-border-radius: 1px; border-radius: 1px; } -._720kb-datepicker-calendar-day:hover,._720kb-datepicker-calendar-day._720kb-datepicker-active { +._720kb-datepicker-calendar-day:hover, +._720kb-datepicker-calendar-day._720kb-datepicker-active { background: rgba(0, 0, 0, 0.03); } ._720kb-datepicker-calendar-header a, ._720kb-datepicker-calendar-header a:hover { @@ -163,13 +172,13 @@ datepicker, .datepicker, [datepicker], border-bottom:1px solid rgba(0,0,0,0.02); } ._720kb-datepicker-calendar-days-header div{ - width: 13.2%; - font-weight: 500; - font-size: 11.5px; - padding:10px 0.5%; - float:left; - text-align: center; - color:rgba(0,0,0,0.7); + width: 14.18%; + font-weight: 500; + font-size: 11.5px; + padding:10px 0; + float:left; + text-align: center; + color:rgba(0,0,0,0.7); } ._720kb-datepicker-calendar-days ._720kb-datepicker-default-button{ @@ -177,6 +186,9 @@ datepicker, .datepicker, [datepicker], position: relative; bottom:-0.5px; } +._720kb-datepicker-default-button{ + padding:0 4.5px; +} ._720kb-datepicker-calendar-header-middle._720kb-datepicker-mobile-item{ width:95%; float:none; diff --git a/src/js/angular-datepicker.js b/src/js/angular-datepicker.js index a4d230b..971dbc9 100644 --- a/src/js/angular-datepicker.js +++ b/src/js/angular-datepicker.js @@ -1,5 +1,6 @@ -/*global angular, navigator*/ +/*global angular document navigator*/ (function withAngular(angular, navigator) { + 'use strict'; var A_DAY_IN_MILLISECONDS = 86400000 @@ -17,7 +18,12 @@ return true; } }()) - , generateMonthAndYearHeader = function generateMonthAndYearHeader(prevButton, nextButton) { + , generateMonthAndYearHeader = function generateMonthAndYearHeader(prevButton, nextButton, preventMobile) { + + if (preventMobile) { + + isMobile = false; + } if (isMobile) { @@ -25,7 +31,7 @@ '
', '
', '', @@ -34,7 +40,7 @@ '
', '
', '', @@ -46,13 +52,13 @@ return [ '
', '', '', '', @@ -72,7 +78,7 @@ return [ '' ]; } - , generateHtmlTemplate = function generateHtmlTemplate(prevButton, nextButton) { + , generateHtmlTemplate = function generateHtmlTemplate(prevButton, nextButton, preventMobile) { var toReturn = [ - '
', + '
', '
' ] - , monthAndYearHeader = generateMonthAndYearHeader(prevButton, nextButton) + , monthAndYearHeader = generateMonthAndYearHeader(prevButton, nextButton, preventMobile) , yearsPaginationHeader = generateYearsPaginationHeader(prevButton, nextButton) , daysColumns = generateDaysColumns() , days = generateDays() @@ -135,7 +141,7 @@ return toReturn.join(''); } - , datepickerDirective = function datepickerDirective($window, $compile, $locale, $filter, $interpolate) { + , datepickerDirective = function datepickerDirective($window, $compile, $locale, $filter, $interpolate, $timeout) { var linkingFunction = function linkingFunction($scope, element, attr) { @@ -143,29 +149,116 @@ 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 //, dateMinLimit //, dateMaxLimit - , dateDisabledDates = $scope.dateDisabledDates + , dateDisabledDates = $scope.$eval($scope.dateDisabledDates) + , dateEnabledDates = $scope.$eval($scope.dateEnabledDates) + , dateDisabledWeekdays = $scope.$eval($scope.dateDisabledWeekdays) , date = new Date() - //, currentDay = $filter('date')(date, 'd') - , currentMonthNumber = $filter('date')(date, 'M') - //, currentYear = $filter('date')(date, 'yyyy') , isMouseOn = false , isMouseOnInput = false + , preventMobile = typeof attr.datepickerMobile !== 'undefined' && attr.datepickerMobile !== 'false' , datetime = $locale.DATETIME_FORMATS , pageDatepickers - , htmlTemplate = generateHtmlTemplate(prevButton, nextButton) + , hours24h = 86400000 + , htmlTemplate = generateHtmlTemplate(prevButton, nextButton, preventMobile) + , n + , onClickOnWindow = function onClickOnWindow() { + + if (!isMouseOn && + !isMouseOnInput && theCalendar) { + + $scope.hideCalendar(); + } + } + , setDaysInMonth = function setDaysInMonth(month, year) { + + var i + , limitDate = new Date(year, month, 0).getDate() + , firstDayMonthNumber = new Date(year + '/' + month + '/' + 1).getDay() + , lastDayMonthNumber = new Date(year + '/' + month + '/' + limitDate).getDay() + , prevMonthDays = [] + , nextMonthDays = [] + , howManyNextDays + , howManyPreviousDays + , monthAlias + , dateWeekEndDay; + + $scope.days = []; + $scope.dateWeekStartDay = $scope.validateWeekDay($scope.dateWeekStartDay); + dateWeekEndDay = ($scope.dateWeekStartDay + 6) % 7; + + for (i = 1; i <= limitDate; i += 1) { + + $scope.days.push(i); + } + + //get previous month days if first day in month is not first day in week + if (firstDayMonthNumber === $scope.dateWeekStartDay) { + + //no need for it + $scope.prevMonthDays = []; + } else { + + howManyPreviousDays = firstDayMonthNumber - $scope.dateWeekStartDay; + + if (firstDayMonthNumber < $scope.dateWeekStartDay) { + + howManyPreviousDays += 7; + } + + //get previous month + if (Number(month) === 1) { + + monthAlias = 12; + } else { + + monthAlias = month - 1; + } + //return previous month days + for (i = 1; i <= new Date(year, monthAlias, 0).getDate(); i += 1) { + + prevMonthDays.push(i); + } + //attach previous month days + $scope.prevMonthDays = prevMonthDays.slice(-howManyPreviousDays); + } + + //get next month days if last day in month is not last day in week + if (lastDayMonthNumber === dateWeekEndDay) { + //no need for it + $scope.nextMonthDays = []; + } else { + howManyNextDays = 6 - lastDayMonthNumber + $scope.dateWeekStartDay; + + if (lastDayMonthNumber < $scope.dateWeekStartDay) { + + howManyNextDays -= 7; + } + //get previous month + + //return next month days + for (i = 1; i <= howManyNextDays; i += 1) { + + nextMonthDays.push(i); + } + //attach previous month days + $scope.nextMonthDays = nextMonthDays; + } + } , resetToMinDate = function resetToMinDate() { $scope.month = $filter('date')(new Date($scope.dateMinLimit), 'MMMM'); $scope.monthNumber = Number($filter('date')(new Date($scope.dateMinLimit), 'MM')); $scope.day = Number($filter('date')(new Date($scope.dateMinLimit), 'dd')); $scope.year = Number($filter('date')(new Date($scope.dateMinLimit), 'yyyy')); + + setDaysInMonth($scope.monthNumber, $scope.year); } , resetToMaxDate = function resetToMaxDate() { @@ -173,6 +266,8 @@ $scope.monthNumber = Number($filter('date')(new Date($scope.dateMaxLimit), 'MM')); $scope.day = Number($filter('date')(new Date($scope.dateMaxLimit), 'dd')); $scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy')); + + setDaysInMonth($scope.monthNumber, $scope.year); } , prevYear = function prevYear() { @@ -182,6 +277,62 @@ $scope.year = Number($scope.year) + 1; } + , localDateTimestamp = function localDateTimestamp(rawDate, dateFormatDefinition) { + + var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|MMMM|MMM|MM|M|dd?d?|yy?yy?y?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g + ,formatDate,dateSplit, m, d, y, index, el, longName, shortName; + + for (index = 0; index < datetime.MONTH.length; index += 1) { + longName = datetime.MONTH[index]; + shortName = datetime.SHORTMONTH[index]; + + if (rawDate.indexOf(longName) !== -1) { + rawDate = rawDate.replace(longName, index + 1); + break; + } + + if (rawDate.indexOf(shortName) !== -1) { + rawDate = rawDate.replace(shortName, index + 1); + break; + } + } + + dateSplit = rawDate + .split(/\D/) + .filter(function dateSplitFilter(item) { + return item.length > 0; + }); + + formatDate = dateFormatDefinition + .match(formattingTokens) + .filter(function fromatDateFilter(item) { + return item.match(/^[a-zA-Z]+$/i) !== null; + }); + + for (index = 0; index < formatDate.length; index += 1) { + el = formatDate[index]; + + switch (true) { + case el.indexOf('d') !== -1: { + d = dateSplit[index - (formatDate.length - dateSplit.length)]; + break; + } + case el.indexOf('M') !== -1: { + m = dateSplit[index - (formatDate.length - dateSplit.length)]; + break; + } + case el.indexOf('y') !== -1: { + y = dateSplit[index - (formatDate.length - dateSplit.length)]; + break; + } + default: { + break; + } + } + } + + return new Date(y + '/' + m + '/' + d); + } , setInputValue = function setInputValue() { if ($scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day) && @@ -255,88 +406,109 @@ if (theCalendar.classList) { theCalendar.classList.add('_720kb-datepicker-open'); + if (dateFormat) { + date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + } else { + date = new Date(thisInput[0].value.toString()); + } + $scope.selectedMonth = Number($filter('date')(date, 'MM')); + $scope.selectedDay = Number($filter('date')(date, 'dd')); + $scope.selectedYear = Number($filter('date')(date, 'yyyy')); } else { classHelper.add(theCalendar, '_720kb-datepicker-open'); } - } - , setDaysInMonth = function setDaysInMonth(month, year) { - - var i - , limitDate = new Date(year, month, 0).getDate() - , firstDayMonthNumber = new Date(year + '/' + month + '/' + 1).getDay() - , lastDayMonthNumber = new Date(year + '/' + month + '/' + limitDate).getDay() - , prevMonthDays = [] - , nextMonthDays = [] - , howManyNextDays - , howManyPreviousDays - , monthAlias; - - $scope.days = []; - - for (i = 1; i <= limitDate; i += 1) { - - $scope.days.push(i); - } - - //get previous month days is first day in month is not Sunday - if (firstDayMonthNumber === 0) { - - //no need for it - $scope.prevMonthDays = []; - } else { - - howManyPreviousDays = firstDayMonthNumber; - //get previous month - if (Number(month) === 1) { - - monthAlias = 12; + $scope.today = new Date(); + $timeout(function timeoutForYears() { + if ($scope.selectedDay) { + $scope.year = $scope.selectedYear; + $scope.monthNumber = $scope.selectedMonth; } else { - - monthAlias = month - 1; + $scope.year = $scope.today.getFullYear(); + $scope.monthNumber = $scope.today.getMonth() + 1; } - //return previous month days - for (i = 1; i <= new Date(year, monthAlias, 0).getDate(); i += 1) { + $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); + setDaysInMonth($scope.monthNumber, $scope.year); + }, 0); + } + , checkToggle = function checkToggle() { + if (!$scope.datepickerToggle) { - prevMonthDays.push(i); - } - //attach previous month days - $scope.prevMonthDays = prevMonthDays.slice(-howManyPreviousDays); + return true; } - //get next month days is first day in month is not Sunday - if (lastDayMonthNumber < 6) { - - howManyNextDays = 6 - lastDayMonthNumber; - //get previous month - - //return next month days - for (i = 1; i <= howManyNextDays; i += 1) { + return $scope.$eval($scope.datepickerToggle); + } + , checkVisibility = function checkVisibility() { + if (!$scope.datepickerShow) { - nextMonthDays.push(i); - } - //attach previous month days - $scope.nextMonthDays = nextMonthDays; + return false; + } + if (dateFormat) { + date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); } else { - //no need for it - $scope.nextMonthDays = []; + date = new Date(thisInput[0].value.toString()); } + $scope.selectedMonth = Number($filter('date')(date, 'MM')); + $scope.selectedDay = Number($filter('date')(date, 'dd')); + $scope.selectedYear = Number($filter('date')(date, 'yyyy')); + return $scope.$eval($scope.datepickerShow); } , unregisterDataSetWatcher = $scope.$watch('dateSet', function dateSetWatcher(newValue) { - if (newValue) { + if (newValue && !isNaN(Date.parse(newValue))) { date = new Date(newValue); + $scope.month = $filter('date')(date, 'MMMM');//december-November like $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like $scope.day = Number($filter('date')(date, 'dd')); //01-31 like $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like + setDaysInMonth($scope.monthNumber, $scope.year); + if ($scope.dateSetHidden !== 'true') { setInputValue(); } } + }) + , unregisterDateMinLimitWatcher = $scope.$watch('dateMinLimit', function dateMinLimitWatcher(newValue) { + if (newValue) { + resetToMinDate(); + } + }) + , unregisterDateMaxLimitWatcher = $scope.$watch('dateMaxLimit', function dateMaxLimitWatcher(newValue) { + if (newValue) { + resetToMaxDate(); + } + }) + , unregisterDateFormatWatcher = $scope.$watch('dateFormat', function dateFormatWatcher(newValue) { + if (newValue) { + setInputValue(); + } + }) + , unregisterDateDisabledDatesWatcher = $scope.$watch('dateDisabledDates', function dateDisabledDatesWatcher(newValue) { + if (newValue) { + 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; + } + } + }) + , unregisterDateEnabledDatesWatcher = $scope.$watch('dateEnabledDates', function dateEnabledDatesWatcher(newValue) { + if (newValue) { + 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; + } + } }); $scope.nextMonth = function nextMonth() { @@ -350,24 +522,71 @@ $scope.monthNumber += 1; } - //set next month - $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); - //reinit days - setDaysInMonth($scope.monthNumber, $scope.year); //check if max date is ok - if ($scope.dateMaxLimit && - currentMonthNumber > $scope.monthNumber) { + if ($scope.dateMaxLimit) { - if (!$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { + if (!$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.days[0])) { resetToMaxDate(); } } + + //set next month + $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); + //reinit days + setDaysInMonth($scope.monthNumber, $scope.year); //deactivate selected day $scope.day = undefined; }; + $scope.willPrevMonthBeSelectable = function willPrevMonthBeSelectable() { + var monthNumber = $scope.monthNumber + , year = $scope.year + , prevDay = $filter('date')(new Date(new Date(year + '/' + monthNumber + '/01').getTime() - hours24h), 'dd'); //get last day in previous month + + if (monthNumber === 1) { + + monthNumber = 12; + year = year - 1; + } else { + + monthNumber -= 1; + } + + if ($scope.dateMinLimit) { + if (!$scope.isSelectableMinDate(year + '/' + monthNumber + '/' + prevDay)) { + + return false; + } + } + + return true; + }; + + $scope.willNextMonthBeSelectable = function willNextMonthBeSelectable() { + var monthNumber = $scope.monthNumber + , year = $scope.year; + + if (monthNumber === 12) { + + monthNumber = 1; + year += 1; + } else { + + monthNumber += 1; + } + + if ($scope.dateMaxLimit) { + if (!$scope.isSelectableMaxDate(year + '/' + monthNumber + '/01')) { + + return false; + } + } + + return true; + }; + $scope.prevMonth = function managePrevMonth() { if ($scope.monthNumber === 1) { @@ -379,25 +598,25 @@ $scope.monthNumber -= 1; } - //set next month - $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); - //reinit days - setDaysInMonth($scope.monthNumber, $scope.year); //check if min date is ok if ($scope.dateMinLimit) { - if (!$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { + if (!$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.days[$scope.days.length - 1])) { resetToMinDate(); } } + //set next month + $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); + //reinit days + setDaysInMonth($scope.monthNumber, $scope.year); //deactivate selected day $scope.day = undefined; }; - $scope.selectedMonthHandle = function manageSelectedMonthHandle(selectedMonth) { + $scope.selectedMonthHandle = function manageSelectedMonthHandle(selectedMonthNumber) { - $scope.monthNumber = Number($filter('date')(new Date('01 ' + selectedMonth + ' 2000'), 'MM')); + $scope.monthNumber = Number($filter('date')(new Date(selectedMonthNumber + '/01/2000'), 'MM')); setDaysInMonth($scope.monthNumber, $scope.year); setInputValue(); }; @@ -405,7 +624,9 @@ $scope.setNewYear = function setNewYear(year) { //deactivate selected day - $scope.day = undefined; + if (!isMobile) { + $scope.day = undefined; + } if ($scope.dateMaxLimit && $scope.year < Number(year)) { @@ -423,14 +644,16 @@ } } - $scope.year = Number(year); - setDaysInMonth($scope.monthNumber, $scope.year); $scope.paginateYears(year); $scope.showYearsPagination = false; + $timeout(function timeoutForYears() { + $scope.year = Number(year); + setDaysInMonth($scope.monthNumber, $scope.year); + }, 0); }; $scope.hideCalendar = function hideCalendar() { - if (theCalendar.classList){ + if (theCalendar.classList) { theCalendar.classList.remove('_720kb-datepicker-open'); } else { @@ -440,17 +663,22 @@ $scope.setDatepickerDay = function setDatepickerDay(day) { - if ($scope.isSelectableDate($scope.monthNumber, $scope.year, day) && + if ($scope.isSelectableDay($scope.monthNumber, $scope.year, day) && + $scope.isSelectableDate($scope.monthNumber, $scope.year, day) && $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + day) && $scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + day)) { $scope.day = Number(day); + $scope.selectedDay = $scope.day; + $scope.selectedMonth = $scope.monthNumber; + $scope.selectedYear = $scope.year; + setInputValue(); - + if (attr.hasOwnProperty('dateRefocus')) { thisInput[0].focus(); } - + $scope.hideCalendar(); } }; @@ -483,7 +711,49 @@ theNewYears.push(Number(startingYear) + i); } - + //date typing in input date-typer + if ($scope.dateTyper === 'true') { + + thisInput.on('keyup blur', function onTyping() { + + if (thisInput[0].value && + thisInput[0].value.length && + thisInput[0].value.length > 0) { + + try { + if (dateFormat) { + date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); + } else { + date = new Date(thisInput[0].value.toString()); + } + + if (date.getFullYear() && + !isNaN(date.getDay()) && + !isNaN(date.getMonth()) && + $scope.isSelectableDay(date.getMonth(), date.getFullYear(), date.getDay()) && + $scope.isSelectableDate(date.getMonth(), date.getFullYear(), date.getDay()) && + $scope.isSelectableMaxDate(date) && + $scope.isSelectableMinDate(date)) { + + $scope.$apply(function applyTyping() { + + $scope.month = $filter('date')(date, 'MMMM');//december-November like + $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like + $scope.day = Number($filter('date')(date, 'dd')); //01-31 like + + if (date.getFullYear().toString().length === 4) { + $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like + } + setDaysInMonth($scope.monthNumber, $scope.year); + }); + } + } catch (e) { + + return e; + } + } + }); + } //check range dates if ($scope.dateMaxLimit && theNewYears && @@ -510,6 +780,20 @@ $scope.paginationYears = theNewYears; }; + $scope.isSelectableDay = function isSelectableDay(monthNumber, year, day) { + var i = 0; + + if (dateDisabledWeekdays && dateDisabledWeekdays.length > 0) { + for (i; i <= dateDisabledWeekdays.length; i += 1) { + if (dateDisabledWeekdays[i] === new Date(monthNumber + '/' + day + '/' + year).getDay()) { + return false; + } + } + } + + return true; + }; + $scope.isSelectableDate = function isSelectableDate(monthNumber, year, day) { var i = 0; @@ -517,12 +801,27 @@ dateDisabledDates.length > 0) { for (i; i <= dateDisabledDates.length; i += 1) { + if (new Date(dateDisabledDates[i]).getTime() === new Date(monthNumber + '/' + day + '/' + year).getTime()) { return false; } } } + + if (dateEnabledDates) { + + for (i; i <= dateEnabledDates.length; i += 1) { + + if (new Date(dateEnabledDates[i]).getTime() === new Date(monthNumber + '/' + day + '/' + year).getTime()) { + + return true; + } + } + + return false; + } + return true; }; @@ -570,16 +869,27 @@ return true; }; + $scope.validateWeekDay = function isValidWeekDay(weekDay) { + var validWeekDay = Number(weekDay, 10); + // making sure that the given option is valid + if (!validWeekDay || validWeekDay < 0 || validWeekDay > 6) { + + validWeekDay = 0; + } + return validWeekDay; + }; + // respect previously configured interpolation symbols. htmlTemplate = htmlTemplate.replace(/{{/g, $interpolate.startSymbol()).replace(/}}/g, $interpolate.endSymbol()); $scope.dateMonthTitle = $scope.dateMonthTitle || 'Select month'; $scope.dateYearTitle = $scope.dateYearTitle || 'Select year'; $scope.buttonNextTitle = $scope.buttonNextTitle || 'Next'; $scope.buttonPrevTitle = $scope.buttonPrevTitle || 'Prev'; - $scope.month = $filter('date')(date, 'MMMM');//december-November like $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like $scope.day = Number($filter('date')(date, 'dd')); //01-31 like + $scope.dateWeekStartDay = $scope.validateWeekDay($scope.dateWeekStartDay); + if ($scope.dateMaxLimit) { $scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy'));//2014 like @@ -588,28 +898,70 @@ $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like } $scope.months = datetime.MONTH; - $scope.daysInString = ['0', '1', '2', '3', '4', '5', '6'].map(function mappingFunc(el) { + + $scope.daysInString = []; + for (n = $scope.dateWeekStartDay; n <= $scope.dateWeekStartDay + 6; n += 1) { + + $scope.daysInString.push(n % 7); + } + $scope.daysInString = $scope.daysInString.map(function mappingFunc(el) { return $filter('date')(new Date(new Date('06/08/2014').valueOf() + A_DAY_IN_MILLISECONDS * el), 'EEE'); }); - //create the calendar holder - thisInput.after($compile(angular.element(htmlTemplate))($scope)); - //get the calendar as element - theCalendar = element[0].querySelector('._720kb-datepicker-calendar'); + //create the calendar holder and append where needed + if ($scope.datepickerAppendTo && + $scope.datepickerAppendTo.indexOf('.') !== -1) { - //some tricky dirty events to fire if click is outside of the calendar and show/hide calendar when needed - thisInput.on('focus click', function onFocusAndClick() { + $scope.datepickerID = 'datepicker-id-' + new Date().getTime() + (Math.floor(Math.random() * 6) + 8); + angular.element(document.getElementsByClassName($scope.datepickerAppendTo.replace('.', ''))[0]).append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { - isMouseOnInput = true; - showCalendar(); - }); + theCalendar = angular.element(el)[0]; + })); + } else if ($scope.datepickerAppendTo && + $scope.datepickerAppendTo.indexOf('#') !== -1) { + + $scope.datepickerID = 'datepicker-id-' + new Date().getTime() + (Math.floor(Math.random() * 6) + 8); + angular.element(document.getElementById($scope.datepickerAppendTo.replace('#', ''))).append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { + + theCalendar = angular.element(el)[0]; + })); + } else if ($scope.datepickerAppendTo && + $scope.datepickerAppendTo === 'body') { + $scope.datepickerID = 'datepicker-id-' + (new Date().getTime() + (Math.floor(Math.random() * 6) + 8)); + angular.element(document).find('body').append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { + + theCalendar = angular.element(el)[0]; + })); + } else { + + thisInput.after($compile(angular.element(htmlTemplate))($scope)); + //get the calendar as element + theCalendar = element[0].querySelector('._720kb-datepicker-calendar'); + } + //if datepicker-toggle="" is not present or true by default + if (checkToggle()) { + + thisInput.on('focus click focusin', function onFocusAndClick() { + + isMouseOnInput = true; + + if (!isMouseOn && + !isMouseOnInput && theCalendar) { + + $scope.hideCalendar(); + } else { + + showCalendar(); + } + }); + } thisInput.on('focusout blur', function onBlurAndFocusOut() { isMouseOnInput = false; }); - + //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() { isMouseOn = true; @@ -625,42 +977,41 @@ isMouseOn = true; }); - angular.element($window).on('click focus', function onClickOnWindow() { - - if (!isMouseOn && - !isMouseOnInput && theCalendar) { - - $scope.hideCalendar(); - } - }); + angular.element($window).on('click focus focusin', onClickOnWindow); //check always if given range of dates is ok if ($scope.dateMinLimit && - !$scope.isSelectableMinYear($scope.year)) { + !$scope.isSelectableMinYear($scope.year) || + !$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { resetToMinDate(); } if ($scope.dateMaxLimit && - !$scope.isSelectableMaxYear($scope.year)) { + !$scope.isSelectableMaxYear($scope.year) || + !$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { resetToMaxDate(); } + //datepicker boot start $scope.paginateYears($scope.year); + setDaysInMonth($scope.monthNumber, $scope.year); + $scope.checkVisibility = checkVisibility; $scope.$on('$destroy', function unregisterListener() { unregisterDataSetWatcher(); + unregisterDateMinLimitWatcher(); + unregisterDateMaxLimitWatcher(); + unregisterDateFormatWatcher(); + unregisterDateDisabledDatesWatcher(); + unregisterDateEnabledDatesWatcher(); thisInput.off('focus click focusout blur'); angular.element(theCalendar).off('mouseenter mouseleave focusin'); - angular.element($window).off('click focus'); + angular.element($window).off('click focus focusin', onClickOnWindow); }); - - if (attr.hasOwnProperty('visibleOnLoad')) { - showCalendar(); - } }; return { @@ -674,12 +1025,20 @@ 'buttonNextTitle': '@', 'buttonPrevTitle': '@', 'dateDisabledDates': '@', - 'dateSetHidden': '@' + 'dateEnabledDates': '@', + 'dateDisabledWeekdays': '@', + 'dateSetHidden': '@', + 'dateTyper': '@', + 'dateWeekStartDay': '@', + 'datepickerAppendTo': '@', + 'datepickerToggle': '@', + 'datepickerClass': '@', + 'datepickerShow': '@' }, 'link': linkingFunction }; }; angular.module('720kb.datepicker', []) - .directive('datepicker', ['$window', '$compile', '$locale', '$filter', '$interpolate', datepickerDirective]); + .directive('datepicker', ['$window', '$compile', '$locale', '$filter', '$interpolate', '$timeout', datepickerDirective]); }(angular, navigator)); diff --git a/tasks/copy.js b/tasks/copy.js new file mode 100644 index 0000000..282dcfa --- /dev/null +++ b/tasks/copy.js @@ -0,0 +1,17 @@ +/*global module, require*/ +(function setUp(module, require) { + 'use strict'; + + module.exports = function exportingFunction(grunt) { + + grunt.loadNpmTasks('grunt-contrib-copy'); + return { + 'non-minified': { + 'files': [ + { expand: true, flatten: true, src: ['<%= confs.css %>/**/*.css'], dest: '<%= confs.dist %>/', filter: 'isFile' }, + { expand: true, flatten: true, src: ['<%= confs.js %>/**/*.js'], dest: '<%= confs.dist %>/', filter: 'isFile' }, + ] + } + }; + }; +}(module, require)); diff --git a/themes/README.md b/themes/README.md index 7919b2b..d33433c 100644 --- a/themes/README.md +++ b/themes/README.md @@ -1,3 +1,3 @@ -####Create your own theme and put it into a subfolder here. +#### Create your own theme and put it into a subfolder here. For example ```/myawesometheme/angular-datepicker.css```