├── .gitignore ├── bower.json ├── src ├── angular-mighty-datepicker.less └── angular-mighty-datepicker.coffee ├── LICENSE.txt ├── package.json ├── README.md ├── gulpfile.js └── demo └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules 3 | /bower_components 4 | .sass-cache 5 | *.map 6 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-mighty-datepicker", 3 | "version": "0.0.17", 4 | "authors": [ 5 | "Krzysztof Jung ", 6 | "Patryk Peas ", 7 | "Kamil Nicieja ", 8 | "Bartosz Erbert " 9 | ], 10 | "repository": "git://github.com/monterail/angular-mighty-datepicker.git", 11 | "description": "Angular based datepicker with mighty options", 12 | "main": [ 13 | "build/angular-mighty-datepicker.js", 14 | "build/angular-mighty-datepicker.css" 15 | ], 16 | "dependencies": { 17 | "angular": ">= 1.2", 18 | "angular-bindonce": "*", 19 | "moment": "~2.6.0", 20 | "moment-range": "~1.0.1" 21 | }, 22 | "license": "MIT", 23 | "homepage": "http://github.com/monterail/angular-mighty-datepicker" 24 | } 25 | -------------------------------------------------------------------------------- /src/angular-mighty-datepicker.less: -------------------------------------------------------------------------------- 1 | .mighty-picker-calendar__day { 2 | cursor: pointer; 3 | position: relative; 4 | } 5 | .mighty-picker-calendar__day--disabled { 6 | color: #aaa; 7 | cursor: auto; 8 | } 9 | .mighty-picker-calendar__day-marker-wrapper { 10 | position: relative 11 | } 12 | .mighty-picker-calendar__day-marker { 13 | display: none; 14 | position: absolute; 15 | background: #fff; 16 | padding: 4px 6px; 17 | border: 1px solid #aaa; 18 | bottom: 16px; 19 | } 20 | .mighty-picker-calendar__day--marked:hover .mighty-picker-calendar__day-marker { 21 | display: block; 22 | } 23 | .mighty-picker-calendar__day--marked { 24 | color: orange; 25 | font-weight: bold; 26 | } 27 | .mighty-picker-calendar__day--selected { 28 | color: #3b5; 29 | font-weight: bold; 30 | } 31 | .mighty-picker__month { 32 | display: inline-block; 33 | margin: 0 6px; 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2014 Monterail.com LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-mighty-datepicker", 3 | "version": "0.0.17", 4 | "authors": [ 5 | "Krzysztof Jung ", 6 | "Patryk Peas ", 7 | "Kamil Nicieja ", 8 | "Bartosz Erbert " 9 | ], 10 | "repository": "git://github.com/monterail/angular-mighty-datepicker.git", 11 | "description": "Angular based datepicker with mighty options", 12 | "main": "build/angular-mighty-datepicker.js", 13 | "devDependencies": { 14 | "beepbeep": "^1.2.0", 15 | "gulp": "~3.8.10", 16 | "gulp-bower": "0.0.4", 17 | "gulp-changed": "~0.3.0", 18 | "gulp-clean": "~0.2.4", 19 | "gulp-coffee": "~1.4.2", 20 | "gulp-coffeelint": "^0.3.3", 21 | "gulp-connect": "~2.0.5", 22 | "gulp-less": "~1.2.3", 23 | "gulp-plumber": "^0.6.3", 24 | "gulp-slim": "0.0.4", 25 | "gulp-util": "^2.2.17", 26 | "gulp-watch": "~0.6.4" 27 | }, 28 | "keywords": [ 29 | "angular", 30 | "date", 31 | "picker", 32 | "datepicker" 33 | ], 34 | "license": "MIT", 35 | "homepage": "http://github.com/monterail/angular-mighty-datepicker", 36 | "ignore": [ 37 | "**/.*", 38 | "node_modules", 39 | "bower_components", 40 | "test", 41 | "tests" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular based datepicker with mighty options 2 | 3 | ## Documentation and demo 4 | [http://monterail.github.io/angular-mighty-datepicker/](http://monterail.github.io/angular-mighty-datepicker/) 5 | 6 | ## Changelog: 7 | 8 | 0.0.18 9 | - fixing package.json for npm to work 10 | 11 | 0.0.17 12 | - updating model in `simple` mode fixed (not tangling with model anymore) 13 | 14 | 0.0.16 15 | - cutsom templates fixed 16 | 17 | 0.0.15 18 | - when updating model in `simple` mode calendar moves to current month of new model 19 | 20 | 0.0.14 21 | - fix for custom markers in custom templates 22 | 23 | 0.0.13 24 | - `after`/`before` options moved to attributes (for easy databinding and updating) 25 | - added example with double datepicker for date range 26 | - added changelog in readme section 27 | 28 | 0.0.12 29 | - fixed datepicker for model that is not momentJS object 30 | 31 | 0.0.11 32 | - datepicker is updated when model changes (both single and multiple modes) 33 | 34 | 0.0.10 35 | - option for custom template 36 | 37 | 0.0.9 38 | - fixed marker styling for Firefox 39 | 40 | 0.0.8 41 | - watch and reindex markers when changed 42 | 43 | 0.0.7 44 | - simple markers for calendar days 45 | 46 | 0.0.6 47 | - fixed typos and readme 48 | - BEM classes fixed 49 | 50 | 0.0.5 51 | - filter and callback options 52 | 53 | 0.0.4 54 | - options object fix 55 | 56 | 0.0.3 57 | - changed classnames for elements 58 | 59 | 0.0.2 60 | - added before/after limits 61 | - multiple date select 62 | 63 | 0.0.1 64 | - initial release with simple datepicker functionality 65 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"), 2 | gutil = require('gulp-util'), 3 | watch = require("gulp-watch"), 4 | clean = require("gulp-clean"), 5 | connect = require("gulp-connect"), 6 | changed = require("gulp-changed"), 7 | bower = require("gulp-bower"), 8 | // compilers 9 | less = require("gulp-less"), // gulp-sass is broken 10 | coffee = require("gulp-coffee"), 11 | coffeelint = require("gulp-coffeelint"), 12 | plumber = require('gulp-plumber'); 13 | 14 | var warn = function(err) { console.warn(err); }; 15 | var paths = { 16 | src: "./src/", 17 | dst: "./build/" 18 | } 19 | 20 | var onError = function (err) { 21 | gutil.beep(); 22 | console.log(err); 23 | }; 24 | 25 | gulp.task("default", ["bower", "build"]); 26 | 27 | gulp.task("build", ["coffee", "less"]) 28 | 29 | gulp.task("server", ["build", "watch"], function() { 30 | connect.server({ 31 | root: './test', 32 | port: 8000 33 | }); 34 | }); 35 | 36 | gulp.task("clean", function(){ 37 | return gulp.src(paths.dst, {read: false}) 38 | .pipe(clean()); 39 | }) 40 | 41 | gulp.task("watch", function(){ 42 | return gulp.watch(paths.src + "**/*", ["build"]); 43 | }); 44 | 45 | gulp.task("bower", function() { 46 | return bower("bower_components") 47 | .pipe(gulp.dest("bower_components")) 48 | }); 49 | 50 | // compilers 51 | 52 | // gulp.task("copy", function(){ 53 | // return gulp.src(paths.src + "**/*.{json,png,jpg,gif,eot,svg,ttf,woff}") 54 | // .pipe(changed(paths.dst)) 55 | // .pipe(gulp.dest(paths.dst)) 56 | // .pipe(connect.reload()); 57 | // }); 58 | 59 | gulp.task("less", function(){ 60 | return gulp.src(paths.src + "**/*.less") 61 | .pipe(changed(paths.dst, { extension: '.css' })) 62 | .pipe(plumber({ 63 | errorHandler: onError 64 | })) 65 | .pipe(less().on('error', warn)) 66 | .pipe(gulp.dest(paths.dst)) 67 | .pipe(connect.reload()); 68 | }); 69 | 70 | gulp.task("coffee", function(){ 71 | return gulp.src(paths.src + "**/*.coffee") 72 | .pipe(changed(paths.dst, { extension: '.js' })) 73 | .pipe(coffeelint()) 74 | .pipe(coffeelint.reporter()) 75 | .pipe(plumber({ 76 | errorHandler: onError 77 | })) 78 | .pipe(coffee().on('error', warn)) 79 | .pipe(gulp.dest(paths.dst)) 80 | .pipe(connect.reload()); 81 | }); 82 | // 83 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Angular Mighty Picker by Monterail 5 | 6 | 7 | 8 | 9 | 10 | 64 | 65 | 71 | 72 | 73 |
74 |
75 |

Simple date picker

76 | 77 | 78 |
 79 |         {{date | json}}
 80 |       
81 |
82 |
83 |

Multiple date picker

84 | 85 |
86 |
 87 |         {{ day | json}}
 88 |       
89 |
90 |

Date picker with markers

91 | 92 | 93 |
94 |
95 |

Date picker with date and no start

96 | 97 | {{ dateSt }}} 98 |
99 |
100 |

Double datepicker for data range

101 | 102 | 103 |
104 |
105 | 106 | 107 | -------------------------------------------------------------------------------- /src/angular-mighty-datepicker.coffee: -------------------------------------------------------------------------------- 1 | angular.module "mightyDatepicker", ['pasvaz.bindonce'] 2 | 3 | angular.module("mightyDatepicker").directive "mightyDatepicker", ($compile) -> 4 | pickerTemplate = """ 5 |
6 | 10 |
12 |
13 | 14 | 15 | 19 | 20 | 21 | 38 | 39 |
18 |
29 |
31 |
32 |
35 |
36 |
37 |
40 |
41 | 45 |
46 | """ 47 | options = 48 | mode: "simple" 49 | months: 1 50 | start: null 51 | filter: undefined 52 | callback: undefined 53 | markerTemplate: "{{ day.marker }}" 54 | template: pickerTemplate 55 | restrict: "AE" 56 | replace: true 57 | template: '
' 58 | scope: 59 | model: '=ngModel' 60 | options: '=' 61 | markers: '=' 62 | after: '=' 63 | before: '=' 64 | 65 | link: ($scope, $element, $attrs) -> 66 | _bake = -> 67 | domEl = $compile(angular.element($scope.options.template))($scope) 68 | $element.append(domEl) 69 | 70 | _indexOfMoment = (array, element, match) -> 71 | for key, value of array 72 | return key if element.isSame(value, match) 73 | -1 74 | 75 | _indexMarkers = -> 76 | $scope.markerIndex = (marker.day for marker in $scope.markers) if $scope.markers 77 | 78 | _withinLimits = (day, month) -> 79 | withinLimits = true 80 | withinLimits &&= day.isBefore($scope.before) if $scope.before 81 | withinLimits &&= day.isAfter($scope.after) if $scope.after 82 | withinLimits 83 | 84 | _getMarker = (day) -> 85 | ix = _indexOfMoment($scope.markerIndex, day, 'day') 86 | if ix > -1 87 | return $scope.markers[ix].marker 88 | else 89 | return undefined 90 | 91 | _isSelected = (day) -> 92 | switch $scope.options.mode 93 | when "multiple" 94 | return _indexOfMoment($scope.model, day, 'day') > -1 95 | else 96 | return $scope.model && day.isSame($scope.model, 'day') 97 | 98 | _buildWeek = (time, month) -> 99 | days = [] 100 | filter = true 101 | start = time.startOf('week') 102 | days = [0 .. 6].map (d) -> 103 | day = moment(start).add('days', d) 104 | withinMonth = day.month() == month 105 | withinLimits = _withinLimits(day, month) 106 | filter = $scope.options.filter(day) if $scope.options.filter 107 | date: day 108 | selected: _isSelected(day) && withinMonth 109 | disabled: !(withinLimits && withinMonth && filter) 110 | marker: _getMarker(day) if withinMonth 111 | days 112 | 113 | _buildMonth = (time) -> 114 | weeks = [] 115 | calendarStart = moment(time).startOf('month') 116 | calendarEnd = moment(time).endOf('month') 117 | weeksInMonth = calendarEnd.week() - calendarStart.week() 118 | if weeksInMonth < 0 # year edge 119 | weeksInMonth = 120 | (calendarStart.weeksInYear()-calendarStart.week())+calendarEnd.week() 121 | start = time.startOf('month') 122 | weeks =( 123 | _buildWeek(moment(start).add('weeks', w), moment(start).month() 124 | ) for w in [0 .. weeksInMonth]) 125 | weeks: weeks 126 | name: time.format("MMMM YYYY") 127 | 128 | _setup = -> 129 | tempOptions = {} 130 | for attr, v of options 131 | tempOptions[attr] = v 132 | 133 | if $scope.options 134 | for attr,v of $scope.options 135 | tempOptions[attr] = $scope.options[attr] 136 | 137 | $scope.options = tempOptions 138 | 139 | switch $scope.options.mode 140 | when "multiple" 141 | # add start based on model 142 | if $scope.model && Array.isArray($scope.model) && $scope.model.length>0 143 | if $scope.model.length == 1 144 | start = moment($scope.model[0]) 145 | else 146 | dates = $scope.model.slice(0) 147 | start = moment(dates.sort().slice(-1)[0]) 148 | else 149 | $scope.model = [] 150 | else 151 | start = moment($scope.model) if $scope.model 152 | 153 | $scope.options.start = 154 | $scope.options.start || start || moment().startOf('day') 155 | 156 | _indexMarkers() 157 | $scope.options.template = $scope.options.template.replace('ng-bind-template=""', 158 | 'ng-bind-template="' + $scope.options.markerTemplate + '"') 159 | 160 | _prepare = -> 161 | $scope.months = [] 162 | $scope.months = ( 163 | _buildMonth(moment($scope.options.start).add('months', m) 164 | ) for m in [0 ... $scope.options.months]) 165 | 166 | _build = -> 167 | _prepare() 168 | _bake() 169 | 170 | $scope.moveMonth = (step) -> 171 | $scope.options.start.add('month', step) 172 | _prepare() 173 | return 174 | 175 | $scope.select = (day) -> 176 | if !day.disabled 177 | switch $scope.options.mode 178 | when "multiple" 179 | if day.selected 180 | ix = _indexOfMoment($scope.model, day.date, 'day') 181 | $scope.model.splice(ix, 1) 182 | else 183 | $scope.model.push(moment(day.date)) 184 | else 185 | $scope.model = day.date 186 | $scope.options.callback day.date if $scope.options.callback 187 | _prepare() 188 | 189 | $scope.$watchCollection 'markers', (newMarkers, oldMarkers) -> 190 | _indexMarkers() 191 | _prepare() 192 | 193 | _setup() 194 | _build() 195 | 196 | switch $scope.options.mode 197 | when "multiple" 198 | $scope.$watchCollection 'model', (newVals, oldVals) -> 199 | _prepare() 200 | 201 | when "simple" 202 | $scope.$watch 'model', (newVal, oldVal) -> 203 | newVal = moment(newVal) unless moment.isMoment(newVal) 204 | if !oldVal || oldVal && !newVal.isSame(oldVal, 'day') 205 | $scope.model = newVal 206 | if oldVal 207 | $scope.options.start = moment(newVal) 208 | _prepare() 209 | 210 | $scope.$watch 'before', (newVal, oldVal) -> 211 | if newVal 212 | newVal = moment(newVal) unless moment.isMoment(newVal) 213 | unless newVal.isSame(oldVal, 'day') 214 | _prepare() 215 | 216 | $scope.$watch 'after', (newVal, oldVal) -> 217 | if newVal 218 | newVal = moment(newVal) unless moment.isMoment(newVal) 219 | unless newVal.isSame(oldVal, 'day') 220 | _prepare() 221 | --------------------------------------------------------------------------------