conschedule 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +154 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/config/conschedule_manifest.js +2 -0
  6. data/app/assets/fonts/icomoon.eot +0 -0
  7. data/app/assets/fonts/proxima_nova_100.eot +0 -0
  8. data/app/assets/fonts/proxima_nova_400.eot +0 -0
  9. data/app/assets/fonts/proxima_nova_700.eot +0 -0
  10. data/app/assets/images/conschedule/chosen-sprite-small.png +0 -0
  11. data/app/assets/images/conschedule/chosen-sprite.png +0 -0
  12. data/app/assets/images/conschedule/close.png +0 -0
  13. data/app/assets/images/conschedule/spinner-small.gif +0 -0
  14. data/app/assets/images/conschedule/spinner.gif +0 -0
  15. data/app/assets/javascripts/conschedule/application.js +22 -0
  16. data/app/assets/javascripts/conschedule/calendar.js +467 -0
  17. data/app/assets/javascripts/conschedule/date.js +104 -0
  18. data/app/assets/javascripts/conschedule/form.js +53 -0
  19. data/app/assets/javascripts/conschedule/home.js +149 -0
  20. data/app/assets/javascripts/conschedule/jquery-ui-datepicker.min.js +1674 -0
  21. data/app/assets/javascripts/conschedule/jquery.easing.min.js +44 -0
  22. data/app/assets/javascripts/conschedule/jquery.validate.js +1532 -0
  23. data/app/assets/javascripts/conschedule/js_time_zone.js +1433 -0
  24. data/app/assets/javascripts/conschedule/moment-timezone.js +1209 -0
  25. data/app/assets/javascripts/conschedule/moment.js +4195 -0
  26. data/app/assets/javascripts/conschedule/schedules.js +22 -0
  27. data/app/assets/javascripts/conschedule/time_zones_drop_down.js +609 -0
  28. data/app/assets/stylesheets/conschedule/application.css +4 -0
  29. data/app/assets/stylesheets/conschedule/common.css +816 -0
  30. data/app/assets/stylesheets/conschedule/home.css +2441 -0
  31. data/app/assets/stylesheets/conschedule/main.css +884 -0
  32. data/app/assets/stylesheets/conschedule/schedules.css +4 -0
  33. data/app/controllers/conschedule/application_controller.rb +49 -0
  34. data/app/controllers/conschedule/schedules_controller.rb +125 -0
  35. data/app/helpers/conschedule/application_helper.rb +15 -0
  36. data/app/helpers/conschedule/schedules_helper.rb +43 -0
  37. data/app/jobs/conschedule/application_job.rb +4 -0
  38. data/app/mailers/conschedule/schedules_mailer.rb +46 -0
  39. data/app/models/conschedule/application_record.rb +5 -0
  40. data/app/models/conschedule/schedule.rb +63 -0
  41. data/app/views/conschedule/schedules/_confirmation.html.erb +38 -0
  42. data/app/views/conschedule/schedules/_page_one.html.erb +75 -0
  43. data/app/views/conschedule/schedules/_page_three.html.erb +94 -0
  44. data/app/views/conschedule/schedules/_page_two.html.erb +22 -0
  45. data/app/views/conschedule/schedules/_schedules.html.erb +122 -0
  46. data/app/views/conschedule/schedules/create.js.erb +11 -0
  47. data/app/views/conschedule/schedules/index.html.erb +123 -0
  48. data/app/views/conschedule/schedules/index.js.erb +3 -0
  49. data/app/views/conschedule/schedules/new.html.erb +11 -0
  50. data/app/views/conschedule/schedules_mailer/send_cancel_email_owner.html.erb +61 -0
  51. data/app/views/conschedule/schedules_mailer/send_cancel_email_user.html.erb +29 -0
  52. data/app/views/conschedule/schedules_mailer/send_confirmation_email_owner.html.erb +77 -0
  53. data/app/views/conschedule/schedules_mailer/send_confirmation_email_user.html.erb +30 -0
  54. data/app/views/kaminari/custom_theme/_first_page.html.erb +3 -0
  55. data/app/views/kaminari/custom_theme/_gap.html.erb +1 -0
  56. data/app/views/kaminari/custom_theme/_last_page.html.erb +3 -0
  57. data/app/views/kaminari/custom_theme/_next_page.html.erb +1 -0
  58. data/app/views/kaminari/custom_theme/_page.html.erb +5 -0
  59. data/app/views/kaminari/custom_theme/_paginator.html.erb +23 -0
  60. data/app/views/kaminari/custom_theme/_prev_page.html.erb +1 -0
  61. data/app/views/layouts/conschedule/application.html.erb +14 -0
  62. data/app/views/layouts/conschedule/mailer.html.erb +11 -0
  63. data/app/views/layouts/conschedule/schedules.html.erb +14 -0
  64. data/config/initializers/assets.rb +11 -0
  65. data/config/routes.rb +11 -0
  66. data/db/migrate/20160812085505_create_conschedule_schedules.rb +27 -0
  67. data/lib/conschedule.rb +34 -0
  68. data/lib/conschedule/configuration.rb +25 -0
  69. data/lib/conschedule/engine.rb +5 -0
  70. data/lib/conschedule/gem_dependencies.rb +2 -0
  71. data/lib/conschedule/version.rb +3 -0
  72. data/lib/generators/conschedule/install_generator.rb +23 -0
  73. data/lib/generators/conschedule/views_generator.rb +45 -0
  74. data/lib/generators/templates/README +40 -0
  75. data/lib/generators/templates/initializer.rb +25 -0
  76. data/lib/tasks/conschedule_tasks.rake +4 -0
  77. metadata +182 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Version: 1.0 Alpha-1
3
+ * Build Date: 13-Nov-2007
4
+ * Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
5
+ * License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
6
+ * Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
7
+ */
8
+ Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|after|from)/i,subtract:/^(\-|before|ago)/i,yesterday:/^yesterday/i,today:/^t(oday)?/i,tomorrow:/^tomorrow/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^min(ute)?s?/i,hour:/^h(ou)?rs?/i,week:/^w(ee)?k/i,month:/^m(o(nth)?s?)?/i,day:/^d(ays?)?/i,year:/^y((ea)?rs?)?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a|p)/i},abbreviatedTimeZoneStandard:{GMT:"-000",EST:"-0400",CST:"-0500",MST:"-0600",PST:"-0700"},abbreviatedTimeZoneDST:{GMT:"-000",EDT:"-0500",CDT:"-0600",MDT:"-0700",PDT:"-0800"}};
9
+ Date.getMonthNumberFromName=function(name){var n=Date.CultureInfo.monthNames,m=Date.CultureInfo.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
10
+ return-1;};Date.getDayNumberFromName=function(name){var n=Date.CultureInfo.dayNames,m=Date.CultureInfo.abbreviatedDayNames,o=Date.CultureInfo.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
11
+ return-1;};Date.isLeapYear=function(year){return(((year%4===0)&&(year%100!==0))||(year%400===0));};Date.getDaysInMonth=function(year,month){return[31,(Date.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};Date.getTimezoneOffset=function(s,dst){return(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST[s.toUpperCase()]:Date.CultureInfo.abbreviatedTimeZoneStandard[s.toUpperCase()];};Date.getTimezoneAbbreviation=function(offset,dst){var n=(dst||false)?Date.CultureInfo.abbreviatedTimeZoneDST:Date.CultureInfo.abbreviatedTimeZoneStandard,p;for(p in n){if(n[p]===offset){return p;}}
12
+ return null;};Date.prototype.clone=function(){return new Date(this.getTime());};Date.prototype.compareTo=function(date){if(isNaN(this)){throw new Error(this);}
13
+ if(date instanceof Date&&!isNaN(date)){return(this>date)?1:(this<date)?-1:0;}else{throw new TypeError(date);}};Date.prototype.equals=function(date){return(this.compareTo(date)===0);};Date.prototype.between=function(start,end){var t=this.getTime();return t>=start.getTime()&&t<=end.getTime();};Date.prototype.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};Date.prototype.addSeconds=function(value){return this.addMilliseconds(value*1000);};Date.prototype.addMinutes=function(value){return this.addMilliseconds(value*60000);};Date.prototype.addHours=function(value){return this.addMilliseconds(value*3600000);};Date.prototype.addDays=function(value){return this.addMilliseconds(value*86400000);};Date.prototype.addWeeks=function(value){return this.addMilliseconds(value*604800000);};Date.prototype.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,this.getDaysInMonth()));return this;};Date.prototype.addYears=function(value){return this.addMonths(value*12);};Date.prototype.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
14
+ var x=config;if(x.millisecond||x.milliseconds){this.addMilliseconds(x.millisecond||x.milliseconds);}
15
+ if(x.second||x.seconds){this.addSeconds(x.second||x.seconds);}
16
+ if(x.minute||x.minutes){this.addMinutes(x.minute||x.minutes);}
17
+ if(x.hour||x.hours){this.addHours(x.hour||x.hours);}
18
+ if(x.month||x.months){this.addMonths(x.month||x.months);}
19
+ if(x.year||x.years){this.addYears(x.year||x.years);}
20
+ if(x.day||x.days){this.addDays(x.day||x.days);}
21
+ return this;};Date._validate=function(value,min,max,name){if(typeof value!="number"){throw new TypeError(value+" is not a Number.");}else if(value<min||value>max){throw new RangeError(value+" is not a valid value for "+name+".");}
22
+ return true;};Date.validateMillisecond=function(n){return Date._validate(n,0,999,"milliseconds");};Date.validateSecond=function(n){return Date._validate(n,0,59,"seconds");};Date.validateMinute=function(n){return Date._validate(n,0,59,"minutes");};Date.validateHour=function(n){return Date._validate(n,0,23,"hours");};Date.validateDay=function(n,year,month){return Date._validate(n,1,Date.getDaysInMonth(year,month),"days");};Date.validateMonth=function(n){return Date._validate(n,0,11,"months");};Date.validateYear=function(n){return Date._validate(n,1,9999,"seconds");};Date.prototype.set=function(config){var x=config;if(!x.millisecond&&x.millisecond!==0){x.millisecond=-1;}
23
+ if(!x.second&&x.second!==0){x.second=-1;}
24
+ if(!x.minute&&x.minute!==0){x.minute=-1;}
25
+ if(!x.hour&&x.hour!==0){x.hour=-1;}
26
+ if(!x.day&&x.day!==0){x.day=-1;}
27
+ if(!x.month&&x.month!==0){x.month=-1;}
28
+ if(!x.year&&x.year!==0){x.year=-1;}
29
+ if(x.millisecond!=-1&&Date.validateMillisecond(x.millisecond)){this.addMilliseconds(x.millisecond-this.getMilliseconds());}
30
+ if(x.second!=-1&&Date.validateSecond(x.second)){this.addSeconds(x.second-this.getSeconds());}
31
+ if(x.minute!=-1&&Date.validateMinute(x.minute)){this.addMinutes(x.minute-this.getMinutes());}
32
+ if(x.hour!=-1&&Date.validateHour(x.hour)){this.addHours(x.hour-this.getHours());}
33
+ if(x.month!==-1&&Date.validateMonth(x.month)){this.addMonths(x.month-this.getMonth());}
34
+ if(x.year!=-1&&Date.validateYear(x.year)){this.addYears(x.year-this.getFullYear());}
35
+ if(x.day!=-1&&Date.validateDay(x.day,this.getFullYear(),this.getMonth())){this.addDays(x.day-this.getDate());}
36
+ if(x.timezone){this.setTimezone(x.timezone);}
37
+ if(x.timezoneOffset){this.setTimezoneOffset(x.timezoneOffset);}
38
+ return this;};Date.prototype.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};Date.prototype.isLeapYear=function(){var y=this.getFullYear();return(((y%4===0)&&(y%100!==0))||(y%400===0));};Date.prototype.isWeekday=function(){return!(this.is().sat()||this.is().sun());};Date.prototype.getDaysInMonth=function(){return Date.getDaysInMonth(this.getFullYear(),this.getMonth());};Date.prototype.moveToFirstDayOfMonth=function(){return this.set({day:1});};Date.prototype.moveToLastDayOfMonth=function(){return this.set({day:this.getDaysInMonth()});};Date.prototype.moveToDayOfWeek=function(day,orient){var diff=(day-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};Date.prototype.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};Date.prototype.getDayOfYear=function(){return Math.floor((this-new Date(this.getFullYear(),0,1))/86400000);};Date.prototype.getWeekOfYear=function(firstDayOfWeek){var y=this.getFullYear(),m=this.getMonth(),d=this.getDate();var dow=firstDayOfWeek||Date.CultureInfo.firstDayOfWeek;var offset=7+1-new Date(y,0,1).getDay();if(offset==8){offset=1;}
39
+ var daynum=((Date.UTC(y,m,d,0,0,0)-Date.UTC(y,0,1,0,0,0))/86400000)+1;var w=Math.floor((daynum-offset+7)/7);if(w===dow){y--;var prevOffset=7+1-new Date(y,0,1).getDay();if(prevOffset==2||prevOffset==8){w=53;}else{w=52;}}
40
+ return w;};Date.prototype.isDST=function(){console.log('isDST');return this.toString().match(/(E|C|M|P)(S|D)T/)[2]=="D";};Date.prototype.getTimezone=function(){return Date.getTimezoneAbbreviation(this.getUTCOffset,this.isDST());};Date.prototype.setTimezoneOffset=function(s){var here=this.getTimezoneOffset(),there=Number(s)*-6/10;this.addMinutes(there-here);return this;};Date.prototype.setTimezone=function(s){return this.setTimezoneOffset(Date.getTimezoneOffset(s));};Date.prototype.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r[0]+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};Date.prototype.getDayName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedDayNames[this.getDay()]:Date.CultureInfo.dayNames[this.getDay()];};Date.prototype.getMonthName=function(abbrev){return abbrev?Date.CultureInfo.abbreviatedMonthNames[this.getMonth()]:Date.CultureInfo.monthNames[this.getMonth()];};Date.prototype._toString=Date.prototype.toString;Date.prototype.toString=function(format){var self=this;var p=function p(s){return(s.toString().length==1)?"0"+s:s;};return format?format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g,function(format){switch(format){case"hh":return p(self.getHours()<13?self.getHours():(self.getHours()-12));case"h":return self.getHours()<13?self.getHours():(self.getHours()-12);case"HH":return p(self.getHours());case"H":return self.getHours();case"mm":return p(self.getMinutes());case"m":return self.getMinutes();case"ss":return p(self.getSeconds());case"s":return self.getSeconds();case"yyyy":return self.getFullYear();case"yy":return self.getFullYear().toString().substring(2,4);case"dddd":return self.getDayName();case"ddd":return self.getDayName(true);case"dd":return p(self.getDate());case"d":return self.getDate().toString();case"MMMM":return self.getMonthName();case"MMM":return self.getMonthName(true);case"MM":return p((self.getMonth()+1));case"M":return self.getMonth()+1;case"t":return self.getHours()<12?Date.CultureInfo.amDesignator.substring(0,1):Date.CultureInfo.pmDesignator.substring(0,1);case"tt":return self.getHours()<12?Date.CultureInfo.amDesignator:Date.CultureInfo.pmDesignator;case"zzz":case"zz":case"z":return"";}}):this._toString();};
41
+ Date.now=function(){return new Date();};Date.today=function(){return Date.now().clearTime();};Date.prototype._orient=+1;Date.prototype.next=function(){this._orient=+1;return this;};Date.prototype.last=Date.prototype.prev=Date.prototype.previous=function(){this._orient=-1;return this;};Date.prototype._is=false;Date.prototype.is=function(){this._is=true;return this;};Number.prototype._dateElement="day";Number.prototype.fromNow=function(){var c={};c[this._dateElement]=this;return Date.now().add(c);};Number.prototype.ago=function(){var c={};c[this._dateElement]=this*-1;return Date.now().add(c);};(function(){var $D=Date.prototype,$N=Number.prototype;var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),de;var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
42
+ return this.moveToDayOfWeek(n,this._orient);};};for(var i=0;i<dx.length;i++){$D[dx[i]]=$D[dx[i].substring(0,3)]=df(i);}
43
+ var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
44
+ return this.moveToMonth(n,this._orient);};};for(var j=0;j<mx.length;j++){$D[mx[j]]=$D[mx[j].substring(0,3)]=mf(j);}
45
+ var ef=function(j){return function(){if(j.substring(j.length-1)!="s"){j+="s";}
46
+ return this["add"+j](this._orient);};};var nf=function(n){return function(){this._dateElement=n;return this;};};for(var k=0;k<px.length;k++){de=px[k].toLowerCase();$D[de]=$D[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}}());Date.prototype.toJSONString=function(){return this.toString("yyyy-MM-ddThh:mm:ssZ");};Date.prototype.toShortDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortDatePattern);};Date.prototype.toLongDateString=function(){return this.toString(Date.CultureInfo.formatPatterns.longDatePattern);};Date.prototype.toShortTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.shortTimePattern);};Date.prototype.toLongTimeString=function(){return this.toString(Date.CultureInfo.formatPatterns.longTimePattern);};Date.prototype.getOrdinal=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};
47
+ (function(){Date.Parsing={Exception:function(s){this.message="Parse error at '"+s.substring(0,10)+" ...'";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){return function(s){var mx=s.match(r);if(mx){return([mx[0],s.substring(mx[0].length)]);}else{throw new $P.Exception(s);}};},token:function(s){return function(s){return _.rtoken(new RegExp("^\s*"+s+"\s*"))(s);};},stoken:function(s){return _.rtoken(new RegExp("^"+s));},until:function(p){return function(s){var qx=[],rx=null;while(s.length){try{rx=p.call(this,s);}catch(e){qx.push(rx[0]);s=rx[1];continue;}
48
+ break;}
49
+ return[qx,s];};},many:function(p){return function(s){var rx=[],r=null;while(s.length){try{r=p.call(this,s);}catch(e){return[rx,s];}
50
+ rx.push(r[0]);s=r[1];}
51
+ return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
52
+ return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
53
+ throw new $P.Exception(s);};},ignore:function(p){return p?function(s){var r=null;r=p.call(this,s);return[null,r[1]];}:null;},product:function(){var px=arguments[0],qx=Array.prototype.slice.call(arguments,1),rx=[];for(var i=0;i<px.length;i++){rx.push(_.each(px[i],qx));}
54
+ return rx;},cache:function(rule){var cache={},r=null;return function(s){try{r=cache[s]=(cache[s]||rule.call(this,s));}catch(e){r=cache[s]=e;}
55
+ if(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
56
+ try{r=(px[i].call(this,s));}catch(e){r=null;}
57
+ if(r){return r;}}
58
+ throw new $P.Exception(s);};},each:function(){var px=arguments;return function(s){var rx=[],r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
59
+ try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
60
+ rx.push(r[0]);s=r[1];}
61
+ return[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;if(px.length==1){return px[0];}
62
+ return function(s){var r=null,q=null;var rx=[];for(var i=0;i<px.length;i++){try{r=px[i].call(this,s);}catch(e){break;}
63
+ rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
64
+ s=q[1];}
65
+ if(!r){throw new $P.Exception(s);}
66
+ if(q){throw new $P.Exception(q[1]);}
67
+ if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
68
+ return[rx,(r?r[1]:s)];};},between:function(d1,p,d2){d2=d2||d1;var _fn=_.each(_.ignore(d1),p,_.ignore(d2));return function(s){var rx=_fn.call(this,s);return[[rx[0][0],r[0][2]],rx[1]];};},list:function(p,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return(p instanceof Array?_.each(_.product(p.slice(0,-1),_.ignore(d)),p.slice(-1),_.ignore(c)):_.each(_.many(_.each(p,_.ignore(d))),px,_.ignore(c)));},set:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return function(s){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}
69
+ rx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}
70
+ if(!last&&q[1].length===0){last=true;}
71
+ if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
72
+ p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
73
+ if(rx[1].length<best[1].length){best=rx;}
74
+ if(best[1].length===0){break;}}
75
+ if(best[0].length===0){return best;}
76
+ if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
77
+ best[1]=q[1];}
78
+ return best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},replace:function(rule,repl){return function(s){var r=rule.call(this,s);return[repl,r[1]];};},process:function(rule,fn){return function(s){var r=rule.call(this,s);return[fn.call(this,r[0]),r[1]];};},min:function(min,rule){return function(s){var rx=rule.call(this,s);if(rx[0].length<min){throw new $P.Exception(s);}
79
+ return rx;};}};var _generator=function(op){return function(){var args=null,rx=[];if(arguments.length>1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];}
80
+ if(args){for(var i=0,px=args.shift();i<px.length;i++){args.unshift(px[i]);rx.push(op.apply(null,args));args.shift();return rx;}}else{return op.apply(null,arguments);}};};var gx="optional not ignore cache".split(/\s/);for(var i=0;i<gx.length;i++){_[gx[i]]=_generator(_[gx[i]]);}
81
+ var _vector=function(op){return function(){if(arguments[0]instanceof Array){return op.apply(null,arguments[0]);}else{return op.apply(null,arguments);}};};var vx="each any all".split(/\s/);for(var j=0;j<vx.length;j++){_[vx[j]]=_vector(_[vx[j]]);}}());(function(){var flattenAndCompact=function(ax){var rx=[];for(var i=0;i<ax.length;i++){if(ax[i]instanceof Array){rx=rx.concat(flattenAndCompact(ax[i]));}else{if(ax[i]){rx.push(ax[i]);}}}
82
+ return rx;};Date.Grammar={};Date.Translator={hour:function(s){return function(){this.hour=Number(s);};},minute:function(s){return function(){this.minute=Number(s);};},second:function(s){return function(){this.second=Number(s);};},meridian:function(s){return function(){this.meridian=s.slice(0,1).toLowerCase();};},timezone:function(s){return function(){var n=s.replace(/[^\d\+\-]/g,"");if(n.length){this.timezoneOffset=Number(n);}else{this.timezone=s.toLowerCase();}};},day:function(x){var s=x[0];return function(){this.day=Number(s.match(/\d+/)[0]);};},month:function(s){return function(){this.month=((s.length==3)?Date.getMonthNumberFromName(s):(Number(s)-1));};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<Date.CultureInfo.twoDigitYearMax)?2000:1900)));};},rday:function(s){return function(){switch(s){case"yesterday":this.days=-1;break;case"tomorrow":this.days=1;break;case"today":this.days=0;break;case"now":this.days=0;this.now=true;break;}};},finishExact:function(x){x=(x instanceof Array)?x:[x];var now=new Date();this.year=now.getFullYear();this.month=now.getMonth();this.day=1;this.hour=0;this.minute=0;this.second=0;for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
83
+ this.hour=(this.meridian=="p"&&this.hour<13)?this.hour+12:this.hour;if(this.day>Date.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
84
+ var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});}
85
+ return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
86
+ for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
87
+ if(this.now){return new Date();}
88
+ var today=Date.today();var method=null;var expression=!!(this.days!=null||this.orient||this.operator);if(expression){var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(this.weekday){this.unit="day";gap=(Date.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
89
+ if(this.month){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
90
+ if(!this.unit){this.unit="day";}
91
+ if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
92
+ if(this.unit=="week"){this.unit="day";this.value=this.value*7;}
93
+ this[this.unit+"s"]=this.value*orient;}
94
+ return today.add(this);}else{if(this.meridian&&this.hour){this.hour=(this.hour<13&&this.meridian=="p")?this.hour+12:this.hour;}
95
+ if(this.weekday&&!this.day){this.day=(today.addDays((Date.getDayNumberFromName(this.weekday)-today.getDay()))).getDate();}
96
+ if(this.month&&!this.day){this.day=1;}
97
+ return today.set(this);}}};var _=Date.Parsing.Operators,g=Date.Grammar,t=Date.Translator,_fn;g.datePartDelimiter=_.rtoken(/^([\s\-\.\,\/\x27]+)/);g.timePartDelimiter=_.stoken(":");g.whiteSpace=_.rtoken(/^\s*/);g.generalDelimiter=_.rtoken(/^(([\s\,]|at|on)+)/);var _C={};g.ctoken=function(keys){var fn=_C[keys];if(!fn){var c=Date.CultureInfo.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
98
+ fn=_C[keys]=_.any.apply(null,px);}
99
+ return fn;};g.ctoken2=function(key){return _.rtoken(Date.CultureInfo.regexPatterns[key]);};g.h=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/),t.hour));g.hh=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/),t.hour));g.H=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/),t.hour));g.HH=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/),t.hour));g.m=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.minute));g.mm=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.minute));g.s=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.second));g.ss=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.second));g.hms=_.cache(_.sequence([g.H,g.mm,g.ss],g.timePartDelimiter));g.t=_.cache(_.process(g.ctoken2("shortMeridian"),t.meridian));g.tt=_.cache(_.process(g.ctoken2("longMeridian"),t.meridian));g.z=_.cache(_.process(_.rtoken(/^(\+|\-)?\s*\d\d\d\d?/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^(\+|\-)\s*\d\d\d\d/),t.timezone));g.zzz=_.cache(_.process(g.ctoken2("timezone"),t.timezone));g.timeSuffix=_.each(_.ignore(g.whiteSpace),_.set([g.tt,g.zzz]));g.time=_.each(_.optional(_.ignore(_.stoken("T"))),g.hms,g.timeSuffix);g.d=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.dd=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.ddd=g.dddd=_.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),function(s){return function(){this.weekday=s;};}));g.M=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/),t.month));g.MM=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/),t.month));g.MMM=g.MMMM=_.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"),t.month));g.y=_.cache(_.process(_.rtoken(/^(\d\d?)/),t.year));g.yy=_.cache(_.process(_.rtoken(/^(\d\d)/),t.year));g.yyy=_.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/),t.year));g.yyyy=_.cache(_.process(_.rtoken(/^(\d\d\d\d)/),t.year));_fn=function(){return _.each(_.any.apply(null,arguments),_.not(g.ctoken2("timeContext")));};g.day=_fn(g.d,g.dd);g.month=_fn(g.M,g.MMM);g.year=_fn(g.yyyy,g.yy);g.orientation=_.process(g.ctoken("past future"),function(s){return function(){this.orient=s;};});g.operator=_.process(g.ctoken("add subtract"),function(s){return function(){this.operator=s;};});g.rday=_.process(g.ctoken("yesterday tomorrow today now"),t.rday);g.unit=_.process(g.ctoken("minute hour day week month year"),function(s){return function(){this.unit=s;};});g.value=_.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),function(s){return function(){this.value=s.replace(/\D/g,"");};});g.expression=_.set([g.rday,g.operator,g.value,g.unit,g.orientation,g.ddd,g.MMM]);_fn=function(){return _.set(arguments,g.datePartDelimiter);};g.mdy=_fn(g.ddd,g.month,g.day,g.year);g.ymd=_fn(g.ddd,g.year,g.month,g.day);g.dmy=_fn(g.ddd,g.day,g.month,g.year);g.date=function(s){return((g[Date.CultureInfo.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),function(fmt){if(g[fmt]){return g[fmt];}else{throw Date.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};var _get=function(f){return _F[f]=(_F[f]||g.format(f)[0]);};g.formats=function(fx){if(fx instanceof Array){var rx=[];for(var i=0;i<fx.length;i++){rx.push(_get(fx[i]));}
100
+ return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["yyyy-MM-ddTHH:mm:ss","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","d"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}
101
+ return g._start.call({},s);};}());Date._parse=Date.parse;Date.parse=function(s){var r=null;if(!s){return null;}
102
+ try{r=Date.Grammar.start.call({},s);}catch(e){return null;}
103
+ return((r[1].length===0)?r[0]:null);};Date.getParseFunction=function(fx){var fn=Date.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
104
+ return((r[1].length===0)?r[0]:null);};};Date.parseExact=function(s,fx){return Date.getParseFunction(fx)(s);};
@@ -0,0 +1,53 @@
1
+ function wizard_next_step(ele) {
2
+ var current_fs, next_fs, left, opacity, scale, animating;
3
+ if(animating) return false;
4
+ animating = true;
5
+ current_fs = ele.closest('.section-division');
6
+ next_fs = current_fs.next();
7
+ current_fs.hide();
8
+ next_fs.show();
9
+ }
10
+
11
+ function wizard_previous_step(ele) {
12
+ var current_fs, previous_fs, left, opacity, scale, animating;
13
+ if (animating) return false;
14
+ animating = true;
15
+ current_fs = ele.closest('.section-division');
16
+ previous_fs = $(".section-division:first");
17
+ current_fs.hide();
18
+ previous_fs.show();
19
+ }
20
+
21
+ $( document ).ready(function() {
22
+
23
+ $(".schedule_wizard").validate({
24
+ errorClass: "error-message",
25
+ rules: {
26
+ "schedule[first_name]": "required",
27
+ "schedule[email]": {
28
+ required: true,
29
+ email: true
30
+ },
31
+ "schedule[phone]": "required"
32
+ },
33
+ messages: {
34
+ "schedule[first_name]": {
35
+ required: "can't be blank",
36
+ },
37
+ "schedule[email]": {
38
+ required: "can't be blank",
39
+ email: "Email format is invalid."
40
+ },
41
+ "schedule[phone]": {
42
+ required: "can't be blank",
43
+ }
44
+ }
45
+ });
46
+
47
+ $(".step-back").click(function() {
48
+ if ( !$(this).hasClass('unavailable') ) {
49
+ wizard_previous_step($(this));
50
+ }
51
+ });
52
+
53
+ });
@@ -0,0 +1,149 @@
1
+ function init() {
2
+ if ( location.href.indexOf("status_ids[]=cancelled") > 0 ) {
3
+ $(".filter-cancel").prop('checked', true);
4
+ $(".events-tab").html("Cancelled Events<i class='icon-angle-down'></i>");
5
+ }
6
+
7
+ if ( location.href.indexOf("status_ids[]=active") == -1 ) {
8
+ $(".filter-active").prop('checked', false);
9
+ }
10
+ else {
11
+ $(".events-tab").html("Active Events<i class='icon-angle-down'></i>");
12
+ }
13
+
14
+ if ( location.href.indexOf("status_ids[]=active") > 0 && location.href.indexOf("status_ids[]=cancelled") > 0 ) {
15
+ $(".events-tab").html("All Events<i class='icon-angle-down'></i>");
16
+ }
17
+ }
18
+
19
+ function url_param(name) {
20
+ var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
21
+ if (results==null){
22
+ return "";
23
+ }
24
+ else{
25
+ return results[1] || 0;
26
+ }
27
+ }
28
+
29
+ function cancel_event_bind() {
30
+ $(".js-undo-cancel-event").click(function() {
31
+ $("#popup-region").empty();
32
+ });
33
+ }
34
+
35
+ function update_params(include_status) {
36
+ var query_string = [];
37
+ if ( $("input[name=daterangepicker_period]").val() != "" ) {
38
+ var start_date = $("input[name=daterangepicker_start]").val();
39
+ var end_date = $("input[name=daterangepicker_end]").val();
40
+ var period = $("input[name=daterangepicker_period]").val();
41
+ }
42
+ else {
43
+ var start_date = url_param("start_date");
44
+ var end_date = url_param("end_date");
45
+ var period = url_param("period");
46
+ }
47
+ if (include_status) {
48
+ $('.js-checkbox:checked').each(function() {
49
+ if ( $(this).data("filter-type") == "active" ) {
50
+ query_string.push("status_ids[]=active");
51
+ }
52
+ else {
53
+ query_string.push("status_ids[]=cancelled");
54
+ }
55
+ });
56
+ }
57
+ if (start_date != "" && end_date != "") {
58
+ query_string.push("start_date="+start_date);
59
+ query_string.push("end_date="+end_date);
60
+ query_string.push("period="+period);
61
+ }
62
+ var url = location.protocol + '//' + location.host + location.pathname;
63
+ if ( query_string.length != 0 ) {
64
+ query_string = query_string.join("&");
65
+ location.replace(url + "?" + query_string);
66
+ }
67
+ else {
68
+ location.replace(url);
69
+ }
70
+ }
71
+
72
+ $( document ).ready(function() {
73
+
74
+ init();
75
+
76
+ if ( location.href.indexOf("status_ids[]") > 0 ) {
77
+ $(".js-nested-filters-region").toggle();
78
+ var text = $('.filter-label').text();
79
+ $('.filter-label').text(text == "Show Filter" ? "Hide Filter" : "Show Filter");
80
+ $('.js-clear-filters').show();
81
+ }
82
+ else {
83
+ $(".filter-active").prop('checked', true);
84
+ }
85
+
86
+ $(".js-title-region").click(function() {
87
+ var event_block = $($(this).parent());
88
+ if ( event_block.hasClass('expanded') ) {
89
+ event_block.removeClass('expanded').addClass('collapsed');
90
+ event_block.find(".js-content-body").slideUp( "slow" );
91
+ }
92
+ else {
93
+ $(".js-results-region").find(".expanded").removeClass("expanded");
94
+ $(".js-content-body:visible").slideUp( "slow" );
95
+ event_block.removeClass('collapsed').addClass('expanded');
96
+ event_block.find(".js-content-body").slideDown( "slow" );
97
+ }
98
+ });
99
+
100
+ $(".js-cancel-event-button").click(function(e) {
101
+ e.preventDefault();
102
+ var id = $(this).data('sch-id');
103
+ var time = $.trim($(this).parents().eq(2).find(".time").html());
104
+ var name = $.trim($(this).parents().eq(2).find(".user-name").html());
105
+ var schedule_name = $.trim($(this).parents().eq(2).find(".schedule-name").html());
106
+ var auth_token = $('meta[name=csrf-token]').attr('content');
107
+ if (window.location.pathname == "/") {
108
+ var action_name = '/schedules/' + id + '/cancel';
109
+ }
110
+ else {
111
+ var action_name = window.location.pathname + "/" + id + '/cancel';
112
+ }
113
+ var template = '<div id="popup-region"><div class="popup-overlay"><div class="close-overlay js-close"></div><div class="popup"><form class="schedule_cancel_form" method="post" novalidate="novalidate" remote="true" action="'+ action_name +'"><div class="popup-content"><input type="hidden" name="authenticity_token" value="'+ auth_token +'"><div class="text-center"><h2 class="mbm">Cancel Event</h2><div class="schedule-title">'+ schedule_name +'</div><div><strong class="scheduled-user">'+ name +'</strong></div><div class="mbm schedule-timings">'+ time +'</div></div><div class="mbm">Please confirm that you would like to cancel this event. A cancellation email will also go out to the invitee.</div><textarea class="mbm js-cancel-reason" maxlength="255" name="schedule[cancel_reason]" placeholder="Add an optional cancellation message."></textarea></div><div class="popup-buttons"><div class="col1of2"><button type="submit" class="js-submit-cancel-event" href="">Cancel Event</button></div><div class="col1of2"><button type="reset" class="hollow js-undo-cancel-event" href="">Nevermind</button></div></div></form></div></div></div>';
114
+ $("#popup-region").append(template);
115
+ cancel_event_bind();
116
+ });
117
+
118
+ $(".js-filters-toggle").click(function() {
119
+ $(".js-nested-filters-region").toggle();
120
+ var text = $('.filter-label').text();
121
+ $('.filter-label').text(text == "Show Filter" ? "Hide Filter" : "Show Filter");
122
+ });
123
+
124
+ $(".events-tab, .js-close").click(function() {
125
+ $(".event-options").toggle();
126
+ });
127
+
128
+ $(".js-apply").click(function() {
129
+ update_params(true);
130
+ });
131
+
132
+ $(".js-reset-filters, .js-clear-filters").click(function() {
133
+ var url = location.protocol + '//' + location.host + location.pathname;
134
+ location.replace(url);
135
+ });
136
+
137
+ $('.js-daterangepicker-toggle').daterangepicker({
138
+ locale: {
139
+ format: 'YYYY-MM-DD'
140
+ }
141
+ });
142
+
143
+ $('.js-daterangepicker-toggle').on('hide.daterangepicker', function(ev, picker) {
144
+ if ( $('input[name="daterangepicker_period"]').val() != "") {
145
+ update_params(false);
146
+ }
147
+ });
148
+
149
+ });
@@ -0,0 +1,1674 @@
1
+ /**
2
+ * @version: 2.1.24
3
+ * @author: Dan Grossman http://www.dangrossman.info/
4
+ * @copyright: Copyright (c) 2012-2016 Dan Grossman. All rights reserved.
5
+ * @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
6
+ * @website: https://www.improvely.com/
7
+ */
8
+ // Follow the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js
9
+ (function (root, factory) {
10
+ if (typeof define === 'function' && define.amd) {
11
+ // AMD. Make globaly available as well
12
+ define(['moment', 'jquery'], function (moment, jquery) {
13
+ return (root.daterangepicker = factory(moment, jquery));
14
+ });
15
+ } else if (typeof module === 'object' && module.exports) {
16
+ // Node / Browserify
17
+ //isomorphic issue
18
+ var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined;
19
+ if (!jQuery) {
20
+ jQuery = require('jquery');
21
+ if (!jQuery.fn) jQuery.fn = {};
22
+ }
23
+ module.exports = factory(require('moment'), jQuery);
24
+ } else {
25
+ // Browser globals
26
+ root.daterangepicker = factory(root.moment, root.jQuery);
27
+ }
28
+ }(this, function(moment, $) {
29
+ var DateRangePicker = function(element, options, cb) {
30
+
31
+ //default settings for options
32
+ this.parentEl = 'body';
33
+ this.element = $(element);
34
+ this.startDate = moment().startOf('day');
35
+ this.endDate = moment().endOf('day');
36
+ this.minDate = false;
37
+ this.maxDate = false;
38
+ this.dateLimit = false;
39
+ this.autoApply = false;
40
+ this.singleDatePicker = false;
41
+ this.showDropdowns = false;
42
+ this.showWeekNumbers = false;
43
+ this.showISOWeekNumbers = false;
44
+ this.showCustomRangeLabel = true;
45
+ this.timePicker = false;
46
+ this.timePicker24Hour = false;
47
+ this.timePickerIncrement = 1;
48
+ this.timePickerSeconds = false;
49
+ this.linkedCalendars = true;
50
+ this.autoUpdateInput = true;
51
+ this.alwaysShowCalendars = false;
52
+ this.ranges = {};
53
+
54
+ this.opens = 'left';
55
+ if (this.element.hasClass('pull-right'))
56
+ this.opens = 'left';
57
+
58
+ this.drops = 'down';
59
+ if (this.element.hasClass('dropup'))
60
+ this.drops = 'up';
61
+
62
+ this.buttonClasses = 'btn btn-sm';
63
+ this.applyClass = 'btn-success';
64
+ this.cancelClass = 'hollow';
65
+
66
+ this.locale = {
67
+ direction: 'ltr',
68
+ format: 'MM/DD/YYYY',
69
+ separator: ' - ',
70
+ applyLabel: 'Apply',
71
+ cancelLabel: 'Cancel',
72
+ weekLabel: 'W',
73
+ customRangeLabel: 'Custom Range',
74
+ daysOfWeek: moment.weekdaysMin(),
75
+ monthNames: moment.monthsShort(),
76
+ firstDay: moment.localeData().firstDayOfWeek()
77
+ };
78
+
79
+ this.callback = function() { };
80
+
81
+ //some state information
82
+ this.isShowing = false;
83
+ this.leftCalendar = {};
84
+ this.rightCalendar = {};
85
+
86
+ //custom options from user
87
+ if (typeof options !== 'object' || options === null)
88
+ options = {};
89
+
90
+ //allow setting options with data attributes
91
+ //data-api options will be overwritten with custom javascript options
92
+ options = $.extend(this.element.data(), options);
93
+
94
+ //html template for the picker UI
95
+ if (typeof options.template !== 'string' && !(options.template instanceof $))
96
+ options.template = '<div class="daterangepicker dropdown-menu">' +
97
+ '<div class="bookmarks">' +
98
+ '<ul>' +
99
+ '<li class="bml" data-period="past">All Past</li>' +
100
+ '<li class="active bml" data-period="upcoming">All Upcoming</li>' +
101
+ '<li class="bml" data-period="today">Today</li>' +
102
+ '<li class="bml" data-period="this_week">This Week</li>' +
103
+ '<li class="bml" data-period="this_month">This Month</li>' +
104
+ '</ul>' +
105
+ '</div>' +
106
+ '<div class="row">' +
107
+ '<input class="input-mini form-control" type="text" name="daterangepicker_period" value="" style="display:none;"/>' +
108
+ '<div class="calendar left">' +
109
+ '<div class="daterangepicker_input" style="display:none;">' +
110
+ '<input class="input-mini form-control" type="text" name="daterangepicker_start" value="" />' +
111
+ '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
112
+ '<div class="calendar-time">' +
113
+ '<div></div>' +
114
+ '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
115
+ '</div>' +
116
+ '</div>' +
117
+ '<div class="calendar-table"></div>' +
118
+ '</div>' +
119
+ '<div class="calendar right">' +
120
+ '<div class="daterangepicker_input" style="display:none;">' +
121
+ '<input class="input-mini form-control" type="text" name="daterangepicker_end" value="" />' +
122
+ '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
123
+ '<div class="calendar-time">' +
124
+ '<div></div>' +
125
+ '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
126
+ '</div>' +
127
+ '</div>' +
128
+ '<div class="calendar-table"></div>' +
129
+ '</div>' +
130
+ '</div>' +
131
+ '<div class="ranges">' +
132
+ '<div class="range-inputs">' +
133
+ '<button class="applyBtn" disabled="disabled" type="button"></button> ' +
134
+ '<button class="cancelBtn" type="button"></button>' +
135
+ '</div>' +
136
+ '</div>' +
137
+ '</div>';
138
+
139
+ this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
140
+ this.container = $(options.template).appendTo(this.parentEl);
141
+
142
+ //
143
+ // handle all the possible options overriding defaults
144
+ //
145
+
146
+ if (typeof options.locale === 'object') {
147
+
148
+ if (typeof options.locale.direction === 'string')
149
+ this.locale.direction = options.locale.direction;
150
+
151
+ if (typeof options.locale.format === 'string')
152
+ this.locale.format = options.locale.format;
153
+
154
+ if (typeof options.locale.separator === 'string')
155
+ this.locale.separator = options.locale.separator;
156
+
157
+ if (typeof options.locale.daysOfWeek === 'object')
158
+ this.locale.daysOfWeek = options.locale.daysOfWeek.slice();
159
+
160
+ if (typeof options.locale.monthNames === 'object')
161
+ this.locale.monthNames = options.locale.monthNames.slice();
162
+
163
+ if (typeof options.locale.firstDay === 'number')
164
+ this.locale.firstDay = options.locale.firstDay;
165
+
166
+ if (typeof options.locale.applyLabel === 'string')
167
+ this.locale.applyLabel = options.locale.applyLabel;
168
+
169
+ if (typeof options.locale.cancelLabel === 'string')
170
+ this.locale.cancelLabel = options.locale.cancelLabel;
171
+
172
+ if (typeof options.locale.weekLabel === 'string')
173
+ this.locale.weekLabel = options.locale.weekLabel;
174
+
175
+ if (typeof options.locale.customRangeLabel === 'string')
176
+ this.locale.customRangeLabel = options.locale.customRangeLabel;
177
+
178
+ }
179
+ this.container.addClass(this.locale.direction);
180
+
181
+ if (typeof options.startDate === 'string')
182
+ this.startDate = moment(options.startDate, this.locale.format);
183
+
184
+ if (typeof options.endDate === 'string')
185
+ this.endDate = moment(options.endDate, this.locale.format);
186
+
187
+ if (typeof options.minDate === 'string')
188
+ this.minDate = moment(options.minDate, this.locale.format);
189
+
190
+ if (typeof options.maxDate === 'string')
191
+ this.maxDate = moment(options.maxDate, this.locale.format);
192
+
193
+ if (typeof options.startDate === 'object')
194
+ this.startDate = moment(options.startDate);
195
+
196
+ if (typeof options.endDate === 'object')
197
+ this.endDate = moment(options.endDate);
198
+
199
+ if (typeof options.minDate === 'object')
200
+ this.minDate = moment(options.minDate);
201
+
202
+ if (typeof options.maxDate === 'object')
203
+ this.maxDate = moment(options.maxDate);
204
+
205
+ // sanity check for bad options
206
+ if (this.minDate && this.startDate.isBefore(this.minDate))
207
+ this.startDate = this.minDate.clone();
208
+
209
+ // sanity check for bad options
210
+ if (this.maxDate && this.endDate.isAfter(this.maxDate))
211
+ this.endDate = this.maxDate.clone();
212
+
213
+ if (typeof options.applyClass === 'string')
214
+ this.applyClass = options.applyClass;
215
+
216
+ if (typeof options.cancelClass === 'string')
217
+ this.cancelClass = options.cancelClass;
218
+
219
+ if (typeof options.dateLimit === 'object')
220
+ this.dateLimit = options.dateLimit;
221
+
222
+ if (typeof options.opens === 'string')
223
+ this.opens = options.opens;
224
+
225
+ if (typeof options.drops === 'string')
226
+ this.drops = options.drops;
227
+
228
+ if (typeof options.showWeekNumbers === 'boolean')
229
+ this.showWeekNumbers = options.showWeekNumbers;
230
+
231
+ if (typeof options.showISOWeekNumbers === 'boolean')
232
+ this.showISOWeekNumbers = options.showISOWeekNumbers;
233
+
234
+ if (typeof options.buttonClasses === 'string')
235
+ this.buttonClasses = options.buttonClasses;
236
+
237
+ if (typeof options.buttonClasses === 'object')
238
+ this.buttonClasses = options.buttonClasses.join(' ');
239
+
240
+ if (typeof options.showDropdowns === 'boolean')
241
+ this.showDropdowns = options.showDropdowns;
242
+
243
+ if (typeof options.showCustomRangeLabel === 'boolean')
244
+ this.showCustomRangeLabel = options.showCustomRangeLabel;
245
+
246
+ if (typeof options.singleDatePicker === 'boolean') {
247
+ this.singleDatePicker = options.singleDatePicker;
248
+ if (this.singleDatePicker)
249
+ this.endDate = this.startDate.clone();
250
+ }
251
+
252
+ if (typeof options.timePicker === 'boolean')
253
+ this.timePicker = options.timePicker;
254
+
255
+ if (typeof options.timePickerSeconds === 'boolean')
256
+ this.timePickerSeconds = options.timePickerSeconds;
257
+
258
+ if (typeof options.timePickerIncrement === 'number')
259
+ this.timePickerIncrement = options.timePickerIncrement;
260
+
261
+ if (typeof options.timePicker24Hour === 'boolean')
262
+ this.timePicker24Hour = options.timePicker24Hour;
263
+
264
+ if (typeof options.autoApply === 'boolean')
265
+ this.autoApply = options.autoApply;
266
+
267
+ if (typeof options.autoUpdateInput === 'boolean')
268
+ this.autoUpdateInput = options.autoUpdateInput;
269
+
270
+ if (typeof options.linkedCalendars === 'boolean')
271
+ this.linkedCalendars = options.linkedCalendars;
272
+
273
+ if (typeof options.isInvalidDate === 'function')
274
+ this.isInvalidDate = options.isInvalidDate;
275
+
276
+ if (typeof options.isCustomDate === 'function')
277
+ this.isCustomDate = options.isCustomDate;
278
+
279
+ if (typeof options.alwaysShowCalendars === 'boolean')
280
+ this.alwaysShowCalendars = options.alwaysShowCalendars;
281
+
282
+ // update day names order to firstDay
283
+ if (this.locale.firstDay != 0) {
284
+ var iterator = this.locale.firstDay;
285
+ while (iterator > 0) {
286
+ this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
287
+ iterator--;
288
+ }
289
+ }
290
+
291
+ var start, end, range;
292
+
293
+ //if no start/end dates set, check if an input element contains initial values
294
+ if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
295
+ if ($(this.element).is('input[type=text]')) {
296
+ var val = $(this.element).val(),
297
+ split = val.split(this.locale.separator);
298
+
299
+ start = end = null;
300
+
301
+ if (split.length == 2) {
302
+ start = moment(split[0], this.locale.format);
303
+ end = moment(split[1], this.locale.format);
304
+ } else if (this.singleDatePicker && val !== "") {
305
+ start = moment(val, this.locale.format);
306
+ end = moment(val, this.locale.format);
307
+ }
308
+ if (start !== null && end !== null) {
309
+ this.setStartDate(start);
310
+ this.setEndDate(end);
311
+ }
312
+ }
313
+ }
314
+
315
+ if (typeof options.ranges === 'object') {
316
+ for (range in options.ranges) {
317
+
318
+ if (typeof options.ranges[range][0] === 'string')
319
+ start = moment(options.ranges[range][0], this.locale.format);
320
+ else
321
+ start = moment(options.ranges[range][0]);
322
+
323
+ if (typeof options.ranges[range][1] === 'string')
324
+ end = moment(options.ranges[range][1], this.locale.format);
325
+ else
326
+ end = moment(options.ranges[range][1]);
327
+
328
+ // If the start or end date exceed those allowed by the minDate or dateLimit
329
+ // options, shorten the range to the allowable period.
330
+ if (this.minDate && start.isBefore(this.minDate))
331
+ start = this.minDate.clone();
332
+
333
+ var maxDate = this.maxDate;
334
+ if (this.dateLimit && maxDate && start.clone().add(this.dateLimit).isAfter(maxDate))
335
+ maxDate = start.clone().add(this.dateLimit);
336
+ if (maxDate && end.isAfter(maxDate))
337
+ end = maxDate.clone();
338
+
339
+ // If the end of the range is before the minimum or the start of the range is
340
+ // after the maximum, don't display this range option at all.
341
+ if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day'))
342
+ || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day')))
343
+ continue;
344
+
345
+ //Support unicode chars in the range names.
346
+ var elem = document.createElement('textarea');
347
+ elem.innerHTML = range;
348
+ var rangeHtml = elem.value;
349
+
350
+ this.ranges[rangeHtml] = [start, end];
351
+ }
352
+
353
+ var list = '<ul>';
354
+ for (range in this.ranges) {
355
+ list += '<li data-range-key="' + range + '">' + range + '</li>';
356
+ }
357
+ if (this.showCustomRangeLabel) {
358
+ list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + '</li>';
359
+ }
360
+ list += '</ul>';
361
+ this.container.find('.ranges').prepend(list);
362
+ }
363
+
364
+ if (typeof cb === 'function') {
365
+ this.callback = cb;
366
+ }
367
+
368
+ if (!this.timePicker) {
369
+ this.startDate = this.startDate.startOf('day');
370
+ this.endDate = this.endDate.endOf('day');
371
+ this.container.find('.calendar-time').hide();
372
+ }
373
+
374
+ //can't be used together for now
375
+ if (this.timePicker && this.autoApply)
376
+ this.autoApply = false;
377
+
378
+ if (this.autoApply && typeof options.ranges !== 'object') {
379
+ this.container.find('.ranges').hide();
380
+ } else if (this.autoApply) {
381
+ this.container.find('.applyBtn, .cancelBtn').addClass('hide');
382
+ }
383
+
384
+ if (this.singleDatePicker) {
385
+ this.container.addClass('single');
386
+ this.container.find('.calendar.left').addClass('single');
387
+ this.container.find('.calendar.left').show();
388
+ this.container.find('.calendar.right').hide();
389
+ this.container.find('.daterangepicker_input input, .daterangepicker_input > i').hide();
390
+ if (this.timePicker) {
391
+ this.container.find('.ranges ul').hide();
392
+ } else {
393
+ this.container.find('.ranges').hide();
394
+ }
395
+ }
396
+
397
+ if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) {
398
+ this.container.addClass('show-calendar');
399
+ }
400
+
401
+ this.container.addClass('opens' + this.opens);
402
+
403
+ //swap the position of the predefined ranges if opens right
404
+ if (typeof options.ranges !== 'undefined' && this.opens == 'right') {
405
+ this.container.find('.ranges').prependTo( this.container.find('.calendar.left').parent() );
406
+ }
407
+
408
+ //apply CSS classes and labels to buttons
409
+ this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses);
410
+ if (this.applyClass.length)
411
+ this.container.find('.applyBtn').addClass(this.applyClass);
412
+ if (this.cancelClass.length)
413
+ this.container.find('.cancelBtn').addClass(this.cancelClass);
414
+ this.container.find('.applyBtn').html(this.locale.applyLabel);
415
+ this.container.find('.cancelBtn').html(this.locale.cancelLabel);
416
+
417
+ //
418
+ // event listeners
419
+ //
420
+
421
+ this.container.find('.bookmarks')
422
+ .on('click.daterangepicker', '.bml', $.proxy(this.clickBml, this))
423
+
424
+ this.container.find('.calendar')
425
+ .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
426
+ .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
427
+ .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
428
+ .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
429
+ .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))
430
+ .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
431
+ .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
432
+ .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this))
433
+ .on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this))
434
+ .on('focus.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsFocused, this))
435
+ .on('blur.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsBlurred, this))
436
+ .on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this));
437
+
438
+ this.container.find('.ranges')
439
+ .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
440
+ .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
441
+ .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
442
+ .on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this))
443
+ .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));
444
+
445
+ if (this.element.is('input') || this.element.is('button')) {
446
+ this.element.on({
447
+ 'click.daterangepicker': $.proxy(this.show, this),
448
+ 'focus.daterangepicker': $.proxy(this.show, this),
449
+ 'keyup.daterangepicker': $.proxy(this.elementChanged, this),
450
+ 'keydown.daterangepicker': $.proxy(this.keydown, this)
451
+ });
452
+ } else {
453
+ this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
454
+ }
455
+
456
+ //
457
+ // if attached to a text input, set the initial value
458
+ //
459
+
460
+ if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
461
+ this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
462
+ this.element.trigger('change');
463
+ } else if (this.element.is('input') && this.autoUpdateInput) {
464
+ this.element.val(this.startDate.format(this.locale.format));
465
+ this.element.trigger('change');
466
+ }
467
+
468
+ };
469
+
470
+ DateRangePicker.prototype = {
471
+
472
+ constructor: DateRangePicker,
473
+
474
+ setStartDate: function(startDate) {
475
+ if (typeof startDate === 'string')
476
+ this.startDate = moment(startDate, this.locale.format);
477
+
478
+ if (typeof startDate === 'object')
479
+ this.startDate = moment(startDate);
480
+
481
+ if (!this.timePicker)
482
+ this.startDate = this.startDate.startOf('day');
483
+
484
+ if (this.timePicker && this.timePickerIncrement)
485
+ this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
486
+
487
+ if (this.minDate && this.startDate.isBefore(this.minDate)) {
488
+ this.startDate = this.minDate;
489
+ if (this.timePicker && this.timePickerIncrement)
490
+ this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
491
+ }
492
+
493
+ if (this.maxDate && this.startDate.isAfter(this.maxDate)) {
494
+ this.startDate = this.maxDate;
495
+ if (this.timePicker && this.timePickerIncrement)
496
+ this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
497
+ }
498
+
499
+ if (!this.isShowing)
500
+ this.updateElement();
501
+
502
+ this.updateMonthsInView();
503
+ },
504
+
505
+ setEndDate: function(endDate) {
506
+ if (typeof endDate === 'string')
507
+ this.endDate = moment(endDate, this.locale.format);
508
+
509
+ if (typeof endDate === 'object')
510
+ this.endDate = moment(endDate);
511
+
512
+ if (!this.timePicker)
513
+ this.endDate = this.endDate.endOf('day');
514
+
515
+ if (this.timePicker && this.timePickerIncrement)
516
+ this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
517
+
518
+ if (this.endDate.isBefore(this.startDate))
519
+ this.endDate = this.startDate.clone();
520
+
521
+ if (this.maxDate && this.endDate.isAfter(this.maxDate))
522
+ this.endDate = this.maxDate;
523
+
524
+ if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate))
525
+ this.endDate = this.startDate.clone().add(this.dateLimit);
526
+
527
+ this.previousRightTime = this.endDate.clone();
528
+
529
+ if (!this.isShowing)
530
+ this.updateElement();
531
+
532
+ this.updateMonthsInView();
533
+ },
534
+
535
+ isInvalidDate: function() {
536
+ return false;
537
+ },
538
+
539
+ isCustomDate: function() {
540
+ return false;
541
+ },
542
+
543
+ updateView: function() {
544
+ if (this.timePicker) {
545
+ this.renderTimePicker('left');
546
+ this.renderTimePicker('right');
547
+ if (!this.endDate) {
548
+ this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled');
549
+ } else {
550
+ this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled');
551
+ }
552
+ }
553
+ if (this.endDate) {
554
+ this.container.find('input[name="daterangepicker_end"]').removeClass('active');
555
+ this.container.find('input[name="daterangepicker_start"]').addClass('active');
556
+ } else {
557
+ this.container.find('input[name="daterangepicker_end"]').addClass('active');
558
+ this.container.find('input[name="daterangepicker_start"]').removeClass('active');
559
+ }
560
+ this.updateMonthsInView();
561
+ this.updateCalendars();
562
+ this.updateFormInputs();
563
+ },
564
+
565
+ updateMonthsInView: function() {
566
+ if (this.endDate) {
567
+
568
+ //if both dates are visible already, do nothing
569
+ if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month &&
570
+ (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
571
+ &&
572
+ (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
573
+ ) {
574
+ return;
575
+ }
576
+
577
+ this.leftCalendar.month = this.startDate.clone().date(2);
578
+ if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) {
579
+ this.rightCalendar.month = this.endDate.clone().date(2);
580
+ } else {
581
+ this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
582
+ }
583
+
584
+ } else {
585
+ if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) {
586
+ this.leftCalendar.month = this.startDate.clone().date(2);
587
+ this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
588
+ }
589
+ }
590
+ if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) {
591
+ this.rightCalendar.month = this.maxDate.clone().date(2);
592
+ this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month');
593
+ }
594
+ },
595
+
596
+ updateCalendars: function() {
597
+
598
+ if (this.timePicker) {
599
+ var hour, minute, second;
600
+ if (this.endDate) {
601
+ hour = parseInt(this.container.find('.left .hourselect').val(), 10);
602
+ minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
603
+ second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
604
+ if (!this.timePicker24Hour) {
605
+ var ampm = this.container.find('.left .ampmselect').val();
606
+ if (ampm === 'PM' && hour < 12)
607
+ hour += 12;
608
+ if (ampm === 'AM' && hour === 12)
609
+ hour = 0;
610
+ }
611
+ } else {
612
+ hour = parseInt(this.container.find('.right .hourselect').val(), 10);
613
+ minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
614
+ second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
615
+ if (!this.timePicker24Hour) {
616
+ var ampm = this.container.find('.right .ampmselect').val();
617
+ if (ampm === 'PM' && hour < 12)
618
+ hour += 12;
619
+ if (ampm === 'AM' && hour === 12)
620
+ hour = 0;
621
+ }
622
+ }
623
+ this.leftCalendar.month.hour(hour).minute(minute).second(second);
624
+ this.rightCalendar.month.hour(hour).minute(minute).second(second);
625
+ }
626
+
627
+ this.renderCalendar('left');
628
+ this.renderCalendar('right');
629
+
630
+ //highlight any predefined range matching the current start and end dates
631
+ this.container.find('.ranges li').removeClass('active');
632
+ if (this.endDate == null) return;
633
+
634
+ this.calculateChosenLabel();
635
+ },
636
+
637
+ renderCalendar: function(side) {
638
+
639
+ //
640
+ // Build the matrix of dates that will populate the calendar
641
+ //
642
+
643
+ var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar;
644
+ var month = calendar.month.month();
645
+ var year = calendar.month.year();
646
+ var hour = calendar.month.hour();
647
+ var minute = calendar.month.minute();
648
+ var second = calendar.month.second();
649
+ var daysInMonth = moment([year, month]).daysInMonth();
650
+ var firstDay = moment([year, month, 1]);
651
+ var lastDay = moment([year, month, daysInMonth]);
652
+ var lastMonth = moment(firstDay).subtract(1, 'month').month();
653
+ var lastYear = moment(firstDay).subtract(1, 'month').year();
654
+ var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
655
+ var dayOfWeek = firstDay.day();
656
+
657
+ //initialize a 6 rows x 7 columns array for the calendar
658
+ var calendar = [];
659
+ calendar.firstDay = firstDay;
660
+ calendar.lastDay = lastDay;
661
+
662
+ for (var i = 0; i < 6; i++) {
663
+ calendar[i] = [];
664
+ }
665
+
666
+ //populate the calendar with date objects
667
+ var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;
668
+ if (startDay > daysInLastMonth)
669
+ startDay -= 7;
670
+
671
+ if (dayOfWeek == this.locale.firstDay)
672
+ startDay = daysInLastMonth - 6;
673
+
674
+ var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]);
675
+
676
+ var col, row;
677
+ for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) {
678
+ if (i > 0 && col % 7 === 0) {
679
+ col = 0;
680
+ row++;
681
+ }
682
+ calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second);
683
+ curDate.hour(12);
684
+
685
+ if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') {
686
+ calendar[row][col] = this.minDate.clone();
687
+ }
688
+
689
+ if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') {
690
+ calendar[row][col] = this.maxDate.clone();
691
+ }
692
+
693
+ }
694
+
695
+ //make the calendar object available to hoverDate/clickDate
696
+ if (side == 'left') {
697
+ this.leftCalendar.calendar = calendar;
698
+ } else {
699
+ this.rightCalendar.calendar = calendar;
700
+ }
701
+
702
+ //
703
+ // Display the calendar
704
+ //
705
+
706
+ var minDate = side == 'left' ? this.minDate : this.startDate;
707
+ var maxDate = this.maxDate;
708
+ var selected = side == 'left' ? this.startDate : this.endDate;
709
+ var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left icon-angle-left', right: 'chevron-right icon-angle-right'} : {left: 'chevron-right icon-angle-left', right: 'chevron-left icon-angle-right'};
710
+
711
+ var html = '<table class="table-condensed">';
712
+ html += '<thead>';
713
+ html += '<tr>';
714
+
715
+ // add empty cell for week number
716
+ if (this.showWeekNumbers || this.showISOWeekNumbers)
717
+ html += '<th></th>';
718
+
719
+ if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) {
720
+ html += '<th class="prev available"><i class="fa fa-' + arrow.left + ' glyphicon glyphicon-' + arrow.left + '"></i></th>';
721
+ } else {
722
+ html += '<th></th>';
723
+ }
724
+
725
+ var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");
726
+
727
+ if (this.showDropdowns) {
728
+ var currentMonth = calendar[1][1].month();
729
+ var currentYear = calendar[1][1].year();
730
+ var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);
731
+ var minYear = (minDate && minDate.year()) || (currentYear - 50);
732
+ var inMinYear = currentYear == minYear;
733
+ var inMaxYear = currentYear == maxYear;
734
+
735
+ var monthHtml = '<select class="monthselect">';
736
+ for (var m = 0; m < 12; m++) {
737
+ if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
738
+ monthHtml += "<option value='" + m + "'" +
739
+ (m === currentMonth ? " selected='selected'" : "") +
740
+ ">" + this.locale.monthNames[m] + "</option>";
741
+ } else {
742
+ monthHtml += "<option value='" + m + "'" +
743
+ (m === currentMonth ? " selected='selected'" : "") +
744
+ " disabled='disabled'>" + this.locale.monthNames[m] + "</option>";
745
+ }
746
+ }
747
+ monthHtml += "</select>";
748
+
749
+ var yearHtml = '<select class="yearselect">';
750
+ for (var y = minYear; y <= maxYear; y++) {
751
+ yearHtml += '<option value="' + y + '"' +
752
+ (y === currentYear ? ' selected="selected"' : '') +
753
+ '>' + y + '</option>';
754
+ }
755
+ yearHtml += '</select>';
756
+
757
+ dateHtml = monthHtml + yearHtml;
758
+ }
759
+
760
+ html += '<th colspan="5" class="month">' + dateHtml + '</th>';
761
+ if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) {
762
+ html += '<th class="next available"><i class="fa fa-' + arrow.right + ' glyphicon glyphicon-' + arrow.right + '"></i></th>';
763
+ } else {
764
+ html += '<th></th>';
765
+ }
766
+
767
+ html += '</tr>';
768
+ html += '<tr>';
769
+
770
+ // add week number label
771
+ if (this.showWeekNumbers || this.showISOWeekNumbers)
772
+ html += '<th class="week">' + this.locale.weekLabel + '</th>';
773
+
774
+ $.each(this.locale.daysOfWeek, function(index, dayOfWeek) {
775
+ html += '<th>' + dayOfWeek + '</th>';
776
+ });
777
+
778
+ html += '</tr>';
779
+ html += '</thead>';
780
+ html += '<tbody>';
781
+
782
+ //adjust maxDate to reflect the dateLimit setting in order to
783
+ //grey out end dates beyond the dateLimit
784
+ if (this.endDate == null && this.dateLimit) {
785
+ var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day');
786
+ if (!maxDate || maxLimit.isBefore(maxDate)) {
787
+ maxDate = maxLimit;
788
+ }
789
+ }
790
+
791
+ for (var row = 0; row < 6; row++) {
792
+ html += '<tr>';
793
+
794
+ // add week number
795
+ if (this.showWeekNumbers)
796
+ html += '<td class="week">' + calendar[row][0].week() + '</td>';
797
+ else if (this.showISOWeekNumbers)
798
+ html += '<td class="week">' + calendar[row][0].isoWeek() + '</td>';
799
+
800
+ for (var col = 0; col < 7; col++) {
801
+
802
+ var classes = [];
803
+
804
+ //highlight today's date
805
+ if (calendar[row][col].isSame(new Date(), "day"))
806
+ classes.push('today');
807
+
808
+ //highlight weekends
809
+ if (calendar[row][col].isoWeekday() > 5)
810
+ classes.push('weekend');
811
+
812
+ //grey out the dates in other months displayed at beginning and end of this calendar
813
+ if (calendar[row][col].month() != calendar[1][1].month())
814
+ classes.push('off');
815
+
816
+ //don't allow selection of dates before the minimum date
817
+ if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day'))
818
+ classes.push('off', 'disabled');
819
+
820
+ //don't allow selection of dates after the maximum date
821
+ if (maxDate && calendar[row][col].isAfter(maxDate, 'day'))
822
+ classes.push('off', 'disabled');
823
+
824
+ //don't allow selection of date if a custom function decides it's invalid
825
+ if (this.isInvalidDate(calendar[row][col]))
826
+ classes.push('off', 'disabled');
827
+
828
+ //highlight the currently selected start date
829
+ if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD'))
830
+ classes.push('active', 'start-date');
831
+
832
+ //highlight the currently selected end date
833
+ if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD'))
834
+ classes.push('active', 'end-date');
835
+
836
+ //highlight dates in-between the selected dates
837
+ if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate)
838
+ classes.push('in-range');
839
+
840
+ //apply custom classes for this date
841
+ var isCustom = this.isCustomDate(calendar[row][col]);
842
+ if (isCustom !== false) {
843
+ if (typeof isCustom === 'string')
844
+ classes.push(isCustom);
845
+ else
846
+ Array.prototype.push.apply(classes, isCustom);
847
+ }
848
+
849
+ var cname = '', disabled = false;
850
+ for (var i = 0; i < classes.length; i++) {
851
+ cname += classes[i] + ' ';
852
+ if (classes[i] == 'disabled')
853
+ disabled = true;
854
+ }
855
+ if (!disabled)
856
+ cname += 'available';
857
+
858
+ html += '<td class="' + cname.replace(/^\s+|\s+$/g, '') + '" data-title="' + 'r' + row + 'c' + col + '">' + calendar[row][col].date() + '</td>';
859
+
860
+ }
861
+ html += '</tr>';
862
+ }
863
+
864
+ html += '</tbody>';
865
+ html += '</table>';
866
+
867
+ this.container.find('.calendar.' + side + ' .calendar-table').html(html);
868
+
869
+ },
870
+
871
+ renderTimePicker: function(side) {
872
+
873
+ // Don't bother updating the time picker if it's currently disabled
874
+ // because an end date hasn't been clicked yet
875
+ if (side == 'right' && !this.endDate) return;
876
+
877
+ var html, selected, minDate, maxDate = this.maxDate;
878
+
879
+ if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate)))
880
+ maxDate = this.startDate.clone().add(this.dateLimit);
881
+
882
+ if (side == 'left') {
883
+ selected = this.startDate.clone();
884
+ minDate = this.minDate;
885
+ } else if (side == 'right') {
886
+ selected = this.endDate.clone();
887
+ minDate = this.startDate;
888
+
889
+ //Preserve the time already selected
890
+ var timeSelector = this.container.find('.calendar.right .calendar-time div');
891
+ if (!this.endDate && timeSelector.html() != '') {
892
+
893
+ selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour());
894
+ selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute());
895
+ selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second());
896
+
897
+ if (!this.timePicker24Hour) {
898
+ var ampm = timeSelector.find('.ampmselect option:selected').val();
899
+ if (ampm === 'PM' && selected.hour() < 12)
900
+ selected.hour(selected.hour() + 12);
901
+ if (ampm === 'AM' && selected.hour() === 12)
902
+ selected.hour(0);
903
+ }
904
+
905
+ }
906
+
907
+ if (selected.isBefore(this.startDate))
908
+ selected = this.startDate.clone();
909
+
910
+ if (maxDate && selected.isAfter(maxDate))
911
+ selected = maxDate.clone();
912
+
913
+ }
914
+
915
+ //
916
+ // hours
917
+ //
918
+
919
+ html = '<select class="hourselect">';
920
+
921
+ var start = this.timePicker24Hour ? 0 : 1;
922
+ var end = this.timePicker24Hour ? 23 : 12;
923
+
924
+ for (var i = start; i <= end; i++) {
925
+ var i_in_24 = i;
926
+ if (!this.timePicker24Hour)
927
+ i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i);
928
+
929
+ var time = selected.clone().hour(i_in_24);
930
+ var disabled = false;
931
+ if (minDate && time.minute(59).isBefore(minDate))
932
+ disabled = true;
933
+ if (maxDate && time.minute(0).isAfter(maxDate))
934
+ disabled = true;
935
+
936
+ if (i_in_24 == selected.hour() && !disabled) {
937
+ html += '<option value="' + i + '" selected="selected">' + i + '</option>';
938
+ } else if (disabled) {
939
+ html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>';
940
+ } else {
941
+ html += '<option value="' + i + '">' + i + '</option>';
942
+ }
943
+ }
944
+
945
+ html += '</select> ';
946
+
947
+ //
948
+ // minutes
949
+ //
950
+
951
+ html += ': <select class="minuteselect">';
952
+
953
+ for (var i = 0; i < 60; i += this.timePickerIncrement) {
954
+ var padded = i < 10 ? '0' + i : i;
955
+ var time = selected.clone().minute(i);
956
+
957
+ var disabled = false;
958
+ if (minDate && time.second(59).isBefore(minDate))
959
+ disabled = true;
960
+ if (maxDate && time.second(0).isAfter(maxDate))
961
+ disabled = true;
962
+
963
+ if (selected.minute() == i && !disabled) {
964
+ html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
965
+ } else if (disabled) {
966
+ html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
967
+ } else {
968
+ html += '<option value="' + i + '">' + padded + '</option>';
969
+ }
970
+ }
971
+
972
+ html += '</select> ';
973
+
974
+ //
975
+ // seconds
976
+ //
977
+
978
+ if (this.timePickerSeconds) {
979
+ html += ': <select class="secondselect">';
980
+
981
+ for (var i = 0; i < 60; i++) {
982
+ var padded = i < 10 ? '0' + i : i;
983
+ var time = selected.clone().second(i);
984
+
985
+ var disabled = false;
986
+ if (minDate && time.isBefore(minDate))
987
+ disabled = true;
988
+ if (maxDate && time.isAfter(maxDate))
989
+ disabled = true;
990
+
991
+ if (selected.second() == i && !disabled) {
992
+ html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
993
+ } else if (disabled) {
994
+ html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
995
+ } else {
996
+ html += '<option value="' + i + '">' + padded + '</option>';
997
+ }
998
+ }
999
+
1000
+ html += '</select> ';
1001
+ }
1002
+
1003
+ //
1004
+ // AM/PM
1005
+ //
1006
+
1007
+ if (!this.timePicker24Hour) {
1008
+ html += '<select class="ampmselect">';
1009
+
1010
+ var am_html = '';
1011
+ var pm_html = '';
1012
+
1013
+ if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate))
1014
+ am_html = ' disabled="disabled" class="disabled"';
1015
+
1016
+ if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate))
1017
+ pm_html = ' disabled="disabled" class="disabled"';
1018
+
1019
+ if (selected.hour() >= 12) {
1020
+ html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>';
1021
+ } else {
1022
+ html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>';
1023
+ }
1024
+
1025
+ html += '</select>';
1026
+ }
1027
+
1028
+ this.container.find('.calendar.' + side + ' .calendar-time div').html(html);
1029
+
1030
+ },
1031
+
1032
+ updateFormInputs: function() {
1033
+
1034
+ //ignore mouse movements while an above-calendar text input has focus
1035
+ if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1036
+ return;
1037
+
1038
+ this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format));
1039
+ if (this.endDate)
1040
+ this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format));
1041
+
1042
+ if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) {
1043
+ this.container.find('button.applyBtn').removeAttr('disabled');
1044
+ } else {
1045
+ this.container.find('button.applyBtn').attr('disabled', 'disabled');
1046
+ }
1047
+
1048
+ },
1049
+
1050
+ move: function() {
1051
+ var parentOffset = { top: 0, left: 0 },
1052
+ containerTop;
1053
+ var parentRightEdge = $(window).width();
1054
+ if (!this.parentEl.is('body')) {
1055
+ parentOffset = {
1056
+ top: this.parentEl.offset().top - this.parentEl.scrollTop(),
1057
+ left: this.parentEl.offset().left - this.parentEl.scrollLeft()
1058
+ };
1059
+ parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;
1060
+ }
1061
+
1062
+ if (this.drops == 'up')
1063
+ containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
1064
+ else
1065
+ containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;
1066
+ this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup');
1067
+
1068
+ if (this.opens == 'left') {
1069
+ this.container.css({
1070
+ top: containerTop,
1071
+ right: parentRightEdge - this.element.offset().left - this.element.outerWidth(),
1072
+ left: 'auto'
1073
+ });
1074
+ if (this.container.offset().left < 0) {
1075
+ this.container.css({
1076
+ right: 'auto',
1077
+ left: 9
1078
+ });
1079
+ }
1080
+ } else if (this.opens == 'center') {
1081
+ this.container.css({
1082
+ top: containerTop,
1083
+ left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2
1084
+ - this.container.outerWidth() / 2,
1085
+ right: 'auto'
1086
+ });
1087
+ if (this.container.offset().left < 0) {
1088
+ this.container.css({
1089
+ right: 'auto',
1090
+ left: 9
1091
+ });
1092
+ }
1093
+ } else {
1094
+ this.container.css({
1095
+ top: containerTop,
1096
+ left: this.element.offset().left - parentOffset.left,
1097
+ right: 'auto'
1098
+ });
1099
+ if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
1100
+ this.container.css({
1101
+ left: 'auto',
1102
+ right: 0
1103
+ });
1104
+ }
1105
+ }
1106
+ },
1107
+
1108
+ show: function(e) {
1109
+ if (this.isShowing) return;
1110
+
1111
+ // Create a click proxy that is private to this instance of datepicker, for unbinding
1112
+ this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this);
1113
+
1114
+ // Bind global datepicker mousedown for hiding and
1115
+ $(document)
1116
+ .on('mousedown.daterangepicker', this._outsideClickProxy)
1117
+ // also support mobile devices
1118
+ .on('touchend.daterangepicker', this._outsideClickProxy)
1119
+ // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them
1120
+ .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)
1121
+ // and also close when focus changes to outside the picker (eg. tabbing between controls)
1122
+ .on('focusin.daterangepicker', this._outsideClickProxy);
1123
+
1124
+ // Reposition the picker if the window is resized while it's open
1125
+ $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this));
1126
+
1127
+ this.oldStartDate = this.startDate.clone();
1128
+ this.oldEndDate = this.endDate.clone();
1129
+ this.previousRightTime = this.endDate.clone();
1130
+
1131
+ this.updateView();
1132
+ this.container.show();
1133
+ this.move();
1134
+ this.element.trigger('show.daterangepicker', this);
1135
+ this.isShowing = true;
1136
+ },
1137
+
1138
+ hide: function(e) {
1139
+ if (!this.isShowing) return;
1140
+
1141
+ //incomplete date selection, revert to last values
1142
+ if (!this.endDate) {
1143
+ this.startDate = this.oldStartDate.clone();
1144
+ this.endDate = this.oldEndDate.clone();
1145
+ }
1146
+
1147
+ //if a new date range was selected, invoke the user callback function
1148
+ if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
1149
+ this.callback(this.startDate, this.endDate, this.chosenLabel);
1150
+
1151
+ //if picker is attached to a text input, update it
1152
+ this.updateElement();
1153
+
1154
+ $(document).off('.daterangepicker');
1155
+ $(window).off('.daterangepicker');
1156
+ this.container.hide();
1157
+ this.element.trigger('hide.daterangepicker', this);
1158
+ this.isShowing = false;
1159
+ },
1160
+
1161
+ toggle: function(e) {
1162
+ if (this.isShowing) {
1163
+ this.hide();
1164
+ } else {
1165
+ this.show();
1166
+ }
1167
+ },
1168
+
1169
+ outsideClick: function(e) {
1170
+ var target = $(e.target);
1171
+ // if the page is clicked anywhere except within the daterangerpicker/button
1172
+ // itself then call this.hide()
1173
+ if (
1174
+ // ie modal dialog fix
1175
+ e.type == "focusin" ||
1176
+ target.closest(this.element).length ||
1177
+ target.closest(this.container).length ||
1178
+ target.closest('.calendar-table').length
1179
+ ) return;
1180
+ this.hide();
1181
+ this.element.trigger('outsideClick.daterangepicker', this);
1182
+ },
1183
+
1184
+ showCalendars: function() {
1185
+ this.container.addClass('show-calendar');
1186
+ this.move();
1187
+ this.element.trigger('showCalendar.daterangepicker', this);
1188
+ },
1189
+
1190
+ hideCalendars: function() {
1191
+ this.container.removeClass('show-calendar');
1192
+ this.element.trigger('hideCalendar.daterangepicker', this);
1193
+ },
1194
+
1195
+ hoverRange: function(e) {
1196
+
1197
+ //ignore mouse movements while an above-calendar text input has focus
1198
+ if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1199
+ return;
1200
+
1201
+ var label = e.target.getAttribute('data-range-key');
1202
+
1203
+ if (label == this.locale.customRangeLabel) {
1204
+ this.updateView();
1205
+ } else {
1206
+ var dates = this.ranges[label];
1207
+ this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format));
1208
+ this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format));
1209
+ }
1210
+
1211
+ },
1212
+
1213
+ clickRange: function(e) {
1214
+ var label = e.target.getAttribute('data-range-key');
1215
+ this.chosenLabel = label;
1216
+ if (label == this.locale.customRangeLabel) {
1217
+ this.showCalendars();
1218
+ } else {
1219
+ var dates = this.ranges[label];
1220
+ this.startDate = dates[0];
1221
+ this.endDate = dates[1];
1222
+
1223
+ if (!this.timePicker) {
1224
+ this.startDate.startOf('day');
1225
+ this.endDate.endOf('day');
1226
+ }
1227
+
1228
+ if (!this.alwaysShowCalendars)
1229
+ this.hideCalendars();
1230
+ this.clickApply();
1231
+ }
1232
+ },
1233
+
1234
+ clickPrev: function(e) {
1235
+ var cal = $(e.target).parents('.calendar');
1236
+ if (cal.hasClass('left')) {
1237
+ this.leftCalendar.month.subtract(1, 'month');
1238
+ if (this.linkedCalendars)
1239
+ this.rightCalendar.month.subtract(1, 'month');
1240
+ } else {
1241
+ this.rightCalendar.month.subtract(1, 'month');
1242
+ }
1243
+ this.updateCalendars();
1244
+ },
1245
+
1246
+ clickNext: function(e) {
1247
+ var cal = $(e.target).parents('.calendar');
1248
+ if (cal.hasClass('left')) {
1249
+ this.leftCalendar.month.add(1, 'month');
1250
+ } else {
1251
+ this.rightCalendar.month.add(1, 'month');
1252
+ if (this.linkedCalendars)
1253
+ this.leftCalendar.month.add(1, 'month');
1254
+ }
1255
+ this.updateCalendars();
1256
+ },
1257
+
1258
+ hoverDate: function(e) {
1259
+
1260
+ //ignore mouse movements while an above-calendar text input has focus
1261
+ //if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
1262
+ // return;
1263
+
1264
+ //ignore dates that can't be selected
1265
+ if (!$(e.target).hasClass('available')) return;
1266
+
1267
+ //have the text inputs above calendars reflect the date being hovered over
1268
+ var title = $(e.target).attr('data-title');
1269
+ var row = title.substr(1, 1);
1270
+ var col = title.substr(3, 1);
1271
+ var cal = $(e.target).parents('.calendar');
1272
+ var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
1273
+
1274
+ if (this.endDate && !this.container.find('input[name=daterangepicker_start]').is(":focus")) {
1275
+ this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format));
1276
+ } else if (!this.endDate && !this.container.find('input[name=daterangepicker_end]').is(":focus")) {
1277
+ this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format));
1278
+ }
1279
+
1280
+ //highlight the dates between the start date and the date being hovered as a potential end date
1281
+ var leftCalendar = this.leftCalendar;
1282
+ var rightCalendar = this.rightCalendar;
1283
+ var startDate = this.startDate;
1284
+ if (!this.endDate) {
1285
+ this.container.find('.calendar td').each(function(index, el) {
1286
+
1287
+ //skip week numbers, only look at dates
1288
+ if ($(el).hasClass('week')) return;
1289
+
1290
+ var title = $(el).attr('data-title');
1291
+ var row = title.substr(1, 1);
1292
+ var col = title.substr(3, 1);
1293
+ var cal = $(el).parents('.calendar');
1294
+ var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];
1295
+
1296
+ if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) {
1297
+ $(el).addClass('in-range');
1298
+ } else {
1299
+ $(el).removeClass('in-range');
1300
+ }
1301
+
1302
+ });
1303
+ }
1304
+
1305
+ },
1306
+
1307
+ clickDate: function(e) {
1308
+
1309
+ if (!$(e.target).hasClass('available')) return;
1310
+
1311
+ var title = $(e.target).attr('data-title');
1312
+ var row = title.substr(1, 1);
1313
+ var col = title.substr(3, 1);
1314
+ var cal = $(e.target).parents('.calendar');
1315
+ var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];
1316
+
1317
+ //
1318
+ // this function needs to do a few things:
1319
+ // * alternate between selecting a start and end date for the range,
1320
+ // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date
1321
+ // * if autoapply is enabled, and an end date was chosen, apply the selection
1322
+ // * if single date picker mode, and time picker isn't enabled, apply the selection immediately
1323
+ // * if one of the inputs above the calendars was focused, cancel that manual input
1324
+ //
1325
+
1326
+ if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start
1327
+ if (this.timePicker) {
1328
+ var hour = parseInt(this.container.find('.left .hourselect').val(), 10);
1329
+ if (!this.timePicker24Hour) {
1330
+ var ampm = this.container.find('.left .ampmselect').val();
1331
+ if (ampm === 'PM' && hour < 12)
1332
+ hour += 12;
1333
+ if (ampm === 'AM' && hour === 12)
1334
+ hour = 0;
1335
+ }
1336
+ var minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
1337
+ var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
1338
+ date = date.clone().hour(hour).minute(minute).second(second);
1339
+ }
1340
+ this.endDate = null;
1341
+ this.setStartDate(date.clone());
1342
+ } else if (!this.endDate && date.isBefore(this.startDate)) {
1343
+ //special case: clicking the same date for start/end,
1344
+ //but the time of the end date is before the start date
1345
+ this.setEndDate(this.startDate.clone());
1346
+ } else { // picking end
1347
+ if (this.timePicker) {
1348
+ var hour = parseInt(this.container.find('.right .hourselect').val(), 10);
1349
+ if (!this.timePicker24Hour) {
1350
+ var ampm = this.container.find('.right .ampmselect').val();
1351
+ if (ampm === 'PM' && hour < 12)
1352
+ hour += 12;
1353
+ if (ampm === 'AM' && hour === 12)
1354
+ hour = 0;
1355
+ }
1356
+ var minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
1357
+ var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
1358
+ date = date.clone().hour(hour).minute(minute).second(second);
1359
+ }
1360
+ this.setEndDate(date.clone());
1361
+ if (this.autoApply) {
1362
+ this.calculateChosenLabel();
1363
+ this.clickApply();
1364
+ }
1365
+ }
1366
+
1367
+ if (this.singleDatePicker) {
1368
+ this.setEndDate(this.startDate);
1369
+ if (!this.timePicker)
1370
+ this.clickApply();
1371
+ }
1372
+
1373
+ this.updateView();
1374
+
1375
+ //This is to cancel the blur event handler if the mouse was in one of the inputs
1376
+ e.stopPropagation();
1377
+
1378
+ },
1379
+
1380
+ calculateChosenLabel: function() {
1381
+ var customRange = true;
1382
+ var i = 0;
1383
+ for (var range in this.ranges) {
1384
+ if (this.timePicker) {
1385
+ if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) {
1386
+ customRange = false;
1387
+ this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();
1388
+ break;
1389
+ }
1390
+ } else {
1391
+ //ignore times when comparing dates if time picker is not enabled
1392
+ if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) {
1393
+ customRange = false;
1394
+ this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();
1395
+ break;
1396
+ }
1397
+ }
1398
+ i++;
1399
+ }
1400
+ if (customRange && this.showCustomRangeLabel) {
1401
+ this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html();
1402
+ this.showCalendars();
1403
+ }
1404
+ },
1405
+
1406
+ clickApply: function(e) {
1407
+ this.element.trigger('apply.daterangepicker', this);
1408
+ this.container.find('input[name="daterangepicker_period"]').val('range');
1409
+ if ( this.startDate && this.endDate ) {
1410
+ var cal_start_date = moment(this.startDate).format("MMM DD, YYYY");
1411
+ var cal_end_date = moment(this.endDate).format("MMM DD, YYYY");
1412
+ this.element.html(cal_start_date + " - " + cal_end_date + "<i class='icon-angle-down'></i>");
1413
+ }
1414
+ this.hide();
1415
+ },
1416
+
1417
+ clickCancel: function(e) {
1418
+ this.startDate = this.oldStartDate;
1419
+ this.endDate = this.oldEndDate;
1420
+ this.hide();
1421
+ this.element.trigger('cancel.daterangepicker', this);
1422
+ },
1423
+
1424
+ monthOrYearChanged: function(e) {
1425
+ var isLeft = $(e.target).closest('.calendar').hasClass('left'),
1426
+ leftOrRight = isLeft ? 'left' : 'right',
1427
+ cal = this.container.find('.calendar.'+leftOrRight);
1428
+
1429
+ // Month must be Number for new moment versions
1430
+ var month = parseInt(cal.find('.monthselect').val(), 10);
1431
+ var year = cal.find('.yearselect').val();
1432
+
1433
+ if (!isLeft) {
1434
+ if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) {
1435
+ month = this.startDate.month();
1436
+ year = this.startDate.year();
1437
+ }
1438
+ }
1439
+
1440
+ if (this.minDate) {
1441
+ if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) {
1442
+ month = this.minDate.month();
1443
+ year = this.minDate.year();
1444
+ }
1445
+ }
1446
+
1447
+ if (this.maxDate) {
1448
+ if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) {
1449
+ month = this.maxDate.month();
1450
+ year = this.maxDate.year();
1451
+ }
1452
+ }
1453
+
1454
+ if (isLeft) {
1455
+ this.leftCalendar.month.month(month).year(year);
1456
+ if (this.linkedCalendars)
1457
+ this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month');
1458
+ } else {
1459
+ this.rightCalendar.month.month(month).year(year);
1460
+ if (this.linkedCalendars)
1461
+ this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month');
1462
+ }
1463
+ this.updateCalendars();
1464
+ },
1465
+
1466
+ timeChanged: function(e) {
1467
+
1468
+ var cal = $(e.target).closest('.calendar'),
1469
+ isLeft = cal.hasClass('left');
1470
+
1471
+ var hour = parseInt(cal.find('.hourselect').val(), 10);
1472
+ var minute = parseInt(cal.find('.minuteselect').val(), 10);
1473
+ var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0;
1474
+
1475
+ if (!this.timePicker24Hour) {
1476
+ var ampm = cal.find('.ampmselect').val();
1477
+ if (ampm === 'PM' && hour < 12)
1478
+ hour += 12;
1479
+ if (ampm === 'AM' && hour === 12)
1480
+ hour = 0;
1481
+ }
1482
+
1483
+ if (isLeft) {
1484
+ var start = this.startDate.clone();
1485
+ start.hour(hour);
1486
+ start.minute(minute);
1487
+ start.second(second);
1488
+ this.setStartDate(start);
1489
+ if (this.singleDatePicker) {
1490
+ this.endDate = this.startDate.clone();
1491
+ } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) {
1492
+ this.setEndDate(start.clone());
1493
+ }
1494
+ } else if (this.endDate) {
1495
+ var end = this.endDate.clone();
1496
+ end.hour(hour);
1497
+ end.minute(minute);
1498
+ end.second(second);
1499
+ this.setEndDate(end);
1500
+ }
1501
+
1502
+ //update the calendars so all clickable dates reflect the new time component
1503
+ this.updateCalendars();
1504
+
1505
+ //update the form inputs above the calendars with the new time
1506
+ this.updateFormInputs();
1507
+
1508
+ //re-render the time pickers because changing one selection can affect what's enabled in another
1509
+ this.renderTimePicker('left');
1510
+ this.renderTimePicker('right');
1511
+
1512
+ },
1513
+
1514
+ formInputsChanged: function(e) {
1515
+ var isRight = $(e.target).closest('.calendar').hasClass('right');
1516
+ var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format);
1517
+ var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format);
1518
+
1519
+ if (start.isValid() && end.isValid()) {
1520
+
1521
+ if (isRight && end.isBefore(start))
1522
+ start = end.clone();
1523
+
1524
+ this.setStartDate(start);
1525
+ this.setEndDate(end);
1526
+
1527
+ if (isRight) {
1528
+ this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format));
1529
+ } else {
1530
+ this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format));
1531
+ }
1532
+
1533
+ }
1534
+
1535
+ this.updateView();
1536
+ },
1537
+
1538
+ formInputsFocused: function(e) {
1539
+
1540
+ // Highlight the focused input
1541
+ this.container.find('input[name="daterangepicker_start"], input[name="daterangepicker_end"]').removeClass('active');
1542
+ $(e.target).addClass('active');
1543
+
1544
+ // Set the state such that if the user goes back to using a mouse,
1545
+ // the calendars are aware we're selecting the end of the range, not
1546
+ // the start. This allows someone to edit the end of a date range without
1547
+ // re-selecting the beginning, by clicking on the end date input then
1548
+ // using the calendar.
1549
+ var isRight = $(e.target).closest('.calendar').hasClass('right');
1550
+ if (isRight) {
1551
+ this.endDate = null;
1552
+ this.setStartDate(this.startDate.clone());
1553
+ this.updateView();
1554
+ }
1555
+
1556
+ },
1557
+
1558
+ formInputsBlurred: function(e) {
1559
+
1560
+ // this function has one purpose right now: if you tab from the first
1561
+ // text input to the second in the UI, the endDate is nulled so that
1562
+ // you can click another, but if you tab out without clicking anything
1563
+ // or changing the input value, the old endDate should be retained
1564
+
1565
+ if (!this.endDate) {
1566
+ var val = this.container.find('input[name="daterangepicker_end"]').val();
1567
+ var end = moment(val, this.locale.format);
1568
+ if (end.isValid()) {
1569
+ this.setEndDate(end);
1570
+ this.updateView();
1571
+ }
1572
+ }
1573
+
1574
+ },
1575
+
1576
+ elementChanged: function() {
1577
+ if (!this.element.is('input')) return;
1578
+ if (!this.element.val().length) return;
1579
+ if (this.element.val().length < this.locale.format.length) return;
1580
+
1581
+ var dateString = this.element.val().split(this.locale.separator),
1582
+ start = null,
1583
+ end = null;
1584
+
1585
+ if (dateString.length === 2) {
1586
+ start = moment(dateString[0], this.locale.format);
1587
+ end = moment(dateString[1], this.locale.format);
1588
+ }
1589
+
1590
+ if (this.singleDatePicker || start === null || end === null) {
1591
+ start = moment(this.element.val(), this.locale.format);
1592
+ end = start;
1593
+ }
1594
+
1595
+ if (!start.isValid() || !end.isValid()) return;
1596
+
1597
+ this.setStartDate(start);
1598
+ this.setEndDate(end);
1599
+ this.updateView();
1600
+ },
1601
+
1602
+ keydown: function(e) {
1603
+ //hide on tab or enter
1604
+ if ((e.keyCode === 9) || (e.keyCode === 13)) {
1605
+ this.hide();
1606
+ }
1607
+ },
1608
+
1609
+ updateElement: function() {
1610
+ if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
1611
+ this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
1612
+ this.element.trigger('change');
1613
+ } else if (this.element.is('input') && this.autoUpdateInput) {
1614
+ this.element.val(this.startDate.format(this.locale.format));
1615
+ this.element.trigger('change');
1616
+ }
1617
+ },
1618
+
1619
+ remove: function() {
1620
+ this.container.remove();
1621
+ this.element.off('.daterangepicker');
1622
+ this.element.removeData();
1623
+ },
1624
+
1625
+ clickBml: function(e) {
1626
+ this.container.find('.bml').removeClass('active');
1627
+ $(e.target).addClass('active');
1628
+ this.element.html($(e.target).html() + "<i class='icon-angle-down'></i>");
1629
+ var selected_period = $(e.target).data('period');
1630
+ switch (selected_period) {
1631
+ case 'past':
1632
+ this.startDate = moment().subtract(1, 'days');
1633
+ this.endDate = moment().subtract(1, 'days');
1634
+ this.container.find('input[name="daterangepicker_period"]').val('past');
1635
+ break;
1636
+ case 'upcoming':
1637
+ this.startDate = moment();
1638
+ this.endDate = moment();
1639
+ this.container.find('input[name="daterangepicker_period"]').val('upcoming');
1640
+ break;
1641
+ case 'today':
1642
+ this.startDate = moment();
1643
+ this.endDate = moment();
1644
+ this.container.find('input[name="daterangepicker_period"]').val('today');
1645
+ break;
1646
+ case 'this_week':
1647
+ this.startDate = moment().startOf('week');
1648
+ this.endDate = moment().endOf('week');
1649
+ this.container.find('input[name="daterangepicker_period"]').val('this_week');
1650
+ break;
1651
+ case 'this_month':
1652
+ this.startDate = moment(Date.today().clearTime().moveToFirstDayOfMonth());
1653
+ this.endDate = moment(Date.today().clearTime().moveToLastDayOfMonth());
1654
+ this.container.find('input[name="daterangepicker_period"]').val('this_month');
1655
+ break;
1656
+ }
1657
+ this.updateView();
1658
+ this.hide();
1659
+ }
1660
+ };
1661
+
1662
+ $.fn.daterangepicker = function(options, callback) {
1663
+ this.each(function() {
1664
+ var el = $(this);
1665
+ if (el.data('daterangepicker'))
1666
+ el.data('daterangepicker').remove();
1667
+ el.data('daterangepicker', new DateRangePicker(el, options, callback));
1668
+ });
1669
+ return this;
1670
+ };
1671
+
1672
+ return DateRangePicker;
1673
+
1674
+ }));