├── .csslintrc ├── .eslintrc ├── .gitignore ├── .jscsrc ├── .jshintrc ├── .sublime-project ├── Gruntfile.js ├── README.md ├── assets └── js │ └── index.js ├── bower.json ├── dist ├── angular-datepicker.css ├── angular-datepicker.js ├── angular-datepicker.min.css ├── angular-datepicker.min.js └── angular-datepicker.sourcemap.map ├── index.html ├── index.js ├── package.json ├── src ├── css │ └── angular-datepicker.css └── js │ └── angular-datepicker.js ├── tasks ├── concurrent.js ├── confs.js ├── connect.js ├── copy.js ├── csslint.js ├── cssmin.js ├── eslint.js ├── jscs.js ├── uglify.js └── watch.js ├── themes └── README.md ├── twitter-bootstrap.html └── ui-bootstrap ├── assets └── js │ └── index.js ├── index.html └── template └── datepicker ├── datepicker.html ├── day.html ├── month.html ├── popup.html └── year.html /.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "important": true, 3 | "adjoining-classes": false, 4 | "known-properties": false, 5 | "box-sizing": false, 6 | "box-model": false, 7 | "overqualified-elements": false, 8 | "display-property-grouping": false, 9 | "bulletproof-font-face": false, 10 | "compatible-vendor-prefixes": true, 11 | "regex-selectors": false, 12 | "errors": true, 13 | "duplicate-background-images": true, 14 | "duplicate-properties": true, 15 | "empty-rules": true, 16 | "selector-max-approaching": false, 17 | "gradients": true, 18 | "fallback-colors": false, 19 | "font-sizes": false, 20 | "font-faces": false, 21 | "floats": false, 22 | "star-property-hack": false, 23 | "outline-none": false, 24 | "import": true, 25 | "ids": false, 26 | "underscore-property-hack": true, 27 | "rules-count": true, 28 | "qualified-headings": false, 29 | "selector-max": false, 30 | "shorthand": false, 31 | "text-indent": false, 32 | "unique-headings": false, 33 | "universal-selector": false, 34 | "unqualified-attributes": true, 35 | "vendor-prefix": true, 36 | "zero-units": true 37 | } 38 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-cond-assign": 2, 4 | "no-constant-condition": 2, 5 | "comma-dangle": 2, 6 | "no-control-regex": 2, 7 | "no-debugger": 2, 8 | "no-dupe-keys": 2, 9 | "no-empty": 2, 10 | "no-extra-semi": 2, 11 | "no-inner-declarations": 2, 12 | "no-invalid-regexp": 2, 13 | "no-negated-in-lhs": 2, 14 | "no-obj-calls": 2, 15 | "no-regex-spaces": 2, 16 | "no-sparse-arrays": 2, 17 | "no-unreachable": 2, 18 | "use-isnan": 2, 19 | "valid-typeof": 2, 20 | "camelcase": 2, 21 | "eqeqeq": 2, 22 | "no-plusplus": 2, 23 | "no-bitwise": 2, 24 | "block-scoped-var": 2, 25 | "consistent-return": 1, 26 | "curly": [ 27 | 2, 28 | "all" 29 | ], 30 | "default-case": 2, 31 | "dot-notation": 2, 32 | "no-caller": 2, 33 | "no-div-regex": 2, 34 | "no-else-return": 2, 35 | "no-eq-null": 2, 36 | "no-eval": 2, 37 | "no-extend-native": 2, 38 | "no-fallthrough": 2, 39 | "no-floating-decimal": 2, 40 | "no-implied-eval": 2, 41 | "no-labels": 2, 42 | "no-iterator": 2, 43 | "no-lone-blocks": 2, 44 | "no-loop-func": 2, 45 | "no-multi-str": 2, 46 | "no-native-reassign": 2, 47 | "no-new": 2, 48 | "no-new-func": 2, 49 | "no-new-wrappers": 2, 50 | "no-octal": 2, 51 | "no-octal-escape": 2, 52 | "no-proto": 2, 53 | "no-redeclare": 2, 54 | "no-return-assign": 2, 55 | "no-script-url": 2, 56 | "no-self-compare": 2, 57 | "no-sequences": 2, 58 | "no-unused-expressions": 2, 59 | "no-with": 2, 60 | "yoda": 2, 61 | "radix": 2, 62 | "wrap-iife": [ 63 | 2, 64 | "outside" 65 | ], 66 | "strict": 2, 67 | "no-catch-shadow": 2, 68 | "no-delete-var": 2, 69 | "no-label-var": 2, 70 | "no-shadow": 2, 71 | "no-shadow-restricted-names": 2, 72 | "no-undef": 2, 73 | "no-undef-init": 2, 74 | "no-unused-vars": [ 75 | 2, 76 | { 77 | "vars": "all", 78 | "args": "after-used" 79 | } 80 | ], 81 | "no-use-before-define": 2, 82 | "brace-style": [ 83 | 2, 84 | "1tbs" 85 | ], 86 | "consistent-this": [ 87 | 2, 88 | "that" 89 | ], 90 | "new-cap": 2, 91 | "new-parens": 2, 92 | "no-nested-ternary": 2, 93 | "no-array-constructor": 2, 94 | "no-lonely-if": 2, 95 | "no-new-object": 2, 96 | "no-spaced-func": 2, 97 | "semi-spacing": 2, 98 | "no-underscore-dangle": 2, 99 | "no-extra-parens": 2, 100 | "quotes": [ 101 | 2, 102 | "single", 103 | "avoid-escape" 104 | ], 105 | "quote-props": 2, 106 | "semi": [ 107 | 2, 108 | "always" 109 | ], 110 | "keyword-spacing": 2, 111 | "object-curly-spacing": [ 112 | 2, 113 | "never" 114 | ], 115 | "array-bracket-spacing": [ 116 | 2, 117 | "never" 118 | ], 119 | "computed-property-spacing": [ 120 | 2, 121 | "never" 122 | ], 123 | "space-infix-ops": 2, 124 | "space-unary-ops": 2, 125 | "one-var": 2, 126 | "wrap-regex": 2, 127 | 128 | "no-extra-boolean-cast": 1, 129 | "no-console": 1, 130 | "no-alert": 1, 131 | "no-empty-character-class": 1, 132 | "no-ex-assign": 1, 133 | "no-func-assign": 1, 134 | "valid-jsdoc": 1, 135 | "guard-for-in": 1, 136 | "no-warning-comments": [ 137 | 1, 138 | { 139 | "terms": ["todo", "fixme", "xxx"], 140 | "location": "anywhere" 141 | } 142 | ], 143 | "func-style": [ 144 | 1, 145 | "expression" 146 | ], 147 | "func-names": 1, 148 | 149 | "no-ternary": 0, 150 | "sort-vars": 0 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | npm-debug.log 4 | **/.idea -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "validateIndentation": 2, 3 | "disallowAnonymousFunctions": true, 4 | "disallowCapitalizedComments": true, 5 | "disallowDanglingUnderscores": true, 6 | "disallowEmptyBlocks": true, 7 | "disallowFunctionDeclarations": true, 8 | "disallowImplicitTypeConversion": [ 9 | "numeric", 10 | "binary", 11 | "string" 12 | ], 13 | "disallowKeywordsOnNewLine": [ 14 | "else" 15 | ], 16 | "disallowKeywords": [ 17 | "with" 18 | ], 19 | "disallowMixedSpacesAndTabs": true, 20 | "disallowMultipleLineBreaks": true, 21 | "disallowMultipleLineStrings": true, 22 | "disallowMultipleSpaces": true, 23 | "disallowNewlineBeforeBlockStatements": true, 24 | "disallowNotOperatorsInConditionals": true, 25 | "disallowOperatorBeforeLineBreak": [ 26 | ".", 27 | "+" 28 | ], 29 | "disallowSpacesInCallExpression": true, 30 | "disallowYodaConditions": true, 31 | "requireBlocksOnNewline": true, 32 | "requireCurlyBraces": [ 33 | "if", 34 | "else", 35 | "for", 36 | "while", 37 | "do", 38 | "try", 39 | "catch", 40 | "case", 41 | "default" 42 | ], 43 | "requireDotNotation": true, 44 | "requireLineBreakAfterVariableAssignment": true, 45 | "requireLineFeedAtFileEnd": true, 46 | "requireMultipleVarDecl": true, 47 | "requireNamedUnassignedFunctions": true, 48 | "requireOperatorBeforeLineBreak": [ 49 | "?", 50 | "=", 51 | "+", 52 | "-", 53 | "/", 54 | "*", 55 | "==", 56 | "===", 57 | "!=", 58 | "!==", 59 | ">", 60 | ">=", 61 | "<", 62 | "<=" 63 | ], 64 | "requirePaddingNewLineAfterVariableDeclaration": true, 65 | "requirePaddingNewLinesAfterUseStrict": true, 66 | "requirePaddingNewLinesBeforeExport": true, 67 | "requirePaddingNewLinesInObjects": true, 68 | "requireParenthesesAroundIIFE": true, 69 | "requireQuotedKeysInObjects": true, 70 | "requireSpaceBetweenArguments": true, 71 | "requireSpacesInAnonymousFunctionExpression": { 72 | "beforeOpeningRoundBrace": true, 73 | "beforeOpeningCurlyBrace": true 74 | }, 75 | "requireSpacesInForStatement": true, 76 | "requireSpacesInFunctionDeclaration": { 77 | "beforeOpeningCurlyBrace": true 78 | }, 79 | "disallowSpacesInFunctionDeclaration": { 80 | "beforeOpeningRoundBrace": true 81 | }, 82 | "requireSpacesInFunctionExpression": { 83 | "beforeOpeningCurlyBrace": true 84 | }, 85 | "disallowSpacesInFunctionExpression": { 86 | "beforeOpeningRoundBrace": true 87 | }, 88 | "requireSpacesInFunction": { 89 | "beforeOpeningCurlyBrace": true 90 | }, 91 | "disallowSpacesInFunction": { 92 | "beforeOpeningRoundBrace": true 93 | }, 94 | "requireSpacesInNamedFunctionExpression": { 95 | "beforeOpeningCurlyBrace": true 96 | }, 97 | "disallowSpacesInNamedFunctionExpression": { 98 | "beforeOpeningRoundBrace": true 99 | }, 100 | "safeContextKeyword": [ 101 | "that" 102 | ], 103 | "validateAlignedFunctionParameters": { 104 | "lineBreakAfterOpeningBraces": true 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "laxcomma": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": true, 7 | "forin": true, 8 | "freeze": true, 9 | "futurehostile": true, 10 | "latedef": true, 11 | "noarg": true, 12 | "nocomma": true, 13 | "nonbsp": true, 14 | "nonew": true, 15 | "notypeof": true, 16 | "singleGroups": true, 17 | "strict": true, 18 | "undef": true, 19 | "unused": true, 20 | "plusplus": true 21 | } 22 | -------------------------------------------------------------------------------- /.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "./", 5 | "follow_symlinks": false 6 | } 7 | ], 8 | "settings": { 9 | "tab_size": 2, 10 | "translate_tabs_to_spaces": true 11 | }, 12 | "ternjs": { 13 | "exclude": [ 14 | "node_modules/**" 15 | ], 16 | "libs": [ 17 | "browser", 18 | "ecma5" 19 | ], 20 | "plugins": { 21 | "angular": { 22 | "baseURL": "./js" 23 | }, 24 | "node": { 25 | "baseURL": "./js" 26 | } 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | (function setUp(module, require) { 3 | 'use strict'; 4 | 5 | var banner = ['/*!', 6 | ' * Angular Datepicker v<%= pkg.version %>', 7 | ' *', 8 | ' * Released by 720kb.net under the MIT license', 9 | ' * www.opensource.org/licenses/MIT', 10 | ' *', 11 | ' * <%= grunt.template.today("yyyy-mm-dd") %>', 12 | ' */\n\n'].join('\n'); 13 | 14 | module.exports = function doGrunt(grunt) { 15 | var confs = require('./tasks/confs') 16 | , jscs = require('./tasks/jscs')(grunt) 17 | , csslint = require('./tasks/csslint')(grunt) 18 | , eslint = require('./tasks/eslint')(grunt) 19 | , uglify = require('./tasks/uglify')(banner, grunt) 20 | , cssmin = require('./tasks/cssmin')(banner, grunt) 21 | , connect = require('./tasks/connect')(grunt) 22 | , watch = require('./tasks/watch')(grunt) 23 | , concurrent = require('./tasks/concurrent')(grunt) 24 | , copy = require('./tasks/copy')(grunt); 25 | 26 | grunt.initConfig({ 27 | 'pkg': grunt.file.readJSON('package.json'), 28 | 'confs': confs, 29 | 'jscs': jscs, 30 | 'csslint': csslint, 31 | 'eslint': eslint, 32 | 'uglify': uglify, 33 | 'cssmin': cssmin, 34 | 'connect': connect, 35 | 'watch': watch, 36 | 'concurrent': concurrent, 37 | 'copy': copy 38 | }); 39 | 40 | grunt.registerTask('default', [ 41 | 'lint', 42 | 'concurrent:dev' 43 | ]); 44 | 45 | grunt.registerTask('lint', [ 46 | 'csslint', 47 | 'eslint', 48 | 'jscs' 49 | ]); 50 | 51 | grunt.registerTask('prod', [ 52 | 'lint', 53 | 'copy:non-minified', 54 | 'cssmin', 55 | 'uglify' 56 | ]); 57 | }; 58 | }(module, require)); 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Angular Datepicker 2 | ================== 3 | ![Angular datepicker calendar](http://i.imgur.com/jKfADtA.png) 4 | 5 | [![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) 6 | 7 | 8 | Angular datepicker is an angularjs directive that generates a datepicker calendar on your input element. 9 | 10 | The Angularjs Datepicker is developed by [720kb](http://720kb.net). 11 | 12 | ## Requirements 13 | 14 | AngularJS v1.3+ 15 | 16 | ### Browser support 17 | 18 | Chrome | Firefox | IE | Opera | Safari 19 | --- | --- | --- | --- | --- | 20 | ✔ | ✔ | IE9 + | ✔ | ✔ | 21 | 22 | 23 | ## Load 24 | 25 | To use the directive, include the Angular Datepicker's javascript and css files in your web page: 26 | 27 | ```html 28 | 29 | 30 | 31 | 32 | 33 | 34 | //..... 35 | 36 | 37 | 38 | ``` 39 | 40 | ## Installation 41 | 42 | #### Bower 43 | 44 | ``` 45 | $ bower install angularjs-datepicker --save 46 | ``` 47 | #### Npm 48 | 49 | ``` 50 | $ npm install angularjs-datepicker --save 51 | ``` 52 | 53 | _then load the js files in your html_ 54 | 55 | ### Add module dependency 56 | 57 | Add the 720kb.datepicker module dependency 58 | 59 | ```js 60 | angular.module('app', [ 61 | '720kb.datepicker' 62 | ]); 63 | ``` 64 | 65 | Call the directive wherever you want in your html page 66 | 67 | ```html 68 | 69 | 70 | 71 | ``` 72 | > 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. 73 | 74 | 75 | ## DOC 76 | 77 | Option | Type | Default | Description 78 | ------------- | ------------- | ------------- | ------------- 79 | date-set="" | String | false | Set a default date to show and init datepicker 80 | | | | **tip:** _Do not use same scope for ng-model="date" and date-set="{{date}}", this example is wrong._ 81 | | | | **tip:** _If you want to pass a Date Object inside do like this date-set="{{newDateObject.toString()}}"_ 82 | | | | **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."._ 83 | 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) 84 | | | | **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_ 85 | date-min-limit="" | String | false | Set a minimum date limit - you can use all the accepted date formats by the javascript `new Date()` 86 | date-max-limit="" | String | false | Set a maximum date limit - you can use all the accepted date formats by the javascript `new Date()` 87 | date-set-hidden="" | String(Boolean) | false | Set the default date to be shown only in calendar and not in the input field 88 | date-disabled-dates="" | String([Date(), Date(), ...]) | false | Disable specific dates using an _Array_ of dates. 89 | date-enabled-dates="" | String([Date(), Date(), ...]) | false | Enable only the specific dates using an _Array_ of dates. 90 | date-disabled-weekdays="" | String(1, 5, ...]) | false | Disable specific weekdays using an _Array_ of weeks number 91 | date-refocus="" | String(Boolean) | false | Set the datepicker to re-focus the input after selecting a date 92 | date-typer="" | String(Boolean) | false | Set the datepicker to update calendar date when user is typing a date, see validation [tips](#date-validation) 93 | 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) 94 | datepicker-class="" | String('class1 class2 class3') | false | Set custom class/es for the datepicker calendar 95 | datepicker-append-to="" | String('#id','.classname', 'body') | false | Append the datepicker to #id or .class element or to body 96 | datepicker-toggle="" | String(Boolean) | true | Set the datepicker to toggle its visibility on focus and blur 97 | | | | **tip:** Best is to use `pointer-events: none;` on your input if you don't want the user to toggle the calendar visibility. 98 | datepicker-show="" | String | false | Trigger the datepicker visibility, if true datepicker is shown if false it is hidden 99 | | | | **tip:** _Do not mix it with datepicker-toggle for a more stable behavior_ 100 | datepicker-mobile="" | String | true | Set to `false` to force override of mobile styles. Especially useful for using desktop-style pagination control in mobile apps. 101 | 102 | ## Options 103 | Angular datepicker allows you to use some options via `attribute` data 104 | 105 | #### Custom titles 106 | 107 | 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"_) 108 | 109 | ```html 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | ``` 118 | 119 | #### Highlight today day in calendar 120 | To highlight or style the today day in the calendar just use its own CSS class (`._720kb-datepicker-today`) like this: 121 | 122 | ```css 123 | ._720kb-datepicker-calendar-day._720kb-datepicker-today { 124 | background:red; 125 | color:white; 126 | } 127 | ``` 128 | 129 | #### Custom buttons 130 | You can customize the calendar navigation buttons content, let's make an example while using [FontAwesome](http://fontawesome.io) 131 | 132 | ```html 133 | 134 | 135 | 136 | ``` 137 | 138 | #### Custom buttons titles for arrows 139 | 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"_. 140 | 141 | ```html 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | ``` 150 | 151 | #### Input as grandchild 152 | 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 153 | 154 | ```html 155 | 156 |
157 | 158 | 159 | 160 | 161 |
162 |
163 | ``` 164 | #### Manually show and hide datepicker 165 | 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 166 | 167 | ```javascript 168 | .controller('TestController', ['$scope', '$interval', function TestController($scope, $interval) { 169 | $scope.visibility = true; 170 | 171 | $interval(function setInterval() { 172 | //toggling manually everytime 173 | $scope.visibility = !$scope.visibility; 174 | }, 3500); 175 | }]); 176 | ``` 177 | ```html 178 | 179 | 180 | 181 | ``` 182 | _tip: you should use this attribute together with `datepicker-toggle="false" , for a better stable behavior of the datepicker_ 183 | 184 | #### Input as grandchild 185 | 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 186 | 187 | ```html 188 | 189 |
190 | 191 | 192 | 193 | 194 |
195 |
196 | ``` 197 | ### Tips 198 | 199 | #### Date validation 200 | If you want to validate the input, while user is typing for example, you just have to refer to the `ngModel`. 201 | As long as you use something like: 202 | ```html 203 |
204 | 205 |
206 | ``` 207 | You can show validation errors simply validating the ngModel, as you would do for any other type of input, for example: 208 | ```javascript 209 | .controller('Ctrl', ['$scope', function ($scope) { 210 | var liveDate; 211 | 212 | $scope.$watch('myDate', function (value) { 213 | try { 214 | liveDate = new Date(value); 215 | } catch(e) {} 216 | 217 | if (!liveDate) { 218 | 219 | $scope.error = "This is not a valid date"; 220 | } else { 221 | $scope.error = false; 222 | } 223 | }); 224 | }]); 225 | ``` 226 | 227 | Then your final html: 228 | ```html 229 |
230 | 231 |
{{ctrl.error}}
232 |
233 | ``` 234 | 235 | 236 | ### Example 237 | 238 | [Live demo](https://720kb.github.io/angular-datepicker) 239 | 240 | ## Themes :art: 241 | 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! 242 | 243 | More about it https://github.com/720kb/angular-datepicker/tree/master/themes. 244 | 245 | Here is an example of a [Dark Theme](http://codepen.io/45kb/pen/bjslv) made using custom Css. 246 | 247 | ***_Please note that the example may not be uptodate with the latest angular and/or module version_ 248 | 249 | ## Contributing 250 | 251 | We will be much grateful if you help us making this project to grow up. 252 | Feel free to contribute by forking, opening issues, pull requests etc. 253 | 254 | ## License 255 | 256 | The MIT License (MIT) 257 | 258 | Copyright (c) 2014 Filippo Oretti, Dario Andrei 259 | 260 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 261 | 262 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 263 | 264 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 265 | -------------------------------------------------------------------------------- /assets/js/index.js: -------------------------------------------------------------------------------- 1 | /*global angular window*/ 2 | 3 | (function (angular) { 4 | 'use strict'; 5 | 6 | var app = angular.module('720kb', [ 7 | 'ngRoute', 8 | '720kb.datepicker' 9 | ]) 10 | .controller('TestController', ['$scope', '$interval', function TestController($scope, $interval) { 11 | var that = this; 12 | 13 | that.visibility = true; 14 | 15 | $interval(function setInterval() { 16 | //toggle manually everytime 17 | that.visibility = !that.visibility; 18 | window.console.info('Toggling datepicker with interval of 3.5 seconds'); 19 | }, 3500); 20 | }]); 21 | }(angular)); 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-datepicker", 3 | "version": "2.1.23", 4 | "description": "A datepicker directive for angularjs.", 5 | "authors": [ 6 | "Filippo Oretti " 8 | ], 9 | "keywords": [ 10 | "date", 11 | "datepicker", 12 | "input", 13 | "angularjs", 14 | "angular", 15 | "input" 16 | ], 17 | "license": "MIT", 18 | "main": [ 19 | "./dist/angular-datepicker.css", 20 | "./dist/angular-datepicker.js", 21 | "./dist/angular-datepicker.sourcemap.map" 22 | ], 23 | "homepage": "http://720kb.github.io/angular-datepicker", 24 | "ignore": [ 25 | "**/.*", 26 | "node_modules", 27 | "bower_components", 28 | "test", 29 | "tests" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /dist/angular-datepicker.css: -------------------------------------------------------------------------------- 1 | datepicker a, [datepicker] a, .datepicker a{ 2 | color:inherit; 3 | text-decoration:none; 4 | } 5 | datepicker a:hover, [datepicker] a:hover, .datepicker a:hover{ 6 | text-decoration:none; 7 | } 8 | datepicker select, datepicker select:focus, datepicker select:hover, 9 | .datepicker select, .datepicker select:focus, .datepicker select:hover, 10 | [datepicker] select, [datepicker] select:focus, [datepicker] select:hover{ 11 | width:100%; 12 | overflow: hidden; 13 | background:none; 14 | color:#fff; 15 | background-color: #138EFA; 16 | border-radius:2px; 17 | border: 0; 18 | margin-top:5px; 19 | } 20 | datepicker, .datepicker, [datepicker], 21 | ._720kb-datepicker-calendar-header, 22 | ._720kb-datepicker-calendar-body, 23 | ._720kb-datepicker-calendar-days-header, 24 | ._720kb-datepicker-calendar-years-pagination-pages { 25 | font-family: Helvetica Neue, Arial, sans-serif; 26 | font-size: 13.5px; 27 | -webkit-box-sizing: border-box; 28 | -moz-box-sizing: border-box; 29 | -ms-box-sizing: border-box; 30 | box-sizing: border-box; 31 | width: 100%; 32 | margin: 0 auto; 33 | float: left; 34 | clear: right; 35 | position: relative; 36 | } 37 | ._720kb-datepicker-calendar { 38 | background: white; 39 | color: #333; 40 | position: absolute; 41 | z-index: 999; 42 | min-width: 220px; 43 | margin: 0 auto; 44 | width: 101%; 45 | -webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset; 46 | -moz-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset; 47 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset; 48 | visibility: hidden; 49 | overflow:hidden; 50 | margin-left:-0.5%; 51 | padding: 0 0 2% 0; 52 | -webkit-border-radius: 3px; 53 | -moz-border-radius: 3px; 54 | border-radius: 3px; 55 | } 56 | ._720kb-datepicker-calendar._720kb-datepicker-open,._720kb-datepicker-calendar._720kb-datepicker-forced-to-open { 57 | visibility: visible; 58 | } 59 | ._720kb-datepicker-calendar-header { 60 | text-align: center; 61 | font-size: 15px; 62 | line-height: 40px; 63 | } 64 | ._720kb-datepicker-calendar-header:nth-child(odd) { 65 | background: #138EFA; 66 | } 67 | ._720kb-datepicker-calendar-header:nth-child(even) { 68 | background: #7BC6FC; 69 | } 70 | ._720kb-datepicker-calendar-header-left, 71 | ._720kb-datepicker-calendar-header-middle, 72 | ._720kb-datepicker-calendar-header-right { 73 | width: 15%; 74 | float: left; 75 | } 76 | ._720kb-datepicker-calendar-header-middle { 77 | width: 70%; 78 | } 79 | 80 | ._720kb-datepicker-calendar-header-closed-pagination::after { 81 | content: " \25BE"; 82 | } 83 | 84 | ._720kb-datepicker-calendar-header-opened-pagination::after { 85 | content: " \25BE"; 86 | margin-left: 4px; 87 | position: relative; 88 | bottom: -3px; 89 | display:inline-block; 90 | -webkit-transform: rotate(180deg); 91 | -moz-transform: rotate(180deg); 92 | -o-transform: rotate(180deg); 93 | -ms-transform: rotate(180deg); 94 | transform: rotate(180deg); 95 | } 96 | ._720kb-datepicker-calendar-body { 97 | width: 96%; 98 | margin: 2%; 99 | text-align: center; 100 | } 101 | ._720kb-datepicker-calendar-day { 102 | cursor: pointer; 103 | font-size: 12.5px; 104 | width: 12.2%; 105 | margin:5px 1%; 106 | padding: 1.5% 0; 107 | float: left; 108 | -webkit-border-radius: 1px; 109 | -moz-border-radius: 1px; 110 | border-radius: 1px; 111 | } 112 | ._720kb-datepicker-calendar-day:hover, 113 | ._720kb-datepicker-calendar-day._720kb-datepicker-active { 114 | background: rgba(0, 0, 0, 0.03); 115 | } 116 | ._720kb-datepicker-calendar-header a, ._720kb-datepicker-calendar-header a:hover { 117 | text-decoration:none; 118 | padding:3% 9% 4% 9%; 119 | font-size: 13.5px; 120 | color:rgba(0, 0, 0, 0.55); 121 | font-weight: bold; 122 | -webkit-border-radius: 3px; 123 | -moz-border-radius: 3px; 124 | border-radius: 3px; 125 | } 126 | ._720kb-datepicker-calendar-header a:hover { 127 | color:rgba(0, 0, 0, 0.9); 128 | background: rgba(255, 255, 255, 0.45); 129 | } 130 | ._720kb-datepicker-calendar-month { 131 | color:#fff; 132 | } 133 | ._720kb-datepicker-calendar-month span { 134 | font-size: 13px; 135 | color:rgba(0, 0, 0, 0.4); 136 | } 137 | ._720kb-datepicker-calendar-month a span i { 138 | font-style: normal; 139 | font-size:15px; 140 | } 141 | ._720kb-datepicker-calendar-month a, ._720kb-datepicker-calendar-month a:hover { 142 | padding: 3px; 143 | margin-left:1%; 144 | } 145 | ._720kb-datepicker-calendar-years-pagination{ 146 | padding:2% 0 0 0; 147 | float:left; 148 | clear: right; 149 | width: 100%; 150 | } 151 | ._720kb-datepicker-calendar-years-pagination a, ._720kb-datepicker-calendar-years-pagination a:hover { 152 | font-size:12px; 153 | padding:0 7px; 154 | font-weight: normal; 155 | margin:3px 1% 0 1%; 156 | line-height: 20px; 157 | display: inline-block; 158 | } 159 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active { 160 | color:rgba(0, 0, 0, 0.9); 161 | font-weight: 500; 162 | background: rgba(255, 255, 255, 0.45); 163 | } 164 | ._720kb-datepicker-calendar-years-pagination-pages a,._720kb-datepicker-calendar-years-pagination-pages a:hover{ 165 | padding:5px 10px; 166 | } 167 | ._720kb-datepicker-calendar-days-header{ 168 | max-width: 100%; 169 | margin:0 auto; 170 | padding:0 2% 0 2%; 171 | background: rgba(19, 142, 250, 0.08); 172 | border-bottom:1px solid rgba(0,0,0,0.02); 173 | } 174 | ._720kb-datepicker-calendar-days-header div{ 175 | width: 14.18%; 176 | font-weight: 500; 177 | font-size: 11.5px; 178 | padding:10px 0; 179 | float:left; 180 | text-align: center; 181 | color:rgba(0,0,0,0.7); 182 | } 183 | ._720kb-datepicker-calendar-days 184 | ._720kb-datepicker-default-button{ 185 | font-size: 18.5px; 186 | position: relative; 187 | bottom:-0.5px; 188 | } 189 | ._720kb-datepicker-default-button{ 190 | padding:0 4.5px; 191 | } 192 | ._720kb-datepicker-calendar-header-middle._720kb-datepicker-mobile-item{ 193 | width:95%; 194 | float:none; 195 | margin:0 auto; 196 | } 197 | ._720kb-datepicker-item-hidden{ 198 | visibility:hidden; 199 | } 200 | ._720kb-datepicker-calendar-day._720kb-datepicker-disabled, 201 | ._720kb-datepicker-calendar-day._720kb-datepicker-disabled:hover, 202 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled, 203 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled:hover, 204 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled, 205 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled:hover{ 206 | color:rgba(0,0,0,0.2); 207 | background: rgba(25,2,0,0.02); 208 | cursor: default; 209 | } 210 | -------------------------------------------------------------------------------- /dist/angular-datepicker.js: -------------------------------------------------------------------------------- 1 | /*global angular document navigator*/ 2 | (function withAngular(angular, navigator) { 3 | 4 | 'use strict'; 5 | 6 | var A_DAY_IN_MILLISECONDS = 86400000 7 | , isMobile = (function isMobile() { 8 | 9 | if (navigator.userAgent && 10 | (navigator.userAgent.match(/Android/i) || 11 | navigator.userAgent.match(/webOS/i) || 12 | navigator.userAgent.match(/iPhone/i) || 13 | navigator.userAgent.match(/iPad/i) || 14 | navigator.userAgent.match(/iPod/i) || 15 | navigator.userAgent.match(/BlackBerry/i) || 16 | navigator.userAgent.match(/Windows Phone/i))) { 17 | 18 | return true; 19 | } 20 | }()) 21 | , generateMonthAndYearHeader = function generateMonthAndYearHeader(prevButton, nextButton, preventMobile) { 22 | 23 | if (preventMobile) { 24 | 25 | isMobile = false; 26 | } 27 | 28 | if (isMobile) { 29 | 30 | return [ 31 | '
', 32 | '
', 33 | '', 38 | '
', 39 | '
', 40 | '
', 41 | '
', 42 | '', 47 | '
', 48 | '
' 49 | ]; 50 | } 51 | 52 | return [ 53 | '
', 54 | '
', 55 | '', 56 | prevButton, 57 | '', 58 | '
', 59 | '
', 60 | '{{month}} ', 61 | '', 62 | '', 63 | '{{year}}', 64 | '', 65 | '', 66 | '', 67 | '
', 68 | '
', 69 | '', 70 | nextButton, 71 | '', 72 | '
', 73 | '
' 74 | ]; 75 | } 76 | , generateYearsPaginationHeader = function generateYearsPaginationHeader(prevButton, nextButton) { 77 | 78 | return [ 79 | '
', 80 | '
', 81 | '', 82 | '{{y}}', 83 | '', 84 | '
', 85 | '', 93 | '
' 94 | ]; 95 | } 96 | , generateDaysColumns = function generateDaysColumns() { 97 | 98 | return [ 99 | '
', 100 | '
', 101 | '{{d}}', 102 | '
', 103 | '
' 104 | ]; 105 | } 106 | , generateDays = function generateDays() { 107 | 108 | return [ 109 | '
', 110 | '', 111 | '{{px}}', 112 | '', 113 | '', 114 | '{{item}}', 115 | '', 116 | '', 117 | '{{nx}}', 118 | '', 119 | '
' 120 | ]; 121 | } 122 | , generateHtmlTemplate = function generateHtmlTemplate(prevButton, nextButton, preventMobile) { 123 | 124 | var toReturn = [ 125 | '
', 126 | '
' 127 | ] 128 | , monthAndYearHeader = generateMonthAndYearHeader(prevButton, nextButton, preventMobile) 129 | , yearsPaginationHeader = generateYearsPaginationHeader(prevButton, nextButton) 130 | , daysColumns = generateDaysColumns() 131 | , days = generateDays() 132 | , iterator = function iterator(aRow) { 133 | 134 | toReturn.splice(toReturn.length - 1, 0, aRow); 135 | }; 136 | 137 | monthAndYearHeader.forEach(iterator); 138 | yearsPaginationHeader.forEach(iterator); 139 | daysColumns.forEach(iterator); 140 | days.forEach(iterator); 141 | 142 | return toReturn.join(''); 143 | } 144 | , datepickerDirective = function datepickerDirective($window, $compile, $locale, $filter, $interpolate, $timeout) { 145 | 146 | var linkingFunction = function linkingFunction($scope, element, attr) { 147 | 148 | //get child input 149 | var selector = attr.selector 150 | , thisInput = angular.element(selector ? element[0].querySelector('.' + selector) : element[0].children[0]) 151 | , theCalendar 152 | , defaultPrevButton = '' 153 | , defaultNextButton = '' 154 | , prevButton = attr.buttonPrev || defaultPrevButton 155 | , nextButton = attr.buttonNext || defaultNextButton 156 | , dateFormat = attr.dateFormat 157 | //, dateMinLimit 158 | //, dateMaxLimit 159 | , dateDisabledDates = $scope.$eval($scope.dateDisabledDates) 160 | , dateEnabledDates = $scope.$eval($scope.dateEnabledDates) 161 | , dateDisabledWeekdays = $scope.$eval($scope.dateDisabledWeekdays) 162 | , date = new Date() 163 | , isMouseOn = false 164 | , isMouseOnInput = false 165 | , preventMobile = typeof attr.datepickerMobile !== 'undefined' && attr.datepickerMobile !== 'false' 166 | , datetime = $locale.DATETIME_FORMATS 167 | , pageDatepickers 168 | , hours24h = 86400000 169 | , htmlTemplate = generateHtmlTemplate(prevButton, nextButton, preventMobile) 170 | , n 171 | , onClickOnWindow = function onClickOnWindow() { 172 | 173 | if (!isMouseOn && 174 | !isMouseOnInput && theCalendar) { 175 | 176 | $scope.hideCalendar(); 177 | } 178 | } 179 | , setDaysInMonth = function setDaysInMonth(month, year) { 180 | 181 | var i 182 | , limitDate = new Date(year, month, 0).getDate() 183 | , firstDayMonthNumber = new Date(year + '/' + month + '/' + 1).getDay() 184 | , lastDayMonthNumber = new Date(year + '/' + month + '/' + limitDate).getDay() 185 | , prevMonthDays = [] 186 | , nextMonthDays = [] 187 | , howManyNextDays 188 | , howManyPreviousDays 189 | , monthAlias 190 | , dateWeekEndDay; 191 | 192 | $scope.days = []; 193 | $scope.dateWeekStartDay = $scope.validateWeekDay($scope.dateWeekStartDay); 194 | dateWeekEndDay = ($scope.dateWeekStartDay + 6) % 7; 195 | 196 | for (i = 1; i <= limitDate; i += 1) { 197 | 198 | $scope.days.push(i); 199 | } 200 | 201 | //get previous month days if first day in month is not first day in week 202 | if (firstDayMonthNumber === $scope.dateWeekStartDay) { 203 | 204 | //no need for it 205 | $scope.prevMonthDays = []; 206 | } else { 207 | 208 | howManyPreviousDays = firstDayMonthNumber - $scope.dateWeekStartDay; 209 | 210 | if (firstDayMonthNumber < $scope.dateWeekStartDay) { 211 | 212 | howManyPreviousDays += 7; 213 | } 214 | 215 | //get previous month 216 | if (Number(month) === 1) { 217 | 218 | monthAlias = 12; 219 | } else { 220 | 221 | monthAlias = month - 1; 222 | } 223 | //return previous month days 224 | for (i = 1; i <= new Date(year, monthAlias, 0).getDate(); i += 1) { 225 | 226 | prevMonthDays.push(i); 227 | } 228 | //attach previous month days 229 | $scope.prevMonthDays = prevMonthDays.slice(-howManyPreviousDays); 230 | } 231 | 232 | //get next month days if last day in month is not last day in week 233 | if (lastDayMonthNumber === dateWeekEndDay) { 234 | //no need for it 235 | $scope.nextMonthDays = []; 236 | } else { 237 | howManyNextDays = 6 - lastDayMonthNumber + $scope.dateWeekStartDay; 238 | 239 | if (lastDayMonthNumber < $scope.dateWeekStartDay) { 240 | 241 | howManyNextDays -= 7; 242 | } 243 | //get previous month 244 | 245 | //return next month days 246 | for (i = 1; i <= howManyNextDays; i += 1) { 247 | 248 | nextMonthDays.push(i); 249 | } 250 | //attach previous month days 251 | $scope.nextMonthDays = nextMonthDays; 252 | } 253 | } 254 | , resetToMinDate = function resetToMinDate() { 255 | 256 | $scope.month = $filter('date')(new Date($scope.dateMinLimit), 'MMMM'); 257 | $scope.monthNumber = Number($filter('date')(new Date($scope.dateMinLimit), 'MM')); 258 | $scope.day = Number($filter('date')(new Date($scope.dateMinLimit), 'dd')); 259 | $scope.year = Number($filter('date')(new Date($scope.dateMinLimit), 'yyyy')); 260 | 261 | setDaysInMonth($scope.monthNumber, $scope.year); 262 | } 263 | , resetToMaxDate = function resetToMaxDate() { 264 | 265 | $scope.month = $filter('date')(new Date($scope.dateMaxLimit), 'MMMM'); 266 | $scope.monthNumber = Number($filter('date')(new Date($scope.dateMaxLimit), 'MM')); 267 | $scope.day = Number($filter('date')(new Date($scope.dateMaxLimit), 'dd')); 268 | $scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy')); 269 | 270 | setDaysInMonth($scope.monthNumber, $scope.year); 271 | } 272 | , prevYear = function prevYear() { 273 | 274 | $scope.year = Number($scope.year) - 1; 275 | } 276 | , nextYear = function nextYear() { 277 | 278 | $scope.year = Number($scope.year) + 1; 279 | } 280 | , localDateTimestamp = function localDateTimestamp(rawDate, dateFormatDefinition) { 281 | 282 | 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 283 | ,formatDate,dateSplit, m, d, y, index, el, longName, shortName; 284 | 285 | for (index = 0; index < datetime.MONTH.length; index += 1) { 286 | longName = datetime.MONTH[index]; 287 | shortName = datetime.SHORTMONTH[index]; 288 | 289 | if (rawDate.indexOf(longName) !== -1) { 290 | rawDate = rawDate.replace(longName, index + 1); 291 | break; 292 | } 293 | 294 | if (rawDate.indexOf(shortName) !== -1) { 295 | rawDate = rawDate.replace(shortName, index + 1); 296 | break; 297 | } 298 | } 299 | 300 | dateSplit = rawDate 301 | .split(/\D/) 302 | .filter(function dateSplitFilter(item) { 303 | return item.length > 0; 304 | }); 305 | 306 | formatDate = dateFormatDefinition 307 | .match(formattingTokens) 308 | .filter(function fromatDateFilter(item) { 309 | return item.match(/^[a-zA-Z]+$/i) !== null; 310 | }); 311 | 312 | for (index = 0; index < formatDate.length; index += 1) { 313 | el = formatDate[index]; 314 | 315 | switch (true) { 316 | case el.indexOf('d') !== -1: { 317 | d = dateSplit[index - (formatDate.length - dateSplit.length)]; 318 | break; 319 | } 320 | case el.indexOf('M') !== -1: { 321 | m = dateSplit[index - (formatDate.length - dateSplit.length)]; 322 | break; 323 | } 324 | case el.indexOf('y') !== -1: { 325 | y = dateSplit[index - (formatDate.length - dateSplit.length)]; 326 | break; 327 | } 328 | default: { 329 | break; 330 | } 331 | } 332 | } 333 | 334 | return new Date(y + '/' + m + '/' + d); 335 | } 336 | , setInputValue = function setInputValue() { 337 | 338 | if ($scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day) && 339 | $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { 340 | 341 | var modelDate = new Date($scope.year + '/' + $scope.monthNumber + '/' + $scope.day); 342 | 343 | if (attr.dateFormat) { 344 | 345 | thisInput.val($filter('date')(modelDate, dateFormat)); 346 | } else { 347 | 348 | thisInput.val(modelDate); 349 | } 350 | 351 | thisInput.triggerHandler('input'); 352 | thisInput.triggerHandler('change');//just to be sure; 353 | } else { 354 | 355 | return false; 356 | } 357 | } 358 | , classHelper = { 359 | 'add': function add(ele, klass) { 360 | var classes; 361 | 362 | if (ele.className.indexOf(klass) > -1) { 363 | 364 | return; 365 | } 366 | 367 | classes = ele.className.split(' '); 368 | classes.push(klass); 369 | ele.className = classes.join(' '); 370 | }, 371 | 'remove': function remove(ele, klass) { 372 | var i 373 | , classes; 374 | 375 | if (ele.className.indexOf(klass) === -1) { 376 | 377 | return; 378 | } 379 | 380 | classes = ele.className.split(' '); 381 | for (i = 0; i < classes.length; i += 1) { 382 | 383 | if (classes[i] === klass) { 384 | 385 | classes = classes.slice(0, i).concat(classes.slice(i + 1)); 386 | break; 387 | } 388 | } 389 | ele.className = classes.join(' '); 390 | } 391 | } 392 | , showCalendar = function showCalendar() { 393 | //lets hide all the latest instances of datepicker 394 | pageDatepickers = $window.document.getElementsByClassName('_720kb-datepicker-calendar'); 395 | 396 | angular.forEach(pageDatepickers, function forEachDatepickerPages(value, key) { 397 | if (pageDatepickers[key].classList) { 398 | 399 | pageDatepickers[key].classList.remove('_720kb-datepicker-open'); 400 | } else { 401 | 402 | classHelper.remove(pageDatepickers[key], '_720kb-datepicker-open'); 403 | } 404 | }); 405 | 406 | if (theCalendar.classList) { 407 | 408 | theCalendar.classList.add('_720kb-datepicker-open'); 409 | if (dateFormat) { 410 | date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); 411 | } else { 412 | date = new Date(thisInput[0].value.toString()); 413 | } 414 | $scope.selectedMonth = Number($filter('date')(date, 'MM')); 415 | $scope.selectedDay = Number($filter('date')(date, 'dd')); 416 | $scope.selectedYear = Number($filter('date')(date, 'yyyy')); 417 | } else { 418 | 419 | classHelper.add(theCalendar, '_720kb-datepicker-open'); 420 | } 421 | $scope.today = new Date(); 422 | $timeout(function timeoutForYears() { 423 | if ($scope.selectedDay) { 424 | $scope.year = $scope.selectedYear; 425 | $scope.monthNumber = $scope.selectedMonth; 426 | } else { 427 | $scope.year = $scope.today.getFullYear(); 428 | $scope.monthNumber = $scope.today.getMonth() + 1; 429 | } 430 | $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); 431 | setDaysInMonth($scope.monthNumber, $scope.year); 432 | }, 0); 433 | } 434 | , checkToggle = function checkToggle() { 435 | if (!$scope.datepickerToggle) { 436 | 437 | return true; 438 | } 439 | 440 | return $scope.$eval($scope.datepickerToggle); 441 | } 442 | , checkVisibility = function checkVisibility() { 443 | if (!$scope.datepickerShow) { 444 | 445 | return false; 446 | } 447 | if (dateFormat) { 448 | date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); 449 | } else { 450 | date = new Date(thisInput[0].value.toString()); 451 | } 452 | $scope.selectedMonth = Number($filter('date')(date, 'MM')); 453 | $scope.selectedDay = Number($filter('date')(date, 'dd')); 454 | $scope.selectedYear = Number($filter('date')(date, 'yyyy')); 455 | return $scope.$eval($scope.datepickerShow); 456 | } 457 | , unregisterDataSetWatcher = $scope.$watch('dateSet', function dateSetWatcher(newValue) { 458 | 459 | if (newValue && !isNaN(Date.parse(newValue))) { 460 | 461 | date = new Date(newValue); 462 | 463 | $scope.month = $filter('date')(date, 'MMMM');//december-November like 464 | $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like 465 | $scope.day = Number($filter('date')(date, 'dd')); //01-31 like 466 | $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like 467 | 468 | setDaysInMonth($scope.monthNumber, $scope.year); 469 | 470 | if ($scope.dateSetHidden !== 'true') { 471 | 472 | setInputValue(); 473 | } 474 | } 475 | }) 476 | , unregisterDateMinLimitWatcher = $scope.$watch('dateMinLimit', function dateMinLimitWatcher(newValue) { 477 | if (newValue) { 478 | resetToMinDate(); 479 | } 480 | }) 481 | , unregisterDateMaxLimitWatcher = $scope.$watch('dateMaxLimit', function dateMaxLimitWatcher(newValue) { 482 | if (newValue) { 483 | resetToMaxDate(); 484 | } 485 | }) 486 | , unregisterDateFormatWatcher = $scope.$watch('dateFormat', function dateFormatWatcher(newValue) { 487 | if (newValue) { 488 | setInputValue(); 489 | } 490 | }) 491 | , unregisterDateDisabledDatesWatcher = $scope.$watch('dateDisabledDates', function dateDisabledDatesWatcher(newValue) { 492 | if (newValue) { 493 | dateDisabledDates = $scope.$eval(newValue); 494 | 495 | if (!$scope.isSelectableDate($scope.monthNumber, $scope.year, $scope.day)) { 496 | thisInput.val(''); 497 | thisInput.triggerHandler('input'); 498 | thisInput.triggerHandler('change');//just to be sure; 499 | } 500 | } 501 | }) 502 | , unregisterDateEnabledDatesWatcher = $scope.$watch('dateEnabledDates', function dateEnabledDatesWatcher(newValue) { 503 | if (newValue) { 504 | dateEnabledDates = $scope.$eval(newValue); 505 | 506 | if (!$scope.isSelectableDate($scope.monthNumber, $scope.year, $scope.day)) { 507 | thisInput.val(''); 508 | thisInput.triggerHandler('input'); 509 | thisInput.triggerHandler('change');//just to be sure; 510 | } 511 | } 512 | }); 513 | 514 | $scope.nextMonth = function nextMonth() { 515 | 516 | if ($scope.monthNumber === 12) { 517 | 518 | $scope.monthNumber = 1; 519 | //its happy new year 520 | nextYear(); 521 | } else { 522 | 523 | $scope.monthNumber += 1; 524 | } 525 | 526 | //check if max date is ok 527 | if ($scope.dateMaxLimit) { 528 | 529 | if (!$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.days[0])) { 530 | 531 | resetToMaxDate(); 532 | } 533 | } 534 | 535 | //set next month 536 | $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); 537 | //reinit days 538 | setDaysInMonth($scope.monthNumber, $scope.year); 539 | //deactivate selected day 540 | $scope.day = undefined; 541 | }; 542 | 543 | $scope.willPrevMonthBeSelectable = function willPrevMonthBeSelectable() { 544 | var monthNumber = $scope.monthNumber 545 | , year = $scope.year 546 | , prevDay = $filter('date')(new Date(new Date(year + '/' + monthNumber + '/01').getTime() - hours24h), 'dd'); //get last day in previous month 547 | 548 | if (monthNumber === 1) { 549 | 550 | monthNumber = 12; 551 | year = year - 1; 552 | } else { 553 | 554 | monthNumber -= 1; 555 | } 556 | 557 | if ($scope.dateMinLimit) { 558 | if (!$scope.isSelectableMinDate(year + '/' + monthNumber + '/' + prevDay)) { 559 | 560 | return false; 561 | } 562 | } 563 | 564 | return true; 565 | }; 566 | 567 | $scope.willNextMonthBeSelectable = function willNextMonthBeSelectable() { 568 | var monthNumber = $scope.monthNumber 569 | , year = $scope.year; 570 | 571 | if (monthNumber === 12) { 572 | 573 | monthNumber = 1; 574 | year += 1; 575 | } else { 576 | 577 | monthNumber += 1; 578 | } 579 | 580 | if ($scope.dateMaxLimit) { 581 | if (!$scope.isSelectableMaxDate(year + '/' + monthNumber + '/01')) { 582 | 583 | return false; 584 | } 585 | } 586 | 587 | return true; 588 | }; 589 | 590 | $scope.prevMonth = function managePrevMonth() { 591 | 592 | if ($scope.monthNumber === 1) { 593 | 594 | $scope.monthNumber = 12; 595 | //its happy new year 596 | prevYear(); 597 | } else { 598 | 599 | $scope.monthNumber -= 1; 600 | } 601 | //check if min date is ok 602 | if ($scope.dateMinLimit) { 603 | 604 | if (!$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.days[$scope.days.length - 1])) { 605 | 606 | resetToMinDate(); 607 | } 608 | } 609 | //set next month 610 | $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); 611 | //reinit days 612 | setDaysInMonth($scope.monthNumber, $scope.year); 613 | //deactivate selected day 614 | $scope.day = undefined; 615 | }; 616 | 617 | $scope.selectedMonthHandle = function manageSelectedMonthHandle(selectedMonthNumber) { 618 | 619 | $scope.monthNumber = Number($filter('date')(new Date(selectedMonthNumber + '/01/2000'), 'MM')); 620 | setDaysInMonth($scope.monthNumber, $scope.year); 621 | setInputValue(); 622 | }; 623 | 624 | $scope.setNewYear = function setNewYear(year) { 625 | 626 | //deactivate selected day 627 | if (!isMobile) { 628 | $scope.day = undefined; 629 | } 630 | 631 | if ($scope.dateMaxLimit && 632 | $scope.year < Number(year)) { 633 | 634 | if (!$scope.isSelectableMaxYear(year)) { 635 | 636 | return; 637 | } 638 | } else if ($scope.dateMinLimit && 639 | $scope.year > Number(year)) { 640 | 641 | if (!$scope.isSelectableMinYear(year)) { 642 | 643 | return; 644 | } 645 | } 646 | 647 | $scope.paginateYears(year); 648 | $scope.showYearsPagination = false; 649 | $timeout(function timeoutForYears() { 650 | $scope.year = Number(year); 651 | setDaysInMonth($scope.monthNumber, $scope.year); 652 | }, 0); 653 | }; 654 | 655 | $scope.hideCalendar = function hideCalendar() { 656 | if (theCalendar.classList) { 657 | theCalendar.classList.remove('_720kb-datepicker-open'); 658 | } else { 659 | 660 | classHelper.remove(theCalendar, '_720kb-datepicker-open'); 661 | } 662 | }; 663 | 664 | $scope.setDatepickerDay = function setDatepickerDay(day) { 665 | 666 | if ($scope.isSelectableDay($scope.monthNumber, $scope.year, day) && 667 | $scope.isSelectableDate($scope.monthNumber, $scope.year, day) && 668 | $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + day) && 669 | $scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + day)) { 670 | 671 | $scope.day = Number(day); 672 | $scope.selectedDay = $scope.day; 673 | $scope.selectedMonth = $scope.monthNumber; 674 | $scope.selectedYear = $scope.year; 675 | 676 | setInputValue(); 677 | 678 | if (attr.hasOwnProperty('dateRefocus')) { 679 | thisInput[0].focus(); 680 | } 681 | 682 | $scope.hideCalendar(); 683 | } 684 | }; 685 | 686 | $scope.paginateYears = function paginateYears(startingYear) { 687 | var i 688 | , theNewYears = [] 689 | , daysToPrepend = 10 690 | , daysToAppend = 10; 691 | 692 | $scope.paginationYears = []; 693 | if (isMobile) { 694 | 695 | daysToPrepend = 50; 696 | daysToAppend = 50; 697 | if ( $scope.dateMinLimit && $scope.dateMaxLimit) { 698 | 699 | startingYear = new Date($scope.dateMaxLimit).getFullYear(); 700 | daysToPrepend = startingYear - new Date($scope.dateMinLimit).getFullYear(); 701 | daysToAppend = 1; 702 | } 703 | } 704 | 705 | for (i = daysToPrepend; i > 0; i -= 1) { 706 | 707 | theNewYears.push(Number(startingYear) - i); 708 | } 709 | 710 | for (i = 0; i < daysToAppend; i += 1) { 711 | 712 | theNewYears.push(Number(startingYear) + i); 713 | } 714 | //date typing in input date-typer 715 | if ($scope.dateTyper === 'true') { 716 | 717 | thisInput.on('keyup blur', function onTyping() { 718 | 719 | if (thisInput[0].value && 720 | thisInput[0].value.length && 721 | thisInput[0].value.length > 0) { 722 | 723 | try { 724 | if (dateFormat) { 725 | date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); 726 | } else { 727 | date = new Date(thisInput[0].value.toString()); 728 | } 729 | 730 | if (date.getFullYear() && 731 | !isNaN(date.getDay()) && 732 | !isNaN(date.getMonth()) && 733 | $scope.isSelectableDay(date.getMonth(), date.getFullYear(), date.getDay()) && 734 | $scope.isSelectableDate(date.getMonth(), date.getFullYear(), date.getDay()) && 735 | $scope.isSelectableMaxDate(date) && 736 | $scope.isSelectableMinDate(date)) { 737 | 738 | $scope.$apply(function applyTyping() { 739 | 740 | $scope.month = $filter('date')(date, 'MMMM');//december-November like 741 | $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like 742 | $scope.day = Number($filter('date')(date, 'dd')); //01-31 like 743 | 744 | if (date.getFullYear().toString().length === 4) { 745 | $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like 746 | } 747 | setDaysInMonth($scope.monthNumber, $scope.year); 748 | }); 749 | } 750 | } catch (e) { 751 | 752 | return e; 753 | } 754 | } 755 | }); 756 | } 757 | //check range dates 758 | if ($scope.dateMaxLimit && 759 | theNewYears && 760 | theNewYears.length && 761 | !$scope.isSelectableMaxYear(Number(theNewYears[theNewYears.length - 1]) + 1)) { 762 | 763 | $scope.paginationYearsNextDisabled = true; 764 | } else { 765 | 766 | $scope.paginationYearsNextDisabled = false; 767 | } 768 | 769 | if ($scope.dateMinLimit && 770 | theNewYears && 771 | theNewYears.length && 772 | !$scope.isSelectableMinYear(Number(theNewYears[0]) - 1)) { 773 | 774 | $scope.paginationYearsPrevDisabled = true; 775 | } else { 776 | 777 | $scope.paginationYearsPrevDisabled = false; 778 | } 779 | 780 | $scope.paginationYears = theNewYears; 781 | }; 782 | 783 | $scope.isSelectableDay = function isSelectableDay(monthNumber, year, day) { 784 | var i = 0; 785 | 786 | if (dateDisabledWeekdays && dateDisabledWeekdays.length > 0) { 787 | for (i; i <= dateDisabledWeekdays.length; i += 1) { 788 | if (dateDisabledWeekdays[i] === new Date(monthNumber + '/' + day + '/' + year).getDay()) { 789 | return false; 790 | } 791 | } 792 | } 793 | 794 | return true; 795 | }; 796 | 797 | $scope.isSelectableDate = function isSelectableDate(monthNumber, year, day) { 798 | var i = 0; 799 | 800 | if (dateDisabledDates && 801 | dateDisabledDates.length > 0) { 802 | 803 | for (i; i <= dateDisabledDates.length; i += 1) { 804 | 805 | if (new Date(dateDisabledDates[i]).getTime() === new Date(monthNumber + '/' + day + '/' + year).getTime()) { 806 | 807 | return false; 808 | } 809 | } 810 | } 811 | 812 | if (dateEnabledDates) { 813 | 814 | for (i; i <= dateEnabledDates.length; i += 1) { 815 | 816 | if (new Date(dateEnabledDates[i]).getTime() === new Date(monthNumber + '/' + day + '/' + year).getTime()) { 817 | 818 | return true; 819 | } 820 | } 821 | 822 | return false; 823 | } 824 | 825 | return true; 826 | }; 827 | 828 | $scope.isSelectableMinDate = function isSelectableMinDate(aDate) { 829 | //if current date 830 | if (!!$scope.dateMinLimit && 831 | !!new Date($scope.dateMinLimit) && 832 | new Date(aDate).getTime() < new Date($scope.dateMinLimit).getTime()) { 833 | 834 | return false; 835 | } 836 | 837 | return true; 838 | }; 839 | 840 | $scope.isSelectableMaxDate = function isSelectableMaxDate(aDate) { 841 | //if current date 842 | if (!!$scope.dateMaxLimit && 843 | !!new Date($scope.dateMaxLimit) && 844 | new Date(aDate).getTime() > new Date($scope.dateMaxLimit).getTime()) { 845 | 846 | return false; 847 | } 848 | 849 | return true; 850 | }; 851 | 852 | $scope.isSelectableMaxYear = function isSelectableMaxYear(year) { 853 | if (!!$scope.dateMaxLimit && 854 | year > new Date($scope.dateMaxLimit).getFullYear()) { 855 | 856 | return false; 857 | } 858 | 859 | return true; 860 | }; 861 | 862 | $scope.isSelectableMinYear = function isSelectableMinYear(year) { 863 | if (!!$scope.dateMinLimit && 864 | year < new Date($scope.dateMinLimit).getFullYear()) { 865 | 866 | return false; 867 | } 868 | 869 | return true; 870 | }; 871 | 872 | $scope.validateWeekDay = function isValidWeekDay(weekDay) { 873 | var validWeekDay = Number(weekDay, 10); 874 | // making sure that the given option is valid 875 | if (!validWeekDay || validWeekDay < 0 || validWeekDay > 6) { 876 | 877 | validWeekDay = 0; 878 | } 879 | return validWeekDay; 880 | }; 881 | 882 | // respect previously configured interpolation symbols. 883 | htmlTemplate = htmlTemplate.replace(/{{/g, $interpolate.startSymbol()).replace(/}}/g, $interpolate.endSymbol()); 884 | $scope.dateMonthTitle = $scope.dateMonthTitle || 'Select month'; 885 | $scope.dateYearTitle = $scope.dateYearTitle || 'Select year'; 886 | $scope.buttonNextTitle = $scope.buttonNextTitle || 'Next'; 887 | $scope.buttonPrevTitle = $scope.buttonPrevTitle || 'Prev'; 888 | $scope.month = $filter('date')(date, 'MMMM');//december-November like 889 | $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like 890 | $scope.day = Number($filter('date')(date, 'dd')); //01-31 like 891 | $scope.dateWeekStartDay = $scope.validateWeekDay($scope.dateWeekStartDay); 892 | 893 | if ($scope.dateMaxLimit) { 894 | 895 | $scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy'));//2014 like 896 | } else { 897 | 898 | $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like 899 | } 900 | $scope.months = datetime.MONTH; 901 | 902 | $scope.daysInString = []; 903 | for (n = $scope.dateWeekStartDay; n <= $scope.dateWeekStartDay + 6; n += 1) { 904 | 905 | $scope.daysInString.push(n % 7); 906 | } 907 | $scope.daysInString = $scope.daysInString.map(function mappingFunc(el) { 908 | 909 | return $filter('date')(new Date(new Date('06/08/2014').valueOf() + A_DAY_IN_MILLISECONDS * el), 'EEE'); 910 | }); 911 | 912 | //create the calendar holder and append where needed 913 | if ($scope.datepickerAppendTo && 914 | $scope.datepickerAppendTo.indexOf('.') !== -1) { 915 | 916 | $scope.datepickerID = 'datepicker-id-' + new Date().getTime() + (Math.floor(Math.random() * 6) + 8); 917 | angular.element(document.getElementsByClassName($scope.datepickerAppendTo.replace('.', ''))[0]).append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { 918 | 919 | theCalendar = angular.element(el)[0]; 920 | })); 921 | } else if ($scope.datepickerAppendTo && 922 | $scope.datepickerAppendTo.indexOf('#') !== -1) { 923 | 924 | $scope.datepickerID = 'datepicker-id-' + new Date().getTime() + (Math.floor(Math.random() * 6) + 8); 925 | angular.element(document.getElementById($scope.datepickerAppendTo.replace('#', ''))).append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { 926 | 927 | theCalendar = angular.element(el)[0]; 928 | })); 929 | } else if ($scope.datepickerAppendTo && 930 | $scope.datepickerAppendTo === 'body') { 931 | $scope.datepickerID = 'datepicker-id-' + (new Date().getTime() + (Math.floor(Math.random() * 6) + 8)); 932 | angular.element(document).find('body').append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { 933 | 934 | theCalendar = angular.element(el)[0]; 935 | })); 936 | } else { 937 | 938 | thisInput.after($compile(angular.element(htmlTemplate))($scope)); 939 | //get the calendar as element 940 | theCalendar = element[0].querySelector('._720kb-datepicker-calendar'); 941 | } 942 | //if datepicker-toggle="" is not present or true by default 943 | if (checkToggle()) { 944 | 945 | thisInput.on('focus click focusin', function onFocusAndClick() { 946 | 947 | isMouseOnInput = true; 948 | 949 | if (!isMouseOn && 950 | !isMouseOnInput && theCalendar) { 951 | 952 | $scope.hideCalendar(); 953 | } else { 954 | 955 | showCalendar(); 956 | } 957 | }); 958 | } 959 | 960 | thisInput.on('focusout blur', function onBlurAndFocusOut() { 961 | 962 | isMouseOnInput = false; 963 | }); 964 | //some tricky dirty events to fire if click is outside of the calendar and show/hide calendar when needed 965 | angular.element(theCalendar).on('mouseenter', function onMouseEnter() { 966 | 967 | isMouseOn = true; 968 | }); 969 | 970 | angular.element(theCalendar).on('mouseleave', function onMouseLeave() { 971 | 972 | isMouseOn = false; 973 | }); 974 | 975 | angular.element(theCalendar).on('focusin', function onCalendarFocus() { 976 | 977 | isMouseOn = true; 978 | }); 979 | 980 | angular.element($window).on('click focus focusin', onClickOnWindow); 981 | 982 | //check always if given range of dates is ok 983 | if ($scope.dateMinLimit && 984 | !$scope.isSelectableMinYear($scope.year) || 985 | !$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { 986 | 987 | resetToMinDate(); 988 | } 989 | 990 | if ($scope.dateMaxLimit && 991 | !$scope.isSelectableMaxYear($scope.year) || 992 | !$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { 993 | 994 | resetToMaxDate(); 995 | } 996 | 997 | //datepicker boot start 998 | $scope.paginateYears($scope.year); 999 | 1000 | setDaysInMonth($scope.monthNumber, $scope.year); 1001 | $scope.checkVisibility = checkVisibility; 1002 | 1003 | $scope.$on('$destroy', function unregisterListener() { 1004 | 1005 | unregisterDataSetWatcher(); 1006 | unregisterDateMinLimitWatcher(); 1007 | unregisterDateMaxLimitWatcher(); 1008 | unregisterDateFormatWatcher(); 1009 | unregisterDateDisabledDatesWatcher(); 1010 | unregisterDateEnabledDatesWatcher(); 1011 | thisInput.off('focus click focusout blur'); 1012 | angular.element(theCalendar).off('mouseenter mouseleave focusin'); 1013 | angular.element($window).off('click focus focusin', onClickOnWindow); 1014 | }); 1015 | }; 1016 | 1017 | return { 1018 | 'restrict': 'AEC', 1019 | 'scope': { 1020 | 'dateSet': '@', 1021 | 'dateMinLimit': '@', 1022 | 'dateMaxLimit': '@', 1023 | 'dateMonthTitle': '@', 1024 | 'dateYearTitle': '@', 1025 | 'buttonNextTitle': '@', 1026 | 'buttonPrevTitle': '@', 1027 | 'dateDisabledDates': '@', 1028 | 'dateEnabledDates': '@', 1029 | 'dateDisabledWeekdays': '@', 1030 | 'dateSetHidden': '@', 1031 | 'dateTyper': '@', 1032 | 'dateWeekStartDay': '@', 1033 | 'datepickerAppendTo': '@', 1034 | 'datepickerToggle': '@', 1035 | 'datepickerClass': '@', 1036 | 'datepickerShow': '@' 1037 | }, 1038 | 'link': linkingFunction 1039 | }; 1040 | }; 1041 | 1042 | angular.module('720kb.datepicker', []) 1043 | .directive('datepicker', ['$window', '$compile', '$locale', '$filter', '$interpolate', '$timeout', datepickerDirective]); 1044 | }(angular, navigator)); 1045 | -------------------------------------------------------------------------------- /dist/angular-datepicker.min.css: -------------------------------------------------------------------------------- 1 | .datepicker a,[datepicker] a,datepicker a{color:inherit;text-decoration:none}.datepicker a:hover,[datepicker] a:hover,datepicker a:hover{text-decoration:none}.datepicker select,.datepicker select:focus,.datepicker select:hover,[datepicker] select,[datepicker] select:focus,[datepicker] select:hover,datepicker select,datepicker select:focus,datepicker select:hover{width:100%;overflow:hidden;background:0 0;color:#fff;background-color:#138efa;border-radius:2px;border:0;margin-top:5px}._720kb-datepicker-calendar-body,._720kb-datepicker-calendar-days-header,._720kb-datepicker-calendar-header,._720kb-datepicker-calendar-years-pagination-pages,.datepicker,[datepicker],datepicker{font-family:Helvetica Neue,Arial,sans-serif;font-size:13.5px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;width:100%;margin:0 auto;float:left;clear:right;position:relative}._720kb-datepicker-calendar{background:#fff;color:#333;position:absolute;z-index:999;min-width:220px;margin:0 auto;width:101%;-webkit-box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;-moz-box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;box-shadow:0 0 0 1px rgba(0,0,0,.1) inset;visibility:hidden;overflow:hidden;margin-left:-.5%;padding:0 0 2% 0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}._720kb-datepicker-calendar._720kb-datepicker-forced-to-open,._720kb-datepicker-calendar._720kb-datepicker-open{visibility:visible}._720kb-datepicker-calendar-header{text-align:center;font-size:15px;line-height:40px}._720kb-datepicker-calendar-header:nth-child(odd){background:#138efa}._720kb-datepicker-calendar-header:nth-child(even){background:#7bc6fc}._720kb-datepicker-calendar-header-left,._720kb-datepicker-calendar-header-middle,._720kb-datepicker-calendar-header-right{width:15%;float:left}._720kb-datepicker-calendar-header-middle{width:70%}._720kb-datepicker-calendar-header-closed-pagination::after{content:" \25BE"}._720kb-datepicker-calendar-header-opened-pagination::after{content:" \25BE";margin-left:4px;position:relative;bottom:-3px;display:inline-block;-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-o-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}._720kb-datepicker-calendar-body{width:96%;margin:2%;text-align:center}._720kb-datepicker-calendar-day{cursor:pointer;font-size:12.5px;width:12.2%;margin:5px 1%;padding:1.5% 0;float:left;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}._720kb-datepicker-calendar-day._720kb-datepicker-active,._720kb-datepicker-calendar-day:hover{background:rgba(0,0,0,.03)}._720kb-datepicker-calendar-header a,._720kb-datepicker-calendar-header a:hover{text-decoration:none;padding:3% 9% 4% 9%;font-size:13.5px;color:rgba(0,0,0,.55);font-weight:700;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}._720kb-datepicker-calendar-header a:hover{color:rgba(0,0,0,.9);background:rgba(255,255,255,.45)}._720kb-datepicker-calendar-month{color:#fff}._720kb-datepicker-calendar-month span{font-size:13px;color:rgba(0,0,0,.4)}._720kb-datepicker-calendar-month a span i{font-style:normal;font-size:15px}._720kb-datepicker-calendar-month a,._720kb-datepicker-calendar-month a:hover{padding:3px;margin-left:1%}._720kb-datepicker-calendar-years-pagination{padding:2% 0 0 0;float:left;clear:right;width:100%}._720kb-datepicker-calendar-years-pagination a,._720kb-datepicker-calendar-years-pagination a:hover{font-size:12px;padding:0 7px;font-weight:400;margin:3px 1% 0 1%;line-height:20px;display:inline-block}._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active{color:rgba(0,0,0,.9);font-weight:500;background:rgba(255,255,255,.45)}._720kb-datepicker-calendar-years-pagination-pages a,._720kb-datepicker-calendar-years-pagination-pages a:hover{padding:5px 10px}._720kb-datepicker-calendar-days-header{max-width:100%;margin:0 auto;padding:0 2% 0 2%;background:rgba(19,142,250,.08);border-bottom:1px solid rgba(0,0,0,.02)}._720kb-datepicker-calendar-days-header div{width:14.18%;font-weight:500;font-size:11.5px;padding:10px 0;float:left;text-align:center;color:rgba(0,0,0,.7)}._720kb-datepicker-calendar-days ._720kb-datepicker-default-button{font-size:18.5px;position:relative;bottom:-.5px}._720kb-datepicker-default-button{padding:0 4.5px}._720kb-datepicker-calendar-header-middle._720kb-datepicker-mobile-item{width:95%;float:none;margin:0 auto}._720kb-datepicker-item-hidden{visibility:hidden}._720kb-datepicker-calendar-day._720kb-datepicker-disabled,._720kb-datepicker-calendar-day._720kb-datepicker-disabled:hover,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled:hover,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled,._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled:hover{color:rgba(0,0,0,.2);background:rgba(25,2,0,.02);cursor:default} -------------------------------------------------------------------------------- /dist/angular-datepicker.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Angular Datepicker v2.1.23 3 | * 4 | * Released by 720kb.net under the MIT license 5 | * www.opensource.org/licenses/MIT 6 | * 7 | * 2017-06-28 8 | */ 9 | 10 | 11 | !function(e,a){"use strict";var t=function(){if(a.userAgent&&(a.userAgent.match(/Android/i)||a.userAgent.match(/webOS/i)||a.userAgent.match(/iPhone/i)||a.userAgent.match(/iPad/i)||a.userAgent.match(/iPod/i)||a.userAgent.match(/BlackBerry/i)||a.userAgent.match(/Windows Phone/i)))return!0}(),n=function(e,a,n){return n&&(t=!1),t?['
','
','","
","
",'
','
','","
","
"]:['
','
','',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=['
','',"{{px}}","","","{{item}}","",'',"{{nx}}","","
"],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); 12 | //# sourceMappingURL=angular-datepicker.sourcemap.map -------------------------------------------------------------------------------- /dist/angular-datepicker.sourcemap.map: -------------------------------------------------------------------------------- 1 | {"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"} -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 16 | Angularjs Datepicker 17 | 18 | 19 |
20 |
21 |
22 |
23 | 24 |
25 | Date 1 is: {{date1}} 26 |
27 |
28 |
39 | 40 |
41 | Date 2 is: {{date2}} 42 | 43 |
44 |
45 | 46 | 47 | 48 | Date 3 is: {{date3}} 49 |
50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | (function setUp(module, require) { 3 | 'use strict'; 4 | 5 | require('./dist/angular-datepicker'); 6 | 7 | module.exports = '720kb.datepicker'; 8 | }(module, require)); 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-datepicker", 3 | "version": "2.1.23", 4 | "description": "A datepicker directive for angularjs.", 5 | "homepage": "http://720kb.github.io/angular-datepicker", 6 | "keywords": [ 7 | "date", 8 | "datepicker", 9 | "input", 10 | "angularjs", 11 | "angular", 12 | "input" 13 | ], 14 | "scripts": { 15 | "precommit": "grunt lint", 16 | "lint": "grunt lint", 17 | "dist": "grunt prod" 18 | }, 19 | "main": "dist/angular-datepicker.min.js", 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/720kb/angular-datepicker.git" 23 | }, 24 | "license": "MIT", 25 | "devDependencies": { 26 | "connect-modrewrite": "*", 27 | "grunt": "*", 28 | "grunt-concurrent": "*", 29 | "grunt-contrib-connect": "*", 30 | "grunt-contrib-copy": "*", 31 | "grunt-contrib-csslint": "*", 32 | "grunt-contrib-cssmin": "*", 33 | "grunt-contrib-uglify": "*", 34 | "grunt-contrib-watch": "*", 35 | "grunt-eslint": "*", 36 | "grunt-jscs": "*", 37 | "husky": "*" 38 | }, 39 | "author": { 40 | "name": "Filippo Oretti", 41 | "email": "filippo.oretti@gmail.com", 42 | "url": "https://github.com/45kb" 43 | }, 44 | "contributors": [ 45 | { 46 | "name": "Dario Andrei", 47 | "email": "wouldgo84@gmail.com", 48 | "url": "https://github.com/wouldgo" 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /src/css/angular-datepicker.css: -------------------------------------------------------------------------------- 1 | datepicker a, [datepicker] a, .datepicker a{ 2 | color:inherit; 3 | text-decoration:none; 4 | } 5 | datepicker a:hover, [datepicker] a:hover, .datepicker a:hover{ 6 | text-decoration:none; 7 | } 8 | datepicker select, datepicker select:focus, datepicker select:hover, 9 | .datepicker select, .datepicker select:focus, .datepicker select:hover, 10 | [datepicker] select, [datepicker] select:focus, [datepicker] select:hover{ 11 | width:100%; 12 | overflow: hidden; 13 | background:none; 14 | color:#fff; 15 | background-color: #138EFA; 16 | border-radius:2px; 17 | border: 0; 18 | margin-top:5px; 19 | } 20 | datepicker, .datepicker, [datepicker], 21 | ._720kb-datepicker-calendar-header, 22 | ._720kb-datepicker-calendar-body, 23 | ._720kb-datepicker-calendar-days-header, 24 | ._720kb-datepicker-calendar-years-pagination-pages { 25 | font-family: Helvetica Neue, Arial, sans-serif; 26 | font-size: 13.5px; 27 | -webkit-box-sizing: border-box; 28 | -moz-box-sizing: border-box; 29 | -ms-box-sizing: border-box; 30 | box-sizing: border-box; 31 | width: 100%; 32 | margin: 0 auto; 33 | float: left; 34 | clear: right; 35 | position: relative; 36 | } 37 | ._720kb-datepicker-calendar { 38 | background: white; 39 | color: #333; 40 | position: absolute; 41 | z-index: 999; 42 | min-width: 220px; 43 | margin: 0 auto; 44 | width: 101%; 45 | -webkit-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset; 46 | -moz-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset; 47 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset; 48 | visibility: hidden; 49 | overflow:hidden; 50 | margin-left:-0.5%; 51 | padding: 0 0 2% 0; 52 | -webkit-border-radius: 3px; 53 | -moz-border-radius: 3px; 54 | border-radius: 3px; 55 | } 56 | ._720kb-datepicker-calendar._720kb-datepicker-open,._720kb-datepicker-calendar._720kb-datepicker-forced-to-open { 57 | visibility: visible; 58 | } 59 | ._720kb-datepicker-calendar-header { 60 | text-align: center; 61 | font-size: 15px; 62 | line-height: 40px; 63 | } 64 | ._720kb-datepicker-calendar-header:nth-child(odd) { 65 | background: #138EFA; 66 | } 67 | ._720kb-datepicker-calendar-header:nth-child(even) { 68 | background: #7BC6FC; 69 | } 70 | ._720kb-datepicker-calendar-header-left, 71 | ._720kb-datepicker-calendar-header-middle, 72 | ._720kb-datepicker-calendar-header-right { 73 | width: 15%; 74 | float: left; 75 | } 76 | ._720kb-datepicker-calendar-header-middle { 77 | width: 70%; 78 | } 79 | 80 | ._720kb-datepicker-calendar-header-closed-pagination::after { 81 | content: " \25BE"; 82 | } 83 | 84 | ._720kb-datepicker-calendar-header-opened-pagination::after { 85 | content: " \25BE"; 86 | margin-left: 4px; 87 | position: relative; 88 | bottom: -3px; 89 | display:inline-block; 90 | -webkit-transform: rotate(180deg); 91 | -moz-transform: rotate(180deg); 92 | -o-transform: rotate(180deg); 93 | -ms-transform: rotate(180deg); 94 | transform: rotate(180deg); 95 | } 96 | ._720kb-datepicker-calendar-body { 97 | width: 96%; 98 | margin: 2%; 99 | text-align: center; 100 | } 101 | ._720kb-datepicker-calendar-day { 102 | cursor: pointer; 103 | font-size: 12.5px; 104 | width: 12.2%; 105 | margin:5px 1%; 106 | padding: 1.5% 0; 107 | float: left; 108 | -webkit-border-radius: 1px; 109 | -moz-border-radius: 1px; 110 | border-radius: 1px; 111 | } 112 | ._720kb-datepicker-calendar-day:hover, 113 | ._720kb-datepicker-calendar-day._720kb-datepicker-active { 114 | background: rgba(0, 0, 0, 0.03); 115 | } 116 | ._720kb-datepicker-calendar-header a, ._720kb-datepicker-calendar-header a:hover { 117 | text-decoration:none; 118 | padding:3% 9% 4% 9%; 119 | font-size: 13.5px; 120 | color:rgba(0, 0, 0, 0.55); 121 | font-weight: bold; 122 | -webkit-border-radius: 3px; 123 | -moz-border-radius: 3px; 124 | border-radius: 3px; 125 | } 126 | ._720kb-datepicker-calendar-header a:hover { 127 | color:rgba(0, 0, 0, 0.9); 128 | background: rgba(255, 255, 255, 0.45); 129 | } 130 | ._720kb-datepicker-calendar-month { 131 | color:#fff; 132 | } 133 | ._720kb-datepicker-calendar-month span { 134 | font-size: 13px; 135 | color:rgba(0, 0, 0, 0.4); 136 | } 137 | ._720kb-datepicker-calendar-month a span i { 138 | font-style: normal; 139 | font-size:15px; 140 | } 141 | ._720kb-datepicker-calendar-month a, ._720kb-datepicker-calendar-month a:hover { 142 | padding: 3px; 143 | margin-left:1%; 144 | } 145 | ._720kb-datepicker-calendar-years-pagination{ 146 | padding:2% 0 0 0; 147 | float:left; 148 | clear: right; 149 | width: 100%; 150 | } 151 | ._720kb-datepicker-calendar-years-pagination a, ._720kb-datepicker-calendar-years-pagination a:hover { 152 | font-size:12px; 153 | padding:0 7px; 154 | font-weight: normal; 155 | margin:3px 1% 0 1%; 156 | line-height: 20px; 157 | display: inline-block; 158 | } 159 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active { 160 | color:rgba(0, 0, 0, 0.9); 161 | font-weight: 500; 162 | background: rgba(255, 255, 255, 0.45); 163 | } 164 | ._720kb-datepicker-calendar-years-pagination-pages a,._720kb-datepicker-calendar-years-pagination-pages a:hover{ 165 | padding:5px 10px; 166 | } 167 | ._720kb-datepicker-calendar-days-header{ 168 | max-width: 100%; 169 | margin:0 auto; 170 | padding:0 2% 0 2%; 171 | background: rgba(19, 142, 250, 0.08); 172 | border-bottom:1px solid rgba(0,0,0,0.02); 173 | } 174 | ._720kb-datepicker-calendar-days-header div{ 175 | width: 14.18%; 176 | font-weight: 500; 177 | font-size: 11.5px; 178 | padding:10px 0; 179 | float:left; 180 | text-align: center; 181 | color:rgba(0,0,0,0.7); 182 | } 183 | ._720kb-datepicker-calendar-days 184 | ._720kb-datepicker-default-button{ 185 | font-size: 18.5px; 186 | position: relative; 187 | bottom:-0.5px; 188 | } 189 | ._720kb-datepicker-default-button{ 190 | padding:0 4.5px; 191 | } 192 | ._720kb-datepicker-calendar-header-middle._720kb-datepicker-mobile-item{ 193 | width:95%; 194 | float:none; 195 | margin:0 auto; 196 | } 197 | ._720kb-datepicker-item-hidden{ 198 | visibility:hidden; 199 | } 200 | ._720kb-datepicker-calendar-day._720kb-datepicker-disabled, 201 | ._720kb-datepicker-calendar-day._720kb-datepicker-disabled:hover, 202 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled, 203 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-disabled:hover, 204 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled, 205 | ._720kb-datepicker-calendar-years-pagination a._720kb-datepicker-active._720kb-datepicker-disabled:hover{ 206 | color:rgba(0,0,0,0.2); 207 | background: rgba(25,2,0,0.02); 208 | cursor: default; 209 | } 210 | -------------------------------------------------------------------------------- /src/js/angular-datepicker.js: -------------------------------------------------------------------------------- 1 | /*global angular document navigator*/ 2 | (function withAngular(angular, navigator) { 3 | 4 | 'use strict'; 5 | 6 | var A_DAY_IN_MILLISECONDS = 86400000 7 | , isMobile = (function isMobile() { 8 | 9 | if (navigator.userAgent && 10 | (navigator.userAgent.match(/Android/i) || 11 | navigator.userAgent.match(/webOS/i) || 12 | navigator.userAgent.match(/iPhone/i) || 13 | navigator.userAgent.match(/iPad/i) || 14 | navigator.userAgent.match(/iPod/i) || 15 | navigator.userAgent.match(/BlackBerry/i) || 16 | navigator.userAgent.match(/Windows Phone/i))) { 17 | 18 | return true; 19 | } 20 | }()) 21 | , generateMonthAndYearHeader = function generateMonthAndYearHeader(prevButton, nextButton, preventMobile) { 22 | 23 | if (preventMobile) { 24 | 25 | isMobile = false; 26 | } 27 | 28 | if (isMobile) { 29 | 30 | return [ 31 | '
', 32 | '
', 33 | '', 38 | '
', 39 | '
', 40 | '
', 41 | '
', 42 | '', 47 | '
', 48 | '
' 49 | ]; 50 | } 51 | 52 | return [ 53 | '
', 54 | '
', 55 | '', 56 | prevButton, 57 | '', 58 | '
', 59 | '
', 60 | '{{month}} ', 61 | '', 62 | '', 63 | '{{year}}', 64 | '', 65 | '', 66 | '', 67 | '
', 68 | '
', 69 | '', 70 | nextButton, 71 | '', 72 | '
', 73 | '
' 74 | ]; 75 | } 76 | , generateYearsPaginationHeader = function generateYearsPaginationHeader(prevButton, nextButton) { 77 | 78 | return [ 79 | '
', 80 | '
', 81 | '', 82 | '{{y}}', 83 | '', 84 | '
', 85 | '', 93 | '
' 94 | ]; 95 | } 96 | , generateDaysColumns = function generateDaysColumns() { 97 | 98 | return [ 99 | '
', 100 | '
', 101 | '{{d}}', 102 | '
', 103 | '
' 104 | ]; 105 | } 106 | , generateDays = function generateDays() { 107 | 108 | return [ 109 | '' 120 | ]; 121 | } 122 | , generateHtmlTemplate = function generateHtmlTemplate(prevButton, nextButton, preventMobile) { 123 | 124 | var toReturn = [ 125 | '
', 126 | '
' 127 | ] 128 | , monthAndYearHeader = generateMonthAndYearHeader(prevButton, nextButton, preventMobile) 129 | , yearsPaginationHeader = generateYearsPaginationHeader(prevButton, nextButton) 130 | , daysColumns = generateDaysColumns() 131 | , days = generateDays() 132 | , iterator = function iterator(aRow) { 133 | 134 | toReturn.splice(toReturn.length - 1, 0, aRow); 135 | }; 136 | 137 | monthAndYearHeader.forEach(iterator); 138 | yearsPaginationHeader.forEach(iterator); 139 | daysColumns.forEach(iterator); 140 | days.forEach(iterator); 141 | 142 | return toReturn.join(''); 143 | } 144 | , datepickerDirective = function datepickerDirective($window, $compile, $locale, $filter, $interpolate, $timeout) { 145 | 146 | var linkingFunction = function linkingFunction($scope, element, attr) { 147 | 148 | //get child input 149 | var selector = attr.selector 150 | , thisInput = angular.element(selector ? element[0].querySelector('.' + selector) : element[0].children[0]) 151 | , theCalendar 152 | , defaultPrevButton = '' 153 | , defaultNextButton = '' 154 | , prevButton = attr.buttonPrev || defaultPrevButton 155 | , nextButton = attr.buttonNext || defaultNextButton 156 | , dateFormat = attr.dateFormat 157 | //, dateMinLimit 158 | //, dateMaxLimit 159 | , dateDisabledDates = $scope.$eval($scope.dateDisabledDates) 160 | , dateEnabledDates = $scope.$eval($scope.dateEnabledDates) 161 | , dateDisabledWeekdays = $scope.$eval($scope.dateDisabledWeekdays) 162 | , date = new Date() 163 | , isMouseOn = false 164 | , isMouseOnInput = false 165 | , preventMobile = typeof attr.datepickerMobile !== 'undefined' && attr.datepickerMobile !== 'false' 166 | , datetime = $locale.DATETIME_FORMATS 167 | , pageDatepickers 168 | , hours24h = 86400000 169 | , htmlTemplate = generateHtmlTemplate(prevButton, nextButton, preventMobile) 170 | , n 171 | , onClickOnWindow = function onClickOnWindow() { 172 | 173 | if (!isMouseOn && 174 | !isMouseOnInput && theCalendar) { 175 | 176 | $scope.hideCalendar(); 177 | } 178 | } 179 | , setDaysInMonth = function setDaysInMonth(month, year) { 180 | 181 | var i 182 | , limitDate = new Date(year, month, 0).getDate() 183 | , firstDayMonthNumber = new Date(year + '/' + month + '/' + 1).getDay() 184 | , lastDayMonthNumber = new Date(year + '/' + month + '/' + limitDate).getDay() 185 | , prevMonthDays = [] 186 | , nextMonthDays = [] 187 | , howManyNextDays 188 | , howManyPreviousDays 189 | , monthAlias 190 | , dateWeekEndDay; 191 | 192 | $scope.days = []; 193 | $scope.dateWeekStartDay = $scope.validateWeekDay($scope.dateWeekStartDay); 194 | dateWeekEndDay = ($scope.dateWeekStartDay + 6) % 7; 195 | 196 | for (i = 1; i <= limitDate; i += 1) { 197 | 198 | $scope.days.push(i); 199 | } 200 | 201 | //get previous month days if first day in month is not first day in week 202 | if (firstDayMonthNumber === $scope.dateWeekStartDay) { 203 | 204 | //no need for it 205 | $scope.prevMonthDays = []; 206 | } else { 207 | 208 | howManyPreviousDays = firstDayMonthNumber - $scope.dateWeekStartDay; 209 | 210 | if (firstDayMonthNumber < $scope.dateWeekStartDay) { 211 | 212 | howManyPreviousDays += 7; 213 | } 214 | 215 | //get previous month 216 | if (Number(month) === 1) { 217 | 218 | monthAlias = 12; 219 | } else { 220 | 221 | monthAlias = month - 1; 222 | } 223 | //return previous month days 224 | for (i = 1; i <= new Date(year, monthAlias, 0).getDate(); i += 1) { 225 | 226 | prevMonthDays.push(i); 227 | } 228 | //attach previous month days 229 | $scope.prevMonthDays = prevMonthDays.slice(-howManyPreviousDays); 230 | } 231 | 232 | //get next month days if last day in month is not last day in week 233 | if (lastDayMonthNumber === dateWeekEndDay) { 234 | //no need for it 235 | $scope.nextMonthDays = []; 236 | } else { 237 | howManyNextDays = 6 - lastDayMonthNumber + $scope.dateWeekStartDay; 238 | 239 | if (lastDayMonthNumber < $scope.dateWeekStartDay) { 240 | 241 | howManyNextDays -= 7; 242 | } 243 | //get previous month 244 | 245 | //return next month days 246 | for (i = 1; i <= howManyNextDays; i += 1) { 247 | 248 | nextMonthDays.push(i); 249 | } 250 | //attach previous month days 251 | $scope.nextMonthDays = nextMonthDays; 252 | } 253 | } 254 | , resetToMinDate = function resetToMinDate() { 255 | 256 | $scope.month = $filter('date')(new Date($scope.dateMinLimit), 'MMMM'); 257 | $scope.monthNumber = Number($filter('date')(new Date($scope.dateMinLimit), 'MM')); 258 | $scope.day = Number($filter('date')(new Date($scope.dateMinLimit), 'dd')); 259 | $scope.year = Number($filter('date')(new Date($scope.dateMinLimit), 'yyyy')); 260 | 261 | setDaysInMonth($scope.monthNumber, $scope.year); 262 | } 263 | , resetToMaxDate = function resetToMaxDate() { 264 | 265 | $scope.month = $filter('date')(new Date($scope.dateMaxLimit), 'MMMM'); 266 | $scope.monthNumber = Number($filter('date')(new Date($scope.dateMaxLimit), 'MM')); 267 | $scope.day = Number($filter('date')(new Date($scope.dateMaxLimit), 'dd')); 268 | $scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy')); 269 | 270 | setDaysInMonth($scope.monthNumber, $scope.year); 271 | } 272 | , prevYear = function prevYear() { 273 | 274 | $scope.year = Number($scope.year) - 1; 275 | } 276 | , nextYear = function nextYear() { 277 | 278 | $scope.year = Number($scope.year) + 1; 279 | } 280 | , localDateTimestamp = function localDateTimestamp(rawDate, dateFormatDefinition) { 281 | 282 | 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 283 | ,formatDate,dateSplit, m, d, y, index, el, longName, shortName; 284 | 285 | for (index = 0; index < datetime.MONTH.length; index += 1) { 286 | longName = datetime.MONTH[index]; 287 | shortName = datetime.SHORTMONTH[index]; 288 | 289 | if (rawDate.indexOf(longName) !== -1) { 290 | rawDate = rawDate.replace(longName, index + 1); 291 | break; 292 | } 293 | 294 | if (rawDate.indexOf(shortName) !== -1) { 295 | rawDate = rawDate.replace(shortName, index + 1); 296 | break; 297 | } 298 | } 299 | 300 | dateSplit = rawDate 301 | .split(/\D/) 302 | .filter(function dateSplitFilter(item) { 303 | return item.length > 0; 304 | }); 305 | 306 | formatDate = dateFormatDefinition 307 | .match(formattingTokens) 308 | .filter(function fromatDateFilter(item) { 309 | return item.match(/^[a-zA-Z]+$/i) !== null; 310 | }); 311 | 312 | for (index = 0; index < formatDate.length; index += 1) { 313 | el = formatDate[index]; 314 | 315 | switch (true) { 316 | case el.indexOf('d') !== -1: { 317 | d = dateSplit[index - (formatDate.length - dateSplit.length)]; 318 | break; 319 | } 320 | case el.indexOf('M') !== -1: { 321 | m = dateSplit[index - (formatDate.length - dateSplit.length)]; 322 | break; 323 | } 324 | case el.indexOf('y') !== -1: { 325 | y = dateSplit[index - (formatDate.length - dateSplit.length)]; 326 | break; 327 | } 328 | default: { 329 | break; 330 | } 331 | } 332 | } 333 | 334 | return new Date(y + '/' + m + '/' + d); 335 | } 336 | , setInputValue = function setInputValue() { 337 | 338 | if ($scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day) && 339 | $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { 340 | 341 | var modelDate = new Date($scope.year + '/' + $scope.monthNumber + '/' + $scope.day); 342 | 343 | if (attr.dateFormat) { 344 | 345 | thisInput.val($filter('date')(modelDate, dateFormat)); 346 | } else { 347 | 348 | thisInput.val(modelDate); 349 | } 350 | 351 | thisInput.triggerHandler('input'); 352 | thisInput.triggerHandler('change');//just to be sure; 353 | } else { 354 | 355 | return false; 356 | } 357 | } 358 | , classHelper = { 359 | 'add': function add(ele, klass) { 360 | var classes; 361 | 362 | if (ele.className.indexOf(klass) > -1) { 363 | 364 | return; 365 | } 366 | 367 | classes = ele.className.split(' '); 368 | classes.push(klass); 369 | ele.className = classes.join(' '); 370 | }, 371 | 'remove': function remove(ele, klass) { 372 | var i 373 | , classes; 374 | 375 | if (ele.className.indexOf(klass) === -1) { 376 | 377 | return; 378 | } 379 | 380 | classes = ele.className.split(' '); 381 | for (i = 0; i < classes.length; i += 1) { 382 | 383 | if (classes[i] === klass) { 384 | 385 | classes = classes.slice(0, i).concat(classes.slice(i + 1)); 386 | break; 387 | } 388 | } 389 | ele.className = classes.join(' '); 390 | } 391 | } 392 | , showCalendar = function showCalendar() { 393 | //lets hide all the latest instances of datepicker 394 | pageDatepickers = $window.document.getElementsByClassName('_720kb-datepicker-calendar'); 395 | 396 | angular.forEach(pageDatepickers, function forEachDatepickerPages(value, key) { 397 | if (pageDatepickers[key].classList) { 398 | 399 | pageDatepickers[key].classList.remove('_720kb-datepicker-open'); 400 | } else { 401 | 402 | classHelper.remove(pageDatepickers[key], '_720kb-datepicker-open'); 403 | } 404 | }); 405 | 406 | if (theCalendar.classList) { 407 | 408 | theCalendar.classList.add('_720kb-datepicker-open'); 409 | if (dateFormat) { 410 | date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); 411 | } else { 412 | date = new Date(thisInput[0].value.toString()); 413 | } 414 | $scope.selectedMonth = Number($filter('date')(date, 'MM')); 415 | $scope.selectedDay = Number($filter('date')(date, 'dd')); 416 | $scope.selectedYear = Number($filter('date')(date, 'yyyy')); 417 | } else { 418 | 419 | classHelper.add(theCalendar, '_720kb-datepicker-open'); 420 | } 421 | $scope.today = new Date(); 422 | $timeout(function timeoutForYears() { 423 | if ($scope.selectedDay) { 424 | $scope.year = $scope.selectedYear; 425 | $scope.monthNumber = $scope.selectedMonth; 426 | } else { 427 | $scope.year = $scope.today.getFullYear(); 428 | $scope.monthNumber = $scope.today.getMonth() + 1; 429 | } 430 | $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); 431 | setDaysInMonth($scope.monthNumber, $scope.year); 432 | }, 0); 433 | } 434 | , checkToggle = function checkToggle() { 435 | if (!$scope.datepickerToggle) { 436 | 437 | return true; 438 | } 439 | 440 | return $scope.$eval($scope.datepickerToggle); 441 | } 442 | , checkVisibility = function checkVisibility() { 443 | if (!$scope.datepickerShow) { 444 | 445 | return false; 446 | } 447 | if (dateFormat) { 448 | date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); 449 | } else { 450 | date = new Date(thisInput[0].value.toString()); 451 | } 452 | $scope.selectedMonth = Number($filter('date')(date, 'MM')); 453 | $scope.selectedDay = Number($filter('date')(date, 'dd')); 454 | $scope.selectedYear = Number($filter('date')(date, 'yyyy')); 455 | return $scope.$eval($scope.datepickerShow); 456 | } 457 | , unregisterDataSetWatcher = $scope.$watch('dateSet', function dateSetWatcher(newValue) { 458 | 459 | if (newValue && !isNaN(Date.parse(newValue))) { 460 | 461 | date = new Date(newValue); 462 | 463 | $scope.month = $filter('date')(date, 'MMMM');//december-November like 464 | $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like 465 | $scope.day = Number($filter('date')(date, 'dd')); //01-31 like 466 | $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like 467 | 468 | setDaysInMonth($scope.monthNumber, $scope.year); 469 | 470 | if ($scope.dateSetHidden !== 'true') { 471 | 472 | setInputValue(); 473 | } 474 | } 475 | }) 476 | , unregisterDateMinLimitWatcher = $scope.$watch('dateMinLimit', function dateMinLimitWatcher(newValue) { 477 | if (newValue) { 478 | resetToMinDate(); 479 | } 480 | }) 481 | , unregisterDateMaxLimitWatcher = $scope.$watch('dateMaxLimit', function dateMaxLimitWatcher(newValue) { 482 | if (newValue) { 483 | resetToMaxDate(); 484 | } 485 | }) 486 | , unregisterDateFormatWatcher = $scope.$watch('dateFormat', function dateFormatWatcher(newValue) { 487 | if (newValue) { 488 | setInputValue(); 489 | } 490 | }) 491 | , unregisterDateDisabledDatesWatcher = $scope.$watch('dateDisabledDates', function dateDisabledDatesWatcher(newValue) { 492 | if (newValue) { 493 | dateDisabledDates = $scope.$eval(newValue); 494 | 495 | if (!$scope.isSelectableDate($scope.monthNumber, $scope.year, $scope.day)) { 496 | thisInput.val(''); 497 | thisInput.triggerHandler('input'); 498 | thisInput.triggerHandler('change');//just to be sure; 499 | } 500 | } 501 | }) 502 | , unregisterDateEnabledDatesWatcher = $scope.$watch('dateEnabledDates', function dateEnabledDatesWatcher(newValue) { 503 | if (newValue) { 504 | dateEnabledDates = $scope.$eval(newValue); 505 | 506 | if (!$scope.isSelectableDate($scope.monthNumber, $scope.year, $scope.day)) { 507 | thisInput.val(''); 508 | thisInput.triggerHandler('input'); 509 | thisInput.triggerHandler('change');//just to be sure; 510 | } 511 | } 512 | }); 513 | 514 | $scope.nextMonth = function nextMonth() { 515 | 516 | if ($scope.monthNumber === 12) { 517 | 518 | $scope.monthNumber = 1; 519 | //its happy new year 520 | nextYear(); 521 | } else { 522 | 523 | $scope.monthNumber += 1; 524 | } 525 | 526 | //check if max date is ok 527 | if ($scope.dateMaxLimit) { 528 | 529 | if (!$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.days[0])) { 530 | 531 | resetToMaxDate(); 532 | } 533 | } 534 | 535 | //set next month 536 | $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); 537 | //reinit days 538 | setDaysInMonth($scope.monthNumber, $scope.year); 539 | //deactivate selected day 540 | $scope.day = undefined; 541 | }; 542 | 543 | $scope.willPrevMonthBeSelectable = function willPrevMonthBeSelectable() { 544 | var monthNumber = $scope.monthNumber 545 | , year = $scope.year 546 | , prevDay = $filter('date')(new Date(new Date(year + '/' + monthNumber + '/01').getTime() - hours24h), 'dd'); //get last day in previous month 547 | 548 | if (monthNumber === 1) { 549 | 550 | monthNumber = 12; 551 | year = year - 1; 552 | } else { 553 | 554 | monthNumber -= 1; 555 | } 556 | 557 | if ($scope.dateMinLimit) { 558 | if (!$scope.isSelectableMinDate(year + '/' + monthNumber + '/' + prevDay)) { 559 | 560 | return false; 561 | } 562 | } 563 | 564 | return true; 565 | }; 566 | 567 | $scope.willNextMonthBeSelectable = function willNextMonthBeSelectable() { 568 | var monthNumber = $scope.monthNumber 569 | , year = $scope.year; 570 | 571 | if (monthNumber === 12) { 572 | 573 | monthNumber = 1; 574 | year += 1; 575 | } else { 576 | 577 | monthNumber += 1; 578 | } 579 | 580 | if ($scope.dateMaxLimit) { 581 | if (!$scope.isSelectableMaxDate(year + '/' + monthNumber + '/01')) { 582 | 583 | return false; 584 | } 585 | } 586 | 587 | return true; 588 | }; 589 | 590 | $scope.prevMonth = function managePrevMonth() { 591 | 592 | if ($scope.monthNumber === 1) { 593 | 594 | $scope.monthNumber = 12; 595 | //its happy new year 596 | prevYear(); 597 | } else { 598 | 599 | $scope.monthNumber -= 1; 600 | } 601 | //check if min date is ok 602 | if ($scope.dateMinLimit) { 603 | 604 | if (!$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.days[$scope.days.length - 1])) { 605 | 606 | resetToMinDate(); 607 | } 608 | } 609 | //set next month 610 | $scope.month = $filter('date')(new Date($scope.year, $scope.monthNumber - 1), 'MMMM'); 611 | //reinit days 612 | setDaysInMonth($scope.monthNumber, $scope.year); 613 | //deactivate selected day 614 | $scope.day = undefined; 615 | }; 616 | 617 | $scope.selectedMonthHandle = function manageSelectedMonthHandle(selectedMonthNumber) { 618 | 619 | $scope.monthNumber = Number($filter('date')(new Date(selectedMonthNumber + '/01/2000'), 'MM')); 620 | setDaysInMonth($scope.monthNumber, $scope.year); 621 | setInputValue(); 622 | }; 623 | 624 | $scope.setNewYear = function setNewYear(year) { 625 | 626 | //deactivate selected day 627 | if (!isMobile) { 628 | $scope.day = undefined; 629 | } 630 | 631 | if ($scope.dateMaxLimit && 632 | $scope.year < Number(year)) { 633 | 634 | if (!$scope.isSelectableMaxYear(year)) { 635 | 636 | return; 637 | } 638 | } else if ($scope.dateMinLimit && 639 | $scope.year > Number(year)) { 640 | 641 | if (!$scope.isSelectableMinYear(year)) { 642 | 643 | return; 644 | } 645 | } 646 | 647 | $scope.paginateYears(year); 648 | $scope.showYearsPagination = false; 649 | $timeout(function timeoutForYears() { 650 | $scope.year = Number(year); 651 | setDaysInMonth($scope.monthNumber, $scope.year); 652 | }, 0); 653 | }; 654 | 655 | $scope.hideCalendar = function hideCalendar() { 656 | if (theCalendar.classList) { 657 | theCalendar.classList.remove('_720kb-datepicker-open'); 658 | } else { 659 | 660 | classHelper.remove(theCalendar, '_720kb-datepicker-open'); 661 | } 662 | }; 663 | 664 | $scope.setDatepickerDay = function setDatepickerDay(day) { 665 | 666 | if ($scope.isSelectableDay($scope.monthNumber, $scope.year, day) && 667 | $scope.isSelectableDate($scope.monthNumber, $scope.year, day) && 668 | $scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + day) && 669 | $scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + day)) { 670 | 671 | $scope.day = Number(day); 672 | $scope.selectedDay = $scope.day; 673 | $scope.selectedMonth = $scope.monthNumber; 674 | $scope.selectedYear = $scope.year; 675 | 676 | setInputValue(); 677 | 678 | if (attr.hasOwnProperty('dateRefocus')) { 679 | thisInput[0].focus(); 680 | } 681 | 682 | $scope.hideCalendar(); 683 | } 684 | }; 685 | 686 | $scope.paginateYears = function paginateYears(startingYear) { 687 | var i 688 | , theNewYears = [] 689 | , daysToPrepend = 10 690 | , daysToAppend = 10; 691 | 692 | $scope.paginationYears = []; 693 | if (isMobile) { 694 | 695 | daysToPrepend = 50; 696 | daysToAppend = 50; 697 | if ( $scope.dateMinLimit && $scope.dateMaxLimit) { 698 | 699 | startingYear = new Date($scope.dateMaxLimit).getFullYear(); 700 | daysToPrepend = startingYear - new Date($scope.dateMinLimit).getFullYear(); 701 | daysToAppend = 1; 702 | } 703 | } 704 | 705 | for (i = daysToPrepend; i > 0; i -= 1) { 706 | 707 | theNewYears.push(Number(startingYear) - i); 708 | } 709 | 710 | for (i = 0; i < daysToAppend; i += 1) { 711 | 712 | theNewYears.push(Number(startingYear) + i); 713 | } 714 | //date typing in input date-typer 715 | if ($scope.dateTyper === 'true') { 716 | 717 | thisInput.on('keyup blur', function onTyping() { 718 | 719 | if (thisInput[0].value && 720 | thisInput[0].value.length && 721 | thisInput[0].value.length > 0) { 722 | 723 | try { 724 | if (dateFormat) { 725 | date = localDateTimestamp(thisInput[0].value.toString(), dateFormat); 726 | } else { 727 | date = new Date(thisInput[0].value.toString()); 728 | } 729 | 730 | if (date.getFullYear() && 731 | !isNaN(date.getDay()) && 732 | !isNaN(date.getMonth()) && 733 | $scope.isSelectableDay(date.getMonth(), date.getFullYear(), date.getDay()) && 734 | $scope.isSelectableDate(date.getMonth(), date.getFullYear(), date.getDay()) && 735 | $scope.isSelectableMaxDate(date) && 736 | $scope.isSelectableMinDate(date)) { 737 | 738 | $scope.$apply(function applyTyping() { 739 | 740 | $scope.month = $filter('date')(date, 'MMMM');//december-November like 741 | $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like 742 | $scope.day = Number($filter('date')(date, 'dd')); //01-31 like 743 | 744 | if (date.getFullYear().toString().length === 4) { 745 | $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like 746 | } 747 | setDaysInMonth($scope.monthNumber, $scope.year); 748 | }); 749 | } 750 | } catch (e) { 751 | 752 | return e; 753 | } 754 | } 755 | }); 756 | } 757 | //check range dates 758 | if ($scope.dateMaxLimit && 759 | theNewYears && 760 | theNewYears.length && 761 | !$scope.isSelectableMaxYear(Number(theNewYears[theNewYears.length - 1]) + 1)) { 762 | 763 | $scope.paginationYearsNextDisabled = true; 764 | } else { 765 | 766 | $scope.paginationYearsNextDisabled = false; 767 | } 768 | 769 | if ($scope.dateMinLimit && 770 | theNewYears && 771 | theNewYears.length && 772 | !$scope.isSelectableMinYear(Number(theNewYears[0]) - 1)) { 773 | 774 | $scope.paginationYearsPrevDisabled = true; 775 | } else { 776 | 777 | $scope.paginationYearsPrevDisabled = false; 778 | } 779 | 780 | $scope.paginationYears = theNewYears; 781 | }; 782 | 783 | $scope.isSelectableDay = function isSelectableDay(monthNumber, year, day) { 784 | var i = 0; 785 | 786 | if (dateDisabledWeekdays && dateDisabledWeekdays.length > 0) { 787 | for (i; i <= dateDisabledWeekdays.length; i += 1) { 788 | if (dateDisabledWeekdays[i] === new Date(monthNumber + '/' + day + '/' + year).getDay()) { 789 | return false; 790 | } 791 | } 792 | } 793 | 794 | return true; 795 | }; 796 | 797 | $scope.isSelectableDate = function isSelectableDate(monthNumber, year, day) { 798 | var i = 0; 799 | 800 | if (dateDisabledDates && 801 | dateDisabledDates.length > 0) { 802 | 803 | for (i; i <= dateDisabledDates.length; i += 1) { 804 | 805 | if (new Date(dateDisabledDates[i]).getTime() === new Date(monthNumber + '/' + day + '/' + year).getTime()) { 806 | 807 | return false; 808 | } 809 | } 810 | } 811 | 812 | if (dateEnabledDates) { 813 | 814 | for (i; i <= dateEnabledDates.length; i += 1) { 815 | 816 | if (new Date(dateEnabledDates[i]).getTime() === new Date(monthNumber + '/' + day + '/' + year).getTime()) { 817 | 818 | return true; 819 | } 820 | } 821 | 822 | return false; 823 | } 824 | 825 | return true; 826 | }; 827 | 828 | $scope.isSelectableMinDate = function isSelectableMinDate(aDate) { 829 | //if current date 830 | if (!!$scope.dateMinLimit && 831 | !!new Date($scope.dateMinLimit) && 832 | new Date(aDate).getTime() < new Date($scope.dateMinLimit).getTime()) { 833 | 834 | return false; 835 | } 836 | 837 | return true; 838 | }; 839 | 840 | $scope.isSelectableMaxDate = function isSelectableMaxDate(aDate) { 841 | //if current date 842 | if (!!$scope.dateMaxLimit && 843 | !!new Date($scope.dateMaxLimit) && 844 | new Date(aDate).getTime() > new Date($scope.dateMaxLimit).getTime()) { 845 | 846 | return false; 847 | } 848 | 849 | return true; 850 | }; 851 | 852 | $scope.isSelectableMaxYear = function isSelectableMaxYear(year) { 853 | if (!!$scope.dateMaxLimit && 854 | year > new Date($scope.dateMaxLimit).getFullYear()) { 855 | 856 | return false; 857 | } 858 | 859 | return true; 860 | }; 861 | 862 | $scope.isSelectableMinYear = function isSelectableMinYear(year) { 863 | if (!!$scope.dateMinLimit && 864 | year < new Date($scope.dateMinLimit).getFullYear()) { 865 | 866 | return false; 867 | } 868 | 869 | return true; 870 | }; 871 | 872 | $scope.validateWeekDay = function isValidWeekDay(weekDay) { 873 | var validWeekDay = Number(weekDay, 10); 874 | // making sure that the given option is valid 875 | if (!validWeekDay || validWeekDay < 0 || validWeekDay > 6) { 876 | 877 | validWeekDay = 0; 878 | } 879 | return validWeekDay; 880 | }; 881 | 882 | // respect previously configured interpolation symbols. 883 | htmlTemplate = htmlTemplate.replace(/{{/g, $interpolate.startSymbol()).replace(/}}/g, $interpolate.endSymbol()); 884 | $scope.dateMonthTitle = $scope.dateMonthTitle || 'Select month'; 885 | $scope.dateYearTitle = $scope.dateYearTitle || 'Select year'; 886 | $scope.buttonNextTitle = $scope.buttonNextTitle || 'Next'; 887 | $scope.buttonPrevTitle = $scope.buttonPrevTitle || 'Prev'; 888 | $scope.month = $filter('date')(date, 'MMMM');//december-November like 889 | $scope.monthNumber = Number($filter('date')(date, 'MM')); // 01-12 like 890 | $scope.day = Number($filter('date')(date, 'dd')); //01-31 like 891 | $scope.dateWeekStartDay = $scope.validateWeekDay($scope.dateWeekStartDay); 892 | 893 | if ($scope.dateMaxLimit) { 894 | 895 | $scope.year = Number($filter('date')(new Date($scope.dateMaxLimit), 'yyyy'));//2014 like 896 | } else { 897 | 898 | $scope.year = Number($filter('date')(date, 'yyyy'));//2014 like 899 | } 900 | $scope.months = datetime.MONTH; 901 | 902 | $scope.daysInString = []; 903 | for (n = $scope.dateWeekStartDay; n <= $scope.dateWeekStartDay + 6; n += 1) { 904 | 905 | $scope.daysInString.push(n % 7); 906 | } 907 | $scope.daysInString = $scope.daysInString.map(function mappingFunc(el) { 908 | 909 | return $filter('date')(new Date(new Date('06/08/2014').valueOf() + A_DAY_IN_MILLISECONDS * el), 'EEE'); 910 | }); 911 | 912 | //create the calendar holder and append where needed 913 | if ($scope.datepickerAppendTo && 914 | $scope.datepickerAppendTo.indexOf('.') !== -1) { 915 | 916 | $scope.datepickerID = 'datepicker-id-' + new Date().getTime() + (Math.floor(Math.random() * 6) + 8); 917 | angular.element(document.getElementsByClassName($scope.datepickerAppendTo.replace('.', ''))[0]).append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { 918 | 919 | theCalendar = angular.element(el)[0]; 920 | })); 921 | } else if ($scope.datepickerAppendTo && 922 | $scope.datepickerAppendTo.indexOf('#') !== -1) { 923 | 924 | $scope.datepickerID = 'datepicker-id-' + new Date().getTime() + (Math.floor(Math.random() * 6) + 8); 925 | angular.element(document.getElementById($scope.datepickerAppendTo.replace('#', ''))).append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { 926 | 927 | theCalendar = angular.element(el)[0]; 928 | })); 929 | } else if ($scope.datepickerAppendTo && 930 | $scope.datepickerAppendTo === 'body') { 931 | $scope.datepickerID = 'datepicker-id-' + (new Date().getTime() + (Math.floor(Math.random() * 6) + 8)); 932 | angular.element(document).find('body').append($compile(angular.element(htmlTemplate))($scope, function afterCompile(el) { 933 | 934 | theCalendar = angular.element(el)[0]; 935 | })); 936 | } else { 937 | 938 | thisInput.after($compile(angular.element(htmlTemplate))($scope)); 939 | //get the calendar as element 940 | theCalendar = element[0].querySelector('._720kb-datepicker-calendar'); 941 | } 942 | //if datepicker-toggle="" is not present or true by default 943 | if (checkToggle()) { 944 | 945 | thisInput.on('focus click focusin', function onFocusAndClick() { 946 | 947 | isMouseOnInput = true; 948 | 949 | if (!isMouseOn && 950 | !isMouseOnInput && theCalendar) { 951 | 952 | $scope.hideCalendar(); 953 | } else { 954 | 955 | showCalendar(); 956 | } 957 | }); 958 | } 959 | 960 | thisInput.on('focusout blur', function onBlurAndFocusOut() { 961 | 962 | isMouseOnInput = false; 963 | }); 964 | //some tricky dirty events to fire if click is outside of the calendar and show/hide calendar when needed 965 | angular.element(theCalendar).on('mouseenter', function onMouseEnter() { 966 | 967 | isMouseOn = true; 968 | }); 969 | 970 | angular.element(theCalendar).on('mouseleave', function onMouseLeave() { 971 | 972 | isMouseOn = false; 973 | }); 974 | 975 | angular.element(theCalendar).on('focusin', function onCalendarFocus() { 976 | 977 | isMouseOn = true; 978 | }); 979 | 980 | angular.element($window).on('click focus focusin', onClickOnWindow); 981 | 982 | //check always if given range of dates is ok 983 | if ($scope.dateMinLimit && 984 | !$scope.isSelectableMinYear($scope.year) || 985 | !$scope.isSelectableMinDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { 986 | 987 | resetToMinDate(); 988 | } 989 | 990 | if ($scope.dateMaxLimit && 991 | !$scope.isSelectableMaxYear($scope.year) || 992 | !$scope.isSelectableMaxDate($scope.year + '/' + $scope.monthNumber + '/' + $scope.day)) { 993 | 994 | resetToMaxDate(); 995 | } 996 | 997 | //datepicker boot start 998 | $scope.paginateYears($scope.year); 999 | 1000 | setDaysInMonth($scope.monthNumber, $scope.year); 1001 | $scope.checkVisibility = checkVisibility; 1002 | 1003 | $scope.$on('$destroy', function unregisterListener() { 1004 | 1005 | unregisterDataSetWatcher(); 1006 | unregisterDateMinLimitWatcher(); 1007 | unregisterDateMaxLimitWatcher(); 1008 | unregisterDateFormatWatcher(); 1009 | unregisterDateDisabledDatesWatcher(); 1010 | unregisterDateEnabledDatesWatcher(); 1011 | thisInput.off('focus click focusout blur'); 1012 | angular.element(theCalendar).off('mouseenter mouseleave focusin'); 1013 | angular.element($window).off('click focus focusin', onClickOnWindow); 1014 | }); 1015 | }; 1016 | 1017 | return { 1018 | 'restrict': 'AEC', 1019 | 'scope': { 1020 | 'dateSet': '@', 1021 | 'dateMinLimit': '@', 1022 | 'dateMaxLimit': '@', 1023 | 'dateMonthTitle': '@', 1024 | 'dateYearTitle': '@', 1025 | 'buttonNextTitle': '@', 1026 | 'buttonPrevTitle': '@', 1027 | 'dateDisabledDates': '@', 1028 | 'dateEnabledDates': '@', 1029 | 'dateDisabledWeekdays': '@', 1030 | 'dateSetHidden': '@', 1031 | 'dateTyper': '@', 1032 | 'dateWeekStartDay': '@', 1033 | 'datepickerAppendTo': '@', 1034 | 'datepickerToggle': '@', 1035 | 'datepickerClass': '@', 1036 | 'datepickerShow': '@' 1037 | }, 1038 | 'link': linkingFunction 1039 | }; 1040 | }; 1041 | 1042 | angular.module('720kb.datepicker', []) 1043 | .directive('datepicker', ['$window', '$compile', '$locale', '$filter', '$interpolate', '$timeout', datepickerDirective]); 1044 | }(angular, navigator)); 1045 | -------------------------------------------------------------------------------- /tasks/concurrent.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | (function setUp(module) { 3 | 'use strict'; 4 | 5 | module.exports = function exportingFunction(grunt) { 6 | 7 | grunt.loadNpmTasks('grunt-concurrent'); 8 | return { 9 | 'dev': { 10 | 'tasks': [ 11 | 'connect:server', 12 | 'watch:dev' 13 | ], 14 | 'options': { 15 | 'limit': '<%= concurrent.dev.tasks.length %>', 16 | 'logConcurrentOutput': true 17 | } 18 | } 19 | }; 20 | }; 21 | }(module)); 22 | -------------------------------------------------------------------------------- /tasks/confs.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | (function setUp(module) { 3 | 'use strict'; 4 | 5 | module.exports = { 6 | 'dist': 'dist', 7 | 'css': 'src/css', 8 | 'js': 'src/js', 9 | 'serverPort': 8000 10 | }; 11 | }(module)); 12 | -------------------------------------------------------------------------------- /tasks/connect.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | (function setUp(module, require) { 3 | 'use strict'; 4 | 5 | var modRewrite = require('connect-modrewrite'); 6 | 7 | module.exports = function exportingFunction(grunt) { 8 | 9 | grunt.loadNpmTasks('grunt-contrib-connect'); 10 | return { 11 | 'server': { 12 | 'options': { 13 | 'port': '<%= confs.serverPort %>', 14 | 'base': '.', 15 | 'keepalive': true, 16 | 'middleware': function manageMiddlewares(connect, options, middlewares) { 17 | // enable Angular's HTML5 mode 18 | middlewares.push(modRewrite(['!\\.html|\\.js|\\.svg|\\.css|\\.png|\\.gif$ /index.html [L]'])); 19 | return middlewares; 20 | } 21 | } 22 | } 23 | }; 24 | }; 25 | }(module, require)); 26 | -------------------------------------------------------------------------------- /tasks/copy.js: -------------------------------------------------------------------------------- 1 | /*global module, require*/ 2 | (function setUp(module, require) { 3 | 'use strict'; 4 | 5 | module.exports = function exportingFunction(grunt) { 6 | 7 | grunt.loadNpmTasks('grunt-contrib-copy'); 8 | return { 9 | 'non-minified': { 10 | 'files': [ 11 | { expand: true, flatten: true, src: ['<%= confs.css %>/**/*.css'], dest: '<%= confs.dist %>/', filter: 'isFile' }, 12 | { expand: true, flatten: true, src: ['<%= confs.js %>/**/*.js'], dest: '<%= confs.dist %>/', filter: 'isFile' }, 13 | ] 14 | } 15 | }; 16 | }; 17 | }(module, require)); 18 | -------------------------------------------------------------------------------- /tasks/csslint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | (function setUp(module) { 3 | 'use strict'; 4 | 5 | module.exports = function exportingFunction(grunt) { 6 | 7 | grunt.loadNpmTasks('grunt-contrib-csslint'); 8 | return { 9 | 'options': { 10 | 'csslintrc': '.csslintrc' 11 | }, 12 | 'strict': { 13 | 'src': [ 14 | '<%= confs.css %>/**/*.css' 15 | ] 16 | } 17 | }; 18 | }; 19 | }(module)); 20 | -------------------------------------------------------------------------------- /tasks/cssmin.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | (function setUp(module) { 3 | 'use strict'; 4 | 5 | module.exports = function exportingFunction(banner, grunt) { 6 | 7 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 8 | return { 9 | 'options': { 10 | 'report': 'gzip', 11 | 'banner': banner 12 | }, 13 | 'minifyTarget': { 14 | 'files': { 15 | '<%= confs.dist %>/angular-datepicker.min.css': [ 16 | '<%= confs.css %>/angular-datepicker.css' 17 | ] 18 | } 19 | } 20 | }; 21 | }; 22 | }(module)); 23 | -------------------------------------------------------------------------------- /tasks/eslint.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | (function setUp(module) { 3 | 'use strict'; 4 | 5 | module.exports = function exportingFunction(grunt) { 6 | 7 | grunt.loadNpmTasks('grunt-eslint'); 8 | return { 9 | 'options': { 10 | 'config': '.eslintrc' 11 | }, 12 | 'target': [ 13 | 'Gruntfile.js', 14 | '<%= confs.js %>/**/*.js' 15 | ] 16 | }; 17 | }; 18 | }(module)); 19 | -------------------------------------------------------------------------------- /tasks/jscs.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | (function setUp(module) { 3 | 'use strict'; 4 | 5 | module.exports = function exportingFunction(grunt) { 6 | 7 | grunt.loadNpmTasks('grunt-jscs'); 8 | return { 9 | 'src': '<%= confs.js %>/**/*.js', 10 | 'options': { 11 | 'config': '.jscsrc' 12 | } 13 | }; 14 | }; 15 | }(module)); 16 | -------------------------------------------------------------------------------- /tasks/uglify.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | (function setUp(module) { 3 | 'use strict'; 4 | 5 | module.exports = function exportingFunction(banner, grunt) { 6 | 7 | grunt.loadNpmTasks('grunt-contrib-uglify'); 8 | return { 9 | 'options': { 10 | 'sourceMap': true, 11 | 'sourceMapName': '<%= confs.dist %>/angular-datepicker.sourcemap.map', 12 | 'preserveComments': false, 13 | 'report': 'gzip', 14 | 'banner': banner 15 | }, 16 | 'minifyTarget': { 17 | 'files': { 18 | '<%= confs.dist %>/angular-datepicker.min.js': [ 19 | '<%= confs.js %>/angular-datepicker.js' 20 | ] 21 | } 22 | } 23 | }; 24 | }; 25 | }(module)); 26 | -------------------------------------------------------------------------------- /tasks/watch.js: -------------------------------------------------------------------------------- 1 | /*global module*/ 2 | (function setUp(module) { 3 | 'use strict'; 4 | 5 | module.exports = function exportingFunction(grunt) { 6 | 7 | grunt.loadNpmTasks('grunt-contrib-watch'); 8 | return { 9 | 'dev': { 10 | 'files': [ 11 | 'Gruntfile.js', 12 | '<%= confs.css %>/**/*.css', 13 | '<%= confs.js %>/**/*.js' 14 | ], 15 | 'tasks': [ 16 | 'csslint', 17 | 'eslint' 18 | ], 19 | 'options': { 20 | 'spawn': false 21 | } 22 | } 23 | }; 24 | }; 25 | }(module)); 26 | -------------------------------------------------------------------------------- /themes/README.md: -------------------------------------------------------------------------------- 1 | #### Create your own theme and put it into a subfolder here. 2 | 3 | For example ```/myawesometheme/angular-datepicker.css``` 4 | -------------------------------------------------------------------------------- /twitter-bootstrap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Angularjs Datepicker 10 | 11 | 12 |
13 |
14 |
15 | 21 | 22 | 23 | Date 1 is: {{date1}} 24 |
25 |
26 | 27 | 28 | 29 | Date 2 is: {{date2}} 30 |
31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ui-bootstrap/assets/js/index.js: -------------------------------------------------------------------------------- 1 | /*global angular*/ 2 | 3 | (function (angular) { 4 | 'use strict'; 5 | 6 | angular.module('720kb', [ 7 | 'ngRoute', 8 | 'ui.bootstrap', 9 | '720kb.datepicker' 10 | ]); 11 | }(angular)); 12 | -------------------------------------------------------------------------------- /ui-bootstrap/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 17 | Angularjs Datepicker 18 | 19 | 20 |
21 |
22 |
23 |
29 | 30 |
31 | Date 1 is: {{date1}} 32 |
33 |
34 |
35 | 36 |
37 | Date 2 is: {{date2}} 38 |
39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /ui-bootstrap/template/datepicker/datepicker.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
-------------------------------------------------------------------------------- /ui-bootstrap/template/datepicker/day.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 |
{{label.abbr}}
{{ weekNumbers[$index] }} 17 | 18 |
22 | -------------------------------------------------------------------------------- /ui-bootstrap/template/datepicker/month.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 |
12 | 13 |
17 | -------------------------------------------------------------------------------- /ui-bootstrap/template/datepicker/popup.html: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /ui-bootstrap/template/datepicker/year.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 |
12 | 13 |
17 | --------------------------------------------------------------------------------