From ebe38fd0f3859d84c975bfe00819d98d49d8840c Mon Sep 17 00:00:00 2001 From: Laury GvR Date: Thu, 30 Jun 2016 15:11:28 -0400 Subject: [PATCH 1/1] Initial commit --- glm-timecard.php | 255 +++ js/datepair/GruntFile.js | 55 + js/datepair/README.md | 156 ++ js/datepair/bower.json | 23 + js/datepair/datepair.jquery.json | 27 + js/datepair/dist/datepair.js | 361 +++++ js/datepair/dist/datepair.min.js | 7 + js/datepair/dist/jquery.datepair.js | 46 + js/datepair/dist/jquery.datepair.min.js | 7 + js/datepair/index.html | 503 ++++++ js/datepair/lib/jquery.ptTimeSelect.css | 83 + js/datepair/lib/jquery.ptTimeSelect.js | 478 ++++++ js/datepair/lib/moment.min.js | 6 + js/datepair/lib/pikaday.css | 173 ++ js/datepair/lib/pikaday.js | 973 ++++++++++++ js/datepair/lib/site.css | 200 +++ js/datepair/lib/site.js | 10 + js/datepair/package.json | 24 + js/datepair/src/Datepair.js | 347 ++++ js/datepair/src/jquery.datepair.js | 40 + js/datepair/src/wrapper.js | 9 + js/timepicker/GruntFile.js | 41 + js/timepicker/README.md | 294 ++++ js/timepicker/bower.json | 16 + js/timepicker/index.html | 391 +++++ js/timepicker/jquery.timepicker.css | 72 + js/timepicker/jquery.timepicker.d.ts | 152 ++ js/timepicker/jquery.timepicker.js | 1241 +++++++++++++++ js/timepicker/jquery.timepicker.min.js | 7 + js/timepicker/jt.timepicker.jquery.json | 27 + js/timepicker/lib/bootstrap-datepicker.css | 512 ++++++ js/timepicker/lib/bootstrap-datepicker.js | 1671 ++++++++++++++++++++ js/timepicker/lib/glyphicons-halflings.png | Bin 0 -> 13826 bytes js/timepicker/lib/screenshot.png | Bin 0 -> 4756 bytes js/timepicker/lib/site.css | 195 +++ js/timepicker/lib/site.js | 10 + js/timepicker/package.json | 34 + 37 files changed, 8446 insertions(+) create mode 100644 glm-timecard.php create mode 100644 js/datepair/GruntFile.js create mode 100644 js/datepair/README.md create mode 100644 js/datepair/bower.json create mode 100644 js/datepair/datepair.jquery.json create mode 100644 js/datepair/dist/datepair.js create mode 100644 js/datepair/dist/datepair.min.js create mode 100644 js/datepair/dist/jquery.datepair.js create mode 100644 js/datepair/dist/jquery.datepair.min.js create mode 100644 js/datepair/index.html create mode 100644 js/datepair/lib/jquery.ptTimeSelect.css create mode 100644 js/datepair/lib/jquery.ptTimeSelect.js create mode 100644 js/datepair/lib/moment.min.js create mode 100644 js/datepair/lib/pikaday.css create mode 100644 js/datepair/lib/pikaday.js create mode 100644 js/datepair/lib/site.css create mode 100644 js/datepair/lib/site.js create mode 100644 js/datepair/package.json create mode 100644 js/datepair/src/Datepair.js create mode 100644 js/datepair/src/jquery.datepair.js create mode 100644 js/datepair/src/wrapper.js create mode 100644 js/timepicker/GruntFile.js create mode 100644 js/timepicker/README.md create mode 100644 js/timepicker/bower.json create mode 100644 js/timepicker/index.html create mode 100755 js/timepicker/jquery.timepicker.css create mode 100644 js/timepicker/jquery.timepicker.d.ts create mode 100644 js/timepicker/jquery.timepicker.js create mode 100644 js/timepicker/jquery.timepicker.min.js create mode 100644 js/timepicker/jt.timepicker.jquery.json create mode 100644 js/timepicker/lib/bootstrap-datepicker.css create mode 100755 js/timepicker/lib/bootstrap-datepicker.js create mode 100755 js/timepicker/lib/glyphicons-halflings.png create mode 100755 js/timepicker/lib/screenshot.png create mode 100644 js/timepicker/lib/site.css create mode 100644 js/timepicker/lib/site.js create mode 100644 js/timepicker/package.json diff --git a/glm-timecard.php b/glm-timecard.php new file mode 100644 index 0000000..cbbe0da --- /dev/null +++ b/glm-timecard.php @@ -0,0 +1,255 @@ + + + + + + + + + + + +
+

Staff Details

+ +
+ + +Monday:".strtotime('monday this week'); +// echo "

sunday:".date( 'Y-m-d', strtotime('sunday last week')); +// echo "

monday:".date( 'Y-m-d', strtotime('monday this week')); +// echo "

tuesday:".date( 'Y-m-d', strtotime('tuesday this week')); +// echo "

wednesday:".date( 'Y-m-d', strtotime('wednesday this week')); +// echo "

thursday:".date( 'Y-m-d', strtotime('thursday this week')); +// echo "

friday:".date( 'Y-m-d', strtotime('friday this week')); +// echo "

saturday:".date( 'Y-m-d', strtotime('saturday this week')); +// date_default_timezone_set('EST'); +// echo "EST:".time()."
"; +// $date = date('I','m/d/Y h:i:s a'); +// echo "

".var_dump($date, true)."


"; +// +// $nextWeek = time() + (7 * 24 * 60 * 60); +// +// ini_set('date.timezone', 'EST'); +// echo "time4".date('H:i:s', time() - date('Z')); +// echo "time5".date('H:i:s', gmdate('U')); +// echo "time6".date('H:i:s', time()); + + + // 7 days; 24 hours; 60 mins; 60 secs +//echo 'Now: '. date('Y-m-d') ."\n"; +//echo 'Next Week: '. date('Y-m-d', $nextWeek) ."\n"; +// or using strtotime(): +//echo 'Next Week: '. date('Y-m-d', strtotime('+1 week')) ."\n"; + +echo "

For week starting Monday, ". date( 'Y-m-d', strtotime("monday this week")) ." and ending Sunday, " . date( 'Y-m-d', strtotime("this sunday"))."

"; + + ?> + + + + + + + + + + + + + + + + + + + + + + + + +
DateDayStartEndLunchLunch MinutesTotal MinutesTotal Hours
+ + + + + + +
+ " /> +
Set field to current time
+
+ " /> +
Set field to current time
+
+ +
+ + + +
+
+ + \ No newline at end of file diff --git a/js/datepair/GruntFile.js b/js/datepair/GruntFile.js new file mode 100644 index 0000000..3d51b1a --- /dev/null +++ b/js/datepair/GruntFile.js @@ -0,0 +1,55 @@ +module.exports = function(grunt) { + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + meta: { + banner: '/*!\n' + + ' * <%= pkg.name %> v<%= pkg.version %> - <%= pkg.description %>\n' + + ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> - <%= pkg.homepage %>\n' + + ' * License: <%= pkg.license %>\n' + + ' */\n\n' + }, + + rig: { + options: { + banner: '<%= meta.banner %>' + }, + dist: { + files: { + 'dist/datepair.js': ['src/wrapper.js'], + 'dist/jquery.datepair.js' : ['src/jquery.datepair.js'], + } + } + }, + + uglify: { + options: { + banner: '<%= meta.banner %>', + report: 'gzip' + }, + dist: { + files: { + 'dist/datepair.min.js': 'dist/datepair.js', + 'dist/jquery.datepair.min.js': ['dist/datepair.js', 'dist/jquery.datepair.js'], + } + } + }, + jshint: { + all: ['src/*.js'] + }, + + watch: { + options : { + atBegin : true + }, + files: ['src/*.js'], + tasks: ['rig'] + } + }); + + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-rigger'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + + grunt.registerTask('default', ['rig', 'uglify']); +}; diff --git a/js/datepair/README.md b/js/datepair/README.md new file mode 100644 index 0000000..3f0f2db --- /dev/null +++ b/js/datepair/README.md @@ -0,0 +1,156 @@ +# Datepair.js + +[See a demo and examples here](http://jonthornton.github.com/Datepair.js) + +Datepair.js is a lightweight, modular javascript plugin for intelligently selecting date and time ranges, inspired by Google Calendar. It will keep the start and end date/times in sync and can set default values based on user action. There are no external dependencies, however it can easily be used with jQuery or Zepto. The plugin does not provide any UI widgets; it's preconfigured to work with [jquery-timepicker](https://github.com/jonthornton/jquery-timepicker) and [Bootstrap Datepicker](https://github.com/eternicode/bootstrap-datepicker), but you can use it with any datepicker or timepicker (or none at all). + +*Looking for [jquery-datepair](#jquery-plugin)? Scroll down.* + +## Requirements + +* [jquery-timepicker](https://github.com/jonthornton/jquery-timepicker) (>= 1.3) (this dependency can be overridden) +* [Bootstrap Datepicker](https://github.com/eternicode/bootstrap-datepicker) (>= 1.3) (this dependency can be overridden) + +## Usage + +Include `dist/datepair.js` or `dist/jquery.datepair.min.js` in your app. + +```javascript +var container = document.getElementById('container') +var datepair = new Datepair(container, options); +``` + +Where ```#container``` contains time/date input elements with the appropriate class names. ```options``` is an optional javascript object with parameters explained below. + +You can also install via [Bower](http://bower.io/) with `bower install datepair.js`. + +## Options + +- **anchor** +The input that will control the other input. One of `"start"`, `"end"`, or `null`. See [demo page](http://jonthornton.github.io/Datepair.js/) for more information. +*default: "start"* + +- **dateClass** +Class name of the date inputs, if any. +*default: "date"* + +- **defaultDateDelta** +Fill in the second date value with the specified range when the users selects the first date. Value is in days. Set this to ```null``` to disable automatically setting the second date. +*default: 0* + +- **defaultTimeDelta** +Fill in the second time value with the specified range when the users selects the first time. Value is in milliseconds; set this to ```7200000``` for a 2 hour range, for example. Set this to ```null``` to disable automatically setting the second time. +*default: 0* + +- **endClass** +Class name of the range end input(s). +*default: "end"* + +- **parseDate** +A function that takes a jQuery element for a date input and returns a local time ```Date``` object representing the date input value. +*default: function for [Bootstrap Datepicker](https://github.com/eternicode/bootstrap-datepicker)* + +- **parseTime** +A function that takes a jQuery element for a time input and returns a local time ```Date``` object representing the time input value. See [example page](http://jonthornton.github.com/Datepair.js) for more info. +*default: function for [jquery-timepicker](https://github.com/jonthornton/jquery-timepicker)* + +- **setMinTime** +A function that takes a jQuery element for a time input and a local time ```Date``` object representing the time, and sets the timepicker minTime value. +*default: function for [jquery-timepicker](https://github.com/jonthornton/jquery-timepicker)* + +- **startClass** +Class name of the range start input(s). +*default: "start"* + +- **timeClass** +Class name of the time inputs, if any. +*default: "time"* + +- **updateDate** +A function that takes a jQuery element for a date input and a local time ```Date``` object representing the date, and sets the input value. +*default: function for [Bootstrap Datepicker](https://github.com/eternicode/bootstrap-datepicker)* + +- **updateTime** +A function that takes a jQuery element for a time input and a local time ```Date``` object representing the time, and sets the input value. +*default: function for [jquery-timepicker](https://github.com/jonthornton/jquery-timepicker)* + + +## Methods + +- **getTimeDiff** +Get the date/time range size, in milliseconds. + + ```javascript + var milliseconds = datepair.getTimeDiff(); + ``` + +- **refresh** +Call this method if you programmatically update the date/time fields after first initialization of datepair. + + ```javascript + $('#someInput').val(someValue) + datepair.refresh(); + ``` + +- **remove** +Unbind the datepair functionality from a set of inputs. + + ```javascript + datepair.remove(); + ``` + +## Events + +- **rangeError** +Fired after the user interacts with the datepair inputs but selects an invalid range, where the end time/date is before the start. + +- **rangeIncomplete** +Fired after the user interacts with the datepair inputs but one or more empty inputs remain. Unpaired inputs (such as a start date with no corresponding end date) will not be taken into account. + +- **rangeSelected** +Fired after the user interacts with the datepair inputs and all paired inputs have valid values. + +## jQuery Plugin + +Datepair.js includes an optional jQuery interface that can simplify usage when working with jQuery or Zepto. To activate, include both `datepair.js` and `jquery.datepair.js`, or just `jquery.datepair.min.js`. (The minified version includes both scripts.) + +### Usage + +```javascript +$('#container').datepair(options); +var milliseconds = $('#container').datepair('getTimeDiff'); +$('#container').datepair('remove'); +$('#container').datepair('refresh'); +``` + +## jQuery-UI Datepicker + +By default, Datepair.js is configured to work with [Bootstrap Datepicker](https://github.com/eternicode/bootstrap-datepicker). This is different from [jQuery UI Datepicker](http://jqueryui.com/datepicker/). To use jQuery UI Datepicker, override the `parseDate` and `updateDate` methods: + +```javascript +$('#some-container').datepair({ + parseDate: function (el) { + var utc = new Date($(el).datepicker('getDate')); + return utc && new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000)); + }, + updateDate: function (el, v) { + $(el).datepicker('setDate', new Date(v.getTime() - (v.getTimezoneOffset() * 60000))); + } +}); +``` + +## Help + +Submit a [GitHub Issues request](https://github.com/jonthornton/Datepair.js/issues/new). + +## Development Guidelines + +* Install dependencies (grunt) `npm install` +* To build and minify, run `grunt` +* Use `grunt watch` to continuously build while developing + +Datepair.js follows [semantic versioning](http://semver.org/). + +- - - + +This software is made available under the open source MIT License. © 2014 [Jon Thornton](http://www.jonthornton.com). diff --git a/js/datepair/bower.json b/js/datepair/bower.json new file mode 100644 index 0000000..79f48c5 --- /dev/null +++ b/js/datepair/bower.json @@ -0,0 +1,23 @@ +{ + "name": "datepair.js", + "version": "0.4.14", + "main": ["dist/datepair.js", "dist/jquery.datepair.js"], + "ignore": [ + "**/.*", + "node_modules", + "components", + "spec", + "Gruntfile.js", + "src", + "bower_components", + "test", + "tests" + ], + "homepage": "http://jonthornton.github.com/Datepair.js", + "authors": [ + "Jon Thornton" + ], + "description": "A javascript plugin for intelligently selecting date and time ranges inspired by Google Calendar.", + "keywords": [ "timepicker", "datepicker", "time", "date", "picker", "ui", "calendar", "input", "form" ], + "license": "MIT" +} diff --git a/js/datepair/datepair.jquery.json b/js/datepair/datepair.jquery.json new file mode 100644 index 0000000..0df8366 --- /dev/null +++ b/js/datepair/datepair.jquery.json @@ -0,0 +1,27 @@ +{ + "name": "datepair", + "version": "0.4.10", + "title": "Datepair.js", + "description": "A plugin for intelligently selecting date and time ranges inspired by Google Calendar.", + "author": { + "name": "Jon Thornton", + "email": "thornton.jon@gmail.com", + "url": "https://github.com/jonthornton" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://opensource.org/licenses/MIT" + } + ], + "dependencies": { + "jquery": ">=1.7" + }, + "keywords": [ "timepicker", "datepicker", "time", "date", "picker", "ui", "calendar", "input", "form" ], + "homepage": "http://jonthornton.github.com/jquery-datepair/", + "bugs": { + "url": "https://github.com/jonthornton/jquery-datepair/issues" + }, + "docs": "https://github.com/jonthornton/jquery-datepair", + "download": "https://github.com/jonthornton/jquery-datepair" +} diff --git a/js/datepair/dist/datepair.js b/js/datepair/dist/datepair.js new file mode 100644 index 0000000..2b5dc28 --- /dev/null +++ b/js/datepair/dist/datepair.js @@ -0,0 +1,361 @@ +/*! + * datepair.js v0.4.14 - A javascript plugin for intelligently selecting date and time ranges inspired by Google Calendar. + * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/Datepair.js + * License: MIT + */ + +(function(window, document) { + + 'use strict'; + + var _ONE_DAY = 86400000; + var jq = window.Zepto || window.jQuery; + + function simpleExtend(obj1, obj2) { + var out = obj2 || {}; + + for (var i in obj1) { + if (!(i in out)) { + out[i] = obj1[i]; + } + } + + return out; + } + + // IE's custom event support is totally borked. + // Use jQuery if possible + function triggerSimpleCustomEvent(el, eventName) { + if (jq) { + jq(el).trigger(eventName); + } else { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent(eventName, true, true, {}); + el.dispatchEvent(event); + } + } + + // el.classList not supported by < IE10 + // use jQuery if available + function hasClass(el, className) { + if (jq) { + return jq(el).hasClass(className); + } else { + return el.classList.contains(className); + } + } + + function Datepair(container, options) { + this.dateDelta = null; + this.timeDelta = null; + this._defaults = { + startClass: 'start', + endClass: 'end', + timeClass: 'time', + dateClass: 'date', + defaultDateDelta: 0, + defaultTimeDelta: 3600000, + anchor: 'start', + + // defaults for jquery-timepicker; override when using other input widgets + parseTime: function(input){ + return jq(input).timepicker('getTime'); + }, + updateTime: function(input, dateObj){ + jq(input).timepicker('setTime', dateObj); + }, + setMinTime: function(input, dateObj){ + jq(input).timepicker('option', 'minTime', dateObj); + }, + + // defaults for bootstrap datepicker; override when using other input widgets + parseDate: function(input){ + return input.value && jq(input).datepicker('getDate'); + }, + updateDate: function(input, dateObj){ + jq(input).datepicker('update', dateObj); + } + }; + + this.container = container; + this.settings = simpleExtend(this._defaults, options); + + this.startDateInput = this.container.querySelector('.'+this.settings.startClass+'.'+this.settings.dateClass); + this.endDateInput = this.container.querySelector('.'+this.settings.endClass+'.'+this.settings.dateClass); + this.startTimeInput = this.container.querySelector('.'+this.settings.startClass+'.'+this.settings.timeClass); + this.endTimeInput = this.container.querySelector('.'+this.settings.endClass+'.'+this.settings.timeClass); + + // initialize date and time deltas + this.refresh(); + + // init starts here + this._bindChangeHandler(); + } + + Datepair.prototype = { + constructor: Datepair, + + option: function(key, value) + { + if (typeof key == 'object') { + this.settings = simpleExtend(this.settings, key); + + } else if (typeof key == 'string' && typeof value != 'undefined') { + this.settings[key] = value; + + } else if (typeof key == 'string') { + return this.settings[key]; + } + + this._updateEndMintime(); + }, + + getTimeDiff: function() + { + // due to the fact that times can wrap around, timeDiff for any + // time-only pair will always be >= 0 + var delta = this.dateDelta + this.timeDelta; + if (delta < 0 && (!this.startDateInput || !this.endDateInput) ) { + delta += _ONE_DAY; + } + + return delta; + }, + + refresh: function() + { + if (this.startDateInput && this.startDateInput.value && this.endDateInput && this.endDateInput.value) { + var startDate = this.settings.parseDate(this.startDateInput); + var endDate = this.settings.parseDate(this.endDateInput); + if (startDate && endDate) { + this.dateDelta = endDate.getTime() - startDate.getTime(); + } + } + if (this.startTimeInput && this.startTimeInput.value && this.endTimeInput && this.endTimeInput.value) { + var startTime = this.settings.parseTime(this.startTimeInput); + var endTime = this.settings.parseTime(this.endTimeInput); + if (startTime && endTime) { + this.timeDelta = endTime.getTime() - startTime.getTime(); + this._updateEndMintime(); + } + } + }, + + remove: function() + { + this._unbindChangeHandler(); + }, + + _bindChangeHandler: function(){ + // addEventListener doesn't work with synthetic "change" events + // fired by jQuery's trigger() functioin. If jQuery is present, + // use that for event binding + if (jq) { + jq(this.container).on('change.datepair', jq.proxy(this.handleEvent, this)); + } else { + this.container.addEventListener('change', this, false); + } + }, + + _unbindChangeHandler: function(){ + if (jq) { + jq(this.container).off('change.datepair'); + } else { + this.container.removeEventListener('change', this, false); + } + }, + + // This function will be called when passing 'this' to addEventListener + handleEvent: function(e){ + // temporarily unbind the change handler to prevent triggering this + // if we update other inputs + this._unbindChangeHandler(); + + if (hasClass(e.target, this.settings.dateClass)) { + if (e.target.value != '') { + this._dateChanged(e.target); + this._timeChanged(e.target); + } else { + this.dateDelta = null; + } + + } else if (hasClass(e.target, this.settings.timeClass)) { + if (e.target.value != '') { + this._timeChanged(e.target); + } else { + this.timeDelta = null; + } + } + + this._validateRanges(); + this._updateEndMintime(); + this._bindChangeHandler(); + }, + + _dateChanged: function(target){ + if (!this.startDateInput || !this.endDateInput) { + return; + } + + var startDate = this.settings.parseDate(this.startDateInput); + var endDate = this.settings.parseDate(this.endDateInput); + + if (!startDate || !endDate) { + if (this.settings.defaultDateDelta !== null) { + if (startDate) { + var newEnd = new Date(startDate.getTime() + this.settings.defaultDateDelta * _ONE_DAY); + this.settings.updateDate(this.endDateInput, newEnd); + + } else if (endDate) { + var newStart = new Date(endDate.getTime() - this.settings.defaultDateDelta * _ONE_DAY); + this.settings.updateDate(this.startDateInput, newStart); + } + + this.dateDelta = this.settings.defaultDateDelta * _ONE_DAY; + } else { + this.dateDelta = null; + } + + return; + } + + if (this.settings.anchor == 'start' && hasClass(target, this.settings.startClass)) { + var newDate = new Date(startDate.getTime() + this.dateDelta); + this.settings.updateDate(this.endDateInput, newDate); + } else if (this.settings.anchor == 'end' && hasClass(target, this.settings.endClass)) { + var newDate = new Date(endDate.getTime() - this.dateDelta); + this.settings.updateDate(this.startDateInput, newDate); + } else { + if (endDate < startDate) { + var otherInput = hasClass(target, this.settings.startClass) ? this.endDateInput : this.startDateInput; + var selectedDate = this.settings.parseDate(target); + this.dateDelta = 0; + this.settings.updateDate(otherInput, selectedDate); + } else { + this.dateDelta = endDate.getTime() - startDate.getTime(); + } + } + }, + + _timeChanged: function(target){ + if (!this.startTimeInput || !this.endTimeInput) { + return; + } + + var startTime = this.settings.parseTime(this.startTimeInput); + var endTime = this.settings.parseTime(this.endTimeInput); + + if (!startTime || !endTime) { + if (this.settings.defaultTimeDelta !== null) { + if (startTime) { + var newEnd = new Date(startTime.getTime() + this.settings.defaultTimeDelta); + this.settings.updateTime(this.endTimeInput, newEnd); + } else if (endTime) { + var newStart = new Date(endTime.getTime() - this.settings.defaultTimeDelta); + this.settings.updateTime(this.startTimeInput, newStart); + } + + this.timeDelta = this.settings.defaultTimeDelta; + } else { + this.timeDelta = null; + } + + return; + } + + if (this.settings.anchor == 'start' && hasClass(target, this.settings.startClass)) { + var newTime = new Date(startTime.getTime() + this.timeDelta); + this.settings.updateTime(this.endTimeInput, newTime); + endTime = this.settings.parseTime(this.endTimeInput); + + this._doMidnightRollover(startTime, endTime); + } else if (this.settings.anchor == 'end' && hasClass(target, this.settings.endClass)) { + var newTime = new Date(endTime.getTime() - this.timeDelta); + this.settings.updateTime(this.startTimeInput, newTime); + startTime = this.settings.parseTime(this.startTimeInput); + + this._doMidnightRollover(startTime, endTime); + } else { + this._doMidnightRollover(startTime, endTime); + + var startDate, endDate; + if (this.startDateInput && this.endDateInput) { + startDate = this.settings.parseDate(this.startDateInput); + endDate = this.settings.parseDate(this.endDateInput); + } + + if ((+startDate == +endDate) && (endTime < startTime)) { + var thisInput = hasClass(target, this.settings.endClass) ? this.endTimeInput : this.startTimeInput; + var otherInput = hasClass(target, this.settings.startClass) ? this.endTimeInput : this.startTimeInput; + var selectedTime = this.settings.parseTime(thisInput); + this.timeDelta = 0; + this.settings.updateTime(otherInput, selectedTime); + } else { + this.timeDelta = endTime.getTime() - startTime.getTime(); + } + } + + + }, + + _doMidnightRollover: function(startTime, endTime) { + if (!this.startDateInput || !this.endDateInput) { + return; + } + + var endDate = this.settings.parseDate(this.endDateInput); + var startDate = this.settings.parseDate(this.startDateInput); + var newDelta = endTime.getTime() - startTime.getTime(); + var offset = (endTime < startTime) ? _ONE_DAY : -1 * _ONE_DAY; + + if (this.dateDelta !== null + && this.dateDelta + this.timeDelta <= _ONE_DAY + && this.dateDelta + newDelta != 0 + && (offset > 0 || this.dateDelta != 0) + && ((newDelta >= 0 && this.timeDelta < 0) || (newDelta < 0 && this.timeDelta >= 0))) { + + if (this.settings.anchor == 'start') { + this.settings.updateDate(this.endDateInput, new Date(endDate.getTime() + offset)); + this._dateChanged(this.endDateInput); + } else if (this.settings.anchor == 'end') { + this.settings.updateDate(this.startDateInput, new Date(startDate.getTime() - offset)); + this._dateChanged(this.startDateInput); + } + } + this.timeDelta = newDelta; + }, + + _updateEndMintime: function(){ + if (typeof this.settings.setMinTime != 'function') return; + + var baseTime = null; + if (this.settings.anchor == 'start' && (!this.dateDelta || this.dateDelta < _ONE_DAY || (this.timeDelta && this.dateDelta + this.timeDelta < _ONE_DAY))) { + baseTime = this.settings.parseTime(this.startTimeInput); + } + + this.settings.setMinTime(this.endTimeInput, baseTime); + }, + + _validateRanges: function(){ + if (this.startTimeInput && this.endTimeInput && this.timeDelta === null) { + triggerSimpleCustomEvent(this.container, 'rangeIncomplete'); + return; + } + + if (this.startDateInput && this.endDateInput && this.dateDelta === null) { + triggerSimpleCustomEvent(this.container, 'rangeIncomplete'); + return; + } + + // due to the fact that times can wrap around, any time-only pair will be considered valid + if (!this.startDateInput || !this.endDateInput || this.dateDelta + this.timeDelta >= 0) { + triggerSimpleCustomEvent(this.container, 'rangeSelected'); + } else { + triggerSimpleCustomEvent(this.container, 'rangeError'); + } + } + }; + + window.Datepair = Datepair; + +}(window, document)); \ No newline at end of file diff --git a/js/datepair/dist/datepair.min.js b/js/datepair/dist/datepair.min.js new file mode 100644 index 0000000..b4b13ea --- /dev/null +++ b/js/datepair/dist/datepair.min.js @@ -0,0 +1,7 @@ +/*! + * datepair.js v0.4.14 - A javascript plugin for intelligently selecting date and time ranges inspired by Google Calendar. + * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/Datepair.js + * License: MIT + */ + +!function(a,b){"use strict";function c(a,b){var c=b||{};for(var d in a)d in c||(c[d]=a[d]);return c}function d(a,c){if(h)h(a).trigger(c);else{var d=b.createEvent("CustomEvent");d.initCustomEvent(c,!0,!0,{}),a.dispatchEvent(d)}}function e(a,b){return h?h(a).hasClass(b):a.classList.contains(b)}function f(a,b){this.dateDelta=null,this.timeDelta=null,this._defaults={startClass:"start",endClass:"end",timeClass:"time",dateClass:"date",defaultDateDelta:0,defaultTimeDelta:36e5,anchor:"start",parseTime:function(a){return h(a).timepicker("getTime")},updateTime:function(a,b){h(a).timepicker("setTime",b)},setMinTime:function(a,b){h(a).timepicker("option","minTime",b)},parseDate:function(a){return a.value&&h(a).datepicker("getDate")},updateDate:function(a,b){h(a).datepicker("update",b)}},this.container=a,this.settings=c(this._defaults,b),this.startDateInput=this.container.querySelector("."+this.settings.startClass+"."+this.settings.dateClass),this.endDateInput=this.container.querySelector("."+this.settings.endClass+"."+this.settings.dateClass),this.startTimeInput=this.container.querySelector("."+this.settings.startClass+"."+this.settings.timeClass),this.endTimeInput=this.container.querySelector("."+this.settings.endClass+"."+this.settings.timeClass),this.refresh(),this._bindChangeHandler()}var g=864e5,h=a.Zepto||a.jQuery;f.prototype={constructor:f,option:function(a,b){if("object"==typeof a)this.settings=c(this.settings,a);else if("string"==typeof a&&"undefined"!=typeof b)this.settings[a]=b;else if("string"==typeof a)return this.settings[a];this._updateEndMintime()},getTimeDiff:function(){var a=this.dateDelta+this.timeDelta;return!(0>a)||this.startDateInput&&this.endDateInput||(a+=g),a},refresh:function(){if(this.startDateInput&&this.startDateInput.value&&this.endDateInput&&this.endDateInput.value){var a=this.settings.parseDate(this.startDateInput),b=this.settings.parseDate(this.endDateInput);a&&b&&(this.dateDelta=b.getTime()-a.getTime())}if(this.startTimeInput&&this.startTimeInput.value&&this.endTimeInput&&this.endTimeInput.value){var c=this.settings.parseTime(this.startTimeInput),d=this.settings.parseTime(this.endTimeInput);c&&d&&(this.timeDelta=d.getTime()-c.getTime(),this._updateEndMintime())}},remove:function(){this._unbindChangeHandler()},_bindChangeHandler:function(){h?h(this.container).on("change.datepair",h.proxy(this.handleEvent,this)):this.container.addEventListener("change",this,!1)},_unbindChangeHandler:function(){h?h(this.container).off("change.datepair"):this.container.removeEventListener("change",this,!1)},handleEvent:function(a){this._unbindChangeHandler(),e(a.target,this.settings.dateClass)?""!=a.target.value?(this._dateChanged(a.target),this._timeChanged(a.target)):this.dateDelta=null:e(a.target,this.settings.timeClass)&&(""!=a.target.value?this._timeChanged(a.target):this.timeDelta=null),this._validateRanges(),this._updateEndMintime(),this._bindChangeHandler()},_dateChanged:function(a){if(this.startDateInput&&this.endDateInput){var b=this.settings.parseDate(this.startDateInput),c=this.settings.parseDate(this.endDateInput);if(b&&c)if("start"==this.settings.anchor&&e(a,this.settings.startClass)){var d=new Date(b.getTime()+this.dateDelta);this.settings.updateDate(this.endDateInput,d)}else if("end"==this.settings.anchor&&e(a,this.settings.endClass)){var d=new Date(c.getTime()-this.dateDelta);this.settings.updateDate(this.startDateInput,d)}else if(b>c){var f=e(a,this.settings.startClass)?this.endDateInput:this.startDateInput,h=this.settings.parseDate(a);this.dateDelta=0,this.settings.updateDate(f,h)}else this.dateDelta=c.getTime()-b.getTime();else if(null!==this.settings.defaultDateDelta){if(b){var i=new Date(b.getTime()+this.settings.defaultDateDelta*g);this.settings.updateDate(this.endDateInput,i)}else if(c){var j=new Date(c.getTime()-this.settings.defaultDateDelta*g);this.settings.updateDate(this.startDateInput,j)}this.dateDelta=this.settings.defaultDateDelta*g}else this.dateDelta=null}},_timeChanged:function(a){if(this.startTimeInput&&this.endTimeInput){var b=this.settings.parseTime(this.startTimeInput),c=this.settings.parseTime(this.endTimeInput);if(b&&c)if("start"==this.settings.anchor&&e(a,this.settings.startClass)){var d=new Date(b.getTime()+this.timeDelta);this.settings.updateTime(this.endTimeInput,d),c=this.settings.parseTime(this.endTimeInput),this._doMidnightRollover(b,c)}else if("end"==this.settings.anchor&&e(a,this.settings.endClass)){var d=new Date(c.getTime()-this.timeDelta);this.settings.updateTime(this.startTimeInput,d),b=this.settings.parseTime(this.startTimeInput),this._doMidnightRollover(b,c)}else{this._doMidnightRollover(b,c);var f,g;if(this.startDateInput&&this.endDateInput&&(f=this.settings.parseDate(this.startDateInput),g=this.settings.parseDate(this.endDateInput)),+f==+g&&b>c){var h=e(a,this.settings.endClass)?this.endTimeInput:this.startTimeInput,i=e(a,this.settings.startClass)?this.endTimeInput:this.startTimeInput,j=this.settings.parseTime(h);this.timeDelta=0,this.settings.updateTime(i,j)}else this.timeDelta=c.getTime()-b.getTime()}else if(null!==this.settings.defaultTimeDelta){if(b){var k=new Date(b.getTime()+this.settings.defaultTimeDelta);this.settings.updateTime(this.endTimeInput,k)}else if(c){var l=new Date(c.getTime()-this.settings.defaultTimeDelta);this.settings.updateTime(this.startTimeInput,l)}this.timeDelta=this.settings.defaultTimeDelta}else this.timeDelta=null}},_doMidnightRollover:function(a,b){if(this.startDateInput&&this.endDateInput){var c=this.settings.parseDate(this.endDateInput),d=this.settings.parseDate(this.startDateInput),e=b.getTime()-a.getTime(),f=a>b?g:-1*g;null!==this.dateDelta&&this.dateDelta+this.timeDelta<=g&&this.dateDelta+e!=0&&(f>0||0!=this.dateDelta)&&(e>=0&&this.timeDelta<0||0>e&&this.timeDelta>=0)&&("start"==this.settings.anchor?(this.settings.updateDate(this.endDateInput,new Date(c.getTime()+f)),this._dateChanged(this.endDateInput)):"end"==this.settings.anchor&&(this.settings.updateDate(this.startDateInput,new Date(d.getTime()-f)),this._dateChanged(this.startDateInput))),this.timeDelta=e}},_updateEndMintime:function(){if("function"==typeof this.settings.setMinTime){var a=null;"start"==this.settings.anchor&&(!this.dateDelta||this.dateDelta=0?d(this.container,"rangeSelected"):d(this.container,"rangeError"))}},a.Datepair=f}(window,document); \ No newline at end of file diff --git a/js/datepair/dist/jquery.datepair.js b/js/datepair/dist/jquery.datepair.js new file mode 100644 index 0000000..1964a7f --- /dev/null +++ b/js/datepair/dist/jquery.datepair.js @@ -0,0 +1,46 @@ +/*! + * datepair.js v0.4.14 - A javascript plugin for intelligently selecting date and time ranges inspired by Google Calendar. + * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/Datepair.js + * License: MIT + */ + +(function($) { + + if(!$) { + return; + } + + //////////// + // Plugin // + //////////// + + $.fn.datepair = function(option) { + var out; + this.each(function() { + var $this = $(this); + var data = $this.data('datepair'); + var options = typeof option === 'object' && option; + + if (!data) { + data = new Datepair(this, options); + $this.data('datepair', data); + } + + if (typeof option === 'string') { + out = data[option](); + } + }); + + return out || this; + }; + + ////////////// + // Data API // + ////////////// + + $('[data-datepair]').each(function() { + var $this = $(this); + $this.datepair($this.data()); + }); + +}(window.Zepto || window.jQuery)); \ No newline at end of file diff --git a/js/datepair/dist/jquery.datepair.min.js b/js/datepair/dist/jquery.datepair.min.js new file mode 100644 index 0000000..f49b667 --- /dev/null +++ b/js/datepair/dist/jquery.datepair.min.js @@ -0,0 +1,7 @@ +/*! + * datepair.js v0.4.14 - A javascript plugin for intelligently selecting date and time ranges inspired by Google Calendar. + * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/Datepair.js + * License: MIT + */ + +!function(a,b){"use strict";function c(a,b){var c=b||{};for(var d in a)d in c||(c[d]=a[d]);return c}function d(a,c){if(h)h(a).trigger(c);else{var d=b.createEvent("CustomEvent");d.initCustomEvent(c,!0,!0,{}),a.dispatchEvent(d)}}function e(a,b){return h?h(a).hasClass(b):a.classList.contains(b)}function f(a,b){this.dateDelta=null,this.timeDelta=null,this._defaults={startClass:"start",endClass:"end",timeClass:"time",dateClass:"date",defaultDateDelta:0,defaultTimeDelta:36e5,anchor:"start",parseTime:function(a){return h(a).timepicker("getTime")},updateTime:function(a,b){h(a).timepicker("setTime",b)},setMinTime:function(a,b){h(a).timepicker("option","minTime",b)},parseDate:function(a){return a.value&&h(a).datepicker("getDate")},updateDate:function(a,b){h(a).datepicker("update",b)}},this.container=a,this.settings=c(this._defaults,b),this.startDateInput=this.container.querySelector("."+this.settings.startClass+"."+this.settings.dateClass),this.endDateInput=this.container.querySelector("."+this.settings.endClass+"."+this.settings.dateClass),this.startTimeInput=this.container.querySelector("."+this.settings.startClass+"."+this.settings.timeClass),this.endTimeInput=this.container.querySelector("."+this.settings.endClass+"."+this.settings.timeClass),this.refresh(),this._bindChangeHandler()}var g=864e5,h=a.Zepto||a.jQuery;f.prototype={constructor:f,option:function(a,b){if("object"==typeof a)this.settings=c(this.settings,a);else if("string"==typeof a&&"undefined"!=typeof b)this.settings[a]=b;else if("string"==typeof a)return this.settings[a];this._updateEndMintime()},getTimeDiff:function(){var a=this.dateDelta+this.timeDelta;return!(0>a)||this.startDateInput&&this.endDateInput||(a+=g),a},refresh:function(){if(this.startDateInput&&this.startDateInput.value&&this.endDateInput&&this.endDateInput.value){var a=this.settings.parseDate(this.startDateInput),b=this.settings.parseDate(this.endDateInput);a&&b&&(this.dateDelta=b.getTime()-a.getTime())}if(this.startTimeInput&&this.startTimeInput.value&&this.endTimeInput&&this.endTimeInput.value){var c=this.settings.parseTime(this.startTimeInput),d=this.settings.parseTime(this.endTimeInput);c&&d&&(this.timeDelta=d.getTime()-c.getTime(),this._updateEndMintime())}},remove:function(){this._unbindChangeHandler()},_bindChangeHandler:function(){h?h(this.container).on("change.datepair",h.proxy(this.handleEvent,this)):this.container.addEventListener("change",this,!1)},_unbindChangeHandler:function(){h?h(this.container).off("change.datepair"):this.container.removeEventListener("change",this,!1)},handleEvent:function(a){this._unbindChangeHandler(),e(a.target,this.settings.dateClass)?""!=a.target.value?(this._dateChanged(a.target),this._timeChanged(a.target)):this.dateDelta=null:e(a.target,this.settings.timeClass)&&(""!=a.target.value?this._timeChanged(a.target):this.timeDelta=null),this._validateRanges(),this._updateEndMintime(),this._bindChangeHandler()},_dateChanged:function(a){if(this.startDateInput&&this.endDateInput){var b=this.settings.parseDate(this.startDateInput),c=this.settings.parseDate(this.endDateInput);if(b&&c)if("start"==this.settings.anchor&&e(a,this.settings.startClass)){var d=new Date(b.getTime()+this.dateDelta);this.settings.updateDate(this.endDateInput,d)}else if("end"==this.settings.anchor&&e(a,this.settings.endClass)){var d=new Date(c.getTime()-this.dateDelta);this.settings.updateDate(this.startDateInput,d)}else if(b>c){var f=e(a,this.settings.startClass)?this.endDateInput:this.startDateInput,h=this.settings.parseDate(a);this.dateDelta=0,this.settings.updateDate(f,h)}else this.dateDelta=c.getTime()-b.getTime();else if(null!==this.settings.defaultDateDelta){if(b){var i=new Date(b.getTime()+this.settings.defaultDateDelta*g);this.settings.updateDate(this.endDateInput,i)}else if(c){var j=new Date(c.getTime()-this.settings.defaultDateDelta*g);this.settings.updateDate(this.startDateInput,j)}this.dateDelta=this.settings.defaultDateDelta*g}else this.dateDelta=null}},_timeChanged:function(a){if(this.startTimeInput&&this.endTimeInput){var b=this.settings.parseTime(this.startTimeInput),c=this.settings.parseTime(this.endTimeInput);if(b&&c)if("start"==this.settings.anchor&&e(a,this.settings.startClass)){var d=new Date(b.getTime()+this.timeDelta);this.settings.updateTime(this.endTimeInput,d),c=this.settings.parseTime(this.endTimeInput),this._doMidnightRollover(b,c)}else if("end"==this.settings.anchor&&e(a,this.settings.endClass)){var d=new Date(c.getTime()-this.timeDelta);this.settings.updateTime(this.startTimeInput,d),b=this.settings.parseTime(this.startTimeInput),this._doMidnightRollover(b,c)}else{this._doMidnightRollover(b,c);var f,g;if(this.startDateInput&&this.endDateInput&&(f=this.settings.parseDate(this.startDateInput),g=this.settings.parseDate(this.endDateInput)),+f==+g&&b>c){var h=e(a,this.settings.endClass)?this.endTimeInput:this.startTimeInput,i=e(a,this.settings.startClass)?this.endTimeInput:this.startTimeInput,j=this.settings.parseTime(h);this.timeDelta=0,this.settings.updateTime(i,j)}else this.timeDelta=c.getTime()-b.getTime()}else if(null!==this.settings.defaultTimeDelta){if(b){var k=new Date(b.getTime()+this.settings.defaultTimeDelta);this.settings.updateTime(this.endTimeInput,k)}else if(c){var l=new Date(c.getTime()-this.settings.defaultTimeDelta);this.settings.updateTime(this.startTimeInput,l)}this.timeDelta=this.settings.defaultTimeDelta}else this.timeDelta=null}},_doMidnightRollover:function(a,b){if(this.startDateInput&&this.endDateInput){var c=this.settings.parseDate(this.endDateInput),d=this.settings.parseDate(this.startDateInput),e=b.getTime()-a.getTime(),f=a>b?g:-1*g;null!==this.dateDelta&&this.dateDelta+this.timeDelta<=g&&this.dateDelta+e!=0&&(f>0||0!=this.dateDelta)&&(e>=0&&this.timeDelta<0||0>e&&this.timeDelta>=0)&&("start"==this.settings.anchor?(this.settings.updateDate(this.endDateInput,new Date(c.getTime()+f)),this._dateChanged(this.endDateInput)):"end"==this.settings.anchor&&(this.settings.updateDate(this.startDateInput,new Date(d.getTime()-f)),this._dateChanged(this.startDateInput))),this.timeDelta=e}},_updateEndMintime:function(){if("function"==typeof this.settings.setMinTime){var a=null;"start"==this.settings.anchor&&(!this.dateDelta||this.dateDelta=0?d(this.container,"rangeSelected"):d(this.container,"rangeError"))}},a.Datepair=f}(window,document),function(a){a&&(a.fn.datepair=function(b){var c;return this.each(function(){var d=a(this),e=d.data("datepair"),f="object"==typeof b&&b;e||(e=new Datepair(this,f),d.data("datepair",e)),"string"==typeof b&&(c=e[b]())}),c||this},a("[data-datepair]").each(function(){var b=a(this);b.datepair(b.data())}))}(window.Zepto||window.jQuery); \ No newline at end of file diff --git a/js/datepair/index.html b/js/datepair/index.html new file mode 100644 index 0000000..92980f3 --- /dev/null +++ b/js/datepair/index.html @@ -0,0 +1,503 @@ + + + + + + Datepair.js – Demos and Documentation + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Datepair.js

+

+ A javascript plugin for intelligently selecting date and time ranges
+ inspired by Google Calendar.
+

+ + +
+ +
+

Use this plugin to link date and time inputs when you need to select ranges.
No dependencies, with optional support for jQuery/Zepto.

+
+ +
+
+
+

Basic Example

+

Datepair.js doesn't include any date or time picker widgets, but it's preconfigured to work with jquery-timepicker and Bootstrap Datepicker. Include input widgets as you normally would, and then use Datepair.js to link them.

+ +

+ + to + + +

+
+ +
+<p id="basicExample">
+    <input type="text" class="date start" />
+    <input type="text" class="time start" /> to
+    <input type="text" class="time end" />
+    <input type="text" class="date end" />
+</p>
+
+<!-- include input widgets; this is independent of Datepair.js -->
+<link rel="styleshee" type="text/css" href="jquery.timepicker.css" />
+<link rel="stylesheet" type="text/css" href="bootstrap-datepicker.css" />
+<script type="text/javascript" src="bootstrap-datepicker.js"></script>
+<script type="text/javascript" src="jquery.timepicker.js"></script>
+
+<script type="text/javascript" src="datepair.js"></script>
+<script>
+    // initialize input widgets first
+    $('#basicExample .time').timepicker({
+        'showDuration': true,
+        'timeFormat': 'g:ia'
+    });
+
+    $('#basicExample .date').datepicker({
+        'format': 'm/d/yyyy',
+        'autoclose': true
+    });
+
+    // initialize datepair
+    var basicExampleEl = document.getElementById('basicExample');
+    var datepair = new Datepair(basicExampleEl);
+</script>
+            
+ + +
+ +
+
+

jQuery Example

+

Include the optional jquery.datepicker.js file to interact with Datepair.js with a jQuery interface.

+ +

+ + to + + +

+
+ +
+<p id="basicExample">
+    <input type="text" class="date start" />
+    <input type="text" class="time start" /> to
+    <input type="text" class="time end" />
+    <input type="text" class="date end" />
+</p>
+
+<script type="text/javascript" src="datepair.js"></script>
+<script type="text/javascript" src="jquery.datepair.js"></script>
+<script>
+    // initialize input widgets first
+    $('#jqueryExample .time').timepicker({
+        'showDuration': true,
+        'timeFormat': 'g:ia'
+    });
+
+    $('#jqueryExample .date').datepicker({
+        'format': 'm/d/yyyy',
+        'autoclose': true
+    });
+
+    // initialize datepair
+    $('#jqueryExample').datepair();
+</script>
+            
+ + +
+ +
+
+

Date-only Example

+ +

You can use datepair with just dates, or just times.

+ +

+ to + +

+ +

+ to + +

+
+ +
+// HTML not shown for brevity
+
+$('#timeOnlyExample .time').timepicker({
+    'showDuration': true,
+    'timeFormat': 'g:ia'
+});
+
+var timeOnlyExampleEl = document.getElementById('timeOnlyExample');
+var timeOnlyDatepair = new Datepair(timeOnlyExampleEl);
+
+$('#dateOnlyExample .date').datepicker({
+    'format': 'yyyy-m-d',
+    'autoclose': true
+});
+
+var dateOnlyExampleEl = document.getElementById('dateOnlyExample');
+var dateOnlyDatepair = new Datepair(dateOnlyExampleEl);
+            
+ + +
+ +
+
+

Default Delta Example

+ +

Datepair can automatically set the other input when a first value is selected.

+ +

+ + to + + +

+
+ +
+// HTML not shown for brevity
+
+var defaultDeltaExampleEl = document.getElementById('defaultDeltaExample');
+var defaultDeltaDatepair = new Datepair(defaultDeltaExampleEl, {
+    'defaultDateDelta': 1,      // days
+    'defaultTimeDelta': 7200000 // milliseconds
+});
+            
+ + +
+ +
+
+

Alternate UI Widgets Example

+ +

jquery-datepair is widget agnostic and can work with any date and time pickers. Here's an example with jQuery.ptTimeSelect and Pikaday.

+ +

+ + to
+ + +

+
+ +
+<p id="alternateUiWidgetsExample">
+    <input type="text" class="date start" />
+    <input type="text" class="time start" /> to<br />
+    <input type="text" class="date end" />
+    <input type="text" class="time end" />
+</p>
+<script type="text/javascript" src="pikaday.js"></script>
+<script type="text/javascript" src="jquery.ptTimeSelect.js"></script>
+<script type="text/javascript" src="moment.js"></script>
+<script>
+    // initialize input widgets
+    // ptTimeSelect doesn't trigger change event by default
+    $('#alternateUiWidgetsExample .time').ptTimeSelect({
+        'onClose': function($self) {
+            $self.trigger('change');
+        }
+    });
+
+    $('#alternateUiWidgetsExample .date').pikaday();
+
+    var TIMEFORMAT = 'h:mm a';
+    var alternateUiWidgetsExampleEl = document.getElementById('alternateUiWidgetsExample');
+    var alternateWidgetsDatepair = new Datepair(alternateUiWidgetsExampleEl, {
+        parseTime: function(input){
+            // use moment.js to parse time
+            var m = moment(input.value, TIMEFORMAT);
+            return m.toDate();
+        },
+        updateTime: function(input, dateObj){
+            var m = moment(dateObj);
+            input.value = m.format(TIMEFORMAT);
+        },
+        parseDate: function(input){
+            var picker = $(input).data('pikaday');
+            return picker.getDate();
+        },
+        updateDate: function(input, dateObj){
+            var picker = $(input).data('pikaday');
+            return picker.setDate(dateObj);
+        }
+    });
+</script>
+            
+ + +
+ +
+
+

Events Example

+

Datepair fires several events to indicate the status of the inputs.

+ +

+ + to + + +

+ +

+
+ +
+// HTML not shown for brevity
+
+// initialize input widgets first
+$('#eventsExample .time').timepicker({
+    'showDuration': true,
+    'timeFormat': 'g:ia'
+});
+
+$('#eventsExample .date').datepicker({
+    'format': 'm/d/yyyy',
+    'autoclose': true
+});
+
+var eventsExampleEl = document.getElementById('eventsExample');
+var eventsExampleDatepair = new Datepair(eventsExampleEl);
+
+// some sample handlers
+$('#eventsExample').on('rangeSelected', function(){
+    $('#eventsExampleStatus').text('Valid range selected');
+}).on('rangeIncomplete', function(){
+    $('#eventsExampleStatus').text('Incomplete range');
+}).on('rangeError', function(){
+    $('#eventsExampleStatus').text('Invalid range');
+});
+            
+ + +
+ +
+
+

Anchor Example

+

Datepair defaults to move the end time/date based on changes to the start time/date. This can be changed to the end inputs, or disabled completely.

+ +

Anchor: + +

+

+ + to + + +

+
+ +
+var anchorExampleEl = document.getElementById('anchorExample');
+var anchorDatepair = new Datepair(anchorExampleEl, {
+    anchor: $('#anchorSelect').val()
+});
+
+$('#anchorSelect').on('change', function(){
+    anchorDatepair.option('anchor', $('#anchorSelect').val());
+});
+            
+ + +
+
+ +
+

Need Help?

+

Check the documenation or submit an issue on GitHub.

+
+ + + + + + + diff --git a/js/datepair/lib/jquery.ptTimeSelect.css b/js/datepair/lib/jquery.ptTimeSelect.css new file mode 100644 index 0000000..b03b05d --- /dev/null +++ b/js/datepair/lib/jquery.ptTimeSelect.css @@ -0,0 +1,83 @@ +/** + * FILE: jquery.ptTileSelect.css + * Default style for the timeselect container. + * + * LAST UPDATED: + * + * - $Date: 2009/04/12 20:23:02 $ + * - $Author: paulinho4u $ + * - $Revision: 1.1 $ + */ +#ptTimeSelectCntr { + width: 250px; + font-size: .9em; + position: absolute; + z-index: 10; + display: none; +} +#ptTimeSelectCntr .ui-widget{ + padding: .2em; +} +#ptTimeSelectCntr .ui-widget-header { + padding: .2em; +} +#ptTimeSelectCntr #ptTimeSelectUserTime { + font-size: larger; + padding: .2em; + padding-left: 1em; + text-align: center; +} +#ptTimeSelectCntr #ptTimeSelectCloseCntr { + display: block; + padding: .2em; +} +#ptTimeSelectCntr #ptTimeSelectCloseCntr a { + display: block; + padding: .2em; +} +#ptTimeSelectCntr .ui-widget-content { + margin-top: .1em; + margin-bottom: .1em; + padding: .2em; +} +#ptTimeSelectCntr .ui-widget.ui-widget-content { + margin-top: 0; +} +#ptTimeSelectCntr .ptTimeSelectLeftPane.ui-widget-content { + border-top:none; + border-bottom:none; + border-left:none; + border-right-width: 2px; +} +#ptTimeSelectCntr .ptTimeSelectRightPane.ui-widget-content { + border: none; +} +#ptTimeSelectCntr .ptTimeSelectHrCntr a, +#ptTimeSelectCntr .ptTimeSelectMinCntr a { + display: block; + float: left; + padding: .2em; + width: 1.9em; + margin: 1px; + text-align: center; + text-decoration: none; +} +#ptTimeSelectCntr .ptTimeSelectHrAmPmCntr a { + text-align: center; + margin: 1px; +} +#ptTimeSelectCntr .ptTimeSelectTimeLabelsCntr { + font-weight: bold; + font-size: .9em; +} +#ptTimeSelectCntr #ptTimeSelectSetButton { + padding-top: .2em; + padding-bottom: .2em; +} +#ptTimeSelectCntr #ptTimeSelectSetButton a { + display: block; + padding: .2em; + width: 30%; + text-align: center; + float: right; +} diff --git a/js/datepair/lib/jquery.ptTimeSelect.js b/js/datepair/lib/jquery.ptTimeSelect.js new file mode 100644 index 0000000..65a7992 --- /dev/null +++ b/js/datepair/lib/jquery.ptTimeSelect.js @@ -0,0 +1,478 @@ +/** + * FILE: jQuery.ptTileSelect.js + * + * @fileOverview + * jQuery plugin for displaying a popup that allows a user + * to define a time and set that time back to a form's input + * field. + * + * @version 0.8 + * @author Paul Tavares, www.purtuga.com + * @see http://pttimeselect.sourceforge.net + * + * @requires jQuery {@link http://www.jquery.com} + * + * + * LICENSE: + * + * Copyright (c) 2007 Paul T. (purtuga.com) + * Dual licensed under the: + * + * - MIT + * + * + * - GPL + * + * + * User can pick whichever one applies best for their project + * and doesn not have to contact me. + * + * + * INSTALLATION: + * + * There are two files (.css and .js) delivered with this plugin and + * that must be included in your html page after the jquery.js library + * and the jQuery UI style sheet (the jQuery UI javascript library is + * not necessary). + * Both of these are to be included inside of the 'head' element of + * the document. Example below demonstrates this along side the jQuery + * libraries. + * + * | + * | + * | + * | + * | + * | + * + * USAGE: + * + * - See <$(ele).ptTimeSelect()> + * + * + * + * LAST UPDATED: + * + * - $Date: 2012/08/05 19:40:21 $ + * - $Author: paulinho4u $ + * - $Revision: 1.8 $ + * + */ + +(function($){ + + /** + * jQuery definition + * + * @see http://jquery.com/ + * @name jQuery + * @class jQuery Library + */ + + /** + * jQuery 'fn' definition to anchor all public plugin methods. + * + * @see http://jquery.com/ + * @name fn + * @class jQuery Library public method anchor + * @memberOf jQuery + */ + + /** + * Namespace for all properties and methods + * + * @namespace ptTimeSelect + * @memberOf jQuery + */ + jQuery.ptTimeSelect = {}; + jQuery.ptTimeSelect.version = "__BUILD_VERSION_NUMBER__"; + + /** + * The default options for all calls to ptTimeSelect. Can be + * overwriten with each individual call to {@link jQuery.fn.ptTimeSelect} + * + * @type {Object} options + * @memberOf jQuery.ptTimeSelect + * @see jQuery.fn.ptTimeSelect + */ + jQuery.ptTimeSelect.options = { + containerClass: undefined, + containerWidth: '22em', + hoursLabel: 'Hour', + minutesLabel: 'Minutes', + setButtonLabel: 'Set', + popupImage: undefined, + onFocusDisplay: true, + zIndex: 10, + onBeforeShow: undefined, + onClose: undefined + }; + + /** + * Internal method. Called when page is initialized to add the time + * selection area to the DOM. + * + * @private + * @memberOf jQuery.ptTimeSelect + * @return {undefined} + */ + jQuery.ptTimeSelect._ptTimeSelectInit = function () { + jQuery(document).ready( + function () { + //if the html is not yet created in the document, then do it now + if (!jQuery('#ptTimeSelectCntr').length) { + jQuery("body").append( + '
' + + '
' + + '
' + + '
' + + ' ' + + ' X' + + ' ' + + '
' + + '
' + + ' 1 : ' + + ' 00 ' + + ' AM' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
Hour
' + + '
Minutes
' + + '
' + + '
' + + '
' + + '
' + + '
' + + ' AM' + + ' PM' + + '
' + + '
' + + '
' + + ' 1' + + ' 2' + + ' 3' + + ' 4' + + ' 5' + + ' 6' + + ' 7' + + ' 8' + + ' 9' + + ' 10' + + ' 11' + + ' 12' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + ' 00' + + ' 05' + + ' 10' + + ' 15' + + ' 20' + + ' 25' + + ' 30' + + ' 35' + + ' 40' + + ' 45' + + ' 50' + + ' 55' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + ' ' + + ' SET' + + ' ' + + '
' + + '
' + + ' ' + + '
' + ); + + var e = jQuery('#ptTimeSelectCntr'); + + // Add the events to the functions + e.find('.ptTimeSelectMin') + .bind("click", function(){ + jQuery.ptTimeSelect.setMin($(this).text()); + }); + + e.find('.ptTimeSelectHr') + .bind("click", function(){ + jQuery.ptTimeSelect.setHr($(this).text()); + }); + + $(document).mousedown(jQuery.ptTimeSelect._doCheckMouseClick); + }//end if + } + ); + }();// jQuery.ptTimeSelectInit() + + + /** + * Sets the hour selected by the user on the popup. + * + * @private + * @param {Integer} h - Interger indicating the hour. This value + * is the same as the text value displayed on the + * popup under the hour. This value can also be the + * words AM or PM. + * @return {undefined} + * + */ + jQuery.ptTimeSelect.setHr = function(h) { + if ( h.toLowerCase() == "am" + || h.toLowerCase() == "pm" + ) { + jQuery('#ptTimeSelectUserSelAmPm').empty().append(h); + } else { + jQuery('#ptTimeSelectUserSelHr').empty().append(h); + } + };// END setHr() function + + /** + * Sets the minutes selected by the user on the popup. + * + * @private + * @param {Integer} m - interger indicating the minutes. This + * value is the same as the text value displayed on the popup + * under the minutes. + * @return {undefined} + */ + jQuery.ptTimeSelect.setMin = function(m) { + jQuery('#ptTimeSelectUserSelMin').empty().append(m); + };// END setMin() function + + /** + * Takes the time defined by the user and sets it to the input + * element that the popup is currently opened for. + * + * @private + * @return {undefined} + */ + jQuery.ptTimeSelect.setTime = function() { + var tSel = jQuery('#ptTimeSelectUserSelHr').text() + + ":" + + jQuery('#ptTimeSelectUserSelMin').text() + + " " + + jQuery('#ptTimeSelectUserSelAmPm').text(); + jQuery(".isPtTimeSelectActive").val(tSel); + this.closeCntr(); + + };// END setTime() function + + /** + * Displays the time definition area on the page, right below + * the input field. Also sets the custom colors/css on the + * displayed area to what ever the input element options were + * set with. + * + * @private + * @param {String} uId - Id of the element for whom the area will + * be displayed. This ID was created when the + * ptTimeSelect() method was called. + * @return {undefined} + * + */ + jQuery.ptTimeSelect.openCntr = function (ele) { + jQuery.ptTimeSelect.closeCntr(); + jQuery(".isPtTimeSelectActive").removeClass("isPtTimeSelectActive"); + var cntr = jQuery("#ptTimeSelectCntr"); + var i = jQuery(ele).eq(0).addClass("isPtTimeSelectActive"); + var opt = i.data("ptTimeSelectOptions"); + var style = i.offset(); + style['z-index'] = opt.zIndex; + style.top = (style.top + i.outerHeight()); + if (opt.containerWidth) { + style.width = opt.containerWidth; + } + if (opt.containerClass) { + cntr.addClass(opt.containerClass); + } + cntr.css(style); + var hr = 1; + var min = '00'; + var tm = 'AM'; + if (i.val()) { + var re = /([0-9]{1,2}).*:.*([0-9]{2}).*(PM|AM)/i; + var match = re.exec(i.val()); + if (match) { + hr = match[1] || 1; + min = match[2] || '00'; + tm = match[3] || 'AM'; + } + } + cntr.find("#ptTimeSelectUserSelHr").empty().append(hr); + cntr.find("#ptTimeSelectUserSelMin").empty().append(min); + cntr.find("#ptTimeSelectUserSelAmPm").empty().append(tm); + cntr.find(".ptTimeSelectTimeLabelsCntr .ptTimeSelectLeftPane") + .empty().append(opt.hoursLabel); + cntr.find(".ptTimeSelectTimeLabelsCntr .ptTimeSelectRightPane") + .empty().append(opt.minutesLabel); + cntr.find("#ptTimeSelectSetButton a").empty().append(opt.setButtonLabel); + if (opt.onBeforeShow) { + opt.onBeforeShow(i, cntr); + } + cntr.slideDown("fast"); + + };// END openCntr() + + /** + * Closes (hides it) the popup container. + * @private + * @param {Object} i - Optional. The input field for which the + * container is being closed. + * @return {undefined} + */ + jQuery.ptTimeSelect.closeCntr = function(i) { + var e = $("#ptTimeSelectCntr"); + if (e.is(":visible") == true) { + + // If IE, then check to make sure it is realy visible + if (jQuery.support.tbody == false) { + if (!(e[0].offsetWidth > 0) && !(e[0].offsetHeight > 0) ) { + return; + } + } + + jQuery('#ptTimeSelectCntr') + .css("display", "none") + .removeClass() + .css("width", ""); + if (!i) { + i = $(".isPtTimeSelectActive"); + } + if (i) { + var opt = i.removeClass("isPtTimeSelectActive") + .data("ptTimeSelectOptions"); + if (opt && opt.onClose) { + opt.onClose(i); + } + } + } + return; + };//end closeCntr() + + /** + * Closes the timePicker popup if user is not longer focused on the + * input field or the timepicker + * + * @private + * @param {jQueryEvent} ev - Event passed in by jQuery + * @return {undefined} + */ + jQuery.ptTimeSelect._doCheckMouseClick = function(ev){ + if (!$("#ptTimeSelectCntr:visible").length) { + return; + } + if ( !jQuery(ev.target).closest("#ptTimeSelectCntr").length + && jQuery(ev.target).not("input.isPtTimeSelectActive").length ){ + jQuery.ptTimeSelect.closeCntr(); + } + + };// jQuery.ptTimeSelect._doCheckMouseClick + + /** + * FUNCTION: $().ptTimeSelect() + * Attaches a ptTimeSelect widget to each matched element. Matched + * elements must be input fields that accept a values (input field). + * Each element, when focused upon, will display a time selection + * popoup where the user can define a time. + * + * @memberOf jQuery + * + * PARAMS: + * + * @param {Object} [opt] - An object with the options for the time selection widget. + * + * @param {String} [opt.containerClass=""] - A class to be associated with the popup widget. + * + * @param {String} [opt.containerWidth=""] - Css width for the container. + * + * @param {String} [opt.hoursLabel="Hours"] - Label for the Hours. + * + * @param {String} [opt.minutesLabel="Minutes"] - Label for the Mintues container. + * + * @param {String} [opt.setButtonLabel="Set"] - Label for the Set button. + * + * @param {String} [opt.popupImage=""] - The html element (ex. img or text) to be appended next to each + * input field and that will display the time select widget upon + * click. + * + * @param {Integer} [opt.zIndex=10] - Integer for the popup widget z-index. + * + * @param {Function} [opt.onBeforeShow=undefined] - Function to be called before the widget is made visible to the + * user. Function is passed 2 arguments: 1) the input field as a + * jquery object and 2) the popup widget as a jquery object. + * + * @param {Function} [opt.onClose=undefined] - Function to be called after closing the popup widget. Function + * is passed 1 argument: the input field as a jquery object. + * + * @param {Bollean} [opt.onFocusDisplay=true] - True or False indicating if popup is auto displayed upon focus + * of the input field. + * + * + * RETURN: + * @return {jQuery} selection + * + * + * + * EXAMPLE: + * @example + * $('#fooTime').ptTimeSelect(); + * + */ + jQuery.fn.ptTimeSelect = function (opt) { + return this.each(function(){ + if(this.nodeName.toLowerCase() != 'input') return; + var e = jQuery(this); + if (e.hasClass('hasPtTimeSelect')){ + return this; + } + var thisOpt = {}; + thisOpt = $.extend(thisOpt, jQuery.ptTimeSelect.options, opt); + e.addClass('hasPtTimeSelect').data("ptTimeSelectOptions", thisOpt); + + //Wrap the input field in a
element with + // a unique id for later referencing. + if (thisOpt.popupImage || !thisOpt.onFocusDisplay) { + var img = jQuery(' ' + + thisOpt.popupImage + '' + ) + .data("ptTimeSelectEle", e); + e.after(img); + } + if (thisOpt.onFocusDisplay){ + e.focus(function(){ + jQuery.ptTimeSelect.openCntr(this); + }); + } + return this; + }); + };// End of jQuery.fn.ptTimeSelect + +})(jQuery); diff --git a/js/datepair/lib/moment.min.js b/js/datepair/lib/moment.min.js new file mode 100644 index 0000000..29e1cef --- /dev/null +++ b/js/datepair/lib/moment.min.js @@ -0,0 +1,6 @@ +//! moment.js +//! version : 2.5.1 +//! authors : Tim Wood, Iskren Chernev, Moment.js contributors +//! license : MIT +//! momentjs.com +(function(a){function b(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invalidFormat:!1,userInvalidated:!1,iso:!1}}function c(a,b){return function(c){return k(a.call(this,c),b)}}function d(a,b){return function(c){return this.lang().ordinal(a.call(this,c),b)}}function e(){}function f(a){w(a),h(this,a)}function g(a){var b=q(a),c=b.year||0,d=b.month||0,e=b.week||0,f=b.day||0,g=b.hour||0,h=b.minute||0,i=b.second||0,j=b.millisecond||0;this._milliseconds=+j+1e3*i+6e4*h+36e5*g,this._days=+f+7*e,this._months=+d+12*c,this._data={},this._bubble()}function h(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return b.hasOwnProperty("toString")&&(a.toString=b.toString),b.hasOwnProperty("valueOf")&&(a.valueOf=b.valueOf),a}function i(a){var b,c={};for(b in a)a.hasOwnProperty(b)&&qb.hasOwnProperty(b)&&(c[b]=a[b]);return c}function j(a){return 0>a?Math.ceil(a):Math.floor(a)}function k(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthd;d++)(c&&a[d]!==b[d]||!c&&s(a[d])!==s(b[d]))&&g++;return g+f}function p(a){if(a){var b=a.toLowerCase().replace(/(.)s$/,"$1");a=Tb[a]||Ub[b]||b}return a}function q(a){var b,c,d={};for(c in a)a.hasOwnProperty(c)&&(b=p(c),b&&(d[b]=a[c]));return d}function r(b){var c,d;if(0===b.indexOf("week"))c=7,d="day";else{if(0!==b.indexOf("month"))return;c=12,d="month"}db[b]=function(e,f){var g,h,i=db.fn._lang[b],j=[];if("number"==typeof e&&(f=e,e=a),h=function(a){var b=db().utc().set(d,a);return i.call(db.fn._lang,b,e||"")},null!=f)return h(f);for(g=0;c>g;g++)j.push(h(g));return j}}function s(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function t(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function u(a){return v(a)?366:365}function v(a){return a%4===0&&a%100!==0||a%400===0}function w(a){var b;a._a&&-2===a._pf.overflow&&(b=a._a[jb]<0||a._a[jb]>11?jb:a._a[kb]<1||a._a[kb]>t(a._a[ib],a._a[jb])?kb:a._a[lb]<0||a._a[lb]>23?lb:a._a[mb]<0||a._a[mb]>59?mb:a._a[nb]<0||a._a[nb]>59?nb:a._a[ob]<0||a._a[ob]>999?ob:-1,a._pf._overflowDayOfYear&&(ib>b||b>kb)&&(b=kb),a._pf.overflow=b)}function x(a){return null==a._isValid&&(a._isValid=!isNaN(a._d.getTime())&&a._pf.overflow<0&&!a._pf.empty&&!a._pf.invalidMonth&&!a._pf.nullInput&&!a._pf.invalidFormat&&!a._pf.userInvalidated,a._strict&&(a._isValid=a._isValid&&0===a._pf.charsLeftOver&&0===a._pf.unusedTokens.length)),a._isValid}function y(a){return a?a.toLowerCase().replace("_","-"):a}function z(a,b){return b._isUTC?db(a).zone(b._offset||0):db(a).local()}function A(a,b){return b.abbr=a,pb[a]||(pb[a]=new e),pb[a].set(b),pb[a]}function B(a){delete pb[a]}function C(a){var b,c,d,e,f=0,g=function(a){if(!pb[a]&&rb)try{require("./lang/"+a)}catch(b){}return pb[a]};if(!a)return db.fn._lang;if(!m(a)){if(c=g(a))return c;a=[a]}for(;f0;){if(c=g(e.slice(0,b).join("-")))return c;if(d&&d.length>=b&&o(e,d,!0)>=b-1)break;b--}f++}return db.fn._lang}function D(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function E(a){var b,c,d=a.match(vb);for(b=0,c=d.length;c>b;b++)d[b]=Yb[d[b]]?Yb[d[b]]:D(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function F(a,b){return a.isValid()?(b=G(b,a.lang()),Vb[b]||(Vb[b]=E(b)),Vb[b](a)):a.lang().invalidDate()}function G(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(wb.lastIndex=0;d>=0&&wb.test(a);)a=a.replace(wb,c),wb.lastIndex=0,d-=1;return a}function H(a,b){var c,d=b._strict;switch(a){case"DDDD":return Ib;case"YYYY":case"GGGG":case"gggg":return d?Jb:zb;case"Y":case"G":case"g":return Lb;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return d?Kb:Ab;case"S":if(d)return Gb;case"SS":if(d)return Hb;case"SSS":if(d)return Ib;case"DDD":return yb;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Cb;case"a":case"A":return C(b._l)._meridiemParse;case"X":return Fb;case"Z":case"ZZ":return Db;case"T":return Eb;case"SSSS":return Bb;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return d?Hb:xb;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return xb;default:return c=new RegExp(P(O(a.replace("\\","")),"i"))}}function I(a){a=a||"";var b=a.match(Db)||[],c=b[b.length-1]||[],d=(c+"").match(Qb)||["-",0,0],e=+(60*d[1])+s(d[2]);return"+"===d[0]?-e:e}function J(a,b,c){var d,e=c._a;switch(a){case"M":case"MM":null!=b&&(e[jb]=s(b)-1);break;case"MMM":case"MMMM":d=C(c._l).monthsParse(b),null!=d?e[jb]=d:c._pf.invalidMonth=b;break;case"D":case"DD":null!=b&&(e[kb]=s(b));break;case"DDD":case"DDDD":null!=b&&(c._dayOfYear=s(b));break;case"YY":e[ib]=s(b)+(s(b)>68?1900:2e3);break;case"YYYY":case"YYYYY":case"YYYYYY":e[ib]=s(b);break;case"a":case"A":c._isPm=C(c._l).isPM(b);break;case"H":case"HH":case"h":case"hh":e[lb]=s(b);break;case"m":case"mm":e[mb]=s(b);break;case"s":case"ss":e[nb]=s(b);break;case"S":case"SS":case"SSS":case"SSSS":e[ob]=s(1e3*("0."+b));break;case"X":c._d=new Date(1e3*parseFloat(b));break;case"Z":case"ZZ":c._useUTC=!0,c._tzm=I(b);break;case"w":case"ww":case"W":case"WW":case"d":case"dd":case"ddd":case"dddd":case"e":case"E":a=a.substr(0,1);case"gg":case"gggg":case"GG":case"GGGG":case"GGGGG":a=a.substr(0,2),b&&(c._w=c._w||{},c._w[a]=b)}}function K(a){var b,c,d,e,f,g,h,i,j,k,l=[];if(!a._d){for(d=M(a),a._w&&null==a._a[kb]&&null==a._a[jb]&&(f=function(b){var c=parseInt(b,10);return b?b.length<3?c>68?1900+c:2e3+c:c:null==a._a[ib]?db().weekYear():a._a[ib]},g=a._w,null!=g.GG||null!=g.W||null!=g.E?h=Z(f(g.GG),g.W||1,g.E,4,1):(i=C(a._l),j=null!=g.d?V(g.d,i):null!=g.e?parseInt(g.e,10)+i._week.dow:0,k=parseInt(g.w,10)||1,null!=g.d&&ju(e)&&(a._pf._overflowDayOfYear=!0),c=U(e,0,a._dayOfYear),a._a[jb]=c.getUTCMonth(),a._a[kb]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=l[b]=d[b];for(;7>b;b++)a._a[b]=l[b]=null==a._a[b]?2===b?1:0:a._a[b];l[lb]+=s((a._tzm||0)/60),l[mb]+=s((a._tzm||0)%60),a._d=(a._useUTC?U:T).apply(null,l)}}function L(a){var b;a._d||(b=q(a._i),a._a=[b.year,b.month,b.day,b.hour,b.minute,b.second,b.millisecond],K(a))}function M(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function N(a){a._a=[],a._pf.empty=!0;var b,c,d,e,f,g=C(a._l),h=""+a._i,i=h.length,j=0;for(d=G(a._f,g).match(vb)||[],b=0;b0&&a._pf.unusedInput.push(f),h=h.slice(h.indexOf(c)+c.length),j+=c.length),Yb[e]?(c?a._pf.empty=!1:a._pf.unusedTokens.push(e),J(e,c,a)):a._strict&&!c&&a._pf.unusedTokens.push(e);a._pf.charsLeftOver=i-j,h.length>0&&a._pf.unusedInput.push(h),a._isPm&&a._a[lb]<12&&(a._a[lb]+=12),a._isPm===!1&&12===a._a[lb]&&(a._a[lb]=0),K(a),w(a)}function O(a){return a.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e})}function P(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function Q(a){var c,d,e,f,g;if(0===a._f.length)return a._pf.invalidFormat=!0,a._d=new Date(0/0),void 0;for(f=0;fg)&&(e=g,d=c));h(a,d||c)}function R(a){var b,c,d=a._i,e=Mb.exec(d);if(e){for(a._pf.iso=!0,b=0,c=Ob.length;c>b;b++)if(Ob[b][1].exec(d)){a._f=Ob[b][0]+(e[6]||" ");break}for(b=0,c=Pb.length;c>b;b++)if(Pb[b][1].exec(d)){a._f+=Pb[b][0];break}d.match(Db)&&(a._f+="Z"),N(a)}else a._d=new Date(d)}function S(b){var c=b._i,d=sb.exec(c);c===a?b._d=new Date:d?b._d=new Date(+d[1]):"string"==typeof c?R(b):m(c)?(b._a=c.slice(0),K(b)):n(c)?b._d=new Date(+c):"object"==typeof c?L(b):b._d=new Date(c)}function T(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function U(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function V(a,b){if("string"==typeof a)if(isNaN(a)){if(a=b.weekdaysParse(a),"number"!=typeof a)return null}else a=parseInt(a,10);return a}function W(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function X(a,b,c){var d=hb(Math.abs(a)/1e3),e=hb(d/60),f=hb(e/60),g=hb(f/24),h=hb(g/365),i=45>d&&["s",d]||1===e&&["m"]||45>e&&["mm",e]||1===f&&["h"]||22>f&&["hh",f]||1===g&&["d"]||25>=g&&["dd",g]||45>=g&&["M"]||345>g&&["MM",hb(g/30)]||1===h&&["y"]||["yy",h];return i[2]=b,i[3]=a>0,i[4]=c,W.apply({},i)}function Y(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=db(a).add("d",f),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function Z(a,b,c,d,e){var f,g,h=U(a,0,1).getUTCDay();return c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:u(a-1)+g}}function $(a){var b=a._i,c=a._f;return null===b?db.invalid({nullInput:!0}):("string"==typeof b&&(a._i=b=C().preparse(b)),db.isMoment(b)?(a=i(b),a._d=new Date(+b._d)):c?m(c)?Q(a):N(a):S(a),new f(a))}function _(a,b){db.fn[a]=db.fn[a+"s"]=function(a){var c=this._isUTC?"UTC":"";return null!=a?(this._d["set"+c+b](a),db.updateOffset(this),this):this._d["get"+c+b]()}}function ab(a){db.duration.fn[a]=function(){return this._data[a]}}function bb(a,b){db.duration.fn["as"+a]=function(){return+this/b}}function cb(a){var b=!1,c=db;"undefined"==typeof ender&&(a?(gb.moment=function(){return!b&&console&&console.warn&&(b=!0,console.warn("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.")),c.apply(null,arguments)},h(gb.moment,c)):gb.moment=db)}for(var db,eb,fb="2.5.1",gb=this,hb=Math.round,ib=0,jb=1,kb=2,lb=3,mb=4,nb=5,ob=6,pb={},qb={_isAMomentObject:null,_i:null,_f:null,_l:null,_strict:null,_isUTC:null,_offset:null,_pf:null,_lang:null},rb="undefined"!=typeof module&&module.exports&&"undefined"!=typeof require,sb=/^\/?Date\((\-?\d+)/i,tb=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,ub=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,vb=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,wb=/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,xb=/\d\d?/,yb=/\d{1,3}/,zb=/\d{1,4}/,Ab=/[+\-]?\d{1,6}/,Bb=/\d+/,Cb=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Db=/Z|[\+\-]\d\d:?\d\d/gi,Eb=/T/i,Fb=/[\+\-]?\d+(\.\d{1,3})?/,Gb=/\d/,Hb=/\d\d/,Ib=/\d{3}/,Jb=/\d{4}/,Kb=/[+-]?\d{6}/,Lb=/[+-]?\d+/,Mb=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Nb="YYYY-MM-DDTHH:mm:ssZ",Ob=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],Pb=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d{1,3}/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],Qb=/([\+\-]|\d\d)/gi,Rb="Date|Hours|Minutes|Seconds|Milliseconds".split("|"),Sb={Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6},Tb={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},Ub={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},Vb={},Wb="DDD w W M D d".split(" "),Xb="M D H h m s w W".split(" "),Yb={M:function(){return this.month()+1},MMM:function(a){return this.lang().monthsShort(this,a)},MMMM:function(a){return this.lang().months(this,a)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(a){return this.lang().weekdaysMin(this,a)},ddd:function(a){return this.lang().weekdaysShort(this,a)},dddd:function(a){return this.lang().weekdays(this,a)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return k(this.year()%100,2)},YYYY:function(){return k(this.year(),4)},YYYYY:function(){return k(this.year(),5)},YYYYYY:function(){var a=this.year(),b=a>=0?"+":"-";return b+k(Math.abs(a),6)},gg:function(){return k(this.weekYear()%100,2)},gggg:function(){return k(this.weekYear(),4)},ggggg:function(){return k(this.weekYear(),5)},GG:function(){return k(this.isoWeekYear()%100,2)},GGGG:function(){return k(this.isoWeekYear(),4)},GGGGG:function(){return k(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.lang().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.lang().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return s(this.milliseconds()/100)},SS:function(){return k(s(this.milliseconds()/10),2)},SSS:function(){return k(this.milliseconds(),3)},SSSS:function(){return k(this.milliseconds(),3)},Z:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+k(s(a/60),2)+":"+k(s(a)%60,2)},ZZ:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+k(s(a/60),2)+k(s(a)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},Zb=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];Wb.length;)eb=Wb.pop(),Yb[eb+"o"]=d(Yb[eb],eb);for(;Xb.length;)eb=Xb.pop(),Yb[eb+eb]=c(Yb[eb],2);for(Yb.DDDD=c(Yb.DDD,3),h(e.prototype,{set:function(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(a){return this._months[a.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(a){return this._monthsShort[a.month()]},monthsParse:function(a){var b,c,d;for(this._monthsParse||(this._monthsParse=[]),b=0;12>b;b++)if(this._monthsParse[b]||(c=db.utc([2e3,b]),d="^"+this.months(c,"")+"|^"+this.monthsShort(c,""),this._monthsParse[b]=new RegExp(d.replace(".",""),"i")),this._monthsParse[b].test(a))return b},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(a){return this._weekdays[a.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(a){return this._weekdaysShort[a.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(a){return this._weekdaysMin[a.day()]},weekdaysParse:function(a){var b,c,d;for(this._weekdaysParse||(this._weekdaysParse=[]),b=0;7>b;b++)if(this._weekdaysParse[b]||(c=db([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D YYYY",LLL:"MMMM D YYYY LT",LLLL:"dddd, MMMM D YYYY LT"},longDateFormat:function(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b},isPM:function(a){return"p"===(a+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(a,b){var c=this._calendar[a];return"function"==typeof c?c.apply(b):c},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)},pastFuture:function(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)},ordinal:function(a){return this._ordinal.replace("%d",a)},_ordinal:"%d",preparse:function(a){return a},postformat:function(a){return a},week:function(a){return Y(a,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),db=function(c,d,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._i=c,g._f=d,g._l=e,g._strict=f,g._isUTC=!1,g._pf=b(),$(g)},db.utc=function(c,d,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._useUTC=!0,g._isUTC=!0,g._l=e,g._i=c,g._f=d,g._strict=f,g._pf=b(),$(g).utc()},db.unix=function(a){return db(1e3*a)},db.duration=function(a,b){var c,d,e,f=a,h=null;return db.isDuration(a)?f={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(f={},b?f[b]=a:f.milliseconds=a):(h=tb.exec(a))?(c="-"===h[1]?-1:1,f={y:0,d:s(h[kb])*c,h:s(h[lb])*c,m:s(h[mb])*c,s:s(h[nb])*c,ms:s(h[ob])*c}):(h=ub.exec(a))&&(c="-"===h[1]?-1:1,e=function(a){var b=a&&parseFloat(a.replace(",","."));return(isNaN(b)?0:b)*c},f={y:e(h[2]),M:e(h[3]),d:e(h[4]),h:e(h[5]),m:e(h[6]),s:e(h[7]),w:e(h[8])}),d=new g(f),db.isDuration(a)&&a.hasOwnProperty("_lang")&&(d._lang=a._lang),d},db.version=fb,db.defaultFormat=Nb,db.updateOffset=function(){},db.lang=function(a,b){var c;return a?(b?A(y(a),b):null===b?(B(a),a="en"):pb[a]||C(a),c=db.duration.fn._lang=db.fn._lang=C(a),c._abbr):db.fn._lang._abbr},db.langData=function(a){return a&&a._lang&&a._lang._abbr&&(a=a._lang._abbr),C(a)},db.isMoment=function(a){return a instanceof f||null!=a&&a.hasOwnProperty("_isAMomentObject")},db.isDuration=function(a){return a instanceof g},eb=Zb.length-1;eb>=0;--eb)r(Zb[eb]);for(db.normalizeUnits=function(a){return p(a)},db.invalid=function(a){var b=db.utc(0/0);return null!=a?h(b._pf,a):b._pf.userInvalidated=!0,b},db.parseZone=function(a){return db(a).parseZone()},h(db.fn=f.prototype,{clone:function(){return db(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().lang("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var a=db(this).utc();return 00:!1},parsingFlags:function(){return h({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(){return this.zone(0)},local:function(){return this.zone(0),this._isUTC=!1,this},format:function(a){var b=F(this,a||db.defaultFormat);return this.lang().postformat(b)},add:function(a,b){var c;return c="string"==typeof a?db.duration(+b,a):db.duration(a,b),l(this,c,1),this},subtract:function(a,b){var c;return c="string"==typeof a?db.duration(+b,a):db.duration(a,b),l(this,c,-1),this},diff:function(a,b,c){var d,e,f=z(a,this),g=6e4*(this.zone()-f.zone());return b=p(b),"year"===b||"month"===b?(d=432e5*(this.daysInMonth()+f.daysInMonth()),e=12*(this.year()-f.year())+(this.month()-f.month()),e+=(this-db(this).startOf("month")-(f-db(f).startOf("month")))/d,e-=6e4*(this.zone()-db(this).startOf("month").zone()-(f.zone()-db(f).startOf("month").zone()))/d,"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:j(e)},from:function(a,b){return db.duration(this.diff(a)).lang(this.lang()._abbr).humanize(!b)},fromNow:function(a){return this.from(db(),a)},calendar:function(){var a=z(db(),this).startOf("day"),b=this.diff(a,"days",!0),c=-6>b?"sameElse":-1>b?"lastWeek":0>b?"lastDay":1>b?"sameDay":2>b?"nextDay":7>b?"nextWeek":"sameElse";return this.format(this.lang().calendar(c,this))},isLeapYear:function(){return v(this.year())},isDST:function(){return this.zone()+db(a).startOf(b)},isBefore:function(a,b){return b="undefined"!=typeof b?b:"millisecond",+this.clone().startOf(b)<+db(a).startOf(b)},isSame:function(a,b){return b=b||"ms",+this.clone().startOf(b)===+z(a,this).startOf(b)},min:function(a){return a=db.apply(null,arguments),this>a?this:a},max:function(a){return a=db.apply(null,arguments),a>this?this:a},zone:function(a){var b=this._offset||0;return null==a?this._isUTC?b:this._d.getTimezoneOffset():("string"==typeof a&&(a=I(a)),Math.abs(a)<16&&(a=60*a),this._offset=a,this._isUTC=!0,b!==a&&l(this,db.duration(b-a,"m"),1,!0),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(a){return a=a?db(a).zone():0,(this.zone()-a)%60===0},daysInMonth:function(){return t(this.year(),this.month())},dayOfYear:function(a){var b=hb((db(this).startOf("day")-db(this).startOf("year"))/864e5)+1;return null==a?b:this.add("d",a-b)},quarter:function(){return Math.ceil((this.month()+1)/3)},weekYear:function(a){var b=Y(this,this.lang()._week.dow,this.lang()._week.doy).year;return null==a?b:this.add("y",a-b)},isoWeekYear:function(a){var b=Y(this,1,4).year;return null==a?b:this.add("y",a-b)},week:function(a){var b=this.lang().week(this);return null==a?b:this.add("d",7*(a-b))},isoWeek:function(a){var b=Y(this,1,4).week;return null==a?b:this.add("d",7*(a-b))},weekday:function(a){var b=(this.day()+7-this.lang()._week.dow)%7;return null==a?b:this.add("d",a-b)},isoWeekday:function(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)},get:function(a){return a=p(a),this[a]()},set:function(a,b){return a=p(a),"function"==typeof this[a]&&this[a](b),this},lang:function(b){return b===a?this._lang:(this._lang=C(b),this)}}),eb=0;eb= 7) { + day -= 7; + } + return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day]; + }, + + renderDay = function(i, isSelected, isToday, isDisabled, isEmpty) + { + if (isEmpty) { + return ''; + } + var arr = []; + if (isDisabled) { + arr.push('is-disabled'); + } + if (isToday) { + arr.push('is-today'); + } + if (isSelected) { + arr.push('is-selected'); + } + return '' + ''; + }, + + renderRow = function(days, isRTL) + { + return '' + (isRTL ? days.reverse() : days).join('') + ''; + }, + + renderBody = function(rows) + { + return '' + rows.join('') + ''; + }, + + renderHead = function(opts) + { + var i, arr = []; + for (i = 0; i < 7; i++) { + arr.push('' + renderDayName(opts, i, true) + ''); + } + return '' + (opts.isRTL ? arr.reverse() : arr).join('') + ''; + }, + + renderTitle = function(instance) + { + var i, j, arr, + opts = instance._o, + month = instance._m, + year = instance._y, + isMinYear = year === opts.minYear, + isMaxYear = year === opts.maxYear, + html = '
', + monthHtml, + yearHtml, + prev = true, + next = true; + + for (arr = [], i = 0; i < 12; i++) { + arr.push(''); + } + monthHtml = '
' + opts.i18n.months[month] + '
'; + + if (isArray(opts.yearRange)) { + i = opts.yearRange[0]; + j = opts.yearRange[1] + 1; + } else { + i = year - opts.yearRange; + j = 1 + year + opts.yearRange; + } + + for (arr = []; i < j && i <= opts.maxYear; i++) { + if (i >= opts.minYear) { + arr.push(''); + } + } + yearHtml = '
' + year + opts.yearSuffix + '
'; + + if (opts.showMonthAfterYear) { + html += yearHtml + monthHtml; + } else { + html += monthHtml + yearHtml; + } + + if (isMinYear && (month === 0 || opts.minMonth >= month)) { + prev = false; + } + + if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { + next = false; + } + + html += ''; + html += ''; + + return html += '
'; + }, + + renderTable = function(opts, data) + { + return '' + renderHead(opts) + renderBody(data) + '
'; + }, + + + /** + * Pikaday constructor + */ + Pikaday = function(options) + { + var self = this, + opts = self.config(options); + + self._onMouseDown = function(e) + { + if (!self._v) { + return; + } + e = e || window.event; + var target = e.target || e.srcElement; + if (!target) { + return; + } + + if (!hasClass(target, 'is-disabled')) { + if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty')) { + self.setDate(new Date(self._y, self._m, parseInt(target.innerHTML, 10))); + if (opts.bound) { + sto(function() { + self.hide(); + }, 100); + } + return; + } + else if (hasClass(target, 'pika-prev')) { + self.prevMonth(); + } + else if (hasClass(target, 'pika-next')) { + self.nextMonth(); + } + } + if (!hasClass(target, 'pika-select')) { + if (e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; + return false; + } + } else { + self._c = true; + } + }; + + self._onChange = function(e) + { + e = e || window.event; + var target = e.target || e.srcElement; + if (!target) { + return; + } + if (hasClass(target, 'pika-select-month')) { + self.gotoMonth(target.value); + } + else if (hasClass(target, 'pika-select-year')) { + self.gotoYear(target.value); + } + }; + + self._onInputChange = function(e) + { + var date; + + if (e.firedBy === self) { + return; + } + if (hasMoment) { + date = moment(opts.field.value, opts.format); + date = (date && date.isValid()) ? date.toDate() : null; + } + else { + date = new Date(Date.parse(opts.field.value)); + } + self.setDate(isDate(date) ? date : null); + if (!self._v) { + self.show(); + } + }; + + self._onInputFocus = function() + { + self.show(); + }; + + self._onInputClick = function() + { + self.show(); + }; + + self._onInputBlur = function() + { + if (!self._c) { + self._b = sto(function() { + self.hide(); + }, 50); + } + self._c = false; + }; + + self._onClick = function(e) + { + e = e || window.event; + var target = e.target || e.srcElement, + pEl = target; + if (!target) { + return; + } + if (!hasEventListeners && hasClass(target, 'pika-select')) { + if (!target.onchange) { + target.setAttribute('onchange', 'return;'); + addEvent(target, 'change', self._onChange); + } + } + do { + if (hasClass(pEl, 'pika-single')) { + return; + } + } + while ((pEl = pEl.parentNode)); + if (self._v && target !== opts.trigger) { + self.hide(); + } + }; + + self.el = document.createElement('div'); + self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : ''); + + addEvent(self.el, 'mousedown', self._onMouseDown, true); + addEvent(self.el, 'change', self._onChange); + + if (opts.field) { + if (opts.bound) { + document.body.appendChild(self.el); + } else { + opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling); + } + addEvent(opts.field, 'change', self._onInputChange); + + if (!opts.defaultDate) { + if (hasMoment && opts.field.value) { + opts.defaultDate = moment(opts.field.value, opts.format).toDate(); + } else { + opts.defaultDate = new Date(Date.parse(opts.field.value)); + } + opts.setDefaultDate = true; + } + } + + var defDate = opts.defaultDate; + + if (isDate(defDate)) { + if (opts.setDefaultDate) { + self.setDate(defDate, true); + } else { + self.gotoDate(defDate); + } + } else { + self.gotoDate(new Date()); + } + + if (opts.bound) { + this.hide(); + self.el.className += ' is-bound'; + addEvent(opts.trigger, 'click', self._onInputClick); + addEvent(opts.trigger, 'focus', self._onInputFocus); + addEvent(opts.trigger, 'blur', self._onInputBlur); + } else { + this.show(); + } + + }; + + + /** + * public Pikaday API + */ + Pikaday.prototype = { + + + /** + * configure functionality + */ + config: function(options) + { + if (!this._o) { + this._o = extend({}, defaults, true); + } + + var opts = extend(this._o, options, true); + + opts.isRTL = !!opts.isRTL; + + opts.field = (opts.field && opts.field.nodeName) ? opts.field : null; + + opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field); + + opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field; + + var nom = parseInt(opts.numberOfMonths, 10) || 1; + opts.numberOfMonths = nom > 4 ? 4 : nom; + + if (!isDate(opts.minDate)) { + opts.minDate = false; + } + if (!isDate(opts.maxDate)) { + opts.maxDate = false; + } + if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) { + opts.maxDate = opts.minDate = false; + } + if (opts.minDate) { + setToStartOfDay(opts.minDate); + opts.minYear = opts.minDate.getFullYear(); + opts.minMonth = opts.minDate.getMonth(); + } + if (opts.maxDate) { + setToStartOfDay(opts.maxDate); + opts.maxYear = opts.maxDate.getFullYear(); + opts.maxMonth = opts.maxDate.getMonth(); + } + + if (isArray(opts.yearRange)) { + var fallback = new Date().getFullYear() - 10; + opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback; + opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback; + } else { + opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange; + if (opts.yearRange > 100) { + opts.yearRange = 100; + } + } + + return opts; + }, + + /** + * return a formatted string of the current selection (using Moment.js if available) + */ + toString: function(format) + { + return !isDate(this._d) ? '' : hasMoment ? moment(this._d).format(format || this._o.format) : this._d.toDateString(); + }, + + /** + * return a Moment.js object of the current selection (if available) + */ + getMoment: function() + { + return hasMoment ? moment(this._d) : null; + }, + + /** + * set the current selection from a Moment.js object (if available) + */ + setMoment: function(date, preventOnSelect) + { + if (hasMoment && moment.isMoment(date)) { + this.setDate(date.toDate(), preventOnSelect); + } + }, + + /** + * return a Date object of the current selection + */ + getDate: function() + { + return isDate(this._d) ? new Date(this._d.getTime()) : null; + }, + + /** + * set the current selection + */ + setDate: function(date, preventOnSelect) + { + if (!date) { + this._d = null; + return this.draw(); + } + if (typeof date === 'string') { + date = new Date(Date.parse(date)); + } + if (!isDate(date)) { + return; + } + + var min = this._o.minDate, + max = this._o.maxDate; + + if (isDate(min) && date < min) { + date = min; + } else if (isDate(max) && date > max) { + date = max; + } + + this._d = new Date(date.getTime()); + setToStartOfDay(this._d); + this.gotoDate(this._d); + + if (this._o.field) { + this._o.field.value = this.toString(); + fireEvent(this._o.field, 'change', { firedBy: this }); + } + if (!preventOnSelect && typeof this._o.onSelect === 'function') { + this._o.onSelect.call(this, this.getDate()); + } + }, + + /** + * change view to a specific date + */ + gotoDate: function(date) + { + if (!isDate(date)) { + return; + } + this._y = date.getFullYear(); + this._m = date.getMonth(); + this.draw(); + }, + + gotoToday: function() + { + this.gotoDate(new Date()); + }, + + /** + * change view to a specific month (zero-index, e.g. 0: January) + */ + gotoMonth: function(month) + { + if (!isNaN( (month = parseInt(month, 10)) )) { + this._m = month < 0 ? 0 : month > 11 ? 11 : month; + this.draw(); + } + }, + + nextMonth: function() + { + if (++this._m > 11) { + this._m = 0; + this._y++; + } + this.draw(); + }, + + prevMonth: function() + { + if (--this._m < 0) { + this._m = 11; + this._y--; + } + this.draw(); + }, + + /** + * change view to a specific full year (e.g. "2012") + */ + gotoYear: function(year) + { + if (!isNaN(year)) { + this._y = parseInt(year, 10); + this.draw(); + } + }, + + /** + * change the minDate + */ + setMinDate: function(value) + { + this._o.minDate = value; + }, + + /** + * change the maxDate + */ + setMaxDate: function(value) + { + this._o.maxDate = value; + }, + + /** + * refresh the HTML + */ + draw: function(force) + { + if (!this._v && !force) { + return; + } + var opts = this._o, + minYear = opts.minYear, + maxYear = opts.maxYear, + minMonth = opts.minMonth, + maxMonth = opts.maxMonth; + + if (this._y <= minYear) { + this._y = minYear; + if (!isNaN(minMonth) && this._m < minMonth) { + this._m = minMonth; + } + } + if (this._y >= maxYear) { + this._y = maxYear; + if (!isNaN(maxMonth) && this._m > maxMonth) { + this._m = maxMonth; + } + } + + this.el.innerHTML = renderTitle(this) + this.render(this._y, this._m); + + if (opts.bound) { + this.adjustPosition(); + if(opts.field.type !== 'hidden') { + sto(function() { + opts.trigger.focus(); + }, 1); + } + } + + if (typeof this._o.onDraw === 'function') { + var self = this; + sto(function() { + self._o.onDraw.call(self); + }, 0); + } + }, + + adjustPosition: function() + { + var field = this._o.trigger, pEl = field, + width = this.el.offsetWidth, height = this.el.offsetHeight, + viewportWidth = window.innerWidth || document.documentElement.clientWidth, + viewportHeight = window.innerHeight || document.documentElement.clientHeight, + scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop, + left, top, clientRect; + + if (typeof field.getBoundingClientRect === 'function') { + clientRect = field.getBoundingClientRect(); + left = clientRect.left + window.pageXOffset; + top = clientRect.bottom + window.pageYOffset; + } else { + left = pEl.offsetLeft; + top = pEl.offsetTop + pEl.offsetHeight; + while((pEl = pEl.offsetParent)) { + left += pEl.offsetLeft; + top += pEl.offsetTop; + } + } + + // default position is bottom & left + if (left + width > viewportWidth || + ( + this._o.position.indexOf('right') > -1 && + left - width + field.offsetWidth > 0 + ) + ) { + left = left - width + field.offsetWidth; + } + if (top + height > viewportHeight + scrollTop || + ( + this._o.position.indexOf('top') > -1 && + top - height - field.offsetHeight > 0 + ) + ) { + top = top - height - field.offsetHeight; + } + this.el.style.cssText = [ + 'position: absolute', + 'left: ' + left + 'px', + 'top: ' + top + 'px' + ].join(';'); + }, + + /** + * render HTML for a particular month + */ + render: function(year, month) + { + var opts = this._o, + now = new Date(), + days = getDaysInMonth(year, month), + before = new Date(year, month, 1).getDay(), + data = [], + row = []; + setToStartOfDay(now); + if (opts.firstDay > 0) { + before -= opts.firstDay; + if (before < 0) { + before += 7; + } + } + var cells = days + before, + after = cells; + while(after > 7) { + after -= 7; + } + cells += 7 - after; + for (var i = 0, r = 0; i < cells; i++) + { + var day = new Date(year, month, 1 + (i - before)), + isDisabled = (opts.minDate && day < opts.minDate) || (opts.maxDate && day > opts.maxDate), + isSelected = isDate(this._d) ? compareDates(day, this._d) : false, + isToday = compareDates(day, now), + isEmpty = i < before || i >= (days + before); + + row.push(renderDay(1 + (i - before), isSelected, isToday, isDisabled, isEmpty)); + + if (++r === 7) { + data.push(renderRow(row, opts.isRTL)); + row = []; + r = 0; + } + } + return renderTable(opts, data); + }, + + isVisible: function() + { + return this._v; + }, + + show: function() + { + if (!this._v) { + if (this._o.bound) { + addEvent(document, 'click', this._onClick); + } + removeClass(this.el, 'is-hidden'); + this._v = true; + this.draw(); + if (typeof this._o.onOpen === 'function') { + this._o.onOpen.call(this); + } + } + }, + + hide: function() + { + var v = this._v; + if (v !== false) { + if (this._o.bound) { + removeEvent(document, 'click', this._onClick); + } + this.el.style.cssText = ''; + addClass(this.el, 'is-hidden'); + this._v = false; + if (v !== undefined && typeof this._o.onClose === 'function') { + this._o.onClose.call(this); + } + } + }, + + /** + * GAME OVER + */ + destroy: function() + { + this.hide(); + removeEvent(this.el, 'mousedown', this._onMouseDown, true); + removeEvent(this.el, 'change', this._onChange); + if (this._o.field) { + removeEvent(this._o.field, 'change', this._onInputChange); + if (this._o.bound) { + removeEvent(this._o.trigger, 'click', this._onInputClick); + removeEvent(this._o.trigger, 'focus', this._onInputFocus); + removeEvent(this._o.trigger, 'blur', this._onInputBlur); + } + } + if (this.el.parentNode) { + this.el.parentNode.removeChild(this.el); + } + } + + }; + + return Pikaday; + +})); + +/*! + * Pikaday jQuery plugin. + * + * Copyright © 2013 David Bushell | BSD & MIT license | https://github.com/dbushell/Pikaday + */ + +(function (root, factory) +{ + 'use strict'; + + if (typeof exports === 'object') { + // CommonJS module + factory(require('jquery'), require('../pikaday')); + } else if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery', 'pikaday'], factory); + } else { + // Browser globals + factory(root.jQuery, root.Pikaday); + } +}(this, function ($, Pikaday) +{ + 'use strict'; + + $.fn.pikaday = function() + { + var args = arguments; + + if (!args || !args.length) { + args = [{ }]; + } + + return this.each(function() + { + var self = $(this), + plugin = self.data('pikaday'); + + if (!(plugin instanceof Pikaday)) { + if (typeof args[0] === 'object') { + var options = $.extend({}, args[0]); + options.field = self[0]; + self.data('pikaday', new Pikaday(options)); + } + } else { + if (typeof args[0] === 'string' && typeof plugin[args[0]] === 'function') { + plugin[args[0]].apply(plugin, Array.prototype.slice.call(args,1)); + } + } + }); + }; + +})); diff --git a/js/datepair/lib/site.css b/js/datepair/lib/site.css new file mode 100644 index 0000000..e1b174d --- /dev/null +++ b/js/datepair/lib/site.css @@ -0,0 +1,200 @@ +body { + background: #015; + color: #bbb; + font-family: helvetica, arial, sans-serif; + font-size: 15px; + line-height: 1.3; + margin: 0; + padding: 0; +} + +header, +section, +footer { + padding: 20px; +} + +header, +footer { + background: #111; + color: #666; + position: relative; +} + +header h1 { + margin: 0; + padding: 0; +} + +header h1 a { + font-family: Lucida Sans Unicode, Lucida Grande, sans-serif; + font-size: 60px; + font-weight: 200; + text-decoration: none; +} + +header p { + font-size: 23px; +} + +#header-links { + margin: 0; + padding: 0; + list-style: none; + position: absolute; + right: 20px; + top: 30px; + text-align: right; +} + +#header-links a { + color: #888; +} + +#header-links a:hover { + color: #06c; +} + +h2 { + color: #eee; + font-size: 35px; + font-weight: normal; + margin: 0; + line-height: 1.1 +} + +p { + margin: 20px 0 0 0; +} + +p:first-child { + margin-top: 0; +} + +input { + font-size: 13px; + -webkit-border-radius: 3px; + -moz-border-radius: 5px; + border-radius: 5px; + padding: 3px; + background: #dde; + border: 1px solid #aac; +} + +input.time { + width: 80px; +} + +input.date { + width: 90px; +} + +a { + color: #06c; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +image { + border: 0; +} + +#examples article { + padding-top: 100px; + clear: both; +} + +#examples article:first-child { + padding-top: 0; +} + +#examples .demo { + width: 450px; + float: left; +} + +#examples .code { + font-size: 12px; + margin: 0 0 0 470px; +} + +footer { + font-size: 12px; +} + +div.ui-datepicker { font-size: 11px; } + +#alternateUiWidgetsExample .date { width: 120px; } + +/** + * Blackboard theme + * + * Adapted from Domenico Carbotta's TextMate theme of the same name + * + * @author Domenico Carbotta + * @author Craig Campbell + * @version 1.0.2 + */ +pre { + background: #0B1022; + word-wrap: break-word; + margin: 0px; + padding: 0px; + padding: 10px; + color: #fff; + font-size: 12px; + margin: 0; + overflow-y: auto; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; +} + +pre, code { + font-family: Consolas, 'Monaco', courier, monospace; +} + +pre .comment { + color: #727272; +} + +pre .constant { + color: #D8FA3C; +} + +pre .storage { + color: #FBDE2D; +} + +pre .string, pre .comment.docstring { + color: #61CE3C; +} + +pre .string.regexp, pre .support.tag.script, pre .support.tag.style { + color: #fff; +} + +pre .keyword, pre .selector { + color: #FBDE2D; +} + +pre .inherited-class { + font-style: italic; +} + +pre .entity { + color: #FF6400; +} + +pre .support, *[data-language="c"] .function.call { + color: #8DA6CE; +} + +pre .variable.global, pre .variable.class, pre .variable.instance { + color: #FF6400; +} + + diff --git a/js/datepair/lib/site.js b/js/datepair/lib/site.js new file mode 100644 index 0000000..473861f --- /dev/null +++ b/js/datepair/lib/site.js @@ -0,0 +1,10 @@ +/* Rainbow v1.1.8 rainbowco.de | included languages: generic, javascript */ +window.Rainbow=function(){function q(a){var b,c=a.getAttribute&&a.getAttribute("data-language")||0;if(!c){a=a.attributes;for(b=0;b=e[d][c])delete e[d][c],delete j[d][c];if(a>=c&&ac&&b'+b+""}function s(a,b,c,h){var f=a.exec(c);if(f){++t;!b.name&&"string"==typeof b.matches[0]&&(b.name=b.matches[0],delete b.matches[0]);var k=f[0],i=f.index,u=f[0].length+i,g=function(){function f(){s(a,b,c,h)}t%100>0?f():setTimeout(f,0)};if(C(i,u))g();else{var m=v(b.matches),l=function(a,c,h){if(a>=c.length)h(k);else{var d=f[c[a]];if(d){var e=b.matches[c[a]],i=e.language,g=e.name&&e.matches? +e.matches:e,j=function(b,d,e){var i;i=0;var g;for(g=1;g/g,">").replace(/&(?![\w\#]+;)/g, +"&"),b,c)}function o(a,b,c){if(b= 0 + var delta = this.dateDelta + this.timeDelta; + if (delta < 0 && (!this.startDateInput || !this.endDateInput) ) { + delta += _ONE_DAY; + } + + return delta; + }, + + refresh: function() + { + if (this.startDateInput && this.startDateInput.value && this.endDateInput && this.endDateInput.value) { + var startDate = this.settings.parseDate(this.startDateInput); + var endDate = this.settings.parseDate(this.endDateInput); + if (startDate && endDate) { + this.dateDelta = endDate.getTime() - startDate.getTime(); + } + } + if (this.startTimeInput && this.startTimeInput.value && this.endTimeInput && this.endTimeInput.value) { + var startTime = this.settings.parseTime(this.startTimeInput); + var endTime = this.settings.parseTime(this.endTimeInput); + if (startTime && endTime) { + this.timeDelta = endTime.getTime() - startTime.getTime(); + this._updateEndMintime(); + } + } + }, + + remove: function() + { + this._unbindChangeHandler(); + }, + + _bindChangeHandler: function(){ + // addEventListener doesn't work with synthetic "change" events + // fired by jQuery's trigger() functioin. If jQuery is present, + // use that for event binding + if (jq) { + jq(this.container).on('change.datepair', jq.proxy(this.handleEvent, this)); + } else { + this.container.addEventListener('change', this, false); + } + }, + + _unbindChangeHandler: function(){ + if (jq) { + jq(this.container).off('change.datepair'); + } else { + this.container.removeEventListener('change', this, false); + } + }, + + // This function will be called when passing 'this' to addEventListener + handleEvent: function(e){ + // temporarily unbind the change handler to prevent triggering this + // if we update other inputs + this._unbindChangeHandler(); + + if (hasClass(e.target, this.settings.dateClass)) { + if (e.target.value != '') { + this._dateChanged(e.target); + this._timeChanged(e.target); + } else { + this.dateDelta = null; + } + + } else if (hasClass(e.target, this.settings.timeClass)) { + if (e.target.value != '') { + this._timeChanged(e.target); + } else { + this.timeDelta = null; + } + } + + this._validateRanges(); + this._updateEndMintime(); + this._bindChangeHandler(); + }, + + _dateChanged: function(target){ + if (!this.startDateInput || !this.endDateInput) { + return; + } + + var startDate = this.settings.parseDate(this.startDateInput); + var endDate = this.settings.parseDate(this.endDateInput); + + if (!startDate || !endDate) { + if (this.settings.defaultDateDelta !== null) { + if (startDate) { + var newEnd = new Date(startDate.getTime() + this.settings.defaultDateDelta * _ONE_DAY); + this.settings.updateDate(this.endDateInput, newEnd); + + } else if (endDate) { + var newStart = new Date(endDate.getTime() - this.settings.defaultDateDelta * _ONE_DAY); + this.settings.updateDate(this.startDateInput, newStart); + } + + this.dateDelta = this.settings.defaultDateDelta * _ONE_DAY; + } else { + this.dateDelta = null; + } + + return; + } + + if (this.settings.anchor == 'start' && hasClass(target, this.settings.startClass)) { + var newDate = new Date(startDate.getTime() + this.dateDelta); + this.settings.updateDate(this.endDateInput, newDate); + } else if (this.settings.anchor == 'end' && hasClass(target, this.settings.endClass)) { + var newDate = new Date(endDate.getTime() - this.dateDelta); + this.settings.updateDate(this.startDateInput, newDate); + } else { + if (endDate < startDate) { + var otherInput = hasClass(target, this.settings.startClass) ? this.endDateInput : this.startDateInput; + var selectedDate = this.settings.parseDate(target); + this.dateDelta = 0; + this.settings.updateDate(otherInput, selectedDate); + } else { + this.dateDelta = endDate.getTime() - startDate.getTime(); + } + } + }, + + _timeChanged: function(target){ + if (!this.startTimeInput || !this.endTimeInput) { + return; + } + + var startTime = this.settings.parseTime(this.startTimeInput); + var endTime = this.settings.parseTime(this.endTimeInput); + + if (!startTime || !endTime) { + if (this.settings.defaultTimeDelta !== null) { + if (startTime) { + var newEnd = new Date(startTime.getTime() + this.settings.defaultTimeDelta); + this.settings.updateTime(this.endTimeInput, newEnd); + } else if (endTime) { + var newStart = new Date(endTime.getTime() - this.settings.defaultTimeDelta); + this.settings.updateTime(this.startTimeInput, newStart); + } + + this.timeDelta = this.settings.defaultTimeDelta; + } else { + this.timeDelta = null; + } + + return; + } + + if (this.settings.anchor == 'start' && hasClass(target, this.settings.startClass)) { + var newTime = new Date(startTime.getTime() + this.timeDelta); + this.settings.updateTime(this.endTimeInput, newTime); + endTime = this.settings.parseTime(this.endTimeInput); + + this._doMidnightRollover(startTime, endTime); + } else if (this.settings.anchor == 'end' && hasClass(target, this.settings.endClass)) { + var newTime = new Date(endTime.getTime() - this.timeDelta); + this.settings.updateTime(this.startTimeInput, newTime); + startTime = this.settings.parseTime(this.startTimeInput); + + this._doMidnightRollover(startTime, endTime); + } else { + this._doMidnightRollover(startTime, endTime); + + var startDate, endDate; + if (this.startDateInput && this.endDateInput) { + startDate = this.settings.parseDate(this.startDateInput); + endDate = this.settings.parseDate(this.endDateInput); + } + + if ((+startDate == +endDate) && (endTime < startTime)) { + var thisInput = hasClass(target, this.settings.endClass) ? this.endTimeInput : this.startTimeInput; + var otherInput = hasClass(target, this.settings.startClass) ? this.endTimeInput : this.startTimeInput; + var selectedTime = this.settings.parseTime(thisInput); + this.timeDelta = 0; + this.settings.updateTime(otherInput, selectedTime); + } else { + this.timeDelta = endTime.getTime() - startTime.getTime(); + } + } + + + }, + + _doMidnightRollover: function(startTime, endTime) { + if (!this.startDateInput || !this.endDateInput) { + return; + } + + var endDate = this.settings.parseDate(this.endDateInput); + var startDate = this.settings.parseDate(this.startDateInput); + var newDelta = endTime.getTime() - startTime.getTime(); + var offset = (endTime < startTime) ? _ONE_DAY : -1 * _ONE_DAY; + + if (this.dateDelta !== null + && this.dateDelta + this.timeDelta <= _ONE_DAY + && this.dateDelta + newDelta != 0 + && (offset > 0 || this.dateDelta != 0) + && ((newDelta >= 0 && this.timeDelta < 0) || (newDelta < 0 && this.timeDelta >= 0))) { + + if (this.settings.anchor == 'start') { + this.settings.updateDate(this.endDateInput, new Date(endDate.getTime() + offset)); + this._dateChanged(this.endDateInput); + } else if (this.settings.anchor == 'end') { + this.settings.updateDate(this.startDateInput, new Date(startDate.getTime() - offset)); + this._dateChanged(this.startDateInput); + } + } + this.timeDelta = newDelta; + }, + + _updateEndMintime: function(){ + if (typeof this.settings.setMinTime != 'function') return; + + var baseTime = null; + if (this.settings.anchor == 'start' && (!this.dateDelta || this.dateDelta < _ONE_DAY || (this.timeDelta && this.dateDelta + this.timeDelta < _ONE_DAY))) { + baseTime = this.settings.parseTime(this.startTimeInput); + } + + this.settings.setMinTime(this.endTimeInput, baseTime); + }, + + _validateRanges: function(){ + if (this.startTimeInput && this.endTimeInput && this.timeDelta === null) { + triggerSimpleCustomEvent(this.container, 'rangeIncomplete'); + return; + } + + if (this.startDateInput && this.endDateInput && this.dateDelta === null) { + triggerSimpleCustomEvent(this.container, 'rangeIncomplete'); + return; + } + + // due to the fact that times can wrap around, any time-only pair will be considered valid + if (!this.startDateInput || !this.endDateInput || this.dateDelta + this.timeDelta >= 0) { + triggerSimpleCustomEvent(this.container, 'rangeSelected'); + } else { + triggerSimpleCustomEvent(this.container, 'rangeError'); + } + } +}; diff --git a/js/datepair/src/jquery.datepair.js b/js/datepair/src/jquery.datepair.js new file mode 100644 index 0000000..b9aadd6 --- /dev/null +++ b/js/datepair/src/jquery.datepair.js @@ -0,0 +1,40 @@ +(function($) { + + if(!$) { + return; + } + + //////////// + // Plugin // + //////////// + + $.fn.datepair = function(option) { + var out; + this.each(function() { + var $this = $(this); + var data = $this.data('datepair'); + var options = typeof option === 'object' && option; + + if (!data) { + data = new Datepair(this, options); + $this.data('datepair', data); + } + + if (typeof option === 'string') { + out = data[option](); + } + }); + + return out || this; + }; + + ////////////// + // Data API // + ////////////// + + $('[data-datepair]').each(function() { + var $this = $(this); + $this.datepair($this.data()); + }); + +}(window.Zepto || window.jQuery)); diff --git a/js/datepair/src/wrapper.js b/js/datepair/src/wrapper.js new file mode 100644 index 0000000..82159eb --- /dev/null +++ b/js/datepair/src/wrapper.js @@ -0,0 +1,9 @@ +(function(window, document) { + + 'use strict'; + + //= ./Datepair.js + + window.Datepair = Datepair; + +}(window, document)); diff --git a/js/timepicker/GruntFile.js b/js/timepicker/GruntFile.js new file mode 100644 index 0000000..7692c06 --- /dev/null +++ b/js/timepicker/GruntFile.js @@ -0,0 +1,41 @@ +module.exports = function(grunt) { + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + meta: { + banner : '/*!\n' + + ' * <%= pkg.title %> v<%= pkg.version %> - <%= pkg.description %>\n' + + ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> - <%= pkg.homepage %>\n' + + ' * License: <%= pkg.license %>\n' + + ' */\n\n' + }, + uglify: { + options : { + banner : '<%= meta.banner %>', + report: 'gzip' + }, + dist: { + files: { + 'jquery.timepicker.min.js': ['jquery.timepicker.js'] + } + } + }, + cssmin: { + minify: { + files: { + 'jquery.timepicker.min.css': ['jquery.timepicker.css'] + } + } + }, + jshint: { + all: ['jquery.timepicker.js'] + }, + }); + + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-cssmin'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + + grunt.registerTask('default', ['uglify', 'cssmin']); + +}; diff --git a/js/timepicker/README.md b/js/timepicker/README.md new file mode 100644 index 0000000..67149f8 --- /dev/null +++ b/js/timepicker/README.md @@ -0,0 +1,294 @@ +Timepicker Plugin for jQuery +======================== + +[timepicker screenshot](http://jonthornton.github.com/jquery-timepicker) + +[See a demo and examples here](http://jonthornton.github.com/jquery-timepicker) + +jquery.timepicker is a lightweight timepicker plugin for jQuery inspired by Google Calendar. It supports both mouse and keyboard navigation, and weighs in at 2.7kb minified and gzipped. + +Requirements +------------ +* [jQuery](http://jquery.com/) (>= 1.7) + +Usage +----- + +```javascript +$('.some-time-inputs').timepicker(options); +``` + +Include `jquery.timepicker.css` and `jquery.timepicker.min.js` in your page. + +```options``` is an optional javascript object with parameters explained below. + +You can also set options as [data attributes](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes) on the intput elements, like ``````. Timepicker still needs to be initialized by calling ```$('#someElement').timepicker();```. + +The defaults for all options are exposed through the ```$.fn.timepicker.defaults``` object. Properties changed in this object (same properties configurable through the constructor) will take effect for every instance created after the change. + +Options +------- + +- **appendTo** +Override where the dropdown is appended. +Takes either a `string` to use as a selector, a `function` that gets passed the clicked input element as argument or a jquery `object` to use directly. +*default: "body"* + +- **className** +A class name to apply to the HTML element that contains the timepicker dropdown. +*default: null* + +- **closeOnWindowScroll** +Close the timepicker when the window is scrolled. (Replicates ```` control. This is ideal for small screen devices, or if you want to prevent the user from entering arbitrary values. This option is not compatible with the following options: ```appendTo```, ```closeOnWindowScroll```, ```disableTouchKeyboard```, ```forceRoundTime```, ```scrollDefault```, ```selectOnBlur```, ```typeAheadHighlight```. +*default: false* + +- **wrapHours** +If a time greater than 24 hours (27:30, for example) is entered, apply modolo 24 to create a valid time. Setting this to `false` will cause an input of 27:30 to result in a `timeFormatError` event. +*default: true* + +Methods +------- + +- **getSecondsFromMidnight** +Get the time as an integer, expressed as seconds from 12am. + + ```javascript + $('#getTimeExample').timepicker('getSecondsFromMidnight'); + ``` + +- **getTime** +Get the time using a Javascript Date object, relative to a Date object (default: today's date). + + ```javascript + $('#getTimeExample').timepicker('getTime'); + $('#getTimeExample').timepicker('getTime', new Date()); + ``` + + You can get the time as a string using jQuery's built-in ```val()``` function: + + ```javascript + $('#getTimeExample').val(); + ``` + +- **hide** +Close the timepicker dropdown. + + ```javascript + $('#hideExample').timepicker('hide'); + ``` + +- **isVisible** +Check if the timepicker attached to *a specific input* is visible. Not compatible with the `useSelect` option. + + ```javascript + $('#hideExample').timepicker('isVisible'); + ``` + +- **option** +Change the settings of an existing timepicker. Calling ```option``` on a visible timepicker will cause the picker to be hidden. + + ```javascript + $('#optionExample').timepicker({ 'timeFormat': 'g:ia' }); // initialize the timepicker sometime earlier in your code + ... + $('#optionExample').timepicker('option', 'minTime', '2:00am'); + $('#optionExample').timepicker('option', { 'minTime': '4:00am', 'timeFormat': 'H:i' }); + ``` + +- **remove** +Unbind an existing timepicker element. + + ```javascript + $('#removeExample').timepicker('remove'); + ``` + +- **setTime** +Set the time using a Javascript Date object. + + ```javascript + $('#setTimeExample').timepicker('setTime', new Date()); + ``` + +- **show** +Display the timepicker dropdown. + + ```javascript + $('#showExample').timepicker('show'); + ``` + +Events +------ + +- **change** +The native ```onChange``` event will fire any time the input value is updated, whether by selection from the timepicker list or manual entry into the text input. Your code should bind to ```change``` after initializing timepicker, or use [event delegation](http://api.jquery.com/on/). + +- **changeTime** +Called after a valid time value is entered or selected. See ```timeFormatError``` and ```timeRangeError``` for error events. Fires before ```change``` event. + +- **hideTimepicker** +Called after the timepicker is closed. + +- **selectTime** +Called after a time value is selected from the timepicker list. Fires before ```change``` event. + +- **showTimepicker** +Called after the timepicker is shown. + +- **timeFormatError** +Called if an unparseable time string is manually entered into the timepicker input. Fires before ```change``` event. + +- **timeRangeError** +Called if a maxTime, minTime, or disableTimeRanges is set and an invalid time is manually entered into the timepicker input. Fires before ```change``` event. + +The `selectTime` and `hideTimepicker` events fire slightly differently when using the `useSelect` option. See https://github.com/jonthornton/jquery-timepicker/issues/427 for more information. + +Theming +------- + +Sample markup with class names: + +```html + +... +
+
    +
  • 12:00am
  • +
  • 12:30am
  • + ... +
  • 4:30pm
  • +
  • 5:00pm
  • +
  • 5:30pm
  • +
  • 6:00pm (1 hour)
  • +
  • 6:30pm
  • + ... +
  • 11:30pm
  • +
+
+``` + +The `ui-timepicker-positioned-top` class will be applied only when the dropdown is positioned above the input. + +## Packaging + +Install from [Bower](http://bower.io/) as ```jquery-timepicker-jt```. + +An AngularJS directive is available at https://github.com/Recras/angular-jquery-timepicker + +Available via CDN at [https://cdnjs.com/libraries/jquery-timepicker](https://cdnjs.com/libraries/jquery-timepicker). + +Help +---- + +Submit a [GitHub Issues request](https://github.com/jonthornton/jquery-timepicker/issues/new). Please try provide code that demonstrates the problem; you can use [this jsFiddle](http://jsfiddle.net/jonthornton/28uvg/) as a starting point. + +Development guidelines +---------------------- + +1. Install dependencies (jquery + grunt) `npm install` +2. For sanity checks and minification run `grunt`, or just `grunt lint` to have the code linted + +jquery-timepicker follows [semantic versioning](http://semver.org/). + +- - - + +This software is made available under the open source MIT License. © 2014 [Jon Thornton](http://www.jonthornton.com) and [contributors](https://github.com/jonthornton/jquery-timepicker/graphs/contributors) diff --git a/js/timepicker/bower.json b/js/timepicker/bower.json new file mode 100644 index 0000000..b40de2e --- /dev/null +++ b/js/timepicker/bower.json @@ -0,0 +1,16 @@ +{ + "name" : "jt.timepicker", + "version" : "1.11.1", + "description" : "A jQuery timepicker plugin inspired by Google Calendar.", + "homepage" : "http://jonthornton.github.com/jquery-timepicker", + "main" : [ "./jquery.timepicker.js", "./jquery.timepicker.css" ], + "dependencies" : { + "jquery" : ">= 1.7" + }, + "keywords" : [ "time", "picker", "google calendar" ], + "author" : { + "name" : "Jon Thornton", + "web" : "https://github.com/jonthornton" + }, + "license": "http://opensource.org/licenses/MIT" +} diff --git a/js/timepicker/index.html b/js/timepicker/index.html new file mode 100644 index 0000000..e3aeb4e --- /dev/null +++ b/js/timepicker/index.html @@ -0,0 +1,391 @@ + + + + + + Timepicker for jQuery – Demos and Documentation + + + + + + + + + + + + + + + +
+ +

jquery.timepicker

+

+ A lightweight, customizable javascript timepicker plugin for jQuery inspired by Google Calendar. +

+ + +
+ +
+

Use this plugin to unobtrusively add a timepicker dropdown to your forms. It's lightweight (2.7kb minified and gzipped) and easy to customize.

+
+ +
+
+
+

Basic Example

+

+
+ + + +
$('#basicExample').timepicker();
+
+ + +
+
+

Scroll Default Example

+

Set the scroll position to local time if no value selected.

+

+
+ + + +
$('#scrollDefaultExample').timepicker({ 'scrollDefault': 'now' });
+
+ +
+
+

Set Time Example

+

Dynamically set the time using a Javascript Date object.

+

+ + +

+
+ + + +
$('#setTimeExample').timepicker();
+$('#setTimeButton').on('click', function (){
+    $('#setTimeExample').timepicker('setTime', new Date());
+});
+
+ +
+
+

Duration Example

+

Set a starting time and see duration from that starting time. You can optionally set an maxTime as well.

+

+
+ + + +
$('#durationExample').timepicker({
+    'minTime': '2:00pm',
+    'maxTime': '11:30pm',
+    'showDuration': true
+});
+
+ +
+
+

Event Example

+

Trigger an event after selecting a value. Fires before the input onchange event.

+

+ + +

+
+ + + +
$('#onselectExample').timepicker();
+$('#onselectExample').on('changeTime', function() {
+    $('#onselectTarget').text($(this).val());
+});
+
+ +
+
+

DisableTimeRanges Example

+

Prevent selection of certain time values.

+

+
+ + + +
$('#disableTimeRangesExample').timepicker({
+    'disableTimeRanges': [
+        ['1am', '2am'],
+        ['3am', '4:01am']
+    ]
+});
+
+ +
+
+

noneOption Example

+

Custom options can be added to the dropdown menu.

+

+
+ + + +
+$('#noneOptionExample').timepicker({
+    'noneOption': [
+        {
+            'label': 'Foobar',
+            'className': 'shibby',
+            'value': '42'
+        },
+        'Foobar2'
+    ]
+});
+        
+
+ +
+
+

timeFormat Example

+

timepicker.jquery uses the time portion of PHP's date formatting commands.

+

+
+ + + +
$('#timeformatExample1').timepicker({ 'timeFormat': 'H:i:s' });
+$('#timeformatExample2').timepicker({ 'timeFormat': 'h:i A' });
+
+ +
+
+

Step Example

+

Generate drop-down options with varying levels of precision.

+

+
+ + + +
$('#stepExample1').timepicker({ 'step': 15 });
+$('#stepExample2').timepicker({
+    'step': function(i) {
+        return (i%2) ? 15 : 45;
+    }
+});
+
+ +
+
+

forceRoundTime Example

+

jquery-timepicker allows entering times via the keyboard. Setting forceRoundTime to true will + round the entered time to the nearest option on the dropdown list.

+

+
+ + + +
$('#roundTimeExample').timepicker({ 'forceRoundTime': true });
+
+ +
+
+

Select Example

+

jquery-timepicker can render itself as a select element too.

+

+
+ + + +
$('#selectExample').timepicker();
+$('#selectButton').click(function(e) {
+  $('#selectExample').timepicker('option', { useSelect: true });
+  $(this).hide();
+});
+
+ +
+
+

Non-input Example

+

jquery-timepicker can be bound to any visibile DOM element, such as spans or divs.

+

+
+ + + +
$('#spanExample').timepicker();
+    $('#openSpanExample').on('click', function(){
+    $('#spanExample').timepicker('show');
+});
+
+ +
+
+

Datepair Plugin Example

+ +

jquery-timepicker is designed to work with the jquery-datepair plugin. + +

+ + to + + +

+
+ + + + + +
+<p id="datepairExample">
+    <input type="text" class="date start" />
+    <input type="text" class="time start" /> to
+    <input type="text" class="time end" />
+    <input type="text" class="date end" />
+</p>
+
+<script type="text/javascript" src="datepair.js"></script>
+<script type="text/javascript" src="jquery.datepair.js"></script>
+<script>
+    // initialize input widgets first
+    $('#datepairExample .time').timepicker({
+        'showDuration': true,
+        'timeFormat': 'g:ia'
+    });
+
+    $('#datepairExample .date').datepicker({
+        'format': 'yyyy-m-d',
+        'autoclose': true
+    });
+
+    // initialize datepair
+    $('#datepairExample').datepair();
+</script>
+ +
+
+ +
+

Need Help?

+

Check the documentation or submit an issue on GitHub.

+
+ + + + +
+ diff --git a/js/timepicker/jquery.timepicker.css b/js/timepicker/jquery.timepicker.css new file mode 100755 index 0000000..cd75f13 --- /dev/null +++ b/js/timepicker/jquery.timepicker.css @@ -0,0 +1,72 @@ +.ui-timepicker-wrapper { + overflow-y: auto; + height: 150px; + width: 6.5em; + background: #fff; + border: 1px solid #ddd; + -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2); + -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2); + box-shadow:0 5px 10px rgba(0,0,0,0.2); + outline: none; + z-index: 10001; + margin: 0; +} + +.ui-timepicker-wrapper.ui-timepicker-with-duration { + width: 13em; +} + +.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30, +.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60 { + width: 11em; +} + +.ui-timepicker-list { + margin: 0; + padding: 0; + list-style: none; +} + +.ui-timepicker-duration { + margin-left: 5px; color: #888; +} + +.ui-timepicker-list:hover .ui-timepicker-duration { + color: #888; +} + +.ui-timepicker-list li { + padding: 3px 0 3px 5px; + cursor: pointer; + white-space: nowrap; + color: #000; + list-style: none; + margin: 0; +} + +.ui-timepicker-list:hover .ui-timepicker-selected { + background: #fff; color: #000; +} + +li.ui-timepicker-selected, +.ui-timepicker-list li:hover, +.ui-timepicker-list .ui-timepicker-selected:hover { + background: #1980EC; color: #fff; +} + +li.ui-timepicker-selected .ui-timepicker-duration, +.ui-timepicker-list li:hover .ui-timepicker-duration { + color: #ccc; +} + +.ui-timepicker-list li.ui-timepicker-disabled, +.ui-timepicker-list li.ui-timepicker-disabled:hover, +.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { + color: #888; + cursor: default; +} + +.ui-timepicker-list li.ui-timepicker-disabled:hover, +.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled { + background: #f2f2f2; +} diff --git a/js/timepicker/jquery.timepicker.d.ts b/js/timepicker/jquery.timepicker.d.ts new file mode 100644 index 0000000..5754f05 --- /dev/null +++ b/js/timepicker/jquery.timepicker.d.ts @@ -0,0 +1,152 @@ +// Type definitions for jQuery.timepicker 1.11.1 +// https://github.com/jonthornton/jquery-timepicker + +/** + * Declaring a namespace because there are several jquery timepickers already out there on DefinitelyTyped. Jt stands for Jon Thornton + */ +declare namespace Jt.Timepicker { + + /** + * Options object for the jquery.timepicker + */ + export interface Options { + /** + * Default: 'body' + * Override where the dropdown is appended. + * Takes either a string to use as a selector, a function that gets passed the clicked input element as argument or a jquery object to use directly. + */ + appendTo?: string | ((clickedElement) => string); + /** + * Default: null + * A class name to apply to the HTML element that contains the timepicker dropdown. + */ + className?: string; + /** + * Default: false + * Close the timepicker when the window is scrolled. (Replicates control. This is ideal for small screen devices, or if you want to prevent the user from entering + * arbitrary values. This option is not compatible with the following options: appendTo, closeOnWindowScroll, disableTouchKeyboard, + * scrollDefault, selectOnBlur, typeAheadHighlight. + */ + useSelect?: boolean; + } + + export interface NoneObject { + label: string; + value: string; + className: string; + } +} diff --git a/js/timepicker/jquery.timepicker.js b/js/timepicker/jquery.timepicker.js new file mode 100644 index 0000000..2908469 --- /dev/null +++ b/js/timepicker/jquery.timepicker.js @@ -0,0 +1,1241 @@ +/*! + * jquery-timepicker v1.11.1 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation. + * Copyright (c) 2015 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/ + * License: MIT + */ + + +(function (factory) { + if (typeof exports === "object" && exports && + typeof module === "object" && module && module.exports === exports) { + // Browserify. Attach to jQuery module. + factory(require("jquery")); + } else if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + var _ONE_DAY = 86400; + var _lang = { + am: 'am', + pm: 'pm', + AM: 'AM', + PM: 'PM', + decimal: '.', + mins: 'mins', + hr: 'hr', + hrs: 'hrs' + }; + + var methods = { + init: function(options) + { + return this.each(function() + { + var self = $(this); + + // pick up settings from data attributes + var attributeOptions = []; + for (var key in $.fn.timepicker.defaults) { + if (self.data(key)) { + attributeOptions[key] = self.data(key); + } + } + + var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options); + + if (settings.lang) { + _lang = $.extend(_lang, settings.lang); + } + + settings = _parseSettings(settings); + self.data('timepicker-settings', settings); + self.addClass('ui-timepicker-input'); + + if (settings.useSelect) { + _render(self); + } else { + self.prop('autocomplete', 'off'); + if (settings.showOn) { + for (var i in settings.showOn) { + self.on(settings.showOn[i]+'.timepicker', methods.show); + } + } + self.on('change.timepicker', _formatValue); + self.on('keydown.timepicker', _keydownhandler); + self.on('keyup.timepicker', _keyuphandler); + if (settings.disableTextInput) { + self.on('keydown.timepicker', _disableTextInputHandler); + } + + _formatValue.call(self.get(0)); + } + }); + }, + + show: function(e) + { + var self = $(this); + var settings = self.data('timepicker-settings'); + + if (e) { + e.preventDefault(); + } + + if (settings.useSelect) { + self.data('timepicker-list').focus(); + return; + } + + if (_hideKeyboard(self)) { + // block the keyboard on mobile devices + self.blur(); + } + + var list = self.data('timepicker-list'); + + // check if input is readonly + if (self.prop('readonly')) { + return; + } + + // check if list needs to be rendered + if (!list || list.length === 0 || typeof settings.durationTime === 'function') { + _render(self); + list = self.data('timepicker-list'); + } + + if (_isVisible(list)) { + return; + } + + self.data('ui-timepicker-value', self.val()); + _setSelected(self, list); + + // make sure other pickers are hidden + methods.hide(); + + // position the dropdown relative to the input + list.show(); + var listOffset = {}; + + if (settings.orientation.match(/r/)) { + // right-align the dropdown + listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10); + } else { + // left-align the dropdown + listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10); + } + + var verticalOrientation; + if (settings.orientation.match(/t/)) { + verticalOrientation = 't'; + } else if (settings.orientation.match(/b/)) { + verticalOrientation = 'b'; + } else if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) { + verticalOrientation = 't'; + } else { + verticalOrientation = 'b'; + } + + if (verticalOrientation == 't') { + // position the dropdown on top + list.addClass('ui-timepicker-positioned-top'); + listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10); + } else { + // put it under the input + list.removeClass('ui-timepicker-positioned-top'); + listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10); + } + + list.offset(listOffset); + + // position scrolling + var selected = list.find('.ui-timepicker-selected'); + + if (!selected.length) { + var timeInt = _time2int(_getTimeValue(self)); + if (timeInt !== null) { + selected = _findRow(self, list, timeInt); + } else if (settings.scrollDefault) { + selected = _findRow(self, list, settings.scrollDefault()); + } + } + + if (selected && selected.length) { + var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight(); + list.scrollTop(topOffset); + } else { + list.scrollTop(0); + } + + // prevent scroll propagation + if(settings.stopScrollPropagation) { + $(document).on('wheel.ui-timepicker', '.ui-timepicker-wrapper', function(e){ + e.preventDefault(); + var currentScroll = $(this).scrollTop(); + $(this).scrollTop(currentScroll + e.originalEvent.deltaY); + }); + } + + // attach close handlers + $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler); + $(window).on('resize.ui-timepicker', _closeHandler); + if (settings.closeOnWindowScroll) { + $(document).on('scroll.ui-timepicker', _closeHandler); + } + + self.trigger('showTimepicker'); + + return this; + }, + + hide: function(e) + { + var self = $(this); + var settings = self.data('timepicker-settings'); + + if (settings && settings.useSelect) { + self.blur(); + } + + $('.ui-timepicker-wrapper').each(function() { + var list = $(this); + if (!_isVisible(list)) { + return; + } + + var self = list.data('timepicker-input'); + var settings = self.data('timepicker-settings'); + + if (settings && settings.selectOnBlur) { + _selectValue(self); + } + + list.hide(); + self.trigger('hideTimepicker'); + }); + + return this; + }, + + option: function(key, value) + { + if (typeof key == 'string' && typeof value == 'undefined') { + return $(this).data('timepicker-settings')[key]; + } + + return this.each(function(){ + var self = $(this); + var settings = self.data('timepicker-settings'); + var list = self.data('timepicker-list'); + + if (typeof key == 'object') { + settings = $.extend(settings, key); + } else if (typeof key == 'string') { + settings[key] = value; + } + + settings = _parseSettings(settings); + + self.data('timepicker-settings', settings); + + if (list) { + list.remove(); + self.data('timepicker-list', false); + } + + if (settings.useSelect) { + _render(self); + } + }); + }, + + getSecondsFromMidnight: function() + { + return _time2int(_getTimeValue(this)); + }, + + getTime: function(relative_date) + { + var self = this; + + var time_string = _getTimeValue(self); + if (!time_string) { + return null; + } + + var offset = _time2int(time_string); + if (offset === null) { + return null; + } + + if (!relative_date) { + relative_date = new Date(); + } + + // construct a Date from relative date, and offset's time + var time = new Date(relative_date); + time.setHours(offset / 3600); + time.setMinutes(offset % 3600 / 60); + time.setSeconds(offset % 60); + time.setMilliseconds(0); + + return time; + }, + + isVisible: function() { + var self = this; + var list = self.data('timepicker-list'); + return !!(list && _isVisible(list)); + }, + + setTime: function(value) + { + var self = this; + var settings = self.data('timepicker-settings'); + + if (settings.forceRoundTime) { + var prettyTime = _roundAndFormatTime(_time2int(value), settings) + } else { + var prettyTime = _int2time(_time2int(value), settings); + } + + if (value && prettyTime === null && settings.noneOption) { + prettyTime = value; + } + + _setTimeValue(self, prettyTime); + if (self.data('timepicker-list')) { + _setSelected(self, self.data('timepicker-list')); + } + + return this; + }, + + remove: function() + { + var self = this; + + // check if this element is a timepicker + if (!self.hasClass('ui-timepicker-input')) { + return; + } + + var settings = self.data('timepicker-settings'); + self.removeAttr('autocomplete', 'off'); + self.removeClass('ui-timepicker-input'); + self.removeData('timepicker-settings'); + self.off('.timepicker'); + + // timepicker-list won't be present unless the user has interacted with this timepicker + if (self.data('timepicker-list')) { + self.data('timepicker-list').remove(); + } + + if (settings.useSelect) { + self.show(); + } + + self.removeData('timepicker-list'); + + return this; + } + }; + + // private methods + + function _isVisible(elem) + { + var el = elem[0]; + return el.offsetWidth > 0 && el.offsetHeight > 0; + } + + function _parseSettings(settings) + { + if (settings.minTime) { + settings.minTime = _time2int(settings.minTime); + } + + if (settings.maxTime) { + settings.maxTime = _time2int(settings.maxTime); + } + + if (settings.durationTime && typeof settings.durationTime !== 'function') { + settings.durationTime = _time2int(settings.durationTime); + } + + if (settings.scrollDefault == 'now') { + settings.scrollDefault = function() { + return settings.roundingFunction(_time2int(new Date()), settings); + } + } else if (settings.scrollDefault && typeof settings.scrollDefault != 'function') { + var val = settings.scrollDefault; + settings.scrollDefault = function() { + return settings.roundingFunction(_time2int(val), settings); + } + } else if (settings.minTime) { + settings.scrollDefault = function() { + return settings.roundingFunction(settings.minTime, settings); + } + } + + if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) { + settings._twelveHourTime = true; + } + + if (settings.showOnFocus === false && settings.showOn.indexOf('focus') != -1) { + settings.showOn.splice(settings.showOn.indexOf('focus'), 1); + } + + if (settings.disableTimeRanges.length > 0) { + // convert string times to integers + for (var i in settings.disableTimeRanges) { + settings.disableTimeRanges[i] = [ + _time2int(settings.disableTimeRanges[i][0]), + _time2int(settings.disableTimeRanges[i][1]) + ]; + } + + // sort by starting time + settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){ + return a[0] - b[0]; + }); + + // merge any overlapping ranges + for (var i = settings.disableTimeRanges.length-1; i > 0; i--) { + if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) { + settings.disableTimeRanges[i-1] = [ + Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]), + Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1]) + ]; + settings.disableTimeRanges.splice(i, 1); + } + } + } + + return settings; + } + + function _render(self) + { + var settings = self.data('timepicker-settings'); + var list = self.data('timepicker-list'); + + if (list && list.length) { + list.remove(); + self.data('timepicker-list', false); + } + + if (settings.useSelect) { + list = $('",{"class":"ui-timepicker-select"});var g=d}else{d=a("
    ",{"class":"ui-timepicker-list"});var g=a("
    ",{"class":"ui-timepicker-wrapper",tabindex:-1});g.css({display:"none",position:"absolute"}).append(d)}if(c.noneOption)if(c.noneOption===!0&&(c.noneOption=c.useSelect?"Time...":"None"),a.isArray(c.noneOption)){for(var i in c.noneOption)if(parseInt(i,10)==i){var k=e(c.noneOption[i],c.useSelect);d.append(k)}}else{var k=e(c.noneOption,c.useSelect);d.append(k)}if(c.className&&g.addClass(c.className),(null!==c.minTime||null!==c.durationTime)&&c.showDuration){"function"==typeof c.step?"function":c.step;g.addClass("ui-timepicker-with-duration"),g.addClass("ui-timepicker-step-"+c.step)}var l=c.minTime;"function"==typeof c.durationTime?l=t(c.durationTime()):null!==c.durationTime&&(l=c.durationTime);var n=null!==c.minTime?c.minTime:0,o=null!==c.maxTime?c.maxTime:n+u-1;n>o&&(o+=u),o===u-1&&"string"===a.type(c.timeFormat)&&c.show2400&&(o=u);var p=c.disableTimeRanges,v=0,x=p.length,y=c.step;"function"!=typeof y&&(y=function(){return c.step});for(var i=n,z=0;o>=i;z++,i+=60*y(z)){var A=i,B=s(A,c);if(c.useSelect){var C=a("