diff --git a/.gitignore b/.gitignore index eea5e09..5c3897c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ node_modules .tmp .sass-cache app/components -.idea \ No newline at end of file +.idea +*.iml diff --git a/.jshintrc b/.jshintrc index 64b7ce8..a365b6e 100644 --- a/.jshintrc +++ b/.jshintrc @@ -3,11 +3,11 @@ "browser": true, "es5": true, "esnext": true, - "bitwise": true, + "bitwise": false, "camelcase": true, "curly": true, "eqeqeq": true, - "immed": true, + "immed": false, "indent": 2, "latedef": true, "newcap": true, diff --git a/Gruntfile.js b/Gruntfile.js index 1682c74..d10bac9 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,12 +6,13 @@ var mountFolder = function (connect, dir) { module.exports = function (grunt) { // load all grunt tasks - require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); + require('load-grunt-tasks')(grunt); // configurable paths var yeomanConfig = { - app : 'app', - dist: 'dist' + app: 'app', + dist: 'dist', + tmp: '.tmp' }; try { @@ -20,21 +21,47 @@ module.exports = function (grunt) { } grunt.initConfig({ - yeoman : yeomanConfig, - watch : { + yeoman: yeomanConfig, + watch: { + less: { + files: ['<%= yeoman.app %>/styles/{,*/}*.less'], + tasks: ['recess', 'copy:styles'], + options: { + nospawn: true + } + }, + styles: { + files: ['<%= yeoman.app %>/styles/{,*/}*.css'], + tasks: ['copy:styles'] + }, livereload: { files: [ '<%= yeoman.app %>/{,*/}*.html', - '{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css', - '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js', + '<%= yeoman.tmp %>/styles/{,*/}*.css', + '{<%= yeoman.tmp %>,<%= yeoman.app %>}/scripts/{,*/}*.js', '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' - ], - tasks: ['livereload'] + ] + } + }, + less: { + options: { + compile: true + }, + dist: { + files: [ + { + expand: true, + cwd: '<%= yeoman.app %>/styles', + src: 'style.less', + dest: '<%= yeoman.tmp %>/styles/', + ext: '.css' + } + ] } }, connect: { - options : { - port : 9000, + options: { + port: 9000, // Change this to '0.0.0.0' to access the server from outside. hostname: 'localhost' }, @@ -43,120 +70,132 @@ module.exports = function (grunt) { middleware: function (connect) { return [ lrSnippet, - mountFolder(connect, '.tmp'), + mountFolder(connect, yeomanConfig.tmp), mountFolder(connect, yeomanConfig.app) ]; } } }, - test : { + test: { options: { middleware: function (connect) { return [ - mountFolder(connect, '.tmp'), + mountFolder(connect, yeomanConfig.tmp), mountFolder(connect, 'test') ]; } } } }, - open : { + open: { server: { url: 'http://localhost:<%= connect.options.port %>' } }, - clean : { - dist : { + clean: { + dist: { files: [ { - dot: true, + dot: false, src: [ - '.tmp', + '<%= yeoman.tmp %>', '<%= yeoman.dist %>' ] } ] }, - server: '.tmp' + server: '<%= yeoman.tmp %>' }, - jshint : { + jshint: { options: { jshintrc: '.jshintrc' }, - all : [ + all: [ 'Gruntfile.js', '<%= yeoman.app %>/scripts/{,*/}*.js' ] }, - karma : { + karma: { unit: { configFile: 'karma.conf.js', - singleRun : true + singleRun: true } }, - cssmin : { + cssmin: { dist: { expand: true, - cwd : '<%= yeoman.dist %>', - src : ['*.css', '!*.min.css'], - dest : '<%= yeoman.dist %>', - ext : '.min.css' + cwd: '<%= yeoman.dist %>', + src: ['*.css', '!*.min.css'], + dest: '<%= yeoman.dist %>', + ext: '.min.css' } }, - ngmin : { + ngmin: { dist: { expand: true, - cwd : '<%= yeoman.dist %>', - src : ['*.js', '!*.min.js'], - dest : '<%= yeoman.dist %>', - ext : '.min.js' + cwd: '<%= yeoman.dist %>', + src: ['*.js', '!*.min.js'], + dest: '<%= yeoman.dist %>', + ext: '.min.js' } }, - uglify : { + uglify: { dist: { expand: true, - cwd : '<%= yeoman.dist %>', - src : ['*.min.js'], - dest : '<%= yeoman.dist %>', - ext : '.min.js' + cwd: '<%= yeoman.dist %>', + src: ['*.min.js'], + dest: '<%= yeoman.dist %>', + ext: '.min.js' } }, - copy : { - dist: { - files: [ - { - expand : true, - flatten: true, - dot : true, - cwd : '<%= yeoman.app %>', - dest : '<%= yeoman.dist %>', - src : [ - 'styles/date.css' - ] - } - ] + copy: { + styles: { + expand: true, + cwd: '<%= yeoman.app %>/styles', + dest: '<%= yeoman.tmp %>/styles/', + src: '{,*/}*.css' } }, ngtemplates: { dist: { options: { - base : '<%= yeoman.app %>', - module: 'dateInput' + base: '<%= yeoman.app %>', + module: 'datePicker' }, - src : '<%= yeoman.app %>/scripts/*.html', - dest : '.tmp/templates.js' + src: '<%= yeoman.app %>/templates/*.html', + dest: '<%= yeoman.tmp %>/templates.js' } }, + concurrent: { + server: [ + 'recess', + 'copy:styles' + ], + test: [ + 'copy:styles' + ], + dist: [ + 'copy:styles' + ] + }, concat: { options: { separator: '\n' }, js: { - src: ['<%= yeoman.app %>/scripts/module.js','.tmp/templates.js'], - dest: '<%= yeoman.dist %>/index.js' + src: ['<%= yeoman.app %>/scripts/{datePicker,input,dateRange,datePickerUtils}.js', '<%= yeoman.tmp %>/templates.js'], + dest: '<%= yeoman.dist %>/index.js', + options: { + banner:'\'use strict\';\n(function(angular){\n', + footer:'})(angular);', + // Replace all 'use strict' statements in the code with a single one at the top + process: function(src) { + return src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1'); + } + } }, css: { - src: ['<%= yeoman.app %>/styles/date.css'], + src: ['<%= yeoman.tmp %>/{,*/}*.css'], dest: '<%= yeoman.dist %>/index.css' } } @@ -166,7 +205,8 @@ module.exports = function (grunt) { grunt.registerTask('server', [ 'clean:server', - 'livereload-start', + 'recess', + 'concurrent:server', 'connect:livereload', 'open', 'watch' @@ -179,8 +219,9 @@ module.exports = function (grunt) { ]); grunt.registerTask('build', [ - 'clean:dist', 'jshint', + 'clean:dist', + 'less', 'ngtemplates', 'concat', 'cssmin', diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..4d6a48f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2013-2014 Piotrek Majewski + +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. diff --git a/README.md b/README.md index 2e960c2..cd0bc97 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,56 @@ # AngularJS datepicker directives -#### Examples +## WIP +#### Requirements -##### defaults +- Angular v1.2+ -```html -
-``` +#### Development version -##### year view +Checkout, run `npm install` and `bower install`. +To build run `grunt build` -```html -
-``` +## Examples + +[Live demo](https://rawgithub.com/g00fy-/angular-datepicker/master/app/index.html) -##### month view +##### defaults ```html -
+
``` -##### only date view +##### views: + +(initial) view ```html -
+
``` - -##### hours view +(max) view ```html -
+
``` +(min) view -##### minutes view +##### only date view ```html -
+
``` +##### Close the picker when min-view is reached + +```html +
+``` ##### input as datepicker @@ -51,7 +58,6 @@ ``` - ##### input with formatted value ```html @@ -64,4 +70,3 @@ ```html
``` - diff --git a/app/index.html b/app/index.html index 8816c27..fdadcfb 100644 --- a/app/index.html +++ b/app/index.html @@ -1,91 +1,176 @@ - - - - - - - - - - - - - - -
-
-

Calendar

- -

views

-
default
-
<div date-picker="start"></div> 
-
-
year
-
<div date-picker="start"  year></div> 
-
-
month
-
<div date-picker="start month></div> 
-
-
date
-
<div date-picker="start" date></div> 
-
-
hours
-
<div date-picker="start" hours></div> 
-
-
minutes
-
<div date-picker="start" minutes></div> 
-
-
-
-

Input

-
default
-
<input type="datetime" ng-model="model" date-time></div> 
- -
Input format
-
<input type="datetime" ng-model="model" date-time format="long"></div> 
- -
A button
-
<div class="dropdown">
-  <a class="dropdown-toggle btn btn-danger">
-    pick a date: {{(date|date)}}
-  </a>
-  <div class="dropdown-menu" ng-click="$event.preventDefault();$event.stopPropagation()">
-    <div date-picker="date" class="datetimepicker"></div>
-  </div>
-</div>
- -
Date range
-
<div date-range start="start" end="end" ></div> 
-
-
Date range button
- -
d + + + + + + + + + + + + + +
+
+

Calendar

+ +
+

default views

+ +
year
+ +
+ +
month
+ +
+ +
date
+ +
+ +
hours
+ +
+ +
minutes
+ +
+
+ + +
+

min views

+ +
year
+ +
+ +
month
+ +
+ +
date
+ +
+ +
hours
+ +
+ +
minutes
+ +
+
+ + +
+

max views

+ +
year
+ +
+ +
month
+ +
+ +
date
+ +
+ +
hours
+ +
+ +
maxutes
+ +
+
+ +
+

max & min views

+ +
time
+ +
+ +
date
+ +
+ +
+ + +
+ + +
+

Input

+
default
+ + +

Input with append

+
default
+ +
+ + + +
+

Input with prepend

+
default
+ +
+ + +
+ +
Input format
+ +
A button
+ + + + +
Date range
+ +
+
Date range button
+ + +
+
- - - - - - - - + + + + + + + + + + diff --git a/app/scripts/datePicker.js b/app/scripts/datePicker.js new file mode 100644 index 0000000..5529084 --- /dev/null +++ b/app/scripts/datePicker.js @@ -0,0 +1,231 @@ +'use strict'; + +var Module = angular.module('datePicker', []); + +Module.constant('datePickerConfig', { + template: 'templates/datepicker.html', + view: 'month', + views: ['year', 'month', 'date', 'hours', 'minutes'], + step: 5 +}); + +Module.filter('time',function () { + function format(date){ + return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2); + } + + return function (date) { + if (!(date instanceof Date)) { + date = new Date(date); + if (isNaN(date.getTime())) { + return undefined; + } + } + return format(date); + }; +}); + +Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function datePickerDirective(datePickerConfig, datePickerUtils) { + + //noinspection JSUnusedLocalSymbols + return { + // this is a bug ? + require:'?ngModel', + template: '
', + scope: { + model: '=datePicker', + after: '=?', + before: '=?' + }, + link: function (scope, element, attrs, ngModel) { + + var arrowClick = false; + + scope.date = new Date(scope.model || new Date()); + scope.views = datePickerConfig.views.concat(); + scope.view = attrs.view || datePickerConfig.view; + scope.now = new Date(); + scope.template = attrs.template || datePickerConfig.template; + + var step = parseInt(attrs.step || datePickerConfig.step, 10); + var partial = !!attrs.partial; + + /** @namespace attrs.minView, attrs.maxView */ + scope.views =scope.views.slice( + scope.views.indexOf(attrs.maxView || 'year'), + scope.views.indexOf(attrs.minView || 'minutes')+1 + ); + + if (scope.views.length === 1 || scope.views.indexOf(scope.view)===-1) { + scope.view = scope.views[0]; + } + + scope.setView = function (nextView) { + if (scope.views.indexOf(nextView) !== -1) { + scope.view = nextView; + } + }; + + scope.setDate = function (date) { + if(attrs.disabled) { + return; + } + scope.date = date; + // change next view + var nextView = scope.views[scope.views.indexOf(scope.view) + 1]; + if ((!nextView || partial) || scope.model) { + + scope.model = new Date(scope.model || date); + //if ngModel , setViewValue and trigger ng-change, etc... + if(ngModel) { + ngModel.$setViewValue(scope.date); + } + + var view = partial ? 'minutes' : scope.view; + //noinspection FallThroughInSwitchStatementJS + switch (view) { + case 'minutes': + scope.model.setMinutes(date.getMinutes()); + /*falls through*/ + case 'hours': + scope.model.setHours(date.getHours()); + /*falls through*/ + case 'date': + scope.model.setDate(date.getDate()); + /*falls through*/ + case 'month': + scope.model.setMonth(date.getMonth()); + /*falls through*/ + case 'year': + scope.model.setFullYear(date.getFullYear()); + } + scope.$emit('setDate', scope.model, scope.view); + } + + if (nextView) { + scope.setView(nextView); + } + + if(!nextView && attrs.autoClose === 'true'){ + element.addClass('hidden'); + } + }; + + function update() { + var view = scope.view; + + if (scope.model && !arrowClick) { + scope.date = new Date(scope.model); + arrowClick = false; + } + var date = scope.date; + + switch (view) { + case 'year': + scope.years = datePickerUtils.getVisibleYears(date); + break; + case 'month': + scope.months = datePickerUtils.getVisibleMonths(date); + break; + case 'date': + scope.weekdays = scope.weekdays || datePickerUtils.getDaysOfWeek(); + scope.weeks = datePickerUtils.getVisibleWeeks(date); + break; + case 'hours': + scope.hours = datePickerUtils.getVisibleHours(date); + break; + case 'minutes': + scope.minutes = datePickerUtils.getVisibleMinutes(date, step); + break; + } + } + + function watch() { + if (scope.view !== 'date') { + return scope.view; + } + return scope.date ? scope.date.getMonth() : null; + } + + + scope.$watch(watch, update); + + scope.next = function (delta) { + var date = scope.date; + delta = delta || 1; + switch (scope.view) { + case 'year': + /*falls through*/ + case 'month': + date.setFullYear(date.getFullYear() + delta); + break; + case 'date': + date.setMonth(date.getMonth() + delta); + break; + case 'hours': + /*falls through*/ + case 'minutes': + date.setHours(date.getHours() + delta); + break; + } + arrowClick = true; + update(); + }; + + scope.prev = function (delta) { + return scope.next(-delta || -1); + }; + + scope.isAfter = function (date) { + return scope.after && datePickerUtils.isAfter(date, scope.after); + }; + + scope.isBefore = function (date) { + return scope.before && datePickerUtils.isBefore(date, scope.before); + }; + + scope.isSameMonth = function (date) { + return datePickerUtils.isSameMonth(scope.model, date); + }; + + scope.isSameYear = function (date) { + return datePickerUtils.isSameYear(scope.model, date); + }; + + scope.isSameDay = function (date) { + return datePickerUtils.isSameDay(scope.model, date); + }; + + scope.isSameHour = function (date) { + return datePickerUtils.isSameHour(scope.model, date); + }; + + scope.isSameMinutes = function (date) { + return datePickerUtils.isSameMinutes(scope.model, date); + }; + + scope.isNow = function (date) { + var is = true; + var now = scope.now; + //noinspection FallThroughInSwitchStatementJS + switch (scope.view) { + case 'minutes': + is &= ~~(date.getMinutes()/step) === ~~(now.getMinutes()/step); + /*falls through*/ + case 'hours': + is &= date.getHours() === now.getHours(); + /*falls through*/ + case 'date': + is &= date.getDate() === now.getDate(); + /*falls through*/ + case 'month': + is &= date.getMonth() === now.getMonth(); + /*falls through*/ + case 'year': + is &= date.getFullYear() === now.getFullYear(); + } + return is; + }; + } + }; +}]); diff --git a/app/scripts/datePickerUtils.js b/app/scripts/datePickerUtils.js new file mode 100644 index 0000000..12e7c38 --- /dev/null +++ b/app/scripts/datePickerUtils.js @@ -0,0 +1,125 @@ +'use strict'; + +angular.module('datePicker').factory('datePickerUtils', function(){ + return { + getVisibleMinutes : function(date, step) { + date = new Date(date || new Date()); + date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours()); + var minutes = []; + var stop = date.getTime() + 60 * 60 * 1000; + while (date.getTime() < stop) { + minutes.push(date); + date = new Date(date.getTime() + step * 60 * 1000); + } + return minutes; + }, + getVisibleWeeks : function(date) { + date = new Date(date || new Date()); + var startMonth = date.getMonth(), startYear = date.getYear(); + date.setDate(1); + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + + if (date.getDay() === 0) { + date.setDate(-5); + } else { + date.setDate(date.getDate() - (date.getDay() - 1)); + } + if (date.getDate() === 1) { + date.setDate(-6); + } + + var weeks = []; + while (weeks.length < 6) { + /*jshint -W116 */ + if(date.getYear()=== startYear && date.getMonth() > startMonth) break; + var week = []; + for (var i = 0; i < 7; i++) { + week.push(new Date(date)); + date.setDate(date.getDate() + 1); + } + weeks.push(week); + } + return weeks; + }, + getVisibleYears : function(date) { + var years = []; + date = new Date(date || new Date()); + date.setFullYear(date.getFullYear() - (date.getFullYear() % 10)); + for (var i = 0; i < 12; i++) { + years.push(new Date(date.getFullYear() + (i - 1), 0, 1)); + } + return years; + }, + getDaysOfWeek : function(date) { + date = new Date(date || new Date()); + date = new Date(date.getFullYear(), date.getMonth(), date.getDate()); + date.setDate(date.getDate() - (date.getDay() - 1)); + var days = []; + for (var i = 0; i < 7; i++) { + days.push(new Date(date)); + date.setDate(date.getDate() + 1); + } + return days; + }, + getVisibleMonths : function(date) { + date = new Date(date || new Date()); + var year = date.getFullYear(); + var months = []; + for (var month = 0; month < 12; month++) { + months.push(new Date(year, month, 1)); + } + return months; + }, + getVisibleHours : function(date) { + date = new Date(date || new Date()); + date.setHours(0); + date.setMinutes(0); + date.setSeconds(0); + date.setMilliseconds(0); + var hours = []; + for (var i = 0; i < 24; i++) { + hours.push(date); + date = new Date(date.getTime() + 60 * 60 * 1000); + } + return hours; + }, + isAfter : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return model && model.getTime() <= date.getTime(); + }, + isBefore : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return model.getTime() >= date.getTime(); + }, + isSameYear : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return model && model.getFullYear() === date.getFullYear(); + }, + isSameMonth : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return this.isSameYear(model, date) && model.getMonth() === date.getMonth(); + }, + isSameDay : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return this.isSameMonth(model, date) && model.getDate() === date.getDate(); + }, + isSameHour : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return this.isSameDay(model, date) && model.getHours() === date.getHours(); + }, + isSameMinutes : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return this.isSameHour(model, date) && model.getMinutes() === date.getMinutes(); + } + }; +}); \ No newline at end of file diff --git a/app/scripts/dateRange.js b/app/scripts/dateRange.js new file mode 100644 index 0000000..38ec101 --- /dev/null +++ b/app/scripts/dateRange.js @@ -0,0 +1,28 @@ +'use strict'; + +var Module = angular.module('datePicker'); + +Module.directive('dateRange', function () { + return { + templateUrl: 'templates/daterange.html', + scope: { + start: '=', + end: '=' + }, + link: function (scope, element, attrs) { + attrs.$observe('disabled', function(isDisabled){ + scope.disableDatePickers = !!isDisabled; + }); + scope.$watch('start.getTime()', function (value) { + if (value && scope.end && value > scope.end.getTime()) { + scope.end = new Date(value); + } + }); + scope.$watch('end.getTime()', function (value) { + if (value && scope.start && value < scope.start.getTime()) { + scope.start = new Date(value); + } + }); + } + }; +}); diff --git a/app/scripts/input.js b/app/scripts/input.js new file mode 100644 index 0000000..49bae6a --- /dev/null +++ b/app/scripts/input.js @@ -0,0 +1,143 @@ +'use strict'; + +var PRISTINE_CLASS = 'ng-pristine', + DIRTY_CLASS = 'ng-dirty'; + +var Module = angular.module('datePicker'); + +Module.constant('dateTimeConfig', { + template: function (attrs) { + return '' + + '
'; + }, + format: 'yyyy-MM-dd HH:mm', + views: ['date', 'year', 'month', 'hours', 'minutes'], + dismiss: false, + position: 'relative' +}); + +Module.directive('dateTimeAppend', function () { + return { + link: function (scope, element) { + element.bind('click', function () { + element.find('input')[0].focus(); + }); + } + }; +}); + +Module.directive('dateTime', ['$compile', '$document', '$filter', 'dateTimeConfig', '$parse', function ($compile, $document, $filter, dateTimeConfig, $parse) { + var body = $document.find('body'); + var dateFilter = $filter('date'); + + return { + require: 'ngModel', + scope:true, + link: function (scope, element, attrs, ngModel) { + var format = attrs.format || dateTimeConfig.format; + var parentForm = element.inheritedData('$formController'); + var views = $parse(attrs.views)(scope) || dateTimeConfig.views.concat(); + var view = attrs.view || views[0]; + var index = views.indexOf(view); + var dismiss = attrs.dismiss ? $parse(attrs.dismiss)(scope) : dateTimeConfig.dismiss; + var picker = null; + var position = attrs.position || dateTimeConfig.position; + var container = null; + + if (index === -1) { + views.splice(index, 1); + } + + views.unshift(view); + + + function formatter(value) { + return dateFilter(value, format); + } + + function parser() { + return ngModel.$modelValue; + } + + ngModel.$formatters.push(formatter); + ngModel.$parsers.unshift(parser); + + + var template = dateTimeConfig.template(attrs); + + function updateInput(event) { + event.stopPropagation(); + if (ngModel.$pristine) { + ngModel.$dirty = true; + ngModel.$pristine = false; + element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS); + if (parentForm) { + parentForm.$setDirty(); + } + ngModel.$render(); + } + } + + function clear() { + if (picker) { + picker.remove(); + picker = null; + } + if (container) { + container.remove(); + container = null; + } + } + + function showPicker() { + if (picker) { + return; + } + // create picker element + picker = $compile(template)(scope); + scope.$digest(); + + scope.$on('setDate', function (event, date, view) { + updateInput(event); + if (dismiss && views[views.length - 1] === view) { + clear(); + } + }); + + scope.$on('$destroy', clear); + + // move picker below input element + + if (position === 'absolute') { + var pos = angular.extend(element.offset(), { height: element[0].offsetHeight }); + picker.css({ top: pos.top + pos.height, left: pos.left, display: 'block', position: position}); + body.append(picker); + } else { + // relative + container = angular.element('
'); + element[0].parentElement.insertBefore(container[0], element[0]); + container.append(picker); +// this approach doesn't work +// element.before(picker); + picker.css({top: element[0].offsetHeight + 'px', display: 'block'}); + } + + picker.bind('mousedown', function (evt) { + evt.preventDefault(); + }); + } + + element.bind('focus', showPicker); + element.bind('blur', clear); + } + }; +}]); diff --git a/app/scripts/module.js b/app/scripts/module.js deleted file mode 100644 index cc5ed75..0000000 --- a/app/scripts/module.js +++ /dev/null @@ -1,448 +0,0 @@ -(function () { - 'use strict'; - var Module = angular.module('dateInput', []); - - - Module.directive('datePicker', function () { - var viewOptions = ['month', 'date', 'year', 'month', 'hours', 'minutes']; - - function isValidDate(date) { - return date instanceof Date && !isNaN(date.getTime()); - } - - function getVisibleMinutes(date) { - console.time('getVisibleMinutes'); - date = new Date(date || new Date()); - date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours()); - var minutes = []; - var step = 5; - var stop = date.getTime() + 60 * 60 * 1000; - while (date.getTime() < stop) { - minutes.push(date); - date = new Date(date.getTime() + step * 60 * 1000); - } - console.timeEnd('getVisibleMinutes'); - return minutes; - } - - function getVisibleWeeks(date) { - console.time('getVisibleWeeks'); - date = new Date(date || new Date()); - date.setDate(1); - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - - if (date.getDay() === 0) { - date.setDate(-5); - } else { - date.setDate(date.getDate() - (date.getDay() - 1)); - } - if (date.getDate() === 1) { - date.setDate(-6); - } - - - var weeks = []; - while (weeks.length < 6) { - var week = []; - for (var i = 0; i < 7; i++) { - week.push(new Date(date)); - date.setDate(date.getDate() + 1); - } - weeks.push(week); - } - console.timeEnd('getVisibleWeeks'); - return weeks; - } - - - function getVisibleYears(date) { - console.time('getVisibleYears'); - var years = []; - date = new Date(date || new Date()); - date.setFullYear(date.getFullYear() - (date.getFullYear() % 10)); - for (var i = 0; i < 12; i++) { - years.push(new Date(date.getFullYear() + (i - 1), 0, 1)); - } - console.timeEnd('getVisibleYears'); - return years; - } - - function getDaysOfWeek(date) { - console.time('getDaysOfWeek'); - date = new Date(date || new Date()); - date = new Date(date.getFullYear(), date.getMonth(), date.getDate()); - date.setDate(date.getDate() - (date.getDay() - 1)); - var days = []; - for (var i = 0; i < 7; i++) { - days.push(new Date(date)); - date.setDate(date.getDate() + 1); - } - console.timeEnd('getDaysOfWeek'); - return days; - } - - function getVisibleMonths(date) { - console.time('getVisibleMonths'); - date = new Date(date || new Date()); - var year = date.getFullYear(); - var months = []; - for (var month = 0; month < 12; month++) { - months.push(new Date(year, month, 1)); - } - console.timeEnd('getVisibleMonths'); - return months; - } - - function getVisibleHours(date) { - console.time('getVisibleHours'); - date = new Date(date || new Date()); - date.setHours(0); - date.setMinutes(0); - date.setSeconds(0); - date.setMilliseconds(0); - var hours = []; - for (var i = 0; i < 24; i++) { - hours.push(date); - date = new Date(date.getTime() + 60 * 60 * 1000); - } - console.timeEnd('getVisibleHours'); - return hours; - } - - return { - scope : { - date : '=datePicker', - after : '=?', - before: '=?' - }, - link : function (scope, element, attrs) { - - scope.views = []; - for (var attr in attrs) { //noinspection JSUnfilteredForInLoop - if (viewOptions.indexOf(attr) !== -1) { //noinspection JSUnfilteredForInLoop - scope.views.push(attr); - } - } - if (!scope.views.length) { - scope.views = ['date', 'month', 'year', 'hours', 'minutes']; - } - scope.view = scope.views[0]; - - function hasView(view) { - return scope.views.indexOf(view) !== -1; - } - - function ensureDate() { - // we need to return new instance as ngModel $watch watches only for identity - not for equality - if (!(isValidDate(scope.date))) { - scope.date = new Date(2000, 1, 1); - } - scope.date = new Date(scope.date); - } - - function setYear(date) { - ensureDate(); - scope.date.setFullYear(date.getFullYear()); - } - - function setMonth(date) { - setYear(date); - scope.date.setMonth(date.getMonth()); - } - - function setDate(date) { - setMonth(date); - scope.date.setDate(date.getDate()); - } - - function setHours(date) { - setDate(date); - scope.date.setHours(date.getHours()); - } - - function setMinutes(date) { - setHours(date); - scope.date.setMinutes(date.getMinutes()); - } - - scope.setYear = function (date) { - setYear(date); - scope.$emit('setYear', date); - }; - - scope.setMonth = function (date) { - setMonth(date); - scope.$emit('setMonth', date); - }; - - scope.setDate = function (date) { - setDate(date); - scope.$emit('setDate', date); - }; - - scope.setHours = function (date) { - setHours(date); - scope.$emit('setHours', date); - }; - - scope.setMinutes = function (date) { - setMinutes(date); - scope.$emit('setMinutes', date); - }; - - scope.setView = function setView(view) { - if (hasView(view)) { - scope.view = view; - switch (view) { - case 'minutes': - scope.minutes = getVisibleMinutes(scope.visibleDate); - break; - case 'hours' : - scope.hours = getVisibleHours(scope.visibleDate); - break; - case 'date' : - scope.weeks = getVisibleWeeks(scope.visibleDate); - break; - case 'month' : - scope.months = getVisibleMonths(scope.visibleDate); - break; - case 'year' : - scope.years = getVisibleYears(scope.visibleDate); - break; - } - } - }; - - scope.nextMonth = function (delta) { - scope.visibleDate.setMonth(scope.visibleDate.getMonth() + (delta || 1)); - }; - - scope.prevMonth = function (delta) { - scope.nextMonth(-delta || -1); - }; - - scope.nextDay = function (delta) { - scope.visibleDate.setDate(scope.visibleDate.getDate() + (delta || 1)); - }; - - scope.prevDay = function (delta) { - scope.nextDay(-delta || -1); - }; - - scope.nextHour = function (delta) { - scope.visibleDate.setHours(scope.visibleDate.getHours() + (delta || 1)); - }; - - scope.prevHour = function (delta) { - scope.nextHour(-delta || -1); - }; - - scope.nextYear = function (delta) { - scope.visibleDate.setFullYear(scope.visibleDate.getFullYear() + (delta || 1)); - }; - scope.prevYear = function (delta) { - scope.nextYear(-delta || -1); - }; - - scope.visibleDate = new Date(); - - scope.$watch('date', function (date) { - if (date) { - scope.visibleDate = new Date(date); - } - }); - - scope.isAfter = function (date) { - return date >= scope.after; - }; - - scope.isBefore = function (date) { - return date <= scope.before; - }; - - function validDate() { - return scope.date instanceof Date; - } - - scope.isSameMinutes = function (date) { - if (!validDate()){ - return false; - } - var b = scope.date; - return (date.getTime() - date.getSeconds() * 1000 - date.getMilliseconds()) === (b.getTime() - b.getSeconds() * 1000 - b.getMilliseconds()); - }; - - scope.isSameMonth = function (date) { - if (!validDate()){ - return false; - } - return date.getFullYear() === scope.date.getFullYear() && date.getMonth() === scope.date.getMonth(); - }; - - scope.isSameYear = function (date) { - if (!validDate()){ - return false; - } - return date.getFullYear() === scope.date.getFullYear(); - }; - - scope.isSameDate = function (date) { - if (!validDate()){ - return false; - } - return scope.date.getDate() === date.getDate() && scope.isSameMonth(date); - }; - - scope.isSameHour = function (date) { - if (!validDate()){ - return false; - } - return scope.date.getHours() === date.getHours() && scope.isSameDate(date); - }; - - scope.isOldMonth = function (date) { - return date - .getTime() < scope.visibleDate.getTime() && date.getMonth() !== scope.visibleDate.getMonth(); - }; - - scope.isNewHour = function (date) { - return date.getTime() > scope.visibleDate.getTime() && date.getHours() !== scope.visibleDate.getHours(); - }; - - scope.isOldHour = function (date) { - return date.getTime() < scope.visibleDate.getTime() && date.getHours() !== scope.visibleDate.getHours(); - }; - - scope.isNewMonth = function (date) { - return date.getTime() > scope.visibleDate.getTime() && date.getMonth() !== scope.visibleDate.getMonth(); - }; - - - scope.$on('setDate', scope.setView.bind(null, 'hours')); - scope.$on('setMonth', scope.setView.bind(null, 'date')); - scope.$on('setHours', scope.setView.bind(null, 'minutes')); - scope.$on('setYear', scope.setView.bind(null, 'month')); - - scope.$watch(function () { - return isValidDate(scope.visibleDate); - }, function (valid) { - if (!valid) { - scope.visibleDate = new Date(); - } - }); - - //hours - scope.$watch('[visibleDate.getDate(),visibleDate.getHours()].join()', function () { - if (scope.view === 'hours') { - scope.hours = getVisibleHours(scope.visibleDate); - } - }); - //date - scope.$watch('[visibleDate.getFullYear(),visibleDate.getMonth(),visibleDate.getDate()].join()', function () { - if (scope.view === 'date') { - scope.weeks = getVisibleWeeks(scope.visibleDate); - scope.weekdays = getDaysOfWeek(scope.visibleDate); - } - }); - - scope.$watch('[visibleDate.getFullYear(),visibleDate.getMonth()].join()', function () { - if (scope.view === 'month') { - scope.months = getVisibleMonths(scope.visibleDate); - } - }); - - scope.$watch('visibleDate.getYear()', function () { - if (scope.view === 'year') { - scope.years = getVisibleYears(scope.visibleDate); - } - }); - - scope.$watch('visibleDate.getTime()', function () { - if (scope.view === 'minutes') { - scope.minutes = getVisibleMinutes(scope.visibleDate); - } - }); - - }, - transclude : true, - replace : true, - templateUrl: 'scripts/template.html' - }; - }); - - Module.directive('dateTime', function ($compile, $document, $filter) { - var body = $document.find('body'); - var dateFilter = $filter('date'); - return { - require: 'ngModel', - link : function (scope, element, attrs, ngModel) { - var format = attrs.format || 'yyyy-MM-dd HH:mm'; - - var viewsOptions = ['date', 'year', 'month', 'hours', 'minutes', 'month']; - var views = []; - for (var attr in attrs) { - //noinspection JSUnfilteredForInLoop - if (viewsOptions.indexOf(attr) !== -1) { //noinspection JSUnfilteredForInLoop - views.push(attr); - } - } - - function formatter(value) { - return dateFilter(value, format); - } - - ngModel.$formatters = [formatter]; - - var picker = null; - var clear = angular.noop; - - element.bind('focus', function () { - if (!picker) { - picker = $compile('')(scope); - body.append(picker); - scope.$digest(); - var pos = angular.extend({}, element.position(), { height: element[0].offsetHeight }); - picker.css({ top: pos.top + pos.height, left: pos.left, display: 'block', position: 'absolute'}); - picker.bind('mousedown', function () { - return false; - }); - } - return false; - }); - element.bind('blur', function () { - clear(); - clear = angular.noop; - if (picker){ - picker.remove(); - } - picker = null; - }); - } - }; - }); - - Module.directive('dateRange', function () { - return { - template: '
\n \n \n \n \n \n
\n \n \n
', - scope : { - start: '=', - end : '=' - }, - link : function (scope) { - scope.$watch('start.getTime()', function (value) { - if (value && scope.end && value > scope.end.getTime()) { - scope.end = new Date(value); - } - }); - scope.$watch('end.getTime()', function (value) { - if (value && scope.start && value < scope.start.getTime()) { - scope.start = new Date(value); - } - }); - } - }; - }); -})(); \ No newline at end of file diff --git a/app/scripts/template.html b/app/scripts/template.html deleted file mode 100644 index d2b7bd9..0000000 --- a/app/scripts/template.html +++ /dev/null @@ -1,125 +0,0 @@ -
-
- - - - - - - - - - - - - - - - - - - - - -
{{visibleDate|date:"yyyy MMMM"}}
{{ day|date:"EEE"}}
{{ day.getDate() }} -
-
-
- - - - - - - - - - - - - -
{{years[0].getFullYear()}}-{{years[years.length-1].getFullYear()}}
- {{year.getFullYear()}} -
-
- -
- - - - - - - - - - - - - - - - - - -
{{ visibleDate|date:"yyyy" }}
- {{month|date:'MMM'}} -
-
- -
- - - - - - - - - - - - - - - - - - -
{{ visibleDate|date:"dd MMMM yyyy" }}
- {{hour|date:"HH:mm"}} -
-
-
- - - - - - - - - - - - - - - - - - -
{{ visibleDate|date:"dd MMMM yyyy HH:mm" }} -
- {{minute|date:"HH:mm"}} -
-
-
\ No newline at end of file diff --git a/app/styles/date.css b/app/styles/date.css deleted file mode 100644 index f76a1a6..0000000 --- a/app/styles/date.css +++ /dev/null @@ -1,378 +0,0 @@ -/*! - * Datetimepicker for Bootstrap - * - * Copyright 2012 Stefan Petre - * Improvements by Andrew Rowls - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - */ - -.before.after:not(.active){ - background: #2f96b4 linear-gradient(to bottom, #5bc0de, #2f96b4) repeat-x; -} - -.next, .prev{ - font-size: 21px; -} -.datetimepicker table{ - table-layout: fixed; -} - -.datetimepicker { - padding: 4px; - margin-top: 1px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - direction: ltr; - /*.dow { - border-top: 1px solid #ddd !important; - }*/ - -} -.datetimepicker-inline { - width: 220px; -} -.datetimepicker.datetimepicker-rtl { - direction: rtl; -} -.datetimepicker.datetimepicker-rtl table tr td span { - float: right; -} -.datetimepicker-dropdown, .datetimepicker-dropdown-left { - top: 0; - left: 0; -} -[class*=" datetimepicker-dropdown"]:before { - content: ''; - display: inline-block; - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-bottom-color: rgba(0, 0, 0, 0.2); - position: absolute; -} -[class*=" datetimepicker-dropdown"]:after { - content: ''; - display: inline-block; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 6px solid #ffffff; - position: absolute; -} -[class*=" datetimepicker-dropdown-top"]:before { - content: ''; - display: inline-block; - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-top: 7px solid #ccc; - border-top-color: rgba(0, 0, 0, 0.2); - border-bottom: 0; -} -[class*=" datetimepicker-dropdown-top"]:after { - content: ''; - display: inline-block; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid #ffffff; - border-bottom: 0; -} -.datetimepicker-dropdown-bottom-right:before { - top: -7px; - right: 6px; -} -.datetimepicker-dropdown-bottom-right:after { - top: -6px; - right: 7px; -} -.datetimepicker-dropdown-bottom-left:before { - top: -7px; - left: 6px; -} -.datetimepicker-dropdown-bottom-left:after { - top: -6px; - left: 7px; -} -.datetimepicker-dropdown-top-right:before { - bottom: -7px; - right: 6px; -} -.datetimepicker-dropdown-top-right:after { - bottom: -6px; - right: 7px; -} -.datetimepicker-dropdown-top-left:before { - bottom: -7px; - left: 6px; -} -.datetimepicker-dropdown-top-left:after { - bottom: -6px; - left: 7px; -} -/*.datetimepicker > div {*/ - /*display: none;*/ -/*}*/ -.datetimepicker.minutes div.datetimepicker-minutes { - display: block; -} -.datetimepicker.hours div.datetimepicker-hours { - display: block; -} -.datetimepicker.days div.datetimepicker-days { - display: block; -} -.datetimepicker.months div.datetimepicker-months { - display: block; -} -.datetimepicker.years div.datetimepicker-years { - display: block; -} -.datetimepicker table { - margin: 0; -} -.datetimepicker td, -.datetimepicker th { - text-align: center; - width: 20px; - height: 20px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - border: none; -} -.table-striped .datetimepicker table tr td, -.table-striped .datetimepicker table tr th { - background-color: transparent; -} -.datetimepicker table tr td.minute:hover { - background: #eeeeee; - cursor: pointer; -} -.datetimepicker table tr td.hour:hover { - background: #eeeeee; - cursor: pointer; -} -.datetimepicker table tr td.day:hover { - background: #eeeeee; - cursor: pointer; -} -.datetimepicker table tr td.old, -.datetimepicker table tr td.new { - color: #999999; -} -.datetimepicker table tr td.disabled, -.datetimepicker table tr td.disabled:hover { - background: none; - color: #999999; - cursor: default; -} -.datetimepicker table tr td.today, -.datetimepicker table tr td.today:hover, -.datetimepicker table tr td.today.disabled, -.datetimepicker table tr td.today.disabled:hover { - background-color: #fde19a; - background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); - background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); - background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); - background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); - background-image: linear-gradient(top, #fdd49a, #fdf59a); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); - border-color: #fdf59a #fdf59a #fbed50; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} -.datetimepicker table tr td.today:hover, -.datetimepicker table tr td.today:hover:hover, -.datetimepicker table tr td.today.disabled:hover, -.datetimepicker table tr td.today.disabled:hover:hover, -.datetimepicker table tr td.today:active, -.datetimepicker table tr td.today:hover:active, -.datetimepicker table tr td.today.disabled:active, -.datetimepicker table tr td.today.disabled:hover:active, -.datetimepicker table tr td.today.active, -.datetimepicker table tr td.today:hover.active, -.datetimepicker table tr td.today.disabled.active, -.datetimepicker table tr td.today.disabled:hover.active, -.datetimepicker table tr td.today.disabled, -.datetimepicker table tr td.today:hover.disabled, -.datetimepicker table tr td.today.disabled.disabled, -.datetimepicker table tr td.today.disabled:hover.disabled, -.datetimepicker table tr td.today[disabled], -.datetimepicker table tr td.today:hover[disabled], -.datetimepicker table tr td.today.disabled[disabled], -.datetimepicker table tr td.today.disabled:hover[disabled] { - background-color: #fdf59a; -} -.datetimepicker table tr td.today:active, -.datetimepicker table tr td.today:hover:active, -.datetimepicker table tr td.today.disabled:active, -.datetimepicker table tr td.today.disabled:hover:active, -.datetimepicker table tr td.today.active, -.datetimepicker table tr td.today:hover.active, -.datetimepicker table tr td.today.disabled.active, -.datetimepicker table tr td.today.disabled:hover.active { - background-color: #fbf069 \9; -} -.datetimepicker table tr td.active, -.datetimepicker table tr td.active:hover, -.datetimepicker table tr td.active.disabled, -.datetimepicker table tr td.active.disabled:hover { - background-color: #006dcc; - background-image: -moz-linear-gradient(top, #0088cc, #0044cc); - background-image: -ms-linear-gradient(top, #0088cc, #0044cc); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); - background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); - background-image: -o-linear-gradient(top, #0088cc, #0044cc); - background-image: linear-gradient(top, #0088cc, #0044cc); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); - border-color: #0044cc #0044cc #002a80; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - color: #fff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); -} -.datetimepicker table tr td.active:hover, -.datetimepicker table tr td.active:hover:hover, -.datetimepicker table tr td.active.disabled:hover, -.datetimepicker table tr td.active.disabled:hover:hover, -.datetimepicker table tr td.active:active, -.datetimepicker table tr td.active:hover:active, -.datetimepicker table tr td.active.disabled:active, -.datetimepicker table tr td.active.disabled:hover:active, -.datetimepicker table tr td.active.active, -.datetimepicker table tr td.active:hover.active, -.datetimepicker table tr td.active.disabled.active, -.datetimepicker table tr td.active.disabled:hover.active, -.datetimepicker table tr td.active.disabled, -.datetimepicker table tr td.active:hover.disabled, -.datetimepicker table tr td.active.disabled.disabled, -.datetimepicker table tr td.active.disabled:hover.disabled, -.datetimepicker table tr td.active[disabled], -.datetimepicker table tr td.active:hover[disabled], -.datetimepicker table tr td.active.disabled[disabled], -.datetimepicker table tr td.active.disabled:hover[disabled] { - background-color: #0044cc; -} -.datetimepicker table tr td.active:active, -.datetimepicker table tr td.active:hover:active, -.datetimepicker table tr td.active.disabled:active, -.datetimepicker table tr td.active.disabled:hover:active, -.datetimepicker table tr td.active.active, -.datetimepicker table tr td.active:hover.active, -.datetimepicker table tr td.active.disabled.active, -.datetimepicker table tr td.active.disabled:hover.active { - background-color: #003399 \9; -} -.datetimepicker table tr td span { - display: block; - width: 23%; - height: 54px; - line-height: 54px; - float: left; - margin: 1%; - cursor: pointer; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.datetimepicker .datetimepicker-hours span { - height: 26px; - line-height: 26px; -} -.datetimepicker .datetimepicker-hours table tr td span.hour_am, -.datetimepicker .datetimepicker-hours table tr td span.hour_pm { - width: 14.6%; -} -.datetimepicker .datetimepicker-hours fieldset legend, -.datetimepicker .datetimepicker-minutes fieldset legend { - margin-bottom: inherit; - line-height: 30px; -} -.datetimepicker .datetimepicker-minutes span { - height: 26px; - line-height: 26px; -} -.datetimepicker table tr td span:hover { - background: #eeeeee; -} -.datetimepicker table tr td span.disabled, -.datetimepicker table tr td span.disabled:hover { - background: none; - color: #999999; - cursor: default; -} -.datetimepicker table tr td span.active, -.datetimepicker table tr td span.active:hover, -.datetimepicker table tr td span.active.disabled, -.datetimepicker table tr td span.active.disabled:hover { - background-color: #006dcc; - background-image: -moz-linear-gradient(top, #0088cc, #0044cc); - background-image: -ms-linear-gradient(top, #0088cc, #0044cc); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); - background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); - background-image: -o-linear-gradient(top, #0088cc, #0044cc); - background-image: linear-gradient(top, #0088cc, #0044cc); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); - border-color: #0044cc #0044cc #002a80; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - color: #fff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); -} -.datetimepicker table tr td span.active:hover, -.datetimepicker table tr td span.active:hover:hover, -.datetimepicker table tr td span.active.disabled:hover, -.datetimepicker table tr td span.active.disabled:hover:hover, -.datetimepicker table tr td span.active:active, -.datetimepicker table tr td span.active:hover:active, -.datetimepicker table tr td span.active.disabled:active, -.datetimepicker table tr td span.active.disabled:hover:active, -.datetimepicker table tr td span.active.active, -.datetimepicker table tr td span.active:hover.active, -.datetimepicker table tr td span.active.disabled.active, -.datetimepicker table tr td span.active.disabled:hover.active, -.datetimepicker table tr td span.active.disabled, -.datetimepicker table tr td span.active:hover.disabled, -.datetimepicker table tr td span.active.disabled.disabled, -.datetimepicker table tr td span.active.disabled:hover.disabled, -.datetimepicker table tr td span.active[disabled], -.datetimepicker table tr td span.active:hover[disabled], -.datetimepicker table tr td span.active.disabled[disabled], -.datetimepicker table tr td span.active.disabled:hover[disabled] { - background-color: #0044cc; -} -.datetimepicker table tr td span.active:active, -.datetimepicker table tr td span.active:hover:active, -.datetimepicker table tr td span.active.disabled:active, -.datetimepicker table tr td span.active.disabled:hover:active, -.datetimepicker table tr td span.active.active, -.datetimepicker table tr td span.active:hover.active, -.datetimepicker table tr td span.active.disabled.active, -.datetimepicker table tr td span.active.disabled:hover.active { - background-color: #003399 \9; -} -.datetimepicker table tr td span.old { - color: #999999; -} -.datetimepicker th.switch { - width: 145px; -} -.datetimepicker thead tr:first-child th, -.datetimepicker tfoot tr:first-child th { - cursor: pointer; -} -.datetimepicker thead tr:first-child th:hover, -.datetimepicker tfoot tr:first-child th:hover { - background: #eeeeee; -} -.input-append.date .add-on i, -.input-prepend.date .add-on i { - cursor: pointer; - width: 14px; - height: 14px; -} diff --git a/app/styles/mixins.less b/app/styles/mixins.less new file mode 100644 index 0000000..6e017ae --- /dev/null +++ b/app/styles/mixins.less @@ -0,0 +1,692 @@ +// +// Mixins +// -------------------------------------------------- + + +// UTILITY MIXINS +// -------------------------------------------------- + +// Clearfix +// -------- +// For clearing floats like a boss h5bp.com/q +.clearfix { + *zoom: 1; + &:before, + &:after { + display: table; + content: ""; + // Fixes Opera/contenteditable bug: + // http://nicolasgallagher.com/micro-clearfix-hack/#comment-36952 + line-height: 0; + } + &:after { + clear: both; + } +} + +// Webkit-style focus +// ------------------ +.tab-focus() { + // Default + outline: thin dotted #333; + // Webkit + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +// Center-align a block level element +// ---------------------------------- +.center-block() { + display: block; + margin-left: auto; + margin-right: auto; +} + +// IE7 inline-block +// ---------------- +.ie7-inline-block() { + *display: inline; /* IE7 inline-block hack */ + *zoom: 1; +} + +// IE7 likes to collapse whitespace on either side of the inline-block elements. +// Ems because we're attempting to match the width of a space character. Left +// version is for form buttons, which typically come after other elements, and +// right version is for icons, which come before. Applying both is ok, but it will +// mean that space between those elements will be .6em (~2 space characters) in IE7, +// instead of the 1 space in other browsers. +.ie7-restore-left-whitespace() { + *margin-left: .3em; + + &:first-child { + *margin-left: 0; + } +} + +.ie7-restore-right-whitespace() { + *margin-right: .3em; +} + +// Sizing shortcuts +// ------------------------- +.size(@height, @width) { + width: @width; + height: @height; +} +.square(@size) { + .size(@size, @size); +} + +// Placeholder text +// ------------------------- +.placeholder(@color: @placeholderText) { + &:-moz-placeholder { + color: @color; + } + &:-ms-input-placeholder { + color: @color; + } + &::-webkit-input-placeholder { + color: @color; + } +} + +// Text overflow +// ------------------------- +// Requires inline-block or block for proper styling +.text-overflow() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +// CSS image replacement +// ------------------------- +// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + + +// FONTS +// -------------------------------------------------- + +#font { + #family { + .serif() { + font-family: @serifFontFamily; + } + .sans-serif() { + font-family: @sansFontFamily; + } + .monospace() { + font-family: @monoFontFamily; + } + } + .shorthand(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + font-size: @size; + font-weight: @weight; + line-height: @lineHeight; + } + .serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .serif; + #font > .shorthand(@size, @weight, @lineHeight); + } + .sans-serif(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .sans-serif; + #font > .shorthand(@size, @weight, @lineHeight); + } + .monospace(@size: @baseFontSize, @weight: normal, @lineHeight: @baseLineHeight) { + #font > #family > .monospace; + #font > .shorthand(@size, @weight, @lineHeight); + } +} + + +// FORMS +// -------------------------------------------------- + +// Block level inputs +.input-block-level { + display: block; + width: 100%; + min-height: @inputHeight; // Make inputs at least the height of their button counterpart (base line-height + padding + border) + .box-sizing(border-box); // Makes inputs behave like true block-level elements +} + + + +// Mixin for form field states +.formFieldState(@textColor: #555, @borderColor: #ccc, @backgroundColor: #f5f5f5) { + // Set the text color + .control-label, + .help-block, + .help-inline { + color: @textColor; + } + // Style inputs accordingly + .checkbox, + .radio, + input, + select, + textarea { + color: @textColor; + } + input, + select, + textarea { + border-color: @borderColor; + .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work + &:focus { + border-color: darken(@borderColor, 10%); + @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@borderColor, 20%); + .box-shadow(@shadow); + } + } + // Give a small background color for input-prepend/-append + .input-prepend .add-on, + .input-append .add-on { + color: @textColor; + background-color: @backgroundColor; + border-color: @textColor; + } +} + + + +// CSS3 PROPERTIES +// -------------------------------------------------- + +// Border Radius +.border-radius(@radius) { + -webkit-border-radius: @radius; + -moz-border-radius: @radius; + border-radius: @radius; +} + +// Single Corner Border Radius +.border-top-left-radius(@radius) { + -webkit-border-top-left-radius: @radius; + -moz-border-radius-topleft: @radius; + border-top-left-radius: @radius; +} +.border-top-right-radius(@radius) { + -webkit-border-top-right-radius: @radius; + -moz-border-radius-topright: @radius; + border-top-right-radius: @radius; +} +.border-bottom-right-radius(@radius) { + -webkit-border-bottom-right-radius: @radius; + -moz-border-radius-bottomright: @radius; + border-bottom-right-radius: @radius; +} +.border-bottom-left-radius(@radius) { + -webkit-border-bottom-left-radius: @radius; + -moz-border-radius-bottomleft: @radius; + border-bottom-left-radius: @radius; +} + +// Single Side Border Radius +.border-top-radius(@radius) { + .border-top-right-radius(@radius); + .border-top-left-radius(@radius); +} +.border-right-radius(@radius) { + .border-top-right-radius(@radius); + .border-bottom-right-radius(@radius); +} +.border-bottom-radius(@radius) { + .border-bottom-right-radius(@radius); + .border-bottom-left-radius(@radius); +} +.border-left-radius(@radius) { + .border-top-left-radius(@radius); + .border-bottom-left-radius(@radius); +} + +// Drop shadows +.box-shadow(@shadow) { + -webkit-box-shadow: @shadow; + -moz-box-shadow: @shadow; + box-shadow: @shadow; +} + +// Transitions +.transition(@transition) { + -webkit-transition: @transition; + -moz-transition: @transition; + -o-transition: @transition; + transition: @transition; +} +.transition-delay(@transition-delay) { + -webkit-transition-delay: @transition-delay; + -moz-transition-delay: @transition-delay; + -o-transition-delay: @transition-delay; + transition-delay: @transition-delay; +} + +// Transformations +.rotate(@degrees) { + -webkit-transform: rotate(@degrees); + -moz-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} +.scale(@ratio) { + -webkit-transform: scale(@ratio); + -moz-transform: scale(@ratio); + -ms-transform: scale(@ratio); + -o-transform: scale(@ratio); + transform: scale(@ratio); +} +.translate(@x, @y) { + -webkit-transform: translate(@x, @y); + -moz-transform: translate(@x, @y); + -ms-transform: translate(@x, @y); + -o-transform: translate(@x, @y); + transform: translate(@x, @y); +} +.skew(@x, @y) { + -webkit-transform: skew(@x, @y); + -moz-transform: skew(@x, @y); + -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twitter/bootstrap/issues/4885 + -o-transform: skew(@x, @y); + transform: skew(@x, @y); + -webkit-backface-visibility: hidden; // See https://github.com/twitter/bootstrap/issues/5319 +} +.translate3d(@x, @y, @z) { + -webkit-transform: translate3d(@x, @y, @z); + -moz-transform: translate3d(@x, @y, @z); + -o-transform: translate3d(@x, @y, @z); + transform: translate3d(@x, @y, @z); +} + +// Backface visibility +// Prevent browsers from flickering when using CSS 3D transforms. +// Default value is `visible`, but can be changed to `hidden +// See git pull https://github.com/dannykeane/bootstrap.git backface-visibility for examples +.backface-visibility(@visibility){ + -webkit-backface-visibility: @visibility; + -moz-backface-visibility: @visibility; + backface-visibility: @visibility; +} + +// Background clipping +// Heads up: FF 3.6 and under need "padding" instead of "padding-box" +.background-clip(@clip) { + -webkit-background-clip: @clip; + -moz-background-clip: @clip; + background-clip: @clip; +} + +// Background sizing +.background-size(@size) { + -webkit-background-size: @size; + -moz-background-size: @size; + -o-background-size: @size; + background-size: @size; +} + + +// Box sizing +.box-sizing(@boxmodel) { + -webkit-box-sizing: @boxmodel; + -moz-box-sizing: @boxmodel; + box-sizing: @boxmodel; +} + +// User select +// For selecting text on the page +.user-select(@select) { + -webkit-user-select: @select; + -moz-user-select: @select; + -ms-user-select: @select; + -o-user-select: @select; + user-select: @select; +} + +// Resize anything +.resizable(@direction) { + resize: @direction; // Options: horizontal, vertical, both + overflow: auto; // Safari fix +} + +// CSS3 Content Columns +.content-columns(@columnCount, @columnGap: @gridGutterWidth) { + -webkit-column-count: @columnCount; + -moz-column-count: @columnCount; + column-count: @columnCount; + -webkit-column-gap: @columnGap; + -moz-column-gap: @columnGap; + column-gap: @columnGap; +} + +// Optional hyphenation +.hyphens(@mode: auto) { + word-wrap: break-word; + -webkit-hyphens: @mode; + -moz-hyphens: @mode; + -ms-hyphens: @mode; + -o-hyphens: @mode; + hyphens: @mode; +} + +// Opacity +.opacity(@opacity) { + opacity: @opacity / 100; + filter: ~"alpha(opacity=@{opacity})"; +} + + + +// BACKGROUNDS +// -------------------------------------------------- + +// Add an alphatransparency value to any background or border color (via Elyse Holladay) +#translucent { + .background(@color: @white, @alpha: 1) { + background-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); + } + .border(@color: @white, @alpha: 1) { + border-color: hsla(hue(@color), saturation(@color), lightness(@color), @alpha); + .background-clip(padding-box); + } +} + +// Gradient Bar Colors for buttons and alerts +.gradientBar(@primaryColor, @secondaryColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) { + color: @textColor; + text-shadow: @textShadow; + #gradient > .vertical(@primaryColor, @secondaryColor); + border-color: @secondaryColor @secondaryColor darken(@secondaryColor, 15%); + border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fadein(rgba(0,0,0,.1), 15%); +} + +// Gradients +#gradient { + .horizontal(@startColor: #555, @endColor: #333) { + background-color: @endColor; + background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to right, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@startColor),argb(@endColor))); // IE9 and down + } + .vertical(@startColor: #555, @endColor: #333) { + background-color: mix(@startColor, @endColor, 60%); + background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down + } + .directional(@startColor: #555, @endColor: #333, @deg: 45deg) { + background-color: @endColor; + background-repeat: repeat-x; + background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(@deg, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(@deg, @startColor, @endColor); // Standard, IE10 + } + .vertical-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) { + background-color: mix(@midColor, @endColor, 80%); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor)); + background-image: -webkit-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: -moz-linear-gradient(top, @startColor, @midColor @colorStop, @endColor); + background-image: -o-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback + } + .radial(@innerColor: #555, @outerColor: #333) { + background-color: @outerColor; + background-image: -webkit-gradient(radial, center center, 0, center center, 460, from(@innerColor), to(@outerColor)); + background-image: -webkit-radial-gradient(circle, @innerColor, @outerColor); + background-image: -moz-radial-gradient(circle, @innerColor, @outerColor); + background-image: -o-radial-gradient(circle, @innerColor, @outerColor); + background-repeat: no-repeat; + } + .striped(@color: #555, @angle: 45deg) { + background-color: @color; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + } +} +// Reset filters for IE +.reset-filter() { + filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); +} + + + +// COMPONENT MIXINS +// -------------------------------------------------- + +// Horizontal dividers +// ------------------------- +// Dividers (basically an hr) within dropdowns and nav lists +.nav-divider(@top: #e5e5e5, @bottom: @white) { + // IE7 needs a set width since we gave a height. Restricting just + // to IE7 to keep the 1px left/right space in other browsers. + // It is unclear where IE is getting the extra space that we need + // to negative-margin away, but so it goes. + *width: 100%; + height: 1px; + margin: ((@baseLineHeight / 2) - 1) 1px; // 8px 1px + *margin: -5px 0 5px; + overflow: hidden; + background-color: @top; + border-bottom: 1px solid @bottom; +} + +// Button backgrounds +// ------------------ +.buttonBackground(@startColor, @endColor, @textColor: #fff, @textShadow: 0 -1px 0 rgba(0,0,0,.25)) { + // gradientBar will set the background to a pleasing blend of these, to support IE<=9 + .gradientBar(@startColor, @endColor, @textColor, @textShadow); + *background-color: @endColor; /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + .reset-filter(); + + // in these cases the gradient won't cover the background, so we override + &:hover, &:active, &.active, &.disabled, &[disabled] { + color: @textColor; + background-color: @endColor; + *background-color: darken(@endColor, 5%); + } + + // IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves + &:active, + &.active { + background-color: darken(@endColor, 10%) e("\9"); + } +} + +// Navbar vertical align +// ------------------------- +// Vertically center elements in the navbar. +// Example: an element has a height of 30px, so write out `.navbarVerticalAlign(30px);` to calculate the appropriate top margin. +.navbarVerticalAlign(@elementHeight) { + margin-top: (@navbarHeight - @elementHeight) / 2; +} + + + +// Grid System +// ----------- + +// Centered container element +.container-fixed() { + margin-right: auto; + margin-left: auto; + .clearfix(); +} + +// Table columns +.tableColumns(@columnSpan: 1) { + float: none; // undo default grid column styles + width: ((@gridColumnWidth) * @columnSpan) + (@gridGutterWidth * (@columnSpan - 1)) - 16; // 16 is total padding on left and right of table cells + margin-left: 0; // undo default grid column styles +} + +// Make a Grid +// Use .makeRow and .makeColumn to assign semantic layouts grid system behavior +.makeRow() { + margin-left: @gridGutterWidth * -1; + .clearfix(); +} +.makeColumn(@columns: 1, @offset: 0) { + float: left; + margin-left: (@gridColumnWidth * @offset) + (@gridGutterWidth * (@offset - 1)) + (@gridGutterWidth * 2); + width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1)); +} + +// The Grid +#grid { + + .core (@gridColumnWidth, @gridGutterWidth) { + + .spanX (@index) when (@index > 0) { + (.span@{index}) { .span(@index); } + .spanX(@index - 1); + } + .spanX (0) {} + + .offsetX (@index) when (@index > 0) { + (.offset@{index}) { .offset(@index); } + .offsetX(@index - 1); + } + .offsetX (0) {} + + .offset (@columns) { + margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns + 1)); + } + + .span (@columns) { + width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1)); + } + + .row { + margin-left: @gridGutterWidth * -1; + .clearfix(); + } + + [class*="span"] { + float: left; + min-height: 1px; // prevent collapsing columns + margin-left: @gridGutterWidth; + } + + // Set the container width, and override it for fixed navbars in media queries + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { .span(@gridColumns); } + + // generate .spanX and .offsetX + .spanX (@gridColumns); + .offsetX (@gridColumns); + + } + + .fluid (@fluidGridColumnWidth, @fluidGridGutterWidth) { + + .spanX (@index) when (@index > 0) { + (.span@{index}) { .span(@index); } + .spanX(@index - 1); + } + .spanX (0) {} + + .offsetX (@index) when (@index > 0) { + (.offset@{index}) { .offset(@index); } + (.offset@{index}:first-child) { .offsetFirstChild(@index); } + .offsetX(@index - 1); + } + .offsetX (0) {} + + .offset (@columns) { + margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth*2); + *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + (@fluidGridGutterWidth*2) - (.5 / @gridRowWidth * 100 * 1%); + } + + .offsetFirstChild (@columns) { + margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth); + *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%); + } + + .span (@columns) { + width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)); + *width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%); + } + + .row-fluid { + width: 100%; + .clearfix(); + [class*="span"] { + .input-block-level(); + float: left; + margin-left: @fluidGridGutterWidth; + *margin-left: @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%); + } + [class*="span"]:first-child { + margin-left: 0; + } + + // Space grid-sized controls properly if multiple per line + .controls-row [class*="span"] + [class*="span"] { + margin-left: @fluidGridGutterWidth; + } + + // generate .spanX and .offsetX + .spanX (@gridColumns); + .offsetX (@gridColumns); + } + + } + + .input(@gridColumnWidth, @gridGutterWidth) { + .spanX (@index) when (@index > 0) { + /* FIXME: thomas: this line provokes less compilation errors, so I + /* broke it up in three lines + (input.span@{index}, textarea.span@{index}, .uneditable-input.span@{index}) { .span(@index); } + */ + input.span@{index} { .span(@index); } + textarea.span@{index} { .span(@index); } + .uneditable-input.span@{index} { .span(@index); } + + .spanX(@index - 1); + } + .spanX (0) {} + + .span(@columns) { + width: ((@gridColumnWidth) * @columns) + (@gridGutterWidth * (@columns - 1)) - 14; + } + + input, + textarea, + .uneditable-input { + margin-left: 0; // override margin-left from core grid system + } + + // Space grid-sized controls properly if multiple per line + .controls-row [class*="span"] + [class*="span"] { + margin-left: @gridGutterWidth; + } + + // generate .spanX + .spanX (@gridColumns); + + } + +} diff --git a/app/styles/style.less b/app/styles/style.less new file mode 100644 index 0000000..3579b09 --- /dev/null +++ b/app/styles/style.less @@ -0,0 +1,108 @@ +@import "variables.less"; +@import "mixins.less"; + +[date-picker-wrapper]{ + position: relative !important; + display:block; +} + +[date-time-append] [date-picker]{ + position: relative; + margin-right: -1000px; + margin-bottom: -1000px; +} + +[date-range] [date-picker] { + .after.before{ + .buttonBackground(@btnInfoBackground, spin(@btnInfoBackgroundHighlight, 20)); + } +} + +[date-picker].hidden { display: none; } + +[date-picker] { + .user-select(none); + .border-radius(4px); + + /* GENERAL */ + + padding: 4px; + + table { + margin: 0; + } + + td, th { + padding: 4px 5px; + text-align: center; + width: 20px; + height: 20px; + .border-radius(4px); + border: none; + + } + + .switch{ + width: 145px; + } + + span { + display: block; + width: 23%; + height: 26px; + line-height: 25px; + float: left; + margin: 1%; + cursor: pointer; + .border-radius(4px); + &:hover { + background: @grayLighter; + } + &.disabled, &.disabled:hover { + background:none; + color: @grayLight; + cursor: default; + } + + } + + .active , .now{ + .buttonBackground(@btnPrimaryBackground, spin(@btnPrimaryBackground, 20)); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); + } + + .now { + .buttonBackground(@btnDangerBackground, spin(@btnDangerBackground, 20)); + } + + .disabled { + background: none; + color: #999999 !important; + cursor: default; + } + + /* SPECIFIC */ + + [ng-switch-when="year"], [ng-switch-when="month"], [ng-switch-when="minutes"]{ + span { + height: 54px; + line-height: 54px; + } + } + [ng-switch-when="date"]{ + td { + padding: 0; + } + span{ + width: 100%; + height: 26px; + line-height: 26px; + } + } + + th:hover, [ng-switch-when="date"] td span:hover{ + background: @grayLighter; + cursor: pointer; + } +} diff --git a/app/styles/variables.less b/app/styles/variables.less new file mode 100644 index 0000000..de36074 --- /dev/null +++ b/app/styles/variables.less @@ -0,0 +1,301 @@ +// +// Variables +// -------------------------------------------------- + + +// Global values +// -------------------------------------------------- + + +// Grays +// ------------------------- +@black: #000; +@grayDarker: #222; +@grayDark: #333; +@gray: #555; +@grayLight: #999; +@grayLighter: #eee; +@white: #fff; + + +// Accent colors +// ------------------------- +@blue: #049cdb; +@blueDark: #0064cd; +@green: #46a546; +@red: #9d261d; +@yellow: #ffc40d; +@orange: #f89406; +@pink: #c3325f; +@purple: #7a43b6; + + +// Scaffolding +// ------------------------- +@bodyBackground: @white; +@textColor: @grayDark; + + +// Links +// ------------------------- +@linkColor: #08c; +@linkColorHover: darken(@linkColor, 15%); + + +// Typography +// ------------------------- +@sansFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif; +@serifFontFamily: Georgia, "Times New Roman", Times, serif; +@monoFontFamily: Monaco, Menlo, Consolas, "Courier New", monospace; + +@baseFontSize: 14px; +@baseFontFamily: @sansFontFamily; +@baseLineHeight: 20px; +@altFontFamily: @serifFontFamily; + +@headingsFontFamily: inherit; // empty to use BS default, @baseFontFamily +@headingsFontWeight: bold; // instead of browser default, bold +@headingsColor: inherit; // empty to use BS default, @textColor + + +// Component sizing +// ------------------------- +// Based on 14px font-size and 20px line-height + +@fontSizeLarge: @baseFontSize * 1.25; // ~18px +@fontSizeSmall: @baseFontSize * 0.85; // ~12px +@fontSizeMini: @baseFontSize * 0.75; // ~11px + +@paddingLarge: 11px 19px; // 44px +@paddingSmall: 2px 10px; // 26px +@paddingMini: 0 6px; // 22px + +@baseBorderRadius: 4px; +@borderRadiusLarge: 6px; +@borderRadiusSmall: 3px; + + +// Tables +// ------------------------- +@tableBackground: transparent; // overall background-color +@tableBackgroundAccent: #f9f9f9; // for striping +@tableBackgroundHover: #f5f5f5; // for hover +@tableBorder: #ddd; // table and cell border + +// Buttons +// ------------------------- +@btnBackground: @white; +@btnBackgroundHighlight: darken(@white, 10%); +@btnBorder: #bbb; + +@btnPrimaryBackground: @linkColor; +@btnPrimaryBackgroundHighlight: spin(@btnPrimaryBackground, 20%); + +@btnInfoBackground: #5bc0de; +@btnInfoBackgroundHighlight: #2f96b4; + +@btnSuccessBackground: #62c462; +@btnSuccessBackgroundHighlight: #51a351; + +@btnWarningBackground: lighten(@orange, 15%); +@btnWarningBackgroundHighlight: @orange; + +@btnDangerBackground: #ee5f5b; +@btnDangerBackgroundHighlight: #bd362f; + +@btnInverseBackground: #444; +@btnInverseBackgroundHighlight: @grayDarker; + + +// Forms +// ------------------------- +@inputBackground: @white; +@inputBorder: #ccc; +@inputBorderRadius: @baseBorderRadius; +@inputDisabledBackground: @grayLighter; +@formActionsBackground: #f5f5f5; +@inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border + + +// Dropdowns +// ------------------------- +@dropdownBackground: @white; +@dropdownBorder: rgba(0,0,0,.2); +@dropdownDividerTop: #e5e5e5; +@dropdownDividerBottom: @white; + +@dropdownLinkColor: @grayDark; +@dropdownLinkColorHover: @white; +@dropdownLinkColorActive: @white; + +@dropdownLinkBackgroundActive: @linkColor; +@dropdownLinkBackgroundHover: @dropdownLinkBackgroundActive; + + + +// COMPONENT VARIABLES +// -------------------------------------------------- + + +// Z-index master list +// ------------------------- +// Used for a bird's eye view of components dependent on the z-axis +// Try to avoid customizing these :) +@zindexDropdown: 1000; +@zindexPopover: 1010; +@zindexTooltip: 1030; +@zindexFixedNavbar: 1030; +@zindexModalBackdrop: 1040; +@zindexModal: 1050; + + +// Sprite icons path +// ------------------------- +@iconSpritePath: "../img/glyphicons-halflings.png"; +@iconWhiteSpritePath: "../img/glyphicons-halflings-white.png"; + + +// Input placeholder text color +// ------------------------- +@placeholderText: @grayLight; + + +// Hr border color +// ------------------------- +@hrBorder: @grayLighter; + + +// Horizontal forms & lists +// ------------------------- +@horizontalComponentOffset: 180px; + + +// Wells +// ------------------------- +@wellBackground: #f5f5f5; + + +// Navbar +// ------------------------- +@navbarCollapseWidth: 979px; +@navbarCollapseDesktopWidth: @navbarCollapseWidth + 1; + +@navbarHeight: 40px; +@navbarBackgroundHighlight: #ffffff; +@navbarBackground: darken(@navbarBackgroundHighlight, 5%); +@navbarBorder: darken(@navbarBackground, 12%); + +@navbarText: #777; +@navbarLinkColor: #777; +@navbarLinkColorHover: @grayDark; +@navbarLinkColorActive: @gray; +@navbarLinkBackgroundHover: transparent; +@navbarLinkBackgroundActive: darken(@navbarBackground, 5%); + +@navbarBrandColor: @navbarLinkColor; + +// Inverted navbar +@navbarInverseBackground: #111111; +@navbarInverseBackgroundHighlight: #222222; +@navbarInverseBorder: #252525; + +@navbarInverseText: @grayLight; +@navbarInverseLinkColor: @grayLight; +@navbarInverseLinkColorHover: @white; +@navbarInverseLinkColorActive: @navbarInverseLinkColorHover; +@navbarInverseLinkBackgroundHover: transparent; +@navbarInverseLinkBackgroundActive: @navbarInverseBackground; + +@navbarInverseSearchBackground: lighten(@navbarInverseBackground, 25%); +@navbarInverseSearchBackgroundFocus: @white; +@navbarInverseSearchBorder: @navbarInverseBackground; +@navbarInverseSearchPlaceholderColor: #ccc; + +@navbarInverseBrandColor: @navbarInverseLinkColor; + + +// Pagination +// ------------------------- +@paginationBackground: #fff; +@paginationBorder: #ddd; +@paginationActiveBackground: #f5f5f5; + + +// Hero unit +// ------------------------- +@heroUnitBackground: @grayLighter; +@heroUnitHeadingColor: inherit; +@heroUnitLeadColor: inherit; + + +// Form states and alerts +// ------------------------- +@warningText: #c09853; +@warningBackground: #fcf8e3; +@warningBorder: darken(spin(@warningBackground, -10), 3%); + +@errorText: #b94a48; +@errorBackground: #f2dede; +@errorBorder: darken(spin(@errorBackground, -10), 3%); + +@successText: #468847; +@successBackground: #dff0d8; +@successBorder: darken(spin(@successBackground, -10), 5%); + +@infoText: #3a87ad; +@infoBackground: #d9edf7; +@infoBorder: darken(spin(@infoBackground, -10), 7%); + + +// Tooltips and popovers +// ------------------------- +@tooltipColor: #fff; +@tooltipBackground: #000; +@tooltipArrowWidth: 5px; +@tooltipArrowColor: @tooltipBackground; + +@popoverBackground: #fff; +@popoverArrowWidth: 10px; +@popoverArrowColor: #fff; +@popoverTitleBackground: darken(@popoverBackground, 3%); + +// Special enhancement for popovers +@popoverArrowOuterWidth: @popoverArrowWidth + 1; +@popoverArrowOuterColor: rgba(0,0,0,.25); + + + +// GRID +// -------------------------------------------------- + + +// Default 940px grid +// ------------------------- +@gridColumns: 12; +@gridColumnWidth: 60px; +@gridGutterWidth: 20px; +@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1)); + +// 1200px min +@gridColumnWidth1200: 70px; +@gridGutterWidth1200: 30px; +@gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1)); + +// 768px-979px +@gridColumnWidth768: 42px; +@gridGutterWidth768: 20px; +@gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1)); + + +// Fluid grid +// ------------------------- +@fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth); +@fluidGridGutterWidth: percentage(@gridGutterWidth/@gridRowWidth); + +// 1200px min +@fluidGridColumnWidth1200: percentage(@gridColumnWidth1200/@gridRowWidth1200); +@fluidGridGutterWidth1200: percentage(@gridGutterWidth1200/@gridRowWidth1200); + +// 768px-979px +@fluidGridColumnWidth768: percentage(@gridColumnWidth768/@gridRowWidth768); +@fluidGridGutterWidth768: percentage(@gridGutterWidth768/@gridRowWidth768); diff --git a/app/templates/datepicker.html b/app/templates/datepicker.html new file mode 100644 index 0000000..f6c9c73 --- /dev/null +++ b/app/templates/datepicker.html @@ -0,0 +1,108 @@ +
+
+ + + + + + + + + + + + + + + + +
{{date|date:"yyyy MMMM"}}
{{ day|date:"EEE" }}
+ +
+
+
+ + + + + + + + + + + + + +
{{years[0].getFullYear()}}-{{years[years.length-1].getFullYear()}}
+ +
+
+
+ + + + + + + + + + + + + +
{{ date|date:"yyyy" }}
+ +
+
+
+ + + + + + + + + + + + + +
{{ date|date:"dd MMMM yyyy" }}
+ +
+
+
+ + + + + + + + + + + + + +
{{ date|date:"dd MMMM yyyy" }} +
+ +
+
+
diff --git a/app/templates/daterange.html b/app/templates/daterange.html new file mode 100644 index 0000000..bdbb6ed --- /dev/null +++ b/app/templates/daterange.html @@ -0,0 +1,12 @@ +
+ + + + + +
+
+
+
+
+
diff --git a/bower.json b/bower.json index 706f5a4..6bd0ab3 100644 --- a/bower.json +++ b/bower.json @@ -1,19 +1,19 @@ { "name": "angular-datepicker", - "main": ["dist/module.min.js","dist/date.min.css"], "license": "MIT", - "version": "0.0.1", + "version": "1.0.0", + "main": [ + "./dist/index.js", + "./dist/index.css" + ], "ignore": [ - "**/.*" + ".gitignore","README.md" ], "dependencies": {}, "devDependencies": { - "angular": "~1.0.5", - "json3": "~3.2.4", - "es5-shim": "~2.0.8", - "jquery": "~2.0.2", - "angular-mocks": "~1.0.5", - "angular-scenario": "~1.0.5", + "angular": "1.2.14", + "angular-mocks": "1.2.14", + "angular-scenario": "1.2.14", "angular-bootstrap": "~0.3.0" } } diff --git a/component.json b/component.json deleted file mode 100644 index 3ac71d5..0000000 --- a/component.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "dateInput", - "version": "0.0.0", - "dependencies": { - "angular": "~1.0.5", - "json3": "~3.2.4", - "es5-shim": "~2.0.8" - }, - "devDependencies": { - "angular-mocks": "~1.0.5", - "angular-scenario": "~1.0.5" - } -} diff --git a/dist/index.css b/dist/index.css index f76a1a6..e8296a1 100644 --- a/dist/index.css +++ b/dist/index.css @@ -1,138 +1,91 @@ -/*! - * Datetimepicker for Bootstrap - * - * Copyright 2012 Stefan Petre - * Improvements by Andrew Rowls - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - */ - -.before.after:not(.active){ - background: #2f96b4 linear-gradient(to bottom, #5bc0de, #2f96b4) repeat-x; +.clearfix { + *zoom: 1; +} +.clearfix:before, +.clearfix:after { + display: table; + content: ""; + line-height: 0; +} +.clearfix:after { + clear: both; +} +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; } - -.next, .prev{ - font-size: 21px; +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +[date-picker-wrapper] { + position: relative !important; + display: block; } -.datetimepicker table{ - table-layout: fixed; +[date-time-append] [date-picker] { + position: relative; + margin-right: -1000px; + margin-bottom: -1000px; } - -.datetimepicker { - padding: 4px; - margin-top: 1px; +[date-range] [date-picker] .after.before { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #499dcd; + background-image: -moz-linear-gradient(top, #5bc0de, #2f6ab4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f6ab4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f6ab4); + background-image: -o-linear-gradient(top, #5bc0de, #2f6ab4); + background-image: linear-gradient(to bottom, #5bc0de, #2f6ab4); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f6ab4', GradientType=0); + border-color: #2f6ab4 #2f6ab4 #1f4677; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #2f6ab4; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +[date-range] [date-picker] .after.before:hover, +[date-range] [date-picker] .after.before:active, +[date-range] [date-picker] .after.before.active, +[date-range] [date-picker] .after.before.disabled, +[date-range] [date-picker] .after.before[disabled] { + color: #ffffff; + background-color: #2f6ab4; + *background-color: #2a5ea0; +} +[date-range] [date-picker] .after.before:active, +[date-range] [date-picker] .after.before.active { + background-color: #24528c \9; +} +[date-picker].hidden { + display: none; +} +[date-picker] { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; - direction: ltr; - /*.dow { - border-top: 1px solid #ddd !important; - }*/ - -} -.datetimepicker-inline { - width: 220px; -} -.datetimepicker.datetimepicker-rtl { - direction: rtl; -} -.datetimepicker.datetimepicker-rtl table tr td span { - float: right; -} -.datetimepicker-dropdown, .datetimepicker-dropdown-left { - top: 0; - left: 0; -} -[class*=" datetimepicker-dropdown"]:before { - content: ''; - display: inline-block; - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-bottom-color: rgba(0, 0, 0, 0.2); - position: absolute; -} -[class*=" datetimepicker-dropdown"]:after { - content: ''; - display: inline-block; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 6px solid #ffffff; - position: absolute; -} -[class*=" datetimepicker-dropdown-top"]:before { - content: ''; - display: inline-block; - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-top: 7px solid #ccc; - border-top-color: rgba(0, 0, 0, 0.2); - border-bottom: 0; -} -[class*=" datetimepicker-dropdown-top"]:after { - content: ''; - display: inline-block; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid #ffffff; - border-bottom: 0; -} -.datetimepicker-dropdown-bottom-right:before { - top: -7px; - right: 6px; -} -.datetimepicker-dropdown-bottom-right:after { - top: -6px; - right: 7px; -} -.datetimepicker-dropdown-bottom-left:before { - top: -7px; - left: 6px; -} -.datetimepicker-dropdown-bottom-left:after { - top: -6px; - left: 7px; -} -.datetimepicker-dropdown-top-right:before { - bottom: -7px; - right: 6px; -} -.datetimepicker-dropdown-top-right:after { - bottom: -6px; - right: 7px; -} -.datetimepicker-dropdown-top-left:before { - bottom: -7px; - left: 6px; -} -.datetimepicker-dropdown-top-left:after { - bottom: -6px; - left: 7px; -} -/*.datetimepicker > div {*/ - /*display: none;*/ -/*}*/ -.datetimepicker.minutes div.datetimepicker-minutes { - display: block; -} -.datetimepicker.hours div.datetimepicker-hours { - display: block; -} -.datetimepicker.days div.datetimepicker-days { - display: block; -} -.datetimepicker.months div.datetimepicker-months { - display: block; -} -.datetimepicker.years div.datetimepicker-years { - display: block; + /* GENERAL */ + padding: 4px; + /* SPECIFIC */ } -.datetimepicker table { +[date-picker] table { margin: 0; } -.datetimepicker td, -.datetimepicker th { +[date-picker] td, +[date-picker] th { + padding: 4px 5px; text-align: center; width: 20px; height: 20px; @@ -141,137 +94,14 @@ border-radius: 4px; border: none; } -.table-striped .datetimepicker table tr td, -.table-striped .datetimepicker table tr th { - background-color: transparent; -} -.datetimepicker table tr td.minute:hover { - background: #eeeeee; - cursor: pointer; -} -.datetimepicker table tr td.hour:hover { - background: #eeeeee; - cursor: pointer; -} -.datetimepicker table tr td.day:hover { - background: #eeeeee; - cursor: pointer; -} -.datetimepicker table tr td.old, -.datetimepicker table tr td.new { - color: #999999; -} -.datetimepicker table tr td.disabled, -.datetimepicker table tr td.disabled:hover { - background: none; - color: #999999; - cursor: default; -} -.datetimepicker table tr td.today, -.datetimepicker table tr td.today:hover, -.datetimepicker table tr td.today.disabled, -.datetimepicker table tr td.today.disabled:hover { - background-color: #fde19a; - background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); - background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); - background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); - background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); - background-image: linear-gradient(top, #fdd49a, #fdf59a); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); - border-color: #fdf59a #fdf59a #fbed50; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} -.datetimepicker table tr td.today:hover, -.datetimepicker table tr td.today:hover:hover, -.datetimepicker table tr td.today.disabled:hover, -.datetimepicker table tr td.today.disabled:hover:hover, -.datetimepicker table tr td.today:active, -.datetimepicker table tr td.today:hover:active, -.datetimepicker table tr td.today.disabled:active, -.datetimepicker table tr td.today.disabled:hover:active, -.datetimepicker table tr td.today.active, -.datetimepicker table tr td.today:hover.active, -.datetimepicker table tr td.today.disabled.active, -.datetimepicker table tr td.today.disabled:hover.active, -.datetimepicker table tr td.today.disabled, -.datetimepicker table tr td.today:hover.disabled, -.datetimepicker table tr td.today.disabled.disabled, -.datetimepicker table tr td.today.disabled:hover.disabled, -.datetimepicker table tr td.today[disabled], -.datetimepicker table tr td.today:hover[disabled], -.datetimepicker table tr td.today.disabled[disabled], -.datetimepicker table tr td.today.disabled:hover[disabled] { - background-color: #fdf59a; -} -.datetimepicker table tr td.today:active, -.datetimepicker table tr td.today:hover:active, -.datetimepicker table tr td.today.disabled:active, -.datetimepicker table tr td.today.disabled:hover:active, -.datetimepicker table tr td.today.active, -.datetimepicker table tr td.today:hover.active, -.datetimepicker table tr td.today.disabled.active, -.datetimepicker table tr td.today.disabled:hover.active { - background-color: #fbf069 \9; -} -.datetimepicker table tr td.active, -.datetimepicker table tr td.active:hover, -.datetimepicker table tr td.active.disabled, -.datetimepicker table tr td.active.disabled:hover { - background-color: #006dcc; - background-image: -moz-linear-gradient(top, #0088cc, #0044cc); - background-image: -ms-linear-gradient(top, #0088cc, #0044cc); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); - background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); - background-image: -o-linear-gradient(top, #0088cc, #0044cc); - background-image: linear-gradient(top, #0088cc, #0044cc); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); - border-color: #0044cc #0044cc #002a80; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - color: #fff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); -} -.datetimepicker table tr td.active:hover, -.datetimepicker table tr td.active:hover:hover, -.datetimepicker table tr td.active.disabled:hover, -.datetimepicker table tr td.active.disabled:hover:hover, -.datetimepicker table tr td.active:active, -.datetimepicker table tr td.active:hover:active, -.datetimepicker table tr td.active.disabled:active, -.datetimepicker table tr td.active.disabled:hover:active, -.datetimepicker table tr td.active.active, -.datetimepicker table tr td.active:hover.active, -.datetimepicker table tr td.active.disabled.active, -.datetimepicker table tr td.active.disabled:hover.active, -.datetimepicker table tr td.active.disabled, -.datetimepicker table tr td.active:hover.disabled, -.datetimepicker table tr td.active.disabled.disabled, -.datetimepicker table tr td.active.disabled:hover.disabled, -.datetimepicker table tr td.active[disabled], -.datetimepicker table tr td.active:hover[disabled], -.datetimepicker table tr td.active.disabled[disabled], -.datetimepicker table tr td.active.disabled:hover[disabled] { - background-color: #0044cc; -} -.datetimepicker table tr td.active:active, -.datetimepicker table tr td.active:hover:active, -.datetimepicker table tr td.active.disabled:active, -.datetimepicker table tr td.active.disabled:hover:active, -.datetimepicker table tr td.active.active, -.datetimepicker table tr td.active:hover.active, -.datetimepicker table tr td.active.disabled.active, -.datetimepicker table tr td.active.disabled:hover.active { - background-color: #003399 \9; +[date-picker] .switch { + width: 145px; } -.datetimepicker table tr td span { +[date-picker] span { display: block; width: 23%; - height: 54px; - line-height: 54px; + height: 26px; + line-height: 25px; float: left; margin: 1%; cursor: pointer; @@ -279,100 +109,105 @@ -moz-border-radius: 4px; border-radius: 4px; } -.datetimepicker .datetimepicker-hours span { - height: 26px; - line-height: 26px; -} -.datetimepicker .datetimepicker-hours table tr td span.hour_am, -.datetimepicker .datetimepicker-hours table tr td span.hour_pm { - width: 14.6%; -} -.datetimepicker .datetimepicker-hours fieldset legend, -.datetimepicker .datetimepicker-minutes fieldset legend { - margin-bottom: inherit; - line-height: 30px; -} -.datetimepicker .datetimepicker-minutes span { - height: 26px; - line-height: 26px; -} -.datetimepicker table tr td span:hover { +[date-picker] span:hover { background: #eeeeee; } -.datetimepicker table tr td span.disabled, -.datetimepicker table tr td span.disabled:hover { +[date-picker] span.disabled, +[date-picker] span.disabled:hover { background: none; color: #999999; cursor: default; } -.datetimepicker table tr td span.active, -.datetimepicker table tr td span.active:hover, -.datetimepicker table tr td span.active.disabled, -.datetimepicker table tr td span.active.disabled:hover { +[date-picker] .active, +[date-picker] .now { + color: #ffffff; background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); - background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); - background-image: linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + *background-color: #0044cc; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } -.datetimepicker table tr td span.active:hover, -.datetimepicker table tr td span.active:hover:hover, -.datetimepicker table tr td span.active.disabled:hover, -.datetimepicker table tr td span.active.disabled:hover:hover, -.datetimepicker table tr td span.active:active, -.datetimepicker table tr td span.active:hover:active, -.datetimepicker table tr td span.active.disabled:active, -.datetimepicker table tr td span.active.disabled:hover:active, -.datetimepicker table tr td span.active.active, -.datetimepicker table tr td span.active:hover.active, -.datetimepicker table tr td span.active.disabled.active, -.datetimepicker table tr td span.active.disabled:hover.active, -.datetimepicker table tr td span.active.disabled, -.datetimepicker table tr td span.active:hover.disabled, -.datetimepicker table tr td span.active.disabled.disabled, -.datetimepicker table tr td span.active.disabled:hover.disabled, -.datetimepicker table tr td span.active[disabled], -.datetimepicker table tr td span.active:hover[disabled], -.datetimepicker table tr td span.active.disabled[disabled], -.datetimepicker table tr td span.active.disabled:hover[disabled] { +[date-picker] .active:hover, +[date-picker] .now:hover, +[date-picker] .active:active, +[date-picker] .now:active, +[date-picker] .active.active, +[date-picker] .now.active, +[date-picker] .active.disabled, +[date-picker] .now.disabled, +[date-picker] .active[disabled], +[date-picker] .now[disabled] { + color: #ffffff; background-color: #0044cc; + *background-color: #003bb3; } -.datetimepicker table tr td span.active:active, -.datetimepicker table tr td span.active:hover:active, -.datetimepicker table tr td span.active.disabled:active, -.datetimepicker table tr td span.active.disabled:hover:active, -.datetimepicker table tr td span.active.active, -.datetimepicker table tr td span.active:hover.active, -.datetimepicker table tr td span.active.disabled.active, -.datetimepicker table tr td span.active.disabled:hover.active { +[date-picker] .active:active, +[date-picker] .now:active, +[date-picker] .active.active, +[date-picker] .now.active { background-color: #003399 \9; } -.datetimepicker table tr td span.old { - color: #999999; +[date-picker] .now { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #ee735b; + background-image: -moz-linear-gradient(top, #ee5f5b, #ee905b); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#ee905b)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #ee905b); + background-image: -o-linear-gradient(top, #ee5f5b, #ee905b); + background-image: linear-gradient(to bottom, #ee5f5b, #ee905b); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffee905b', GradientType=0); + border-color: #ee905b #ee905b #e56218; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #ee905b; + /* Darken IE7 buttons by default so they stand out more given they won't have borders */ + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +[date-picker] .now:hover, +[date-picker] .now:active, +[date-picker] .now.active, +[date-picker] .now.disabled, +[date-picker] .now[disabled] { + color: #ffffff; + background-color: #ee905b; + *background-color: #ec8044; +} +[date-picker] .now:active, +[date-picker] .now.active { + background-color: #e9712d \9; +} +[date-picker] .disabled { + background: none; + color: #999999 !important; + cursor: default; } -.datetimepicker th.switch { - width: 145px; +[date-picker] [ng-switch-when="year"] span, +[date-picker] [ng-switch-when="month"] span, +[date-picker] [ng-switch-when="minutes"] span { + height: 54px; + line-height: 54px; } -.datetimepicker thead tr:first-child th, -.datetimepicker tfoot tr:first-child th { - cursor: pointer; +[date-picker] [ng-switch-when="date"] td { + padding: 0; } -.datetimepicker thead tr:first-child th:hover, -.datetimepicker tfoot tr:first-child th:hover { - background: #eeeeee; +[date-picker] [ng-switch-when="date"] span { + width: 100%; + height: 26px; + line-height: 26px; } -.input-append.date .add-on i, -.input-prepend.date .add-on i { +[date-picker] th:hover, +[date-picker] [ng-switch-when="date"] td span:hover { + background: #eeeeee; cursor: pointer; - width: 14px; - height: 14px; } diff --git a/dist/index.js b/dist/index.js index e01a998..791f17f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,33 +1,263 @@ -(function () { - 'use strict'; - var Module = angular.module('dateInput', []); +'use strict'; +(function(angular){ +'use strict'; + +var Module = angular.module('datePicker', []); + +Module.constant('datePickerConfig', { + template: 'templates/datepicker.html', + view: 'month', + views: ['year', 'month', 'date', 'hours', 'minutes'], + step: 5 +}); + +Module.filter('time',function () { + function format(date){ + return ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2); + } + + return function (date) { + if (!(date instanceof Date)) { + date = new Date(date); + if (isNaN(date.getTime())) { + return undefined; + } + } + return format(date); + }; +}); + +Module.directive('datePicker', ['datePickerConfig', 'datePickerUtils', function datePickerDirective(datePickerConfig, datePickerUtils) { + + //noinspection JSUnusedLocalSymbols + return { + // this is a bug ? + require:'?ngModel', + template: '
', + scope: { + model: '=datePicker', + after: '=?', + before: '=?', + disableBeforeNow: '@?' + }, + link: function (scope, element, attrs, ngModel) { + + var arrowClick = false; + + scope.date = new Date(scope.model || new Date()); + scope.views = datePickerConfig.views.concat(); + scope.view = attrs.view || datePickerConfig.view; + scope.now = new Date(); + scope.template = attrs.template || datePickerConfig.template; + + var step = parseInt(attrs.step || datePickerConfig.step, 10); + var partial = !!attrs.partial; + + /** @namespace attrs.minView, attrs.maxView */ + scope.views =scope.views.slice( + scope.views.indexOf(attrs.maxView || 'year'), + scope.views.indexOf(attrs.minView || 'minutes')+1 + ); + + if (scope.views.length === 1 || scope.views.indexOf(scope.view)===-1) { + scope.view = scope.views[0]; + } + scope.setView = function (nextView) { + if (scope.views.indexOf(nextView) !== -1) { + scope.view = nextView; + } + }; - Module.directive('datePicker', function () { - var viewOptions = ['month', 'date', 'year', 'month', 'hours', 'minutes']; + scope.setDate = function (date) { + if(attrs.disabled) { + return; + } + if(scope.isPreviousDate(date) && scope.disableBeforeNow){ + return; + } + scope.date = date; + // change next view + var nextView = scope.views[scope.views.indexOf(scope.view) + 1]; + if ((!nextView || partial) || scope.model) { + + scope.model = new Date(scope.model || date); + //if ngModel , setViewValue and trigger ng-change, etc... + if(ngModel) { + ngModel.$setViewValue(scope.date); + } - function isValidDate(date) { - return date instanceof Date && !isNaN(date.getTime()); + var view = partial ? 'minutes' : scope.view; + //noinspection FallThroughInSwitchStatementJS + switch (view) { + case 'minutes': + scope.model.setMinutes(date.getMinutes()); + /*falls through*/ + case 'hours': + scope.model.setHours(date.getHours()); + /*falls through*/ + case 'date': + scope.model.setDate(date.getDate()); + /*falls through*/ + case 'month': + scope.model.setMonth(date.getMonth()); + /*falls through*/ + case 'year': + scope.model.setFullYear(date.getFullYear()); + } + scope.$emit('setDate', scope.model, scope.view); + } + + if (nextView) { + scope.setView(nextView); + } + + if(!nextView && attrs.autoClose === 'true'){ + element.addClass('hidden'); + } + }; + + function update() { + var view = scope.view; + + if (scope.model && !arrowClick) { + scope.date = new Date(scope.model); + arrowClick = false; + } + var date = scope.date; + + switch (view) { + case 'year': + scope.years = datePickerUtils.getVisibleYears(date); + break; + case 'month': + scope.months = datePickerUtils.getVisibleMonths(date); + break; + case 'date': + scope.weekdays = scope.weekdays || datePickerUtils.getDaysOfWeek(); + scope.weeks = datePickerUtils.getVisibleWeeks(date); + break; + case 'hours': + scope.hours = datePickerUtils.getVisibleHours(date); + break; + case 'minutes': + scope.minutes = datePickerUtils.getVisibleMinutes(date, step); + break; + } + } + + function watch() { + if (scope.view !== 'date') { + return scope.view; + } + return scope.date ? scope.date.getMonth() : null; + } + + + scope.$watch(watch, update); + + scope.next = function (delta) { + var date = scope.date; + delta = delta || 1; + switch (scope.view) { + case 'year': + /*falls through*/ + case 'month': + date.setFullYear(date.getFullYear() + delta); + break; + case 'date': + date.setMonth(date.getMonth() + delta); + break; + case 'hours': + /*falls through*/ + case 'minutes': + date.setHours(date.getHours() + delta); + break; + } + arrowClick = true; + update(); + }; + + scope.prev = function (delta) { + return scope.next(-delta || -1); + }; + + scope.isAfter = function (date) { + return scope.after && datePickerUtils.isAfter(date, scope.after); + }; + + scope.isBefore = function (date) { + return scope.before && datePickerUtils.isBefore(date, scope.before); + }; + + scope.isSameMonth = function (date) { + return datePickerUtils.isSameMonth(scope.model, date); + }; + + scope.isSameYear = function (date) { + return datePickerUtils.isSameYear(scope.model, date); + }; + + scope.isSameDay = function (date) { + return datePickerUtils.isSameDay(scope.model, date); + }; + + scope.isSameHour = function (date) { + return datePickerUtils.isSameHour(scope.model, date); + }; + + scope.isSameMinutes = function (date) { + return datePickerUtils.isSameMinutes(scope.model, date); + }; + + scope.isPreviousDate = function (date){ + return scope.now >= date ? true : false; + }; + + scope.isNow = function (date) { + var is = true; + var now = scope.now; + //noinspection FallThroughInSwitchStatementJS + switch (scope.view) { + case 'minutes': + is &= ~~(date.getMinutes()/step) === ~~(now.getMinutes()/step); + /*falls through*/ + case 'hours': + is &= date.getHours() === now.getHours(); + /*falls through*/ + case 'date': + is &= date.getDate() === now.getDate(); + /*falls through*/ + case 'month': + is &= date.getMonth() === now.getMonth(); + /*falls through*/ + case 'year': + is &= date.getFullYear() === now.getFullYear(); + } + return is; + }; } + }; +}]); - function getVisibleMinutes(date) { - console.time('getVisibleMinutes'); +'use strict'; + +angular.module('datePicker').factory('datePickerUtils', function(){ + return { + getVisibleMinutes : function(date, step) { date = new Date(date || new Date()); date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours()); var minutes = []; - var step = 5; var stop = date.getTime() + 60 * 60 * 1000; while (date.getTime() < stop) { minutes.push(date); date = new Date(date.getTime() + step * 60 * 1000); } - console.timeEnd('getVisibleMinutes'); return minutes; - } - - function getVisibleWeeks(date) { - console.time('getVisibleWeeks'); + }, + getVisibleWeeks : function(date) { date = new Date(date || new Date()); + var startMonth = date.getMonth(), startYear = date.getYear(); date.setDate(1); date.setHours(0); date.setMinutes(0); @@ -43,9 +273,10 @@ date.setDate(-6); } - var weeks = []; while (weeks.length < 6) { + /*jshint -W116 */ + if(date.getYear()=== startYear && date.getMonth() > startMonth) break; var week = []; for (var i = 0; i < 7; i++) { week.push(new Date(date)); @@ -53,25 +284,18 @@ } weeks.push(week); } - console.timeEnd('getVisibleWeeks'); return weeks; - } - - - function getVisibleYears(date) { - console.time('getVisibleYears'); + }, + getVisibleYears : function(date) { var years = []; date = new Date(date || new Date()); date.setFullYear(date.getFullYear() - (date.getFullYear() % 10)); for (var i = 0; i < 12; i++) { years.push(new Date(date.getFullYear() + (i - 1), 0, 1)); } - console.timeEnd('getVisibleYears'); return years; - } - - function getDaysOfWeek(date) { - console.time('getDaysOfWeek'); + }, + getDaysOfWeek : function(date) { date = new Date(date || new Date()); date = new Date(date.getFullYear(), date.getMonth(), date.getDate()); date.setDate(date.getDate() - (date.getDay() - 1)); @@ -80,24 +304,18 @@ days.push(new Date(date)); date.setDate(date.getDate() + 1); } - console.timeEnd('getDaysOfWeek'); return days; - } - - function getVisibleMonths(date) { - console.time('getVisibleMonths'); + }, + getVisibleMonths : function(date) { date = new Date(date || new Date()); var year = date.getFullYear(); var months = []; for (var month = 0; month < 12; month++) { months.push(new Date(year, month, 1)); } - console.timeEnd('getVisibleMonths'); return months; - } - - function getVisibleHours(date) { - console.time('getVisibleHours'); + }, + getVisibleHours : function(date) { date = new Date(date || new Date()); date.setHours(0); date.setMinutes(0); @@ -108,596 +326,466 @@ hours.push(date); date = new Date(date.getTime() + 60 * 60 * 1000); } - console.timeEnd('getVisibleHours'); return hours; + }, + isAfter : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return model && model.getTime() <= date.getTime(); + }, + isBefore : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return model.getTime() >= date.getTime(); + }, + isSameYear : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return model && model.getFullYear() === date.getFullYear(); + }, + isSameMonth : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return this.isSameYear(model, date) && model.getMonth() === date.getMonth(); + }, + isSameDay : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return this.isSameMonth(model, date) && model.getDate() === date.getDate(); + }, + isSameHour : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return this.isSameDay(model, date) && model.getHours() === date.getHours(); + }, + isSameMinutes : function(model, date) { + model = (model !== undefined) ? new Date(model) : model; + date = new Date(date); + return this.isSameHour(model, date) && model.getMinutes() === date.getMinutes(); } - - return { - scope : { - date : '=datePicker', - after : '=?', - before: '=?' - }, - link : function (scope, element, attrs) { - - scope.views = []; - for (var attr in attrs) { //noinspection JSUnfilteredForInLoop - if (viewOptions.indexOf(attr) !== -1) { //noinspection JSUnfilteredForInLoop - scope.views.push(attr); - } - } - if (!scope.views.length) { - scope.views = ['date', 'month', 'year', 'hours', 'minutes']; - } - scope.view = scope.views[0]; - - function hasView(view) { - return scope.views.indexOf(view) !== -1; - } - - function ensureDate() { - // we need to return new instance as ngModel $watch watches only for identity - not for equality - if (!(isValidDate(scope.date))) { - scope.date = new Date(2000, 1, 1); - } - scope.date = new Date(scope.date); - } - - function setYear(date) { - ensureDate(); - scope.date.setFullYear(date.getFullYear()); - } - - function setMonth(date) { - setYear(date); - scope.date.setMonth(date.getMonth()); - } - - function setDate(date) { - setMonth(date); - scope.date.setDate(date.getDate()); - } - - function setHours(date) { - setDate(date); - scope.date.setHours(date.getHours()); + }; +}); +'use strict'; + +var Module = angular.module('datePicker'); + +Module.directive('dateRange', function () { + return { + templateUrl: 'templates/daterange.html', + scope: { + start: '=', + end: '=', + disableBeforeNow: '@?' + }, + link: function (scope, element, attrs) { + attrs.$observe('disabled', function(isDisabled){ + scope.disableDatePickers = !!isDisabled; + }); + scope.$watch('start.getTime()', function (value) { + if (value && scope.end && value > scope.end.getTime()) { + scope.end = new Date(value); } - - function setMinutes(date) { - setHours(date); - scope.date.setMinutes(date.getMinutes()); + }); + scope.$watch('end.getTime()', function (value) { + if (value && scope.start && value < scope.start.getTime()) { + scope.start = new Date(value); } + }); + } + }; +}); + +'use strict'; + +var PRISTINE_CLASS = 'ng-pristine', + DIRTY_CLASS = 'ng-dirty'; + +var Module = angular.module('datePicker'); + +Module.constant('dateTimeConfig', { + template: function (attrs) { + return '' + + '
'; + }, + format: 'yyyy-MM-dd HH:mm', + views: ['date', 'year', 'month', 'hours', 'minutes'], + dismiss: false, + position: 'relative' +}); + +Module.directive('dateTimeAppend', function () { + return { + link: function (scope, element) { + element.bind('click', function () { + element.find('input')[0].focus(); + }); + } + }; +}); + +Module.directive('dateTime', ['$compile', '$document', '$filter', 'dateTimeConfig', '$parse', function ($compile, $document, $filter, dateTimeConfig, $parse) { + var body = $document.find('body'); + var dateFilter = $filter('date'); + + return { + require: 'ngModel', + scope:true, + link: function (scope, element, attrs, ngModel) { + var format = attrs.format || dateTimeConfig.format; + var parentForm = element.inheritedData('$formController'); + var views = $parse(attrs.views)(scope) || dateTimeConfig.views.concat(); + var view = attrs.view || views[0]; + var index = views.indexOf(view); + var dismiss = attrs.dismiss ? $parse(attrs.dismiss)(scope) : dateTimeConfig.dismiss; + var picker = null; + var position = attrs.position || dateTimeConfig.position; + var container = null; + + if (index === -1) { + views.splice(index, 1); + } - scope.setYear = function (date) { - setYear(date); - scope.$emit('setYear', date); - }; - - scope.setMonth = function (date) { - setMonth(date); - scope.$emit('setMonth', date); - }; - - scope.setDate = function (date) { - setDate(date); - scope.$emit('setDate', date); - }; - - scope.setHours = function (date) { - setHours(date); - scope.$emit('setHours', date); - }; - - scope.setMinutes = function (date) { - setMinutes(date); - scope.$emit('setMinutes', date); - }; - - scope.setView = function setView(view) { - if (hasView(view)) { - scope.view = view; - switch (view) { - case 'minutes': - scope.minutes = getVisibleMinutes(scope.visibleDate); - break; - case 'hours' : - scope.hours = getVisibleHours(scope.visibleDate); - break; - case 'date' : - scope.weeks = getVisibleWeeks(scope.visibleDate); - break; - case 'month' : - scope.months = getVisibleMonths(scope.visibleDate); - break; - case 'year' : - scope.years = getVisibleYears(scope.visibleDate); - break; - } - } - }; - - scope.nextMonth = function (delta) { - scope.visibleDate.setMonth(scope.visibleDate.getMonth() + (delta || 1)); - }; - - scope.prevMonth = function (delta) { - scope.nextMonth(-delta || -1); - }; + views.unshift(view); - scope.nextDay = function (delta) { - scope.visibleDate.setDate(scope.visibleDate.getDate() + (delta || 1)); - }; - scope.prevDay = function (delta) { - scope.nextDay(-delta || -1); - }; + function formatter(value) { + return dateFilter(value, format); + } - scope.nextHour = function (delta) { - scope.visibleDate.setHours(scope.visibleDate.getHours() + (delta || 1)); - }; + function parser() { + return ngModel.$modelValue; + } - scope.prevHour = function (delta) { - scope.nextHour(-delta || -1); - }; + ngModel.$formatters.push(formatter); + ngModel.$parsers.unshift(parser); - scope.nextYear = function (delta) { - scope.visibleDate.setFullYear(scope.visibleDate.getFullYear() + (delta || 1)); - }; - scope.prevYear = function (delta) { - scope.nextYear(-delta || -1); - }; - scope.visibleDate = new Date(); + var template = dateTimeConfig.template(attrs); - scope.$watch('date', function (date) { - if (date) { - scope.visibleDate = new Date(date); + function updateInput(event) { + event.stopPropagation(); + if (ngModel.$pristine) { + ngModel.$dirty = true; + ngModel.$pristine = false; + element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS); + if (parentForm) { + parentForm.$setDirty(); } - }); - - scope.isAfter = function (date) { - return date >= scope.after; - }; - - scope.isBefore = function (date) { - return date <= scope.before; - }; - - function validDate() { - return scope.date instanceof Date; + ngModel.$render(); } + } - scope.isSameMinutes = function (date) { - if (!validDate()){ - return false; - } - var b = scope.date; - return (date.getTime() - date.getSeconds() * 1000 - date.getMilliseconds()) === (b.getTime() - b.getSeconds() * 1000 - b.getMilliseconds()); - }; - - scope.isSameMonth = function (date) { - if (!validDate()){ - return false; - } - return date.getFullYear() === scope.date.getFullYear() && date.getMonth() === scope.date.getMonth(); - }; - - scope.isSameYear = function (date) { - if (!validDate()){ - return false; - } - return date.getFullYear() === scope.date.getFullYear(); - }; - - scope.isSameDate = function (date) { - if (!validDate()){ - return false; - } - return scope.date.getDate() === date.getDate() && scope.isSameMonth(date); - }; - - scope.isSameHour = function (date) { - if (!validDate()){ - return false; - } - return scope.date.getHours() === date.getHours() && scope.isSameDate(date); - }; - - scope.isOldMonth = function (date) { - return date - .getTime() < scope.visibleDate.getTime() && date.getMonth() !== scope.visibleDate.getMonth(); - }; - - scope.isNewHour = function (date) { - return date.getTime() > scope.visibleDate.getTime() && date.getHours() !== scope.visibleDate.getHours(); - }; - - scope.isOldHour = function (date) { - return date.getTime() < scope.visibleDate.getTime() && date.getHours() !== scope.visibleDate.getHours(); - }; - - scope.isNewMonth = function (date) { - return date.getTime() > scope.visibleDate.getTime() && date.getMonth() !== scope.visibleDate.getMonth(); - }; - - - scope.$on('setDate', scope.setView.bind(null, 'hours')); - scope.$on('setMonth', scope.setView.bind(null, 'date')); - scope.$on('setHours', scope.setView.bind(null, 'minutes')); - scope.$on('setYear', scope.setView.bind(null, 'month')); - - scope.$watch(function () { - return isValidDate(scope.visibleDate); - }, function (valid) { - if (!valid) { - scope.visibleDate = new Date(); - } - }); - - //hours - scope.$watch('[visibleDate.getDate(),visibleDate.getHours()].join()', function () { - if (scope.view === 'hours') { - scope.hours = getVisibleHours(scope.visibleDate); - } - }); - //date - scope.$watch('[visibleDate.getFullYear(),visibleDate.getMonth(),visibleDate.getDate()].join()', function () { - if (scope.view === 'date') { - scope.weeks = getVisibleWeeks(scope.visibleDate); - scope.weekdays = getDaysOfWeek(scope.visibleDate); - } - }); - - scope.$watch('[visibleDate.getFullYear(),visibleDate.getMonth()].join()', function () { - if (scope.view === 'month') { - scope.months = getVisibleMonths(scope.visibleDate); - } - }); - - scope.$watch('visibleDate.getYear()', function () { - if (scope.view === 'year') { - scope.years = getVisibleYears(scope.visibleDate); - } - }); + function clear() { + if (picker) { + picker.remove(); + picker = null; + } + if (container) { + container.remove(); + container = null; + } + } - scope.$watch('visibleDate.getTime()', function () { - if (scope.view === 'minutes') { - scope.minutes = getVisibleMinutes(scope.visibleDate); + function showPicker() { + if (picker) { + return; + } + // create picker element + picker = $compile(template)(scope); + scope.$digest(); + + scope.$on('setDate', function (event, date, view) { + updateInput(event); + if (dismiss && views[views.length - 1] === view) { + clear(); } }); - }, - transclude : true, - replace : true, - templateUrl: 'scripts/template.html' - }; - }); - - Module.directive('dateTime', function ($compile, $document, $filter) { - var body = $document.find('body'); - var dateFilter = $filter('date'); - return { - require: 'ngModel', - link : function (scope, element, attrs, ngModel) { - var format = attrs.format || 'yyyy-MM-dd HH:mm'; - - var viewsOptions = ['date', 'year', 'month', 'hours', 'minutes', 'month']; - var views = []; - for (var attr in attrs) { - //noinspection JSUnfilteredForInLoop - if (viewsOptions.indexOf(attr) !== -1) { //noinspection JSUnfilteredForInLoop - views.push(attr); - } - } - - function formatter(value) { - return dateFilter(value, format); + scope.$on('$destroy', clear); + + // move picker below input element + + if (position === 'absolute') { + var pos = angular.extend(element.offset(), { height: element[0].offsetHeight }); + picker.css({ top: pos.top + pos.height, left: pos.left, display: 'block', position: position}); + body.append(picker); + } else { + // relative + container = angular.element('
'); + element[0].parentElement.insertBefore(container[0], element[0]); + container.append(picker); +// this approach doesn't work +// element.before(picker); + picker.css({top: element[0].offsetHeight + 'px', display: 'block'}); } - ngModel.$formatters = [formatter]; - - var picker = null; - var clear = angular.noop; - - element.bind('focus', function () { - if (!picker) { - picker = $compile('')(scope); - body.append(picker); - scope.$digest(); - var pos = angular.extend({}, element.position(), { height: element[0].offsetHeight }); - picker.css({ top: pos.top + pos.height, left: pos.left, display: 'block', position: 'absolute'}); - picker.bind('mousedown', function () { - return false; - }); - } - return false; - }); - element.bind('blur', function () { - clear(); - clear = angular.noop; - if (picker){ - picker.remove(); - } - picker = null; - }); - } - }; - }); - - Module.directive('dateRange', function () { - return { - template: '
\n \n \n \n \n \n
\n \n \n
', - scope : { - start: '=', - end : '=' - }, - link : function (scope) { - scope.$watch('start.getTime()', function (value) { - if (value && scope.end && value > scope.end.getTime()) { - scope.end = new Date(value); - } - }); - scope.$watch('end.getTime()', function (value) { - if (value && scope.start && value < scope.start.getTime()) { - scope.start = new Date(value); - } + picker.bind('mousedown', function (evt) { + evt.preventDefault(); }); } - }; - }); -})(); -angular.module("dateInput").run(["$templateCache", function($templateCache) { - $templateCache.put("scripts/template.html", - "
\r" + - "\n" + - "
\r" + - "\n" + - " \r" + - "\n" + - " \r" + - "\n" + - " \r" + - "\n" + - " \r" + - "\n" + - " \r" + + element.bind('focus', showPicker); + element.bind('blur', clear); + } + }; +}]); + +angular.module("datePicker").run(["$templateCache", function($templateCache) { + + $templateCache.put("templates/datepicker.html", + "
\r" + "\n" + - "
\r" + + "
\r" + "\n" + - "
\r" + + "
{{visibleDate|date:\"yyyy MMMM\"}}
\r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + "\n" + - " ng-click=\"setDate(day)\">{{ day.getDate() }}\r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + + " Today\r" + + " ng-class=\"{'now':isNow(day),'active':isSameDay(day),'disabled':((day.getMonth()!=date.getMonth()) || isPreviousDate(day)),'after':isAfter(day),'before':isBefore(day)}\"\r" + "\n" + - " \r" + + " ng-click=\"setDate(day)\" ng-bind=\"day.getDate()\">\r" + "\n" + - " \r" + + " \r" + "\n" + - "
{{ day|date:\"EEE\"}}
{{date|date:\"yyyy MMMM\"}}
\r" + "\n" + - " ng-class=\"{'active':isSameDate(day),'old':isOldMonth(day),'new':isNewMonth(day),'after':isAfter(day),'before':isBefore(day)}\"\r" + + " {{ day|date:\"EEE\" }}
\r" + "\n" + - "
\r" + + " \r" + "\n" + - "
\r" + + " \r" + "\n" + - "
\r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + "
\r" + "\n" + - "
\r" + + "
\r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + "\n" + - " \r" + "\n" + - " ng-click=\"setYear(year)\">{{year.getFullYear()}}\r" + + " \r" + + " \r" + + " ng-repeat=\"year in years\"\r" + "\n" + - " \r" + + " ng-click=\"setDate(year)\" ng-bind=\"year.getFullYear()\">\r" + "\n" + - "
{{years[0].getFullYear()}}-{{years[years.length-1].getFullYear()}}
{{years[0].getFullYear()}}-{{years[years.length-1].getFullYear()}}
\r" + + "
\r" + "\n" + - "
\r" + + " \r" + "\n" + - "
\r" + + " \r" + "\n" + - "\r" + + " \r" + "\n" + - "
\r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + "
\r" + "\n" + - "
\r" + + "
\r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + "\n" + - " \r" + "\n" + - " ng-class=\"{'active':isSameMonth(month),'after':isAfter(month),'before':isBefore(month)}\"\r" + + " \r" + + " ng-click=\"setDate(month)\"\r" + "\n" + - " \r" + + " ng-bind=\"month|date:'MMM'\">\r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + "
{{ visibleDate|date:\"yyyy\" }}
{{ date|date:\"yyyy\" }}
\r" + + "
\r" + "\n" + - " ng-click=\"setMonth(month)\">{{month|date:'MMM'}}\r" + + " \r" + + " ng-class=\"{'active':isSameMonth(month),'after':isAfter(month),'before':isBefore(month),'now':isNow(month)}\"\r" + "\n" + - "
Today
\r" + "\n" + - " \r" + + "
\r" + "\n" + - " \r" + + "
\r" + "\n" + - "
\r" + + " \r" + "\n" + - "\r" + + " \r" + "\n" + - "
\r" + + "
\r" + "\n" + - "
\r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + + " \r" + + " ng-class=\"{'now':isNow(hour),'active':isSameHour(hour)}\"\r" + "\n" + - " \r" + "\n" + - " ng-click=\"setHours(hour)\">{{hour|date:\"HH:mm\"}}\r" + + " \r" + "\n" + - " \r" + + "
{{ date|date:\"dd MMMM yyyy\" }}
{{ visibleDate|date:\"dd MMMM yyyy\" }}
\r" + "\n" + - "
\r" + + " ng-click=\"setDate(hour)\" ng-bind=\"hour|time\">\r" + "\n" + - " \r" + "\n" + - " ng-class=\"{'old':isOldHour(hour),'new':isNewHour(hour),'active':isSameHour(hour)}\"\r" + + "
\r" + "\n" + - " \r" + + "
\r" + "\n" + - " \r" + + "
\r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + "
Today
{{ date|date:\"dd MMMM yyyy\" }}\r" + "\n" + - "
\r" + + " \r" + "\n" + - "
\r" + + " ›\r" + "\n" + - "
\r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + + " ng-click=\"setDate(minute)\"\r" + "\n" + - " \r" + + " ng-bind=\"minute|time\">\r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - "
\r" + "\n" + - " {{ visibleDate|date:\"dd MMMM yyyy HH:mm\" }}\r" + + " \r" + + " ng-class=\"{active:isSameMinutes(minute),'now':isNow(minute)}\"\r" + "\n" + - "
\r" + + "
\r" + "\n" + - " \r" + "\n" + - " ng-click=\"setMinutes(minute)\">{{minute|date:\"HH:mm\"}}\r" + + "
\r" + + "\n" + ); + + $templateCache.put("templates/daterange.html", + "
\r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + + "
\r" + "\n" + - " \r" + + " \r" + "\n" + - " \r" + + " \r" + + "
\r" + "\n" + - " \r" + + " \r" + "\n" + - "
\r" + "\n" + - "
Today\r" + "\n" + - "
\r" + + " \r" + "\n" + - "
\r" + + " \r" + "\n" + - "
" + "\r" + + "\n" ); }]); +})(angular); \ No newline at end of file diff --git a/dist/index.min.css b/dist/index.min.css index cb3e23d..b0ca33d 100644 --- a/dist/index.min.css +++ b/dist/index.min.css @@ -1,9 +1 @@ -/*! - * Datetimepicker for Bootstrap - * - * Copyright 2012 Stefan Petre - * Improvements by Andrew Rowls - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - */ .before.after:not(.active){background:#2f96b4 linear-gradient(to bottom,#5bc0de,#2f96b4) repeat-x}.next,.prev{font-size:21px}.datetimepicker table{table-layout:fixed}.datetimepicker{padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;direction:ltr}.datetimepicker-inline{width:220px}.datetimepicker.datetimepicker-rtl{direction:rtl}.datetimepicker.datetimepicker-rtl table tr td span{float:right}.datetimepicker-dropdown,.datetimepicker-dropdown-left{top:0;left:0}[class*=" datetimepicker-dropdown"]:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute}[class*=" datetimepicker-dropdown"]:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute}[class*=" datetimepicker-dropdown-top"]:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);border-bottom:0}[class*=" datetimepicker-dropdown-top"]:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #fff;border-bottom:0}.datetimepicker-dropdown-bottom-right:before{top:-7px;right:6px}.datetimepicker-dropdown-bottom-right:after{top:-6px;right:7px}.datetimepicker-dropdown-bottom-left:before{top:-7px;left:6px}.datetimepicker-dropdown-bottom-left:after{top:-6px;left:7px}.datetimepicker-dropdown-top-right:before{bottom:-7px;right:6px}.datetimepicker-dropdown-top-right:after{bottom:-6px;right:7px}.datetimepicker-dropdown-top-left:before{bottom:-7px;left:6px}.datetimepicker-dropdown-top-left:after{bottom:-6px;left:7px}.datetimepicker.minutes div.datetimepicker-minutes{display:block}.datetimepicker.hours div.datetimepicker-hours{display:block}.datetimepicker.days div.datetimepicker-days{display:block}.datetimepicker.months div.datetimepicker-months{display:block}.datetimepicker.years div.datetimepicker-years{display:block}.datetimepicker table{margin:0}.datetimepicker td,.datetimepicker th{text-align:center;width:20px;height:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0}.table-striped .datetimepicker table tr td,.table-striped .datetimepicker table tr th{background-color:transparent}.datetimepicker table tr td.minute:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.hour:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.day:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.old,.datetimepicker table tr td.new{color:#999}.datetimepicker table tr td.disabled,.datetimepicker table tr td.disabled:hover{background:0;color:#999;cursor:default}.datetimepicker table tr td.today,.datetimepicker table tr td.today:hover,.datetimepicker table tr td.today.disabled,.datetimepicker table tr td.today.disabled:hover{background-color:#fde19a;background-image:-moz-linear-gradient(top,#fdd49a,#fdf59a);background-image:-ms-linear-gradient(top,#fdd49a,#fdf59a);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdd49a),to(#fdf59a));background-image:-webkit-linear-gradient(top,#fdd49a,#fdf59a);background-image:-o-linear-gradient(top,#fdd49a,#fdf59a);background-image:linear-gradient(top,#fdd49a,#fdf59a);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);border-color:#fdf59a #fdf59a #fbed50;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.datetimepicker table tr td.today:hover,.datetimepicker table tr td.today:hover:hover,.datetimepicker table tr td.today.disabled:hover,.datetimepicker table tr td.today.disabled:hover:hover,.datetimepicker table tr td.today:active,.datetimepicker table tr td.today:hover:active,.datetimepicker table tr td.today.disabled:active,.datetimepicker table tr td.today.disabled:hover:active,.datetimepicker table tr td.today.active,.datetimepicker table tr td.today:hover.active,.datetimepicker table tr td.today.disabled.active,.datetimepicker table tr td.today.disabled:hover.active,.datetimepicker table tr td.today.disabled,.datetimepicker table tr td.today:hover.disabled,.datetimepicker table tr td.today.disabled.disabled,.datetimepicker table tr td.today.disabled:hover.disabled,.datetimepicker table tr td.today[disabled],.datetimepicker table tr td.today:hover[disabled],.datetimepicker table tr td.today.disabled[disabled],.datetimepicker table tr td.today.disabled:hover[disabled]{background-color:#fdf59a}.datetimepicker table tr td.today:active,.datetimepicker table tr td.today:hover:active,.datetimepicker table tr td.today.disabled:active,.datetimepicker table tr td.today.disabled:hover:active,.datetimepicker table tr td.today.active,.datetimepicker table tr td.today:hover.active,.datetimepicker table tr td.today.disabled.active,.datetimepicker table tr td.today.disabled:hover.active{background-color:#fbf069 \9}.datetimepicker table tr td.active,.datetimepicker table tr td.active:hover,.datetimepicker table tr td.active.disabled,.datetimepicker table tr td.active.disabled:hover{background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-ms-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(top,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.datetimepicker table tr td.active:hover,.datetimepicker table tr td.active:hover:hover,.datetimepicker table tr td.active.disabled:hover,.datetimepicker table tr td.active.disabled:hover:hover,.datetimepicker table tr td.active:active,.datetimepicker table tr td.active:hover:active,.datetimepicker table tr td.active.disabled:active,.datetimepicker table tr td.active.disabled:hover:active,.datetimepicker table tr td.active.active,.datetimepicker table tr td.active:hover.active,.datetimepicker table tr td.active.disabled.active,.datetimepicker table tr td.active.disabled:hover.active,.datetimepicker table tr td.active.disabled,.datetimepicker table tr td.active:hover.disabled,.datetimepicker table tr td.active.disabled.disabled,.datetimepicker table tr td.active.disabled:hover.disabled,.datetimepicker table tr td.active[disabled],.datetimepicker table tr td.active:hover[disabled],.datetimepicker table tr td.active.disabled[disabled],.datetimepicker table tr td.active.disabled:hover[disabled]{background-color:#04c}.datetimepicker table tr td.active:active,.datetimepicker table tr td.active:hover:active,.datetimepicker table tr td.active.disabled:active,.datetimepicker table tr td.active.disabled:hover:active,.datetimepicker table tr td.active.active,.datetimepicker table tr td.active:hover.active,.datetimepicker table tr td.active.disabled.active,.datetimepicker table tr td.active.disabled:hover.active{background-color:#039 \9}.datetimepicker table tr td span{display:block;width:23%;height:54px;line-height:54px;float:left;margin:1%;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.datetimepicker .datetimepicker-hours span{height:26px;line-height:26px}.datetimepicker .datetimepicker-hours table tr td span.hour_am,.datetimepicker .datetimepicker-hours table tr td span.hour_pm{width:14.6%}.datetimepicker .datetimepicker-hours fieldset legend,.datetimepicker .datetimepicker-minutes fieldset legend{margin-bottom:inherit;line-height:30px}.datetimepicker .datetimepicker-minutes span{height:26px;line-height:26px}.datetimepicker table tr td span:hover{background:#eee}.datetimepicker table tr td span.disabled,.datetimepicker table tr td span.disabled:hover{background:0;color:#999;cursor:default}.datetimepicker table tr td span.active,.datetimepicker table tr td span.active:hover,.datetimepicker table tr td span.active.disabled,.datetimepicker table tr td span.active.disabled:hover{background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-ms-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(top,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.datetimepicker table tr td span.active:hover,.datetimepicker table tr td span.active:hover:hover,.datetimepicker table tr td span.active.disabled:hover,.datetimepicker table tr td span.active.disabled:hover:hover,.datetimepicker table tr td span.active:active,.datetimepicker table tr td span.active:hover:active,.datetimepicker table tr td span.active.disabled:active,.datetimepicker table tr td span.active.disabled:hover:active,.datetimepicker table tr td span.active.active,.datetimepicker table tr td span.active:hover.active,.datetimepicker table tr td span.active.disabled.active,.datetimepicker table tr td span.active.disabled:hover.active,.datetimepicker table tr td span.active.disabled,.datetimepicker table tr td span.active:hover.disabled,.datetimepicker table tr td span.active.disabled.disabled,.datetimepicker table tr td span.active.disabled:hover.disabled,.datetimepicker table tr td span.active[disabled],.datetimepicker table tr td span.active:hover[disabled],.datetimepicker table tr td span.active.disabled[disabled],.datetimepicker table tr td span.active.disabled:hover[disabled]{background-color:#04c}.datetimepicker table tr td span.active:active,.datetimepicker table tr td span.active:hover:active,.datetimepicker table tr td span.active.disabled:active,.datetimepicker table tr td span.active.disabled:hover:active,.datetimepicker table tr td span.active.active,.datetimepicker table tr td span.active:hover.active,.datetimepicker table tr td span.active.disabled.active,.datetimepicker table tr td span.active.disabled:hover.active{background-color:#039 \9}.datetimepicker table tr td span.old{color:#999}.datetimepicker th.switch{width:145px}.datetimepicker thead tr:first-child th,.datetimepicker tfoot tr:first-child th{cursor:pointer}.datetimepicker thead tr:first-child th:hover,.datetimepicker tfoot tr:first-child th:hover{background:#eee}.input-append.date .add-on i,.input-prepend.date .add-on i{cursor:pointer;width:14px;height:14px} \ No newline at end of file +.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}[date-picker-wrapper]{position:relative!important;display:block}[date-time-append] [date-picker]{position:relative;margin-right:-1000px;margin-bottom:-1000px}[date-range] [date-picker] .after.before{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#499dcd;background-image:-moz-linear-gradient(top,#5bc0de,#2f6ab4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f6ab4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f6ab4);background-image:-o-linear-gradient(top,#5bc0de,#2f6ab4);background-image:linear-gradient(to bottom,#5bc0de,#2f6ab4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f6ab4', GradientType=0);border-color:#2f6ab4 #2f6ab4 #1f4677;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);*background-color:#2f6ab4;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}[date-range] [date-picker] .after.before:hover,[date-range] [date-picker] .after.before:active,[date-range] [date-picker] .after.before.active,[date-range] [date-picker] .after.before.disabled,[date-range] [date-picker] .after.before[disabled]{color:#fff;background-color:#2f6ab4;*background-color:#2a5ea0}[date-range] [date-picker] .after.before:active,[date-range] [date-picker] .after.before.active{background-color:#24528c \9}[date-picker].hidden{display:none}[date-picker]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;padding:4px}[date-picker] table{margin:0}[date-picker] td,[date-picker] th{padding:4px 5px;text-align:center;width:20px;height:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0}[date-picker] .switch{width:145px}[date-picker] span{display:block;width:23%;height:26px;line-height:25px;float:left;margin:1%;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}[date-picker] span:hover{background:#eee}[date-picker] span.disabled,[date-picker] span.disabled:hover{background:0;color:#999;cursor:default}[date-picker] .active,[date-picker] .now{color:#fff;background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);*background-color:#04c;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}[date-picker] .active:hover,[date-picker] .now:hover,[date-picker] .active:active,[date-picker] .now:active,[date-picker] .active.active,[date-picker] .now.active,[date-picker] .active.disabled,[date-picker] .now.disabled,[date-picker] .active[disabled],[date-picker] .now[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}[date-picker] .active:active,[date-picker] .now:active,[date-picker] .active.active,[date-picker] .now.active{background-color:#039 \9}[date-picker] .now{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25);background-color:#ee735b;background-image:-moz-linear-gradient(top,#ee5f5b,#ee905b);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#ee905b));background-image:-webkit-linear-gradient(top,#ee5f5b,#ee905b);background-image:-o-linear-gradient(top,#ee5f5b,#ee905b);background-image:linear-gradient(to bottom,#ee5f5b,#ee905b);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffee905b', GradientType=0);border-color:#ee905b #ee905b #e56218;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);*background-color:#ee905b;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}[date-picker] .now:hover,[date-picker] .now:active,[date-picker] .now.active,[date-picker] .now.disabled,[date-picker] .now[disabled]{color:#fff;background-color:#ee905b;*background-color:#ec8044}[date-picker] .now:active,[date-picker] .now.active{background-color:#e9712d \9}[date-picker] .disabled{background:0;color:#999!important;cursor:default}[date-picker] [ng-switch-when=year] span,[date-picker] [ng-switch-when=month] span,[date-picker] [ng-switch-when=minutes] span{height:54px;line-height:54px}[date-picker] [ng-switch-when=date] td{padding:0}[date-picker] [ng-switch-when=date] span{width:100%;height:26px;line-height:26px}[date-picker] th:hover,[date-picker] [ng-switch-when=date] td span:hover{background:#eee;cursor:pointer} \ No newline at end of file diff --git a/dist/index.min.js b/dist/index.min.js index 4b41437..4f94799 100644 --- a/dist/index.min.js +++ b/dist/index.min.js @@ -1 +1 @@ -!function(){"use strict";var a=angular.module("dateInput",[]);a.directive("datePicker",function(){function a(a){return a instanceof Date&&!isNaN(a.getTime())}function b(a){console.time("getVisibleMinutes"),a=new Date(a||new Date),a=new Date(a.getFullYear(),a.getMonth(),a.getDate(),a.getHours());for(var b=[],c=5,d=a.getTime()+36e5;a.getTime()d;d++)c.push(new Date(a)),a.setDate(a.getDate()+1);b.push(c)}return console.timeEnd("getVisibleWeeks"),b}function d(a){console.time("getVisibleYears");var b=[];a=new Date(a||new Date),a.setFullYear(a.getFullYear()-a.getFullYear()%10);for(var c=0;12>c;c++)b.push(new Date(a.getFullYear()+(c-1),0,1));return console.timeEnd("getVisibleYears"),b}function e(a){console.time("getDaysOfWeek"),a=new Date(a||new Date),a=new Date(a.getFullYear(),a.getMonth(),a.getDate()),a.setDate(a.getDate()-(a.getDay()-1));for(var b=[],c=0;7>c;c++)b.push(new Date(a)),a.setDate(a.getDate()+1);return console.timeEnd("getDaysOfWeek"),b}function f(a){console.time("getVisibleMonths"),a=new Date(a||new Date);for(var b=a.getFullYear(),c=[],d=0;12>d;d++)c.push(new Date(b,d,1));return console.timeEnd("getVisibleMonths"),c}function g(a){console.time("getVisibleHours"),a=new Date(a||new Date),a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0);for(var b=[],c=0;24>c;c++)b.push(a),a=new Date(a.getTime()+36e5);return console.timeEnd("getVisibleHours"),b}var h=["month","date","year","month","hours","minutes"];return{scope:{date:"=datePicker",after:"=?",before:"=?"},link:function(i,j,k){function l(a){return-1!==i.views.indexOf(a)}function m(){a(i.date)||(i.date=new Date(2e3,1,1)),i.date=new Date(i.date)}function n(a){m(),i.date.setFullYear(a.getFullYear())}function o(a){n(a),i.date.setMonth(a.getMonth())}function p(a){o(a),i.date.setDate(a.getDate())}function q(a){p(a),i.date.setHours(a.getHours())}function r(a){q(a),i.date.setMinutes(a.getMinutes())}function s(){return i.date instanceof Date}i.views=[];for(var t in k)-1!==h.indexOf(t)&&i.views.push(t);i.views.length||(i.views=["date","month","year","hours","minutes"]),i.view=i.views[0],i.setYear=function(a){n(a),i.$emit("setYear",a)},i.setMonth=function(a){o(a),i.$emit("setMonth",a)},i.setDate=function(a){p(a),i.$emit("setDate",a)},i.setHours=function(a){q(a),i.$emit("setHours",a)},i.setMinutes=function(a){r(a),i.$emit("setMinutes",a)},i.setView=function(a){if(l(a))switch(i.view=a,a){case"minutes":i.minutes=b(i.visibleDate);break;case"hours":i.hours=g(i.visibleDate);break;case"date":i.weeks=c(i.visibleDate);break;case"month":i.months=f(i.visibleDate);break;case"year":i.years=d(i.visibleDate)}},i.nextMonth=function(a){i.visibleDate.setMonth(i.visibleDate.getMonth()+(a||1))},i.prevMonth=function(a){i.nextMonth(-a||-1)},i.nextDay=function(a){i.visibleDate.setDate(i.visibleDate.getDate()+(a||1))},i.prevDay=function(a){i.nextDay(-a||-1)},i.nextHour=function(a){i.visibleDate.setHours(i.visibleDate.getHours()+(a||1))},i.prevHour=function(a){i.nextHour(-a||-1)},i.nextYear=function(a){i.visibleDate.setFullYear(i.visibleDate.getFullYear()+(a||1))},i.prevYear=function(a){i.nextYear(-a||-1)},i.visibleDate=new Date,i.$watch("date",function(a){a&&(i.visibleDate=new Date(a))}),i.isAfter=function(a){return a>=i.after},i.isBefore=function(a){return a<=i.before},i.isSameMinutes=function(a){if(!s())return!1;var b=i.date;return a.getTime()-1e3*a.getSeconds()-a.getMilliseconds()===b.getTime()-1e3*b.getSeconds()-b.getMilliseconds()},i.isSameMonth=function(a){return s()?a.getFullYear()===i.date.getFullYear()&&a.getMonth()===i.date.getMonth():!1},i.isSameYear=function(a){return s()?a.getFullYear()===i.date.getFullYear():!1},i.isSameDate=function(a){return s()?i.date.getDate()===a.getDate()&&i.isSameMonth(a):!1},i.isSameHour=function(a){return s()?i.date.getHours()===a.getHours()&&i.isSameDate(a):!1},i.isOldMonth=function(a){return a.getTime()i.visibleDate.getTime()&&a.getHours()!==i.visibleDate.getHours()},i.isOldHour=function(a){return a.getTime()i.visibleDate.getTime()&&a.getMonth()!==i.visibleDate.getMonth()},i.$on("setDate",i.setView.bind(null,"hours")),i.$on("setMonth",i.setView.bind(null,"date")),i.$on("setHours",i.setView.bind(null,"minutes")),i.$on("setYear",i.setView.bind(null,"month")),i.$watch(function(){return a(i.visibleDate)},function(a){a||(i.visibleDate=new Date)}),i.$watch("[visibleDate.getDate(),visibleDate.getHours()].join()",function(){"hours"===i.view&&(i.hours=g(i.visibleDate))}),i.$watch("[visibleDate.getFullYear(),visibleDate.getMonth(),visibleDate.getDate()].join()",function(){"date"===i.view&&(i.weeks=c(i.visibleDate),i.weekdays=e(i.visibleDate))}),i.$watch("[visibleDate.getFullYear(),visibleDate.getMonth()].join()",function(){"month"===i.view&&(i.months=f(i.visibleDate))}),i.$watch("visibleDate.getYear()",function(){"year"===i.view&&(i.years=d(i.visibleDate))}),i.$watch("visibleDate.getTime()",function(){"minutes"===i.view&&(i.minutes=b(i.visibleDate))})},transclude:!0,replace:!0,templateUrl:"scripts/template.html"}}),a.directive("dateTime",["$compile","$document","$filter",function(a,b,c){var d=b.find("body"),e=c("date");return{require:"ngModel",link:function(b,c,f,g){function h(a){return e(a,i)}var i=f.format||"yyyy-MM-dd HH:mm",j=["date","year","month","hours","minutes","month"],k=[];for(var l in f)-1!==j.indexOf(l)&&k.push(l);g.$formatters=[h];var m=null,n=angular.noop;c.bind("focus",function(){if(!m){m=a('")(b),d.append(m),b.$digest();var e=angular.extend({},c.position(),{height:c[0].offsetHeight});m.css({top:e.top+e.height,left:e.left,display:"block",position:"absolute"}),m.bind("mousedown",function(){return!1})}return!1}),c.bind("blur",function(){n(),n=angular.noop,m&&m.remove(),m=null})}}}]),a.directive("dateRange",function(){return{template:'
\n \n \n \n \n \n
\n \n \n
',scope:{start:"=",end:"="},link:function(a){a.$watch("start.getTime()",function(b){b&&a.end&&b>a.end.getTime()&&(a.end=new Date(b))}),a.$watch("end.getTime()",function(b){b&&a.start&&b\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{visibleDate|date:"yyyy MMMM"}}
{{ day|date:"EEE"}}
{{ day.getDate() }}\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{years[0].getFullYear()}}-{{years[years.length-1].getFullYear()}}
\r\n {{year.getFullYear()}}\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ visibleDate|date:"yyyy" }}
\r\n {{month|date:\'MMM\'}}\r\n
\r\n
\r\n\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ visibleDate|date:"dd MMMM yyyy" }}
\r\n {{hour|date:"HH:mm"}}\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ visibleDate|date:"dd MMMM yyyy HH:mm" }}\r\n
\r\n {{minute|date:"HH:mm"}}\r\n
\r\n
\r\n')}]); \ No newline at end of file +"use strict";!function(a){var b=a.module("datePicker",[]);b.constant("datePickerConfig",{template:"templates/datepicker.html",view:"month",views:["year","month","date","hours","minutes"],step:5}),b.filter("time",function(){function a(a){return("0"+a.getHours()).slice(-2)+":"+("0"+a.getMinutes()).slice(-2)}return function(b){return b instanceof Date||(b=new Date(b),!isNaN(b.getTime()))?a(b):void 0}}),b.directive("datePicker",["datePickerConfig","datePickerUtils",function(a,b){return{require:"?ngModel",template:'
',scope:{model:"=datePicker",after:"=?",before:"=?"},link:function(c,d,e,f){function g(){var a=c.view;c.model&&!i&&(c.date=new Date(c.model),i=!1);var d=c.date;switch(a){case"year":c.years=b.getVisibleYears(d);break;case"month":c.months=b.getVisibleMonths(d);break;case"date":c.weekdays=c.weekdays||b.getDaysOfWeek(),c.weeks=b.getVisibleWeeks(d);break;case"hours":c.hours=b.getVisibleHours(d);break;case"minutes":c.minutes=b.getVisibleMinutes(d,j)}}function h(){return"date"!==c.view?c.view:c.date?c.date.getMonth():null}var i=!1;c.date=new Date(c.model||new Date),c.views=a.views.concat(),c.view=e.view||a.view,c.now=new Date,c.template=e.template||a.template;var j=parseInt(e.step||a.step,10),k=!!e.partial;c.views=c.views.slice(c.views.indexOf(e.maxView||"year"),c.views.indexOf(e.minView||"minutes")+1),(1===c.views.length||-1===c.views.indexOf(c.view))&&(c.view=c.views[0]),c.setView=function(a){-1!==c.views.indexOf(a)&&(c.view=a)},c.setDate=function(a){if(!e.disabled){c.date=a;var b=c.views[c.views.indexOf(c.view)+1];if(!b||k||c.model){c.model=new Date(c.model||a),f&&f.$setViewValue(c.date);var g=k?"minutes":c.view;switch(g){case"minutes":c.model.setMinutes(a.getMinutes());case"hours":c.model.setHours(a.getHours());case"date":c.model.setDate(a.getDate());case"month":c.model.setMonth(a.getMonth());case"year":c.model.setFullYear(a.getFullYear())}c.$emit("setDate",c.model,c.view)}b&&c.setView(b),b||"true"!==e.autoClose||d.addClass("hidden")}},c.$watch(h,g),c.next=function(a){var b=c.date;switch(a=a||1,c.view){case"year":case"month":b.setFullYear(b.getFullYear()+a);break;case"date":b.setMonth(b.getMonth()+a);break;case"hours":case"minutes":b.setHours(b.getHours()+a)}i=!0,g()},c.prev=function(a){return c.next(-a||-1)},c.isAfter=function(a){return c.after&&b.isAfter(a,c.after)},c.isBefore=function(a){return c.before&&b.isBefore(a,c.before)},c.isSameMonth=function(a){return b.isSameMonth(c.model,a)},c.isSameYear=function(a){return b.isSameYear(c.model,a)},c.isSameDay=function(a){return b.isSameDay(c.model,a)},c.isSameHour=function(a){return b.isSameHour(c.model,a)},c.isSameMinutes=function(a){return b.isSameMinutes(c.model,a)},c.isNow=function(a){var b=!0,d=c.now;switch(c.view){case"minutes":b&=~~(a.getMinutes()/j)===~~(d.getMinutes()/j);case"hours":b&=a.getHours()===d.getHours();case"date":b&=a.getDate()===d.getDate();case"month":b&=a.getMonth()===d.getMonth();case"year":b&=a.getFullYear()===d.getFullYear()}return b}}}}]),a.module("datePicker").factory("datePickerUtils",function(){return{getVisibleMinutes:function(a,b){a=new Date(a||new Date),a=new Date(a.getFullYear(),a.getMonth(),a.getDate(),a.getHours());for(var c=[],d=a.getTime()+36e5;a.getTime()b);){for(var e=[],f=0;7>f;f++)e.push(new Date(a)),a.setDate(a.getDate()+1);d.push(e)}return d},getVisibleYears:function(a){var b=[];a=new Date(a||new Date),a.setFullYear(a.getFullYear()-a.getFullYear()%10);for(var c=0;12>c;c++)b.push(new Date(a.getFullYear()+(c-1),0,1));return b},getDaysOfWeek:function(a){a=new Date(a||new Date),a=new Date(a.getFullYear(),a.getMonth(),a.getDate()),a.setDate(a.getDate()-(a.getDay()-1));for(var b=[],c=0;7>c;c++)b.push(new Date(a)),a.setDate(a.getDate()+1);return b},getVisibleMonths:function(a){a=new Date(a||new Date);for(var b=a.getFullYear(),c=[],d=0;12>d;d++)c.push(new Date(b,d,1));return c},getVisibleHours:function(a){a=new Date(a||new Date),a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0);for(var b=[],c=0;24>c;c++)b.push(a),a=new Date(a.getTime()+36e5);return b},isAfter:function(a,b){return a=void 0!==a?new Date(a):a,b=new Date(b),a&&a.getTime()<=b.getTime()},isBefore:function(a,b){return a=void 0!==a?new Date(a):a,b=new Date(b),a.getTime()>=b.getTime()},isSameYear:function(a,b){return a=void 0!==a?new Date(a):a,b=new Date(b),a&&a.getFullYear()===b.getFullYear()},isSameMonth:function(a,b){return a=void 0!==a?new Date(a):a,b=new Date(b),this.isSameYear(a,b)&&a.getMonth()===b.getMonth()},isSameDay:function(a,b){return a=void 0!==a?new Date(a):a,b=new Date(b),this.isSameMonth(a,b)&&a.getDate()===b.getDate()},isSameHour:function(a,b){return a=void 0!==a?new Date(a):a,b=new Date(b),this.isSameDay(a,b)&&a.getHours()===b.getHours()},isSameMinutes:function(a,b){return a=void 0!==a?new Date(a):a,b=new Date(b),this.isSameHour(a,b)&&a.getMinutes()===b.getMinutes()}}});var b=a.module("datePicker");b.directive("dateRange",function(){return{templateUrl:"templates/daterange.html",scope:{start:"=",end:"="},link:function(a,b,c){c.$observe("disabled",function(b){a.disableDatePickers=!!b}),a.$watch("start.getTime()",function(b){b&&a.end&&b>a.end.getTime()&&(a.end=new Date(b))}),a.$watch("end.getTime()",function(b){b&&a.start&&b'},format:"yyyy-MM-dd HH:mm",views:["date","year","month","hours","minutes"],dismiss:!1,position:"relative"}),b.directive("dateTimeAppend",function(){return{link:function(a,b){b.bind("click",function(){b.find("input")[0].focus()})}}}),b.directive("dateTime",["$compile","$document","$filter","dateTimeConfig","$parse",function(b,e,f,g,h){var i=e.find("body"),j=f("date");return{require:"ngModel",scope:!0,link:function(e,f,k,l){function m(a){return j(a,r)}function n(){return l.$modelValue}function o(a){a.stopPropagation(),l.$pristine&&(l.$dirty=!0,l.$pristine=!1,f.removeClass(c).addClass(d),s&&s.$setDirty(),l.$render())}function p(){x&&(x.remove(),x=null),z&&(z.remove(),z=null)}function q(){if(!x){if(x=b(A)(e),e.$digest(),e.$on("setDate",function(a,b,c){o(a),w&&t[t.length-1]===c&&p()}),e.$on("$destroy",p),"absolute"===y){var c=a.extend(f.offset(),{height:f[0].offsetHeight});x.css({top:c.top+c.height,left:c.left,display:"block",position:y}),i.append(x)}else z=a.element("
"),f[0].parentElement.insertBefore(z[0],f[0]),z.append(x),x.css({top:f[0].offsetHeight+"px",display:"block"});x.bind("mousedown",function(a){a.preventDefault()})}}var r=k.format||g.format,s=f.inheritedData("$formController"),t=h(k.views)(e)||g.views.concat(),u=k.view||t[0],v=t.indexOf(u),w=k.dismiss?h(k.dismiss)(e):g.dismiss,x=null,y=k.position||g.position,z=null;-1===v&&t.splice(v,1),t.unshift(u),l.$formatters.push(m),l.$parsers.unshift(n);var A=g.template(k);f.bind("focus",q),f.bind("blur",p)}}}]),a.module("datePicker").run(["$templateCache",function(a){a.put("templates/datepicker.html",'
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{date|date:"yyyy MMMM"}}
{{ day|date:"EEE" }}
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{years[0].getFullYear()}}-{{years[years.length-1].getFullYear()}}
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ date|date:"yyyy" }}
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ date|date:"dd MMMM yyyy" }}
\r\n \r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
{{ date|date:"dd MMMM yyyy" }}\r\n
\r\n \r\n
\r\n
\r\n
\r\n'),a.put("templates/daterange.html",'
\r\n \r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n')}])}(angular); \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js index 64630d0..a72e59d 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -46,7 +46,7 @@ autoWatch = false; // - Safari (only Mac) // - PhantomJS // - IE (only Windows) -browsers = ['ChromeCanary']; +browsers = ['Chrome']; // If browser does not capture in given timeout [ms], kill it captureTimeout = 5000; diff --git a/package.json b/package.json index 1e685a0..12a65f3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-datepicker", - "version": "0.0.0", + "version": "1.0.0", "dependencies": {}, "devDependencies": { "grunt": "~0.4.1", @@ -22,10 +22,12 @@ "grunt-rev": "~0.1.0", "grunt-karma": "~0.3.0", "grunt-open": "~0.2.0", - "matchdep": "~0.1.1", "grunt-google-cdn": "~0.1.1", "grunt-ngmin": "~0.0.2", - "grunt-angular-templates": "~0.3.8" + "grunt-angular-templates": "~0.3.8", + "grunt-contrib-less": "*", + "grunt-concurrent": "~0.4.0", + "load-grunt-tasks": "~0.2.0" }, "engines": { "node": ">=0.8.0" diff --git a/test/spec/datePickerUtilsTest.js b/test/spec/datePickerUtilsTest.js new file mode 100644 index 0000000..205d9ca --- /dev/null +++ b/test/spec/datePickerUtilsTest.js @@ -0,0 +1,136 @@ +describe('Test date Picker Utils', function(){ + var utils, constants; + + var model = new Date('2014-06-29T19:00:00.000Z'); + + beforeEach(angular.mock.module('datePicker')); + + beforeEach(angular.mock.inject(function($injector){ + utils = $injector.get('datePickerUtils'); + constants = $injector.get('datePickerConfig'); + })); + + it('get default visible minutes', function(){ + var mins = utils.getVisibleMinutes(null, constants.step); + + expect(mins).toBeDefined(); + }); + + it('get visible mins provided date', function(){ + var start = new Date('2014-06-29T19:00:00.000Z'); + var end = new Date('2014-06-29T19:55:00.000Z'); + var mins = utils.getVisibleMinutes(start, constants.step); + + expect(mins).toBeDefined(); + expect(mins[0]).toEqual(start); + expect(mins[mins.length-1]).toEqual(end); + }); + + it('get default visible weeks', function(){ + var weeks = utils.getVisibleWeeks(null, constants.step); + + expect(weeks).toBeDefined(); + }); + + it('get visible weeks provided date', function(){ + var start = new Date('2014-05-26T07:00:00.000Z'); + var end = new Date('2014-07-06T07:00:00.000Z'); + var chosen = new Date('2014-06-29T19:00:00.000Z'); + var weeks = utils.getVisibleWeeks(chosen, constants.step); + + expect(weeks).toBeDefined(); + expect(weeks[0][0]).toEqual(start); + expect(weeks[5][weeks[5].length-1]).toEqual(end); + }); + + it('get default visible years', function(){ + var years = utils.getVisibleYears(null, constants.step); + + expect(years).toBeDefined(); + }); + + it('get visible years provided date', function(){ + var start = new Date('2009-01-01T08:00:00.000Z'); + var end = new Date('2020-01-01T08:00:00.000Z'); + var chosen = new Date('2014-06-29T19:00:00.000Z'); + var years = utils.getVisibleYears(chosen, constants.step); + + expect(years).toBeDefined(); + expect(years[0]).toEqual(start); + expect(years[years.length-1]).toEqual(end); + }); + + it('get default days of week', function(){ + var days = utils.getDaysOfWeek(null); + + expect(days).toBeDefined(); + }); + + it('get days of week provided date', function(){ + var start = new Date('2014-05-26T07:00:00.000Z'); + var end = new Date('2014-06-01T07:00:00.000Z'); + var days = utils.getDaysOfWeek(start); + + expect(days).toBeDefined(); + expect(days[0]).toEqual(start); + expect(days[days.length-1]).toEqual(end); + }); + + it('get default months', function(){ + var months = utils.getVisibleMonths(null); + + expect(months).toBeDefined(); + }); + + it('get default months provided date', function(){ + var start = new Date('2014-01-01T08:00:00.000Z'); + var end = new Date('2014-12-01T08:00:00.000Z'); + var chosen = new Date('2014-06-29T19:00:00.000Z'); + var months = utils.getVisibleMonths(chosen); + + expect(months).toBeDefined(); + expect(months[0]).toEqual(start); + expect(months[months.length-1]).toEqual(end); + }); + + it('get default hours', function(){ + var hours = utils.getVisibleHours(null); + + expect(hours).toBeDefined(); + }); + + it('get default hours provided date', function(){ + var start = new Date('2014-06-29T07:00:00.000Z'); + var end = new Date('2014-06-30T06:00:00.000Z'); + var chosen = new Date('2014-06-29T19:00:00.000Z'); + var hours = utils.getVisibleHours(chosen); + + expect(hours).toBeDefined(); + expect(hours[0]).toEqual(start); + expect(hours[hours.length-1]).toEqual(end); + }); + + it('model is after date', function(){ + var dateAfter = new Date('2014-06-29T20:00:00.000Z'); + + expect(utils.isAfter(model, dateAfter)).toBe(true); + expect(utils.isBefore(model, dateAfter)).toBe(false); + }); + + it('model is before date', function(){ + var dateAfter = new Date('2014-06-29T18:00:00.000Z'); + + expect(utils.isAfter(model, dateAfter)).toBe(false); + expect(utils.isBefore(model, dateAfter)).toBe(true); + }); + + it('model is almost same', function(){ + var dateSimilar = new Date('2014-06-29T19:00:55.555Z'); + + expect(utils.isSameYear(model, dateSimilar)).toBe(true); + expect(utils.isSameMonth(model, dateSimilar)).toBe(true); + expect(utils.isSameDay(model, dateSimilar)).toBe(true); + expect(utils.isSameHour(model, dateSimilar)).toBe(true); + expect(utils.isSameMinutes(model, dateSimilar)).toBe(true); + }); +}); \ No newline at end of file