conschedule 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }));