jquery-week-calendar 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.md +17 -0
- data/lib/jquery-week-calendar.rb +11 -0
- data/lib/jquery-week-calendar/engine.rb +8 -0
- data/lib/jquery-week-calendar/generators.rb +24 -0
- data/lib/jquery-week-calendar/railtie.rb +11 -0
- data/vendor/assets/javascripts/jquery-week-calendar.js +3011 -0
- data/vendor/assets/stylesheets/jquery-week-calendar.css +278 -0
- metadata +89 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Adam Fortuna
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Wrapper for the jQuery-Week-Calendar Javascrip library.
|
2
|
+
|
3
|
+
https://github.com/themouette/jquery-week-calendar
|
4
|
+
|
5
|
+
Just add to your gemfile:
|
6
|
+
|
7
|
+
gem 'jquery-week-calendar'
|
8
|
+
|
9
|
+
And include in your application.js:
|
10
|
+
|
11
|
+
//= require jquery-week-calendar
|
12
|
+
|
13
|
+
Optionall include in your application.css
|
14
|
+
|
15
|
+
*= require jquery-week-calendar
|
16
|
+
|
17
|
+
You'll probably want to also use jquery-ui with it for a quick skin. For this I used the 'jquery-ui-themes' gem to get setup, but you can also use the Google hosted version of course.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module JqueryWeekCalendar
|
4
|
+
class Install < ::Rails::Generators::Base
|
5
|
+
JAVASCRIPTS = File.expand_path('../../../vendor/assets/javascripts', __FILE__)
|
6
|
+
STYLESHEETS = File.expand_path('../../../vendor/assets/stylesheets', __FILE__)
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
@source_root ||= JAVASCRIPTS
|
10
|
+
end
|
11
|
+
|
12
|
+
def copy_calendar
|
13
|
+
Dir[File.join(JAVASCRIPTS, '*.js')].each do |file|
|
14
|
+
file = File.split(file).last
|
15
|
+
copy_file file, "public/javascripts/#{file}"
|
16
|
+
end
|
17
|
+
|
18
|
+
Dir[File.join(STYLESHEETS, '*.css')].each do |file|
|
19
|
+
file = File.split(file).last
|
20
|
+
copy_file file, "public/stylesheets/#{file}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,3011 @@
|
|
1
|
+
/**
|
2
|
+
* @version: 1.0 Alpha-1
|
3
|
+
* @author: Coolite Inc. http://www.coolite.com/
|
4
|
+
* @date: 2008-05-13
|
5
|
+
* @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
|
6
|
+
* @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
|
7
|
+
* @website: http://www.datejs.com/
|
8
|
+
*/
|
9
|
+
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:/^(\+|aft(er)?|from|hence)/i,subtract:/^(\-|bef(ore)?|ago)/i,yesterday:/^yes(terday)?/i,today:/^t(od(ay)?)?/i,tomorrow:/^tom(orrow)?/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^mn|min(ute)?s?/i,hour:/^h(our)?s?/i,week:/^w(eek)?s?/i,month:/^m(onth)?s?/i,day:/^d(ay)?s?/i,year:/^y(ear)?s?/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|utc)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a(?!u|p)|p)/i},timezones:[{name:"UTC",offset:"-000"},{name:"GMT",offset:"-000"},{name:"EST",offset:"-0500"},{name:"EDT",offset:"-0400"},{name:"CST",offset:"-0600"},{name:"CDT",offset:"-0500"},{name:"MST",offset:"-0700"},{name:"MDT",offset:"-0600"},{name:"PST",offset:"-0800"},{name:"PDT",offset:"-0700"}]};
|
10
|
+
(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo,p=function(s,l){if(!l){l=2;}
|
11
|
+
return("000"+s).slice(l*-1);};$P.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};$P.setTimeToNow=function(){var n=new Date();this.setHours(n.getHours());this.setMinutes(n.getMinutes());this.setSeconds(n.getSeconds());this.setMilliseconds(n.getMilliseconds());return this;};$D.today=function(){return new Date().clearTime();};$D.compare=function(date1,date2){if(isNaN(date1)||isNaN(date2)){throw new Error(date1+" - "+date2);}else if(date1 instanceof Date&&date2 instanceof Date){return(date1<date2)?-1:(date1>date2)?1:0;}else{throw new TypeError(date1+" - "+date2);}};$D.equals=function(date1,date2){return(date1.compareTo(date2)===0);};$D.getDayNumberFromName=function(name){var n=$C.dayNames,m=$C.abbreviatedDayNames,o=$C.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s||o[i].toLowerCase()==s){return i;}}
|
12
|
+
return-1;};$D.getMonthNumberFromName=function(name){var n=$C.monthNames,m=$C.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
|
13
|
+
return-1;};$D.isLeapYear=function(year){return((year%4===0&&year%100!==0)||year%400===0);};$D.getDaysInMonth=function(year,month){return[31,($D.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};$D.getTimezoneAbbreviation=function(offset){var z=$C.timezones,p;for(var i=0;i<z.length;i++){if(z[i].offset===offset){return z[i].name;}}
|
14
|
+
return null;};$D.getTimezoneOffset=function(name){var z=$C.timezones,p;for(var i=0;i<z.length;i++){if(z[i].name===name.toUpperCase()){return z[i].offset;}}
|
15
|
+
return null;};$P.clone=function(){return new Date(this.getTime());};$P.compareTo=function(date){return Date.compare(this,date);};$P.equals=function(date){return Date.equals(this,date||new Date());};$P.between=function(start,end){return this.getTime()>=start.getTime()&&this.getTime()<=end.getTime();};$P.isAfter=function(date){return this.compareTo(date||new Date())===1;};$P.isBefore=function(date){return(this.compareTo(date||new Date())===-1);};$P.isToday=function(){return this.isSameDay(new Date());};$P.isSameDay=function(date){return this.clone().clearTime().equals(date.clone().clearTime());};$P.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};$P.addSeconds=function(value){return this.addMilliseconds(value*1000);};$P.addMinutes=function(value){return this.addMilliseconds(value*60000);};$P.addHours=function(value){return this.addMilliseconds(value*3600000);};$P.addDays=function(value){this.setDate(this.getDate()+value);return this;};$P.addWeeks=function(value){return this.addDays(value*7);};$P.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,$D.getDaysInMonth(this.getFullYear(),this.getMonth())));return this;};$P.addYears=function(value){return this.addMonths(value*12);};$P.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
|
16
|
+
var x=config;if(x.milliseconds){this.addMilliseconds(x.milliseconds);}
|
17
|
+
if(x.seconds){this.addSeconds(x.seconds);}
|
18
|
+
if(x.minutes){this.addMinutes(x.minutes);}
|
19
|
+
if(x.hours){this.addHours(x.hours);}
|
20
|
+
if(x.weeks){this.addWeeks(x.weeks);}
|
21
|
+
if(x.months){this.addMonths(x.months);}
|
22
|
+
if(x.years){this.addYears(x.years);}
|
23
|
+
if(x.days){this.addDays(x.days);}
|
24
|
+
return this;};var $y,$m,$d;$P.getWeek=function(){var a,b,c,d,e,f,g,n,s,w;$y=(!$y)?this.getFullYear():$y;$m=(!$m)?this.getMonth()+1:$m;$d=(!$d)?this.getDate():$d;if($m<=2){a=$y-1;b=(a/4|0)-(a/100|0)+(a/400|0);c=((a-1)/4|0)-((a-1)/100|0)+((a-1)/400|0);s=b-c;e=0;f=$d-1+(31*($m-1));}else{a=$y;b=(a/4|0)-(a/100|0)+(a/400|0);c=((a-1)/4|0)-((a-1)/100|0)+((a-1)/400|0);s=b-c;e=s+1;f=$d+((153*($m-3)+2)/5)+58+s;}
|
25
|
+
g=(a+b)%7;d=(f+g-e)%7;n=(f+3-d)|0;if(n<0){w=53-((g-s)/5|0);}else if(n>364+s){w=1;}else{w=(n/7|0)+1;}
|
26
|
+
$y=$m=$d=null;return w;};$P.getISOWeek=function(){$y=this.getUTCFullYear();$m=this.getUTCMonth()+1;$d=this.getUTCDate();return p(this.getWeek());};$P.setWeek=function(n){return this.moveToDayOfWeek(1).addWeeks(n-this.getWeek());};$D._validate=function(n,min,max,name){if(typeof n=="undefined"){return false;}else if(typeof n!="number"){throw new TypeError(n+" is not a Number.");}else if(n<min||n>max){throw new RangeError(n+" is not a valid value for "+name+".");}
|
27
|
+
return true;};$D.validateMillisecond=function(value){return $D._validate(value,0,999,"millisecond");};$D.validateSecond=function(value){return $D._validate(value,0,59,"second");};$D.validateMinute=function(value){return $D._validate(value,0,59,"minute");};$D.validateHour=function(value){return $D._validate(value,0,23,"hour");};$D.validateDay=function(value,year,month){return $D._validate(value,1,$D.getDaysInMonth(year,month),"day");};$D.validateMonth=function(value){return $D._validate(value,0,11,"month");};$D.validateYear=function(value){return $D._validate(value,0,9999,"year");};$P.set=function(config){if($D.validateMillisecond(config.millisecond)){this.addMilliseconds(config.millisecond-this.getMilliseconds());}
|
28
|
+
if($D.validateSecond(config.second)){this.addSeconds(config.second-this.getSeconds());}
|
29
|
+
if($D.validateMinute(config.minute)){this.addMinutes(config.minute-this.getMinutes());}
|
30
|
+
if($D.validateHour(config.hour)){this.addHours(config.hour-this.getHours());}
|
31
|
+
if($D.validateMonth(config.month)){this.addMonths(config.month-this.getMonth());}
|
32
|
+
if($D.validateYear(config.year)){this.addYears(config.year-this.getFullYear());}
|
33
|
+
if($D.validateDay(config.day,this.getFullYear(),this.getMonth())){this.addDays(config.day-this.getDate());}
|
34
|
+
if(config.timezone){this.setTimezone(config.timezone);}
|
35
|
+
if(config.timezoneOffset){this.setTimezoneOffset(config.timezoneOffset);}
|
36
|
+
if(config.week&&$D._validate(config.week,0,53,"week")){this.setWeek(config.week);}
|
37
|
+
return this;};$P.moveToFirstDayOfMonth=function(){return this.set({day:1});};$P.moveToLastDayOfMonth=function(){return this.set({day:$D.getDaysInMonth(this.getFullYear(),this.getMonth())});};$P.moveToNthOccurrence=function(dayOfWeek,occurrence){var shift=0;if(occurrence>0){shift=occurrence-1;}
|
38
|
+
else if(occurrence===-1){this.moveToLastDayOfMonth();if(this.getDay()!==dayOfWeek){this.moveToDayOfWeek(dayOfWeek,-1);}
|
39
|
+
return this;}
|
40
|
+
return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek,+1).addWeeks(shift);};$P.moveToDayOfWeek=function(dayOfWeek,orient){var diff=(dayOfWeek-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};$P.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};$P.getOrdinalNumber=function(){return Math.ceil((this.clone().clearTime()-new Date(this.getFullYear(),0,1))/86400000)+1;};$P.getTimezone=function(){return $D.getTimezoneAbbreviation(this.getUTCOffset());};$P.setTimezoneOffset=function(offset){var here=this.getTimezoneOffset(),there=Number(offset)*-6/10;return this.addMinutes(there-here);};$P.setTimezone=function(offset){return this.setTimezoneOffset($D.getTimezoneOffset(offset));};$P.hasDaylightSavingTime=function(){return(Date.today().set({month:0,day:1}).getTimezoneOffset()!==Date.today().set({month:6,day:1}).getTimezoneOffset());};$P.isDaylightSavingTime=function(){return(this.hasDaylightSavingTime()&&new Date().getTimezoneOffset()===Date.today().set({month:6,day:1}).getTimezoneOffset());};$P.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r.charAt(0)+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};$P.getElapsed=function(date){return(date||new Date())-this;};if(!$P.toISOString){$P.toISOString=function(){function f(n){return n<10?'0'+n:n;}
|
41
|
+
return'"'+this.getUTCFullYear()+'-'+
|
42
|
+
f(this.getUTCMonth()+1)+'-'+
|
43
|
+
f(this.getUTCDate())+'T'+
|
44
|
+
f(this.getUTCHours())+':'+
|
45
|
+
f(this.getUTCMinutes())+':'+
|
46
|
+
f(this.getUTCSeconds())+'Z"';};}
|
47
|
+
$P._toString=$P.toString;$P.toString=function(format){var x=this;if(format&&format.length==1){var c=$C.formatPatterns;x.t=x.toString;switch(format){case"d":return x.t(c.shortDate);case"D":return x.t(c.longDate);case"F":return x.t(c.fullDateTime);case"m":return x.t(c.monthDay);case"r":return x.t(c.rfc1123);case"s":return x.t(c.sortableDateTime);case"t":return x.t(c.shortTime);case"T":return x.t(c.longTime);case"u":return x.t(c.universalSortableDateTime);case"y":return x.t(c.yearMonth);}}
|
48
|
+
var ord=function(n){switch(n*1){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};return format?format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,function(m){if(m.charAt(0)==="\\"){return m.replace("\\","");}
|
49
|
+
x.h=x.getHours;switch(m){case"hh":return p(x.h()<13?(x.h()===0?12:x.h()):(x.h()-12));case"h":return x.h()<13?(x.h()===0?12:x.h()):(x.h()-12);case"HH":return p(x.h());case"H":return x.h();case"mm":return p(x.getMinutes());case"m":return x.getMinutes();case"ss":return p(x.getSeconds());case"s":return x.getSeconds();case"yyyy":return p(x.getFullYear(),4);case"yy":return p(x.getFullYear());case"dddd":return $C.dayNames[x.getDay()];case"ddd":return $C.abbreviatedDayNames[x.getDay()];case"dd":return p(x.getDate());case"d":return x.getDate();case"MMMM":return $C.monthNames[x.getMonth()];case"MMM":return $C.abbreviatedMonthNames[x.getMonth()];case"MM":return p((x.getMonth()+1));case"M":return x.getMonth()+1;case"t":return x.h()<12?$C.amDesignator.substring(0,1):$C.pmDesignator.substring(0,1);case"tt":return x.h()<12?$C.amDesignator:$C.pmDesignator;case"S":return ord(x.getDate());default:return m;}}):this._toString();};}());
|
50
|
+
(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo,$N=Number.prototype;$P._orient=+1;$P._nth=null;$P._is=false;$P._same=false;$P._isSecond=false;$N._dateElement="day";$P.next=function(){this._orient=+1;return this;};$D.next=function(){return $D.today().next();};$P.last=$P.prev=$P.previous=function(){this._orient=-1;return this;};$D.last=$D.prev=$D.previous=function(){return $D.today().last();};$P.is=function(){this._is=true;return this;};$P.same=function(){this._same=true;this._isSecond=false;return this;};$P.today=function(){return this.same().day();};$P.weekday=function(){if(this._is){this._is=false;return(!this.is().sat()&&!this.is().sun());}
|
51
|
+
return false;};$P.at=function(time){return(typeof time==="string")?$D.parse(this.toString("d")+" "+time):this.set(time);};$N.fromNow=$N.after=function(date){var c={};c[this._dateElement]=this;return((!date)?new Date():date.clone()).add(c);};$N.ago=$N.before=function(date){var c={};c[this._dateElement]=this*-1;return((!date)?new Date():date.clone()).add(c);};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/),pxf=("Milliseconds Seconds Minutes Hours Date Week Month FullYear").split(/\s/),nth=("final first second third fourth fifth").split(/\s/),de;$P.toObject=function(){var o={};for(var i=0;i<px.length;i++){o[px[i].toLowerCase()]=this["get"+pxf[i]]();}
|
52
|
+
return o;};$D.fromObject=function(config){config.week=null;return Date.today().set(config);};var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
|
53
|
+
if(this._nth!==null){if(this._isSecond){this.addSeconds(this._orient*-1);}
|
54
|
+
this._isSecond=false;var ntemp=this._nth;this._nth=null;var temp=this.clone().moveToLastDayOfMonth();this.moveToNthOccurrence(n,ntemp);if(this>temp){throw new RangeError($D.getDayName(n)+" does not occur "+ntemp+" times in the month of "+$D.getMonthName(temp.getMonth())+" "+temp.getFullYear()+".");}
|
55
|
+
return this;}
|
56
|
+
return this.moveToDayOfWeek(n,this._orient);};};var sdf=function(n){return function(){var t=$D.today(),shift=n-t.getDay();if(n===0&&$C.firstDayOfWeek===1&&t.getDay()!==0){shift=shift+7;}
|
57
|
+
return t.addDays(shift);};};for(var i=0;i<dx.length;i++){$D[dx[i].toUpperCase()]=$D[dx[i].toUpperCase().substring(0,3)]=i;$D[dx[i]]=$D[dx[i].substring(0,3)]=sdf(i);$P[dx[i]]=$P[dx[i].substring(0,3)]=df(i);}
|
58
|
+
var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
|
59
|
+
return this.moveToMonth(n,this._orient);};};var smf=function(n){return function(){return $D.today().set({month:n,day:1});};};for(var j=0;j<mx.length;j++){$D[mx[j].toUpperCase()]=$D[mx[j].toUpperCase().substring(0,3)]=j;$D[mx[j]]=$D[mx[j].substring(0,3)]=smf(j);$P[mx[j]]=$P[mx[j].substring(0,3)]=mf(j);}
|
60
|
+
var ef=function(j){return function(){if(this._isSecond){this._isSecond=false;return this;}
|
61
|
+
if(this._same){this._same=this._is=false;var o1=this.toObject(),o2=(arguments[0]||new Date()).toObject(),v="",k=j.toLowerCase();for(var m=(px.length-1);m>-1;m--){v=px[m].toLowerCase();if(o1[v]!=o2[v]){return false;}
|
62
|
+
if(k==v){break;}}
|
63
|
+
return true;}
|
64
|
+
if(j.substring(j.length-1)!="s"){j+="s";}
|
65
|
+
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();$P[de]=$P[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}
|
66
|
+
$P._ss=ef("Second");var nthfn=function(n){return function(dayOfWeek){if(this._same){return this._ss(arguments[0]);}
|
67
|
+
if(dayOfWeek||dayOfWeek===0){return this.moveToNthOccurrence(dayOfWeek,n);}
|
68
|
+
this._nth=n;if(n===2&&(dayOfWeek===undefined||dayOfWeek===null)){this._isSecond=true;return this.addSeconds(this._orient);}
|
69
|
+
return this;};};for(var l=0;l<nth.length;l++){$P[nth[l]]=(l===0)?nthfn(-1):nthfn(l);}}());
|
70
|
+
(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;}
|
71
|
+
break;}
|
72
|
+
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];}
|
73
|
+
rx.push(r[0]);s=r[1];}
|
74
|
+
return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
|
75
|
+
return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
|
76
|
+
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));}
|
77
|
+
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;}
|
78
|
+
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;}
|
79
|
+
try{r=(px[i].call(this,s));}catch(e){r=null;}
|
80
|
+
if(r){return r;}}
|
81
|
+
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;}
|
82
|
+
try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
|
83
|
+
rx.push(r[0]);s=r[1];}
|
84
|
+
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];}
|
85
|
+
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;}
|
86
|
+
rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
|
87
|
+
s=q[1];}
|
88
|
+
if(!r){throw new $P.Exception(s);}
|
89
|
+
if(q){throw new $P.Exception(q[1]);}
|
90
|
+
if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
|
91
|
+
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;}
|
92
|
+
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;}
|
93
|
+
if(!last&&q[1].length===0){last=true;}
|
94
|
+
if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
|
95
|
+
p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
|
96
|
+
if(rx[1].length<best[1].length){best=rx;}
|
97
|
+
if(best[1].length===0){break;}}
|
98
|
+
if(best[0].length===0){return best;}
|
99
|
+
if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
|
100
|
+
best[1]=q[1];}
|
101
|
+
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);}
|
102
|
+
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];}
|
103
|
+
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]]);}
|
104
|
+
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 $D=Date,$P=$D.prototype,$C=$D.CultureInfo;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]);}}}
|
105
|
+
return rx;};$D.Grammar={};$D.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)?"jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4:Number(s)-1;};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<$C.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];for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
|
106
|
+
var now=new Date();if((this.hour||this.minute)&&(!this.month&&!this.year&&!this.day)){this.day=now.getDate();}
|
107
|
+
if(!this.year){this.year=now.getFullYear();}
|
108
|
+
if(!this.month&&this.month!==0){this.month=now.getMonth();}
|
109
|
+
if(!this.day){this.day=1;}
|
110
|
+
if(!this.hour){this.hour=0;}
|
111
|
+
if(!this.minute){this.minute=0;}
|
112
|
+
if(!this.second){this.second=0;}
|
113
|
+
if(this.meridian&&this.hour){if(this.meridian=="p"&&this.hour<12){this.hour=this.hour+12;}else if(this.meridian=="a"&&this.hour==12){this.hour=0;}}
|
114
|
+
if(this.day>$D.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
|
115
|
+
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});}
|
116
|
+
return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
|
117
|
+
for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
|
118
|
+
var today=$D.today();if(this.now&&!this.unit&&!this.operator){return new Date();}else if(this.now){today=new Date();}
|
119
|
+
var expression=!!(this.days&&this.days!==null||this.orient||this.operator);var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(!this.now&&"hour minute second".indexOf(this.unit)!=-1){today.setTimeToNow();}
|
120
|
+
if(this.month||this.month===0){if("year day hour minute second".indexOf(this.unit)!=-1){this.value=this.month+1;this.month=null;expression=true;}}
|
121
|
+
if(!expression&&this.weekday&&!this.day&&!this.days){var temp=Date[this.weekday]();this.day=temp.getDate();if(!this.month){this.month=temp.getMonth();}
|
122
|
+
this.year=temp.getFullYear();}
|
123
|
+
if(expression&&this.weekday&&this.unit!="month"){this.unit="day";gap=($D.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
|
124
|
+
if(this.month&&this.unit=="day"&&this.operator){this.value=(this.month+1);this.month=null;}
|
125
|
+
if(this.value!=null&&this.month!=null&&this.year!=null){this.day=this.value*1;}
|
126
|
+
if(this.month&&!this.day&&this.value){today.set({day:this.value*1});if(!expression){this.day=this.value*1;}}
|
127
|
+
if(!this.month&&this.value&&this.unit=="month"&&!this.now){this.month=this.value;expression=true;}
|
128
|
+
if(expression&&(this.month||this.month===0)&&this.unit!="year"){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
|
129
|
+
if(!this.unit){this.unit="day";}
|
130
|
+
if(!this.value&&this.operator&&this.operator!==null&&this[this.unit+"s"]&&this[this.unit+"s"]!==null){this[this.unit+"s"]=this[this.unit+"s"]+((this.operator=="add")?1:-1)+(this.value||0)*orient;}else if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
|
131
|
+
this[this.unit+"s"]=this.value*orient;}
|
132
|
+
if(this.meridian&&this.hour){if(this.meridian=="p"&&this.hour<12){this.hour=this.hour+12;}else if(this.meridian=="a"&&this.hour==12){this.hour=0;}}
|
133
|
+
if(this.weekday&&!this.day&&!this.days){var temp=Date[this.weekday]();this.day=temp.getDate();if(temp.getMonth()!==today.getMonth()){this.month=temp.getMonth();}}
|
134
|
+
if((this.month||this.month===0)&&!this.day){this.day=1;}
|
135
|
+
if(!this.orient&&!this.operator&&this.unit=="week"&&this.value&&!this.day&&!this.month){return Date.today().setWeek(this.value);}
|
136
|
+
if(expression&&this.timezone&&this.day&&this.days){this.day=this.days;}
|
137
|
+
return(expression)?today.add(this):today.set(this);}};var _=$D.Parsing.Operators,g=$D.Grammar,t=$D.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=$C.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
|
138
|
+
fn=_C[keys]=_.any.apply(null,px);}
|
139
|
+
return fn;};g.ctoken2=function(key){return _.rtoken($C.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.m,g.s],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)|((\+|\-)\d\d\:?\d\d)/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\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("second 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[$C.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 $D.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]));}
|
140
|
+
return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["\"yyyy-MM-ddTHH:mm:ssZ\"","yyyy-MM-ddTHH:mm:ssZ","yyyy-MM-ddTHH:mm:ssz","yyyy-MM-ddTHH:mm:ss","yyyy-MM-ddTHH:mmZ","yyyy-MM-ddTHH:mmz","yyyy-MM-ddTHH:mm","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","MMddyyyy","ddMMyyyy","Mddyyyy","ddMyyyy","Mdyyyy","dMyyyy","yyyy","Mdyy","dMyy","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){}
|
141
|
+
return g._start.call({},s);};$D._parse=$D.parse;$D.parse=function(s){var r=null;if(!s){return null;}
|
142
|
+
if(s instanceof Date){return s;}
|
143
|
+
try{r=$D.Grammar.start.call({},s.replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1"));}catch(e){return null;}
|
144
|
+
return((r[1].length===0)?r[0]:null);};$D.getParseFunction=function(fx){var fn=$D.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
|
145
|
+
return((r[1].length===0)?r[0]:null);};};$D.parseExact=function(s,fx){return $D.getParseFunction(fx)(s);};}());
|
146
|
+
|
147
|
+
|
148
|
+
/*
|
149
|
+
* jQuery.weekCalendar v2.0-dev
|
150
|
+
*
|
151
|
+
* for support join us at the google group:
|
152
|
+
* - http://groups.google.com/group/jquery-week-calendar
|
153
|
+
* have a look to the wiki for documentation:
|
154
|
+
* - http://wiki.github.com/themouette/jquery-week-calendar/
|
155
|
+
* something went bad ? report an issue:
|
156
|
+
* - http://github.com/themouette/jquery-week-calendar/issues
|
157
|
+
* get the last version on github:
|
158
|
+
* - http://github.com/themouette/jquery-week-calendar
|
159
|
+
*
|
160
|
+
* Copyright (c) 2009 Rob Monie
|
161
|
+
* Copyright (c) 2010 Julien MUETTON
|
162
|
+
* Dual licensed under the MIT and GPL licenses:
|
163
|
+
* http://www.opensource.org/licenses/mit-license.php
|
164
|
+
* http://www.gnu.org/licenses/gpl.html
|
165
|
+
*
|
166
|
+
* If you're after a monthly calendar plugin, check out this one :
|
167
|
+
* http://arshaw.com/fullcalendar/
|
168
|
+
*/
|
169
|
+
|
170
|
+
(function($) {
|
171
|
+
// check the jquery version
|
172
|
+
var _v = $.fn.jquery.split('.'),
|
173
|
+
_jQuery14OrLower = (10 * _v[0] + _v[1]) < 15;
|
174
|
+
|
175
|
+
$.widget('ui.weekCalendar', (function() {
|
176
|
+
var _currentAjaxCall;
|
177
|
+
return {
|
178
|
+
options: {
|
179
|
+
date: new Date(),
|
180
|
+
timeFormat: null,
|
181
|
+
dateFormat: 'M d, Y',
|
182
|
+
alwaysDisplayTimeMinutes: true,
|
183
|
+
use24Hour: false,
|
184
|
+
daysToShow: 7,
|
185
|
+
minBodyHeight: 100,
|
186
|
+
firstDayOfWeek: function(calendar) {
|
187
|
+
if ($(calendar).weekCalendar('option', 'daysToShow') != 5) {
|
188
|
+
return 0;
|
189
|
+
} else {
|
190
|
+
//workweek
|
191
|
+
return 1;
|
192
|
+
}
|
193
|
+
}, // 0 = Sunday, 1 = Monday, 2 = Tuesday, ... , 6 = Saturday
|
194
|
+
useShortDayNames: false,
|
195
|
+
timeSeparator: ' to ',
|
196
|
+
startParam: 'start',
|
197
|
+
endParam: 'end',
|
198
|
+
businessHours: {start: 8, end: 18, limitDisplay: false},
|
199
|
+
newEventText: 'New Event',
|
200
|
+
timeslotHeight: 20,
|
201
|
+
defaultEventLength: 2,
|
202
|
+
timeslotsPerHour: 4,
|
203
|
+
minDate: null,
|
204
|
+
maxDate: null,
|
205
|
+
buttons: true,
|
206
|
+
buttonText: {
|
207
|
+
today: 'today',
|
208
|
+
lastWeek: 'previous',
|
209
|
+
nextWeek: 'next'
|
210
|
+
},
|
211
|
+
switchDisplay: {},
|
212
|
+
scrollToHourMillis: 500,
|
213
|
+
allowEventDelete: false,
|
214
|
+
allowCalEventOverlap: false,
|
215
|
+
overlapEventsSeparate: false,
|
216
|
+
totalEventsWidthPercentInOneColumn : 100,
|
217
|
+
readonly: false,
|
218
|
+
allowEventCreation: true,
|
219
|
+
deletable: function(calEvent, element) {
|
220
|
+
return true;
|
221
|
+
},
|
222
|
+
draggable: function(calEvent, element) {
|
223
|
+
return true;
|
224
|
+
},
|
225
|
+
resizable: function(calEvent, element) {
|
226
|
+
return true;
|
227
|
+
},
|
228
|
+
eventClick: function(calEvent, element, dayFreeBusyManager,
|
229
|
+
calendar, clickEvent) {
|
230
|
+
},
|
231
|
+
eventRender: function(calEvent, element) {
|
232
|
+
return element;
|
233
|
+
},
|
234
|
+
eventAfterRender: function(calEvent, element) {
|
235
|
+
return element;
|
236
|
+
},
|
237
|
+
eventRefresh: function(calEvent, element) {
|
238
|
+
return element;
|
239
|
+
},
|
240
|
+
eventDrag: function(calEvent, element) {
|
241
|
+
},
|
242
|
+
eventDrop: function(calEvent, element) {
|
243
|
+
},
|
244
|
+
eventResize: function(calEvent, element) {
|
245
|
+
},
|
246
|
+
eventNew: function(calEvent, element, dayFreeBusyManager,
|
247
|
+
calendar, mouseupEvent) {
|
248
|
+
},
|
249
|
+
eventMouseover: function(calEvent, $event) {
|
250
|
+
},
|
251
|
+
eventMouseout: function(calEvent, $event) {
|
252
|
+
},
|
253
|
+
eventDelete: function(calEvent, element, dayFreeBusyManager,
|
254
|
+
calendar, clickEvent) {
|
255
|
+
calendar.weekCalendar('removeEvent',calEvent.id);
|
256
|
+
},
|
257
|
+
calendarBeforeLoad: function(calendar) {
|
258
|
+
},
|
259
|
+
calendarAfterLoad: function(calendar) {
|
260
|
+
},
|
261
|
+
noEvents: function() {
|
262
|
+
},
|
263
|
+
eventHeader: function(calEvent, calendar) {
|
264
|
+
var options = calendar.weekCalendar('option');
|
265
|
+
var one_hour = 3600000;
|
266
|
+
var displayTitleWithTime = calEvent.end.getTime() - calEvent.start.getTime() <= (one_hour / options.timeslotsPerHour);
|
267
|
+
if (displayTitleWithTime) {
|
268
|
+
return calendar.weekCalendar(
|
269
|
+
'formatTime', calEvent.start) +
|
270
|
+
': ' + calEvent.title;
|
271
|
+
} else {
|
272
|
+
return calendar.weekCalendar(
|
273
|
+
'formatTime', calEvent.start) +
|
274
|
+
options.timeSeparator +
|
275
|
+
calendar.weekCalendar(
|
276
|
+
'formatTime', calEvent.end);
|
277
|
+
}
|
278
|
+
},
|
279
|
+
eventBody: function(calEvent, calendar) {
|
280
|
+
return calEvent.title;
|
281
|
+
},
|
282
|
+
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
283
|
+
longMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
284
|
+
shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
285
|
+
longDays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
286
|
+
/* multi-users options */
|
287
|
+
/**
|
288
|
+
* the available users for calendar.
|
289
|
+
* if you want to display users separately, enable the
|
290
|
+
* showAsSeparateUsers option.
|
291
|
+
* if you provide a list of user and do not enable showAsSeparateUsers
|
292
|
+
* option, then only the events that belongs to one or several of
|
293
|
+
* given users will be displayed
|
294
|
+
* @type {array}
|
295
|
+
*/
|
296
|
+
users: [],
|
297
|
+
/**
|
298
|
+
* should the calendar be displayed with separate column for each
|
299
|
+
* users.
|
300
|
+
* note that this option does nothing if you do not provide at least
|
301
|
+
* one user.
|
302
|
+
* @type {boolean}
|
303
|
+
*/
|
304
|
+
showAsSeparateUsers: true,
|
305
|
+
/**
|
306
|
+
* callback used to read user id from a user object.
|
307
|
+
* @param {Object} user the user to retrieve the id from.
|
308
|
+
* @param {number} index the user index from user list.
|
309
|
+
* @param {jQuery} calendar the calendar object.
|
310
|
+
* @return {int|String} the user id.
|
311
|
+
*/
|
312
|
+
getUserId: function(user, index, calendar) {
|
313
|
+
return index;
|
314
|
+
},
|
315
|
+
/**
|
316
|
+
* callback used to read user name from a user object.
|
317
|
+
* @param {Object} user the user to retrieve the name from.
|
318
|
+
* @param {number} index the user index from user list.
|
319
|
+
* @param {jQuery} calendar the calendar object.
|
320
|
+
* @return {String} the user name.
|
321
|
+
*/
|
322
|
+
getUserName: function(user, index, calendar) {
|
323
|
+
return user;
|
324
|
+
},
|
325
|
+
/**
|
326
|
+
* reads the id(s) of user(s) for who the event should be displayed.
|
327
|
+
* @param {Object} calEvent the calEvent to read informations from.
|
328
|
+
* @param {jQuery} calendar the calendar object.
|
329
|
+
* @return {number|String|Array} the user id(s) to appened events for.
|
330
|
+
*/
|
331
|
+
getEventUserId: function(calEvent, calendar) {
|
332
|
+
return calEvent.userId;
|
333
|
+
},
|
334
|
+
/**
|
335
|
+
* sets user id(s) to the calEvent
|
336
|
+
* @param {Object} calEvent the calEvent to set informations to.
|
337
|
+
* @param {jQuery} calendar the calendar object.
|
338
|
+
* @return {Object} the calEvent with modified user id.
|
339
|
+
*/
|
340
|
+
setEventUserId: function(userId, calEvent, calendar) {
|
341
|
+
calEvent.userId = userId;
|
342
|
+
return calEvent;
|
343
|
+
},
|
344
|
+
/* freeBusy options */
|
345
|
+
/**
|
346
|
+
* should the calendar display freebusys ?
|
347
|
+
* @type {boolean}
|
348
|
+
*/
|
349
|
+
displayFreeBusys: false,
|
350
|
+
/**
|
351
|
+
* read the id(s) for who the freebusy is available
|
352
|
+
* @param {Object} calEvent the calEvent to read informations from.
|
353
|
+
* @param {jQuery} calendar the calendar object.
|
354
|
+
* @return {number|String|Array} the user id(s) to appened events for.
|
355
|
+
*/
|
356
|
+
getFreeBusyUserId: function(calFreeBusy, calendar) {
|
357
|
+
return calFreeBusy.userId;
|
358
|
+
},
|
359
|
+
/**
|
360
|
+
* the default freeBusy object, used to manage default state
|
361
|
+
* @type {Object}
|
362
|
+
*/
|
363
|
+
defaultFreeBusy: {free: false},
|
364
|
+
/**
|
365
|
+
* function used to display the freeBusy element
|
366
|
+
* @type {Function}
|
367
|
+
* @param {Object} freeBusy the freeBusy timeslot to render.
|
368
|
+
* @param {jQuery} $freeBusy the freeBusy HTML element.
|
369
|
+
* @param {jQuery} calendar the calendar element.
|
370
|
+
*/
|
371
|
+
freeBusyRender: function(freeBusy, $freeBusy, calendar) {
|
372
|
+
if (!freeBusy.free) {
|
373
|
+
$freeBusy.addClass('free-busy-busy');
|
374
|
+
}
|
375
|
+
else {
|
376
|
+
$freeBusy.addClass('free-busy-free');
|
377
|
+
}
|
378
|
+
return $freeBusy;
|
379
|
+
},
|
380
|
+
/* other options */
|
381
|
+
/**
|
382
|
+
* true means start on first day of week, false means starts on
|
383
|
+
* startDate.
|
384
|
+
* @param {jQuery} calendar the calendar object.
|
385
|
+
* @type {Function|bool}
|
386
|
+
*/
|
387
|
+
startOnFirstDayOfWeek: function(calendar) {
|
388
|
+
return $(calendar).weekCalendar('option', 'daysToShow') >= 5;
|
389
|
+
},
|
390
|
+
/**
|
391
|
+
* should the columns be rendered alternatively using odd/even
|
392
|
+
* class
|
393
|
+
* @type {boolean}
|
394
|
+
*/
|
395
|
+
displayOddEven: false,
|
396
|
+
textSize: 13,
|
397
|
+
/**
|
398
|
+
* the title attribute for the calendar. possible placeholders are:
|
399
|
+
* <ul>
|
400
|
+
* <li>%start%</li>
|
401
|
+
* <li>%end%</li>
|
402
|
+
* <li>%date%</li>
|
403
|
+
* </ul>
|
404
|
+
* @type {Function|string}
|
405
|
+
* @param {number} option daysToShow.
|
406
|
+
* @return {String} the title attribute for the calendar.
|
407
|
+
*/
|
408
|
+
title: '%start% - %end%',
|
409
|
+
/**
|
410
|
+
* default options to pass to callback
|
411
|
+
* you can pass a function returning an object or a litteral object
|
412
|
+
* @type {object|function(#calendar)}
|
413
|
+
*/
|
414
|
+
jsonOptions: {},
|
415
|
+
headerSeparator: '<br />',
|
416
|
+
/**
|
417
|
+
* returns formatted header for day display
|
418
|
+
* @type {function(date,calendar)}
|
419
|
+
*/
|
420
|
+
getHeaderDate: null,
|
421
|
+
preventDragOnEventCreation: false,
|
422
|
+
/**
|
423
|
+
* the event on which to bind calendar resize
|
424
|
+
* @type {string}
|
425
|
+
*/
|
426
|
+
resizeEvent: 'resize.weekcalendar'
|
427
|
+
},
|
428
|
+
|
429
|
+
/***********************
|
430
|
+
* Initialise calendar *
|
431
|
+
***********************/
|
432
|
+
_create: function() {
|
433
|
+
var self = this;
|
434
|
+
self._computeOptions();
|
435
|
+
self._setupEventDelegation();
|
436
|
+
self._renderCalendar();
|
437
|
+
self._loadCalEvents();
|
438
|
+
self._resizeCalendar();
|
439
|
+
self._scrollToHour(self.options.date.getHours(), true);
|
440
|
+
|
441
|
+
if (this.options.resizeEvent) {
|
442
|
+
$(window).unbind(this.options.resizeEvent);
|
443
|
+
$(window).bind(this.options.resizeEvent, function() {
|
444
|
+
self._resizeCalendar();
|
445
|
+
});
|
446
|
+
}
|
447
|
+
|
448
|
+
},
|
449
|
+
|
450
|
+
/********************
|
451
|
+
* public functions *
|
452
|
+
********************/
|
453
|
+
/*
|
454
|
+
* Refresh the events for the currently displayed week.
|
455
|
+
*/
|
456
|
+
refresh: function() {
|
457
|
+
//reload with existing week
|
458
|
+
this._loadCalEvents(this.element.data('startDate'));
|
459
|
+
},
|
460
|
+
|
461
|
+
/*
|
462
|
+
* Clear all events currently loaded into the calendar
|
463
|
+
*/
|
464
|
+
clear: function() {
|
465
|
+
this._clearCalendar();
|
466
|
+
},
|
467
|
+
|
468
|
+
/*
|
469
|
+
* Go to this week
|
470
|
+
*/
|
471
|
+
today: function() {
|
472
|
+
this._clearCalendar();
|
473
|
+
this._loadCalEvents(new Date());
|
474
|
+
},
|
475
|
+
|
476
|
+
/*
|
477
|
+
* Go to the previous week relative to the currently displayed week
|
478
|
+
*/
|
479
|
+
prevWeek: function() {
|
480
|
+
//minus more than 1 day to be sure we're in previous week - account for daylight savings or other anomolies
|
481
|
+
var newDate = new Date(this.element.data('startDate').getTime() - (MILLIS_IN_WEEK / 6));
|
482
|
+
this._clearCalendar();
|
483
|
+
this._loadCalEvents(newDate);
|
484
|
+
},
|
485
|
+
|
486
|
+
/*
|
487
|
+
* Go to the next week relative to the currently displayed week
|
488
|
+
*/
|
489
|
+
nextWeek: function() {
|
490
|
+
//add 8 days to be sure of being in prev week - allows for daylight savings or other anomolies
|
491
|
+
var newDate = new Date(this.element.data('startDate').getTime() + MILLIS_IN_WEEK + MILLIS_IN_DAY);
|
492
|
+
this._clearCalendar();
|
493
|
+
this._loadCalEvents(newDate);
|
494
|
+
},
|
495
|
+
|
496
|
+
/*
|
497
|
+
* Reload the calendar to whatever week the date passed in falls on.
|
498
|
+
*/
|
499
|
+
gotoWeek: function(date) {
|
500
|
+
this._clearCalendar();
|
501
|
+
this._loadCalEvents(date);
|
502
|
+
},
|
503
|
+
|
504
|
+
/*
|
505
|
+
* Reload the calendar to whatever week the date passed in falls on.
|
506
|
+
*/
|
507
|
+
gotoDate: function(date) {
|
508
|
+
this._clearCalendar();
|
509
|
+
this._loadCalEvents(date);
|
510
|
+
},
|
511
|
+
|
512
|
+
/**
|
513
|
+
* change the number of days to show
|
514
|
+
*/
|
515
|
+
setDaysToShow: function(daysToShow) {
|
516
|
+
var self = this;
|
517
|
+
var hour = self._getCurrentScrollHour();
|
518
|
+
self.options.daysToShow = daysToShow;
|
519
|
+
$(self.element).html('');
|
520
|
+
self._renderCalendar();
|
521
|
+
self._loadCalEvents();
|
522
|
+
self._resizeCalendar();
|
523
|
+
self._scrollToHour(hour, false);
|
524
|
+
|
525
|
+
if (this.options.resizeEvent) {
|
526
|
+
$(window).unbind(this.options.resizeEvent);
|
527
|
+
$(window).bind(this.options.resizeEvent, function() {
|
528
|
+
self._resizeCalendar();
|
529
|
+
});
|
530
|
+
}
|
531
|
+
},
|
532
|
+
|
533
|
+
/*
|
534
|
+
* Remove an event based on it's id
|
535
|
+
*/
|
536
|
+
removeEvent: function(eventId) {
|
537
|
+
|
538
|
+
var self = this;
|
539
|
+
|
540
|
+
self.element.find('.wc-cal-event').each(function() {
|
541
|
+
if ($(this).data('calEvent').id === eventId) {
|
542
|
+
$(this).remove();
|
543
|
+
return false;
|
544
|
+
}
|
545
|
+
});
|
546
|
+
|
547
|
+
//this could be more efficient rather than running on all days regardless...
|
548
|
+
self.element.find('.wc-day-column-inner').each(function() {
|
549
|
+
self._adjustOverlappingEvents($(this));
|
550
|
+
});
|
551
|
+
},
|
552
|
+
|
553
|
+
/*
|
554
|
+
* Removes any events that have been added but not yet saved (have no id).
|
555
|
+
* This is useful to call after adding a freshly saved new event.
|
556
|
+
*/
|
557
|
+
removeUnsavedEvents: function() {
|
558
|
+
|
559
|
+
var self = this;
|
560
|
+
|
561
|
+
self.element.find('.wc-new-cal-event').each(function() {
|
562
|
+
$(this).remove();
|
563
|
+
});
|
564
|
+
|
565
|
+
//this could be more efficient rather than running on all days regardless...
|
566
|
+
self.element.find('.wc-day-column-inner').each(function() {
|
567
|
+
self._adjustOverlappingEvents($(this));
|
568
|
+
});
|
569
|
+
},
|
570
|
+
|
571
|
+
/*
|
572
|
+
* update an event in the calendar. If the event exists it refreshes
|
573
|
+
* it's rendering. If it's a new event that does not exist in the calendar
|
574
|
+
* it will be added.
|
575
|
+
*/
|
576
|
+
updateEvent: function(calEvent) {
|
577
|
+
this._updateEventInCalendar(calEvent);
|
578
|
+
},
|
579
|
+
|
580
|
+
/*
|
581
|
+
* Returns an array of timeslot start and end times based on
|
582
|
+
* the configured grid of the calendar. Returns in both date and
|
583
|
+
* formatted time based on the 'timeFormat' config option.
|
584
|
+
*/
|
585
|
+
getTimeslotTimes: function(date) {
|
586
|
+
var options = this.options;
|
587
|
+
var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
|
588
|
+
var startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), firstHourDisplayed);
|
589
|
+
|
590
|
+
var times = [],
|
591
|
+
startMillis = startDate.getTime();
|
592
|
+
for (var i = 0; i < options.timeslotsPerDay; i++) {
|
593
|
+
var endMillis = startMillis + options.millisPerTimeslot;
|
594
|
+
times[i] = {
|
595
|
+
start: new Date(startMillis),
|
596
|
+
startFormatted: this.formatTime(new Date(startMillis), options.timeFormat),
|
597
|
+
end: new Date(endMillis),
|
598
|
+
endFormatted: this.formatTime(new Date(endMillis), options.timeFormat)
|
599
|
+
};
|
600
|
+
startMillis = endMillis;
|
601
|
+
}
|
602
|
+
return times;
|
603
|
+
},
|
604
|
+
|
605
|
+
formatDate: function(date, format) {
|
606
|
+
if (format) {
|
607
|
+
return this._formatDate(date, format);
|
608
|
+
} else {
|
609
|
+
return this._formatDate(date, this.options.dateFormat);
|
610
|
+
}
|
611
|
+
},
|
612
|
+
|
613
|
+
formatTime: function(date, format) {
|
614
|
+
if (format) {
|
615
|
+
return this._formatDate(date, format);
|
616
|
+
} else if (this.options.timeFormat) {
|
617
|
+
return this._formatDate(date, this.options.timeFormat);
|
618
|
+
} else if (this.options.use24Hour) {
|
619
|
+
return this._formatDate(date, 'H:i');
|
620
|
+
} else {
|
621
|
+
return this._formatDate(date, 'h:i a');
|
622
|
+
}
|
623
|
+
},
|
624
|
+
|
625
|
+
serializeEvents: function() {
|
626
|
+
var self = this;
|
627
|
+
var calEvents = [];
|
628
|
+
|
629
|
+
self.element.find('.wc-cal-event').each(function() {
|
630
|
+
calEvents.push($(this).data('calEvent'));
|
631
|
+
});
|
632
|
+
return calEvents;
|
633
|
+
},
|
634
|
+
|
635
|
+
next: function() {
|
636
|
+
if (this._startOnFirstDayOfWeek()) {
|
637
|
+
return this.nextWeek();
|
638
|
+
}
|
639
|
+
var newDate = new Date(this.element.data('startDate').getTime());
|
640
|
+
newDate.setDate(newDate.getDate() + this.options.daysToShow);
|
641
|
+
|
642
|
+
this._clearCalendar();
|
643
|
+
this._loadCalEvents(newDate);
|
644
|
+
},
|
645
|
+
|
646
|
+
prev: function() {
|
647
|
+
if (this._startOnFirstDayOfWeek()) {
|
648
|
+
return this.prevWeek();
|
649
|
+
}
|
650
|
+
var newDate = new Date(this.element.data('startDate').getTime());
|
651
|
+
newDate.setDate(newDate.getDate() - this.options.daysToShow);
|
652
|
+
|
653
|
+
this._clearCalendar();
|
654
|
+
this._loadCalEvents(newDate);
|
655
|
+
},
|
656
|
+
getCurrentFirstDay: function() {
|
657
|
+
return this._dateFirstDayOfWeek(this.options.date || new Date());
|
658
|
+
},
|
659
|
+
getCurrentLastDay: function() {
|
660
|
+
return this._addDays(this.getCurrentFirstDay(), this.options.daysToShow - 1);
|
661
|
+
},
|
662
|
+
|
663
|
+
/*********************
|
664
|
+
* private functions *
|
665
|
+
*********************/
|
666
|
+
_setOption: function(key, value) {
|
667
|
+
var self = this;
|
668
|
+
if (self.options[key] != value) {
|
669
|
+
// event callback change, no need to re-render the events
|
670
|
+
if (key == 'beforeEventNew') {
|
671
|
+
self.options[key] = value;
|
672
|
+
return;
|
673
|
+
}
|
674
|
+
|
675
|
+
// this could be made more efficient at some stage by caching the
|
676
|
+
// events array locally in a store but this should be done in conjunction
|
677
|
+
// with a proper binding model.
|
678
|
+
|
679
|
+
var currentEvents = $.map(self.element.find('.wc-cal-event'), function() {
|
680
|
+
return $(this).data('calEvent');
|
681
|
+
});
|
682
|
+
|
683
|
+
var newOptions = {};
|
684
|
+
newOptions[key] = value;
|
685
|
+
self._renderEvents({events: currentEvents, options: newOptions}, self.element.find('.wc-day-column-inner'));
|
686
|
+
}
|
687
|
+
},
|
688
|
+
|
689
|
+
// compute dynamic options based on other config values
|
690
|
+
_computeOptions: function() {
|
691
|
+
var options = this.options;
|
692
|
+
if (options.businessHours.limitDisplay) {
|
693
|
+
options.timeslotsPerDay = options.timeslotsPerHour * (options.businessHours.end - options.businessHours.start);
|
694
|
+
options.millisToDisplay = (options.businessHours.end - options.businessHours.start) * 3600000; // 60 * 60 * 1000
|
695
|
+
options.millisPerTimeslot = options.millisToDisplay / options.timeslotsPerDay;
|
696
|
+
} else {
|
697
|
+
options.timeslotsPerDay = options.timeslotsPerHour * 24;
|
698
|
+
options.millisToDisplay = MILLIS_IN_DAY;
|
699
|
+
options.millisPerTimeslot = MILLIS_IN_DAY / options.timeslotsPerDay;
|
700
|
+
}
|
701
|
+
},
|
702
|
+
|
703
|
+
/*
|
704
|
+
* Resize the calendar scrollable height based on the provided function in options.
|
705
|
+
*/
|
706
|
+
_resizeCalendar: function() {
|
707
|
+
var options = this.options;
|
708
|
+
if (options && $.isFunction(options.height)) {
|
709
|
+
var calendarHeight = options.height(this.element);
|
710
|
+
var headerHeight = this.element.find('.wc-header').outerHeight();
|
711
|
+
var navHeight = this.element.find('.wc-toolbar').outerHeight();
|
712
|
+
var scrollContainerHeight = Math.max(calendarHeight - navHeight - headerHeight, options.minBodyHeight);
|
713
|
+
var timeslotHeight = this.element.find('.wc-time-slots').outerHeight();
|
714
|
+
this.element.find('.wc-scrollable-grid').height(scrollContainerHeight);
|
715
|
+
if (timeslotHeight <= scrollContainerHeight) {
|
716
|
+
this.element.find('.wc-scrollbar-shim').width(0);
|
717
|
+
}
|
718
|
+
else {
|
719
|
+
this.element.find('.wc-scrollbar-shim').width(this._findScrollBarWidth());
|
720
|
+
}
|
721
|
+
this._trigger('resize', this.element);
|
722
|
+
}
|
723
|
+
},
|
724
|
+
|
725
|
+
_findScrollBarWidth: function() {
|
726
|
+
var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body');
|
727
|
+
var child = parent.children();
|
728
|
+
var width = child.innerWidth() - child.height(99).innerWidth();
|
729
|
+
parent.remove();
|
730
|
+
return width || /* default to 16 that is the average */ 16;
|
731
|
+
},
|
732
|
+
|
733
|
+
/*
|
734
|
+
* configure calendar interaction events that are able to use event
|
735
|
+
* delegation for greater efficiency
|
736
|
+
*/
|
737
|
+
_setupEventDelegation: function() {
|
738
|
+
var self = this;
|
739
|
+
var options = this.options;
|
740
|
+
this.element.click(function(event) {
|
741
|
+
var $target = $(event.target),
|
742
|
+
freeBusyManager;
|
743
|
+
if ($target.data('preventClick')) {
|
744
|
+
return;
|
745
|
+
}
|
746
|
+
var $calEvent = $target.hasClass('wc-cal-event') ? $target : $target.parents('.wc-cal-event');
|
747
|
+
if ($calEvent.length) {
|
748
|
+
freeBusyManager = self.getFreeBusyManagerForEvent($calEvent.data('calEvent'));
|
749
|
+
if (options.allowEventDelete && $target.hasClass('wc-cal-event-delete')) {
|
750
|
+
options.eventDelete($calEvent.data('calEvent'), $calEvent, freeBusyManager, self.element, event);
|
751
|
+
}else{
|
752
|
+
options.eventClick($calEvent.data('calEvent'), $calEvent, freeBusyManager, self.element, event);
|
753
|
+
}
|
754
|
+
}
|
755
|
+
}).mouseover(function(event) {
|
756
|
+
var $target = $(event.target);
|
757
|
+
|
758
|
+
if (self._isDraggingOrResizing($target)) {
|
759
|
+
return;
|
760
|
+
}
|
761
|
+
|
762
|
+
if ($target.hasClass('wc-cal-event')) {
|
763
|
+
options.eventMouseover($target.data('calEvent'), $target, event);
|
764
|
+
}
|
765
|
+
}).mouseout(function(event) {
|
766
|
+
var $target = $(event.target);
|
767
|
+
if (self._isDraggingOrResizing($target)) {
|
768
|
+
return;
|
769
|
+
}
|
770
|
+
if ($target.hasClass('wc-cal-event')) {
|
771
|
+
if ($target.data('sizing')) { return;}
|
772
|
+
options.eventMouseout($target.data('calEvent'), $target, event);
|
773
|
+
}
|
774
|
+
});
|
775
|
+
},
|
776
|
+
|
777
|
+
/*
|
778
|
+
* check if a ui draggable or resizable is currently being dragged or resized
|
779
|
+
*/
|
780
|
+
_isDraggingOrResizing: function($target) {
|
781
|
+
return $target.hasClass('ui-draggable-dragging') || $target.hasClass('ui-resizable-resizing');
|
782
|
+
},
|
783
|
+
|
784
|
+
/*
|
785
|
+
* Render the main calendar layout
|
786
|
+
*/
|
787
|
+
_renderCalendar: function() {
|
788
|
+
var $calendarContainer, $weekDayColumns;
|
789
|
+
var self = this;
|
790
|
+
var options = this.options;
|
791
|
+
|
792
|
+
$calendarContainer = $('<div class=\"ui-widget wc-container\">').appendTo(self.element);
|
793
|
+
|
794
|
+
//render the different parts
|
795
|
+
// nav links
|
796
|
+
self._renderCalendarButtons($calendarContainer);
|
797
|
+
// header
|
798
|
+
self._renderCalendarHeader($calendarContainer);
|
799
|
+
// body
|
800
|
+
self._renderCalendarBody($calendarContainer);
|
801
|
+
|
802
|
+
$weekDayColumns = $calendarContainer.find('.wc-day-column-inner');
|
803
|
+
$weekDayColumns.each(function(i, val) {
|
804
|
+
if (!options.readonly) {
|
805
|
+
self._addDroppableToWeekDay($(this));
|
806
|
+
if (options.allowEventCreation) {
|
807
|
+
self._setupEventCreationForWeekDay($(this));
|
808
|
+
}
|
809
|
+
}
|
810
|
+
});
|
811
|
+
},
|
812
|
+
|
813
|
+
/**
|
814
|
+
* render the nav buttons on top of the calendar
|
815
|
+
*/
|
816
|
+
_renderCalendarButtons: function($calendarContainer) {
|
817
|
+
var self = this, options = this.options;
|
818
|
+
if (options.buttons) {
|
819
|
+
var calendarNavHtml = '';
|
820
|
+
|
821
|
+
calendarNavHtml += '<div class=\"ui-widget-header wc-toolbar\">';
|
822
|
+
calendarNavHtml += '<div class=\"wc-display\"></div>';
|
823
|
+
calendarNavHtml += '<div class=\"wc-nav\">';
|
824
|
+
calendarNavHtml += '<button class=\"wc-prev\">' + options.buttonText.lastWeek + '</button>';
|
825
|
+
calendarNavHtml += '<button class=\"wc-today\">' + options.buttonText.today + '</button>';
|
826
|
+
calendarNavHtml += '<button class=\"wc-next\">' + options.buttonText.nextWeek + '</button>';
|
827
|
+
calendarNavHtml += '</div>';
|
828
|
+
calendarNavHtml += '<h1 class=\"wc-title\"></h1>';
|
829
|
+
calendarNavHtml += '</div>';
|
830
|
+
|
831
|
+
$(calendarNavHtml).appendTo($calendarContainer);
|
832
|
+
|
833
|
+
$calendarContainer.find('.wc-nav .wc-today')
|
834
|
+
.button({
|
835
|
+
icons: {primary: 'ui-icon-home'}})
|
836
|
+
.click(function() {
|
837
|
+
self.today();
|
838
|
+
return false;
|
839
|
+
});
|
840
|
+
|
841
|
+
$calendarContainer.find('.wc-nav .wc-prev')
|
842
|
+
.button({
|
843
|
+
text: false,
|
844
|
+
icons: {primary: 'ui-icon-seek-prev'}})
|
845
|
+
.click(function() {
|
846
|
+
self.element.weekCalendar('prev');
|
847
|
+
return false;
|
848
|
+
});
|
849
|
+
|
850
|
+
$calendarContainer.find('.wc-nav .wc-next')
|
851
|
+
.button({
|
852
|
+
text: false,
|
853
|
+
icons: {primary: 'ui-icon-seek-next'}})
|
854
|
+
.click(function() {
|
855
|
+
self.element.weekCalendar('next');
|
856
|
+
return false;
|
857
|
+
});
|
858
|
+
|
859
|
+
// now add buttons to switch display
|
860
|
+
if (this.options.switchDisplay && $.isPlainObject(this.options.switchDisplay)) {
|
861
|
+
var $container = $calendarContainer.find('.wc-display');
|
862
|
+
$.each(this.options.switchDisplay, function(label, option) {
|
863
|
+
var _id = 'wc-switch-display-' + option;
|
864
|
+
var _input = $('<input type="radio" id="' + _id + '" name="wc-switch-display" class="wc-switch-display"/>');
|
865
|
+
var _label = $('<label for="' + _id + '"></label>');
|
866
|
+
_label.html(label);
|
867
|
+
_input.val(option);
|
868
|
+
if (parseInt(self.options.daysToShow, 10) === parseInt(option, 10)) {
|
869
|
+
_input.attr('checked', 'checked');
|
870
|
+
}
|
871
|
+
$container
|
872
|
+
.append(_input)
|
873
|
+
.append(_label);
|
874
|
+
});
|
875
|
+
$container.find('input').change(function() {
|
876
|
+
self.setDaysToShow(parseInt($(this).val(), 10));
|
877
|
+
});
|
878
|
+
}
|
879
|
+
$calendarContainer.find('.wc-nav, .wc-display').buttonset();
|
880
|
+
var _height = $calendarContainer.find('.wc-nav').outerHeight();
|
881
|
+
$calendarContainer.find('.wc-title')
|
882
|
+
.height(_height)
|
883
|
+
.css('line-height', _height + 'px');
|
884
|
+
}else{
|
885
|
+
var calendarNavHtml = '';
|
886
|
+
calendarNavHtml += '<div class=\"ui-widget-header wc-toolbar\">';
|
887
|
+
calendarNavHtml += '<h1 class=\"wc-title\"></h1>';
|
888
|
+
calendarNavHtml += '</div>';
|
889
|
+
$(calendarNavHtml).appendTo($calendarContainer);
|
890
|
+
|
891
|
+
}
|
892
|
+
},
|
893
|
+
|
894
|
+
/**
|
895
|
+
* render the calendar header, including date and user header
|
896
|
+
*/
|
897
|
+
_renderCalendarHeader: function($calendarContainer) {
|
898
|
+
var self = this, options = this.options,
|
899
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
900
|
+
rowspan = '', colspan = '', calendarHeaderHtml;
|
901
|
+
|
902
|
+
if (showAsSeparatedUser) {
|
903
|
+
rowspan = ' rowspan=\"2\"';
|
904
|
+
colspan = ' colspan=\"' + options.users.length + '\" ';
|
905
|
+
}
|
906
|
+
|
907
|
+
//first row
|
908
|
+
calendarHeaderHtml = '<div class=\"ui-widget-content wc-header\">';
|
909
|
+
calendarHeaderHtml += '<table><tbody><tr><td class=\"wc-time-column-header\"></td>';
|
910
|
+
for (var i = 1; i <= options.daysToShow; i++) {
|
911
|
+
calendarHeaderHtml += '<td class=\"wc-day-column-header wc-day-' + i + '\"' + colspan + '></td>';
|
912
|
+
}
|
913
|
+
calendarHeaderHtml += '<td class=\"wc-scrollbar-shim\"' + rowspan + '></td></tr>';
|
914
|
+
|
915
|
+
//users row
|
916
|
+
if (showAsSeparatedUser) {
|
917
|
+
calendarHeaderHtml += '<tr><td class=\"wc-time-column-header\"></td>';
|
918
|
+
var uLength = options.users.length,
|
919
|
+
_headerClass = '';
|
920
|
+
|
921
|
+
for (var i = 1; i <= options.daysToShow; i++) {
|
922
|
+
for (var j = 0; j < uLength; j++) {
|
923
|
+
_headerClass = [];
|
924
|
+
if (j == 0) {
|
925
|
+
_headerClass.push('wc-day-column-first');
|
926
|
+
}
|
927
|
+
if (j == uLength - 1) {
|
928
|
+
_headerClass.push('wc-day-column-last');
|
929
|
+
}
|
930
|
+
if (!_headerClass.length) {
|
931
|
+
_headerClass = 'wc-day-column-middle';
|
932
|
+
}
|
933
|
+
else {
|
934
|
+
_headerClass = _headerClass.join(' ');
|
935
|
+
}
|
936
|
+
calendarHeaderHtml += '<td class=\"' + _headerClass + ' wc-user-header wc-day-' + i + ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
|
937
|
+
// calendarHeaderHtml+= "<div class=\"wc-user-header wc-day-" + i + " wc-user-" + self._getUserIdFromIndex(j) +"\" >";
|
938
|
+
calendarHeaderHtml += self._getUserName(j);
|
939
|
+
// calendarHeaderHtml+= "</div>";
|
940
|
+
calendarHeaderHtml += '</td>';
|
941
|
+
}
|
942
|
+
}
|
943
|
+
calendarHeaderHtml += '</tr>';
|
944
|
+
}
|
945
|
+
//close the header
|
946
|
+
calendarHeaderHtml += '</tbody></table></div>';
|
947
|
+
|
948
|
+
$(calendarHeaderHtml).appendTo($calendarContainer);
|
949
|
+
},
|
950
|
+
|
951
|
+
/**
|
952
|
+
* render the calendar body.
|
953
|
+
* Calendar body is composed of several distinct parts.
|
954
|
+
* Each part is displayed in a separated row to ease rendering.
|
955
|
+
* for further explanations, see each part rendering function.
|
956
|
+
*/
|
957
|
+
_renderCalendarBody: function($calendarContainer) {
|
958
|
+
var self = this, options = this.options,
|
959
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
960
|
+
$calendarBody, $calendarTableTbody;
|
961
|
+
// create the structure
|
962
|
+
$calendarBody = '<div class=\"wc-scrollable-grid\">';
|
963
|
+
$calendarBody += '<table class=\"wc-time-slots\">';
|
964
|
+
$calendarBody += '<tbody>';
|
965
|
+
$calendarBody += '</tbody>';
|
966
|
+
$calendarBody += '</table>';
|
967
|
+
$calendarBody += '</div>';
|
968
|
+
$calendarBody = $($calendarBody);
|
969
|
+
$calendarTableTbody = $calendarBody.find('tbody');
|
970
|
+
|
971
|
+
self._renderCalendarBodyTimeSlots($calendarTableTbody);
|
972
|
+
self._renderCalendarBodyOddEven($calendarTableTbody);
|
973
|
+
self._renderCalendarBodyFreeBusy($calendarTableTbody);
|
974
|
+
self._renderCalendarBodyEvents($calendarTableTbody);
|
975
|
+
|
976
|
+
$calendarBody.appendTo($calendarContainer);
|
977
|
+
|
978
|
+
//set the column height
|
979
|
+
$calendarContainer.find('.wc-full-height-column').height(options.timeslotHeight * options.timeslotsPerDay);
|
980
|
+
//set the timeslot height
|
981
|
+
$calendarContainer.find('.wc-time-slot').height(options.timeslotHeight - 1); //account for border
|
982
|
+
//init the time row header height
|
983
|
+
/**
|
984
|
+
TODO if total height for an hour is less than 11px, there is a display problem.
|
985
|
+
Find a way to handle it
|
986
|
+
*/
|
987
|
+
$calendarContainer.find('.wc-time-header-cell').css({
|
988
|
+
height: (options.timeslotHeight * options.timeslotsPerHour) - 11,
|
989
|
+
padding: 5
|
990
|
+
});
|
991
|
+
//add the user data to every impacted column
|
992
|
+
if (showAsSeparatedUser) {
|
993
|
+
for (var i = 0, uLength = options.users.length; i < uLength; i++) {
|
994
|
+
$calendarContainer.find('.wc-user-' + self._getUserIdFromIndex(i))
|
995
|
+
.data('wcUser', options.users[i])
|
996
|
+
.data('wcUserIndex', i)
|
997
|
+
.data('wcUserId', self._getUserIdFromIndex(i));
|
998
|
+
}
|
999
|
+
}
|
1000
|
+
},
|
1001
|
+
|
1002
|
+
/**
|
1003
|
+
* render the timeslots separation
|
1004
|
+
*/
|
1005
|
+
_renderCalendarBodyTimeSlots: function($calendarTableTbody) {
|
1006
|
+
var options = this.options,
|
1007
|
+
renderRow, i, j,
|
1008
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
1009
|
+
start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
|
1010
|
+
end = (options.businessHours.limitDisplay ? options.businessHours.end : 24),
|
1011
|
+
rowspan = 1;
|
1012
|
+
|
1013
|
+
//calculate the rowspan
|
1014
|
+
if (options.displayOddEven) { rowspan += 1; }
|
1015
|
+
if (options.displayFreeBusys) { rowspan += 1; }
|
1016
|
+
if (rowspan > 1) {
|
1017
|
+
rowspan = ' rowspan=\"' + rowspan + '\"';
|
1018
|
+
}
|
1019
|
+
else {
|
1020
|
+
rowspan = '';
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
renderRow = '<tr class=\"wc-grid-row-timeslot\">';
|
1024
|
+
renderRow += '<td class=\"wc-grid-timeslot-header\"' + rowspan + '></td>';
|
1025
|
+
renderRow += '<td colspan=\"' + options.daysToShow * (showAsSeparatedUser ? options.users.length : 1) + '\">';
|
1026
|
+
renderRow += '<div class=\"wc-no-height-wrapper wc-time-slot-wrapper\">';
|
1027
|
+
renderRow += '<div class=\"wc-time-slots\">';
|
1028
|
+
|
1029
|
+
for (i = start; i < end; i++) {
|
1030
|
+
for (j = 0; j < options.timeslotsPerHour - 1; j++) {
|
1031
|
+
renderRow += '<div class=\"wc-time-slot\"></div>';
|
1032
|
+
}
|
1033
|
+
renderRow += '<div class=\"wc-time-slot wc-hour-end\"></div>';
|
1034
|
+
}
|
1035
|
+
|
1036
|
+
renderRow += '</div>';
|
1037
|
+
renderRow += '</div>';
|
1038
|
+
renderRow += '</td>';
|
1039
|
+
renderRow += '</tr>';
|
1040
|
+
|
1041
|
+
$(renderRow).appendTo($calendarTableTbody);
|
1042
|
+
},
|
1043
|
+
|
1044
|
+
/**
|
1045
|
+
* render the odd even columns
|
1046
|
+
*/
|
1047
|
+
_renderCalendarBodyOddEven: function($calendarTableTbody) {
|
1048
|
+
if (this.options.displayOddEven) {
|
1049
|
+
var options = this.options,
|
1050
|
+
renderRow = '<tr class=\"wc-grid-row-oddeven\">',
|
1051
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
1052
|
+
oddEven,
|
1053
|
+
// let's take advantage of the jquery ui framework
|
1054
|
+
oddEvenClasses = {'odd': 'wc-column-odd', 'even': 'ui-state-hover wc-column-even'};
|
1055
|
+
|
1056
|
+
//now let's display oddEven placeholders
|
1057
|
+
for (var i = 1; i <= options.daysToShow; i++) {
|
1058
|
+
if (!showAsSeparatedUser) {
|
1059
|
+
oddEven = (oddEven == 'odd' ? 'even' : 'odd');
|
1060
|
+
renderRow += '<td class=\"wc-day-column day-' + i + '\">';
|
1061
|
+
renderRow += '<div class=\"wc-no-height-wrapper wc-oddeven-wrapper\">';
|
1062
|
+
renderRow += '<div class=\"wc-full-height-column ' + oddEvenClasses[oddEven] + '\"></div>';
|
1063
|
+
renderRow += '</div>';
|
1064
|
+
renderRow += '</td>';
|
1065
|
+
}
|
1066
|
+
else {
|
1067
|
+
var uLength = options.users.length;
|
1068
|
+
for (var j = 0; j < uLength; j++) {
|
1069
|
+
oddEven = (oddEven == 'odd' ? 'even' : 'odd');
|
1070
|
+
renderRow += '<td class=\"wc-day-column day-' + i + '\">';
|
1071
|
+
renderRow += '<div class=\"wc-no-height-wrapper wc-oddeven-wrapper\">';
|
1072
|
+
renderRow += '<div class=\"wc-full-height-column ' + oddEvenClasses[oddEven] + '\" ></div>';
|
1073
|
+
renderRow += '</div>';
|
1074
|
+
renderRow += '</td>';
|
1075
|
+
}
|
1076
|
+
}
|
1077
|
+
}
|
1078
|
+
renderRow += '</tr>';
|
1079
|
+
|
1080
|
+
$(renderRow).appendTo($calendarTableTbody);
|
1081
|
+
}
|
1082
|
+
},
|
1083
|
+
|
1084
|
+
/**
|
1085
|
+
* render the freebusy placeholders
|
1086
|
+
*/
|
1087
|
+
_renderCalendarBodyFreeBusy: function($calendarTableTbody) {
|
1088
|
+
if (this.options.displayFreeBusys) {
|
1089
|
+
var self = this, options = this.options,
|
1090
|
+
renderRow = '<tr class=\"wc-grid-row-freebusy\">',
|
1091
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
|
1092
|
+
renderRow += '</td>';
|
1093
|
+
|
1094
|
+
//now let's display freebusy placeholders
|
1095
|
+
for (var i = 1; i <= options.daysToShow; i++) {
|
1096
|
+
if (options.displayFreeBusys) {
|
1097
|
+
if (!showAsSeparatedUser) {
|
1098
|
+
renderRow += '<td class=\"wc-day-column day-' + i + '\">';
|
1099
|
+
renderRow += '<div class=\"wc-no-height-wrapper wc-freebusy-wrapper\">';
|
1100
|
+
renderRow += '<div class=\"wc-full-height-column wc-column-freebusy wc-day-' + i + '\"></div>';
|
1101
|
+
renderRow += '</div>';
|
1102
|
+
renderRow += '</td>';
|
1103
|
+
}
|
1104
|
+
else {
|
1105
|
+
var uLength = options.users.length;
|
1106
|
+
for (var j = 0; j < uLength; j++) {
|
1107
|
+
renderRow += '<td class=\"wc-day-column day-' + i + '\">';
|
1108
|
+
renderRow += '<div class=\"wc-no-height-wrapper wc-freebusy-wrapper\">';
|
1109
|
+
renderRow += '<div class=\"wc-full-height-column wc-column-freebusy wc-day-' + i;
|
1110
|
+
renderRow += ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
|
1111
|
+
renderRow += '</div>';
|
1112
|
+
renderRow += '</div>';
|
1113
|
+
renderRow += '</td>';
|
1114
|
+
}
|
1115
|
+
}
|
1116
|
+
}
|
1117
|
+
}
|
1118
|
+
|
1119
|
+
renderRow += '</tr>';
|
1120
|
+
|
1121
|
+
$(renderRow).appendTo($calendarTableTbody);
|
1122
|
+
}
|
1123
|
+
},
|
1124
|
+
|
1125
|
+
/**
|
1126
|
+
* render the calendar body for event placeholders
|
1127
|
+
*/
|
1128
|
+
_renderCalendarBodyEvents: function($calendarTableTbody) {
|
1129
|
+
var self = this, options = this.options,
|
1130
|
+
renderRow,
|
1131
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
1132
|
+
start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
|
1133
|
+
end = (options.businessHours.limitDisplay ? options.businessHours.end : 24);
|
1134
|
+
renderRow = '<tr class=\"wc-grid-row-events\">';
|
1135
|
+
renderRow += '<td class=\"wc-grid-timeslot-header\">';
|
1136
|
+
for (var i = start; i < end; i++) {
|
1137
|
+
var bhClass = (options.businessHours.start <= i && options.businessHours.end > i) ? 'ui-state-active wc-business-hours' : 'ui-state-default';
|
1138
|
+
renderRow += '<div class=\"wc-hour-header ' + bhClass + '\">';
|
1139
|
+
if (options.use24Hour) {
|
1140
|
+
renderRow += '<div class=\"wc-time-header-cell\">' + self._24HourForIndex(i) + '</div>';
|
1141
|
+
}
|
1142
|
+
else {
|
1143
|
+
renderRow += '<div class=\"wc-time-header-cell\">' + self._hourForIndex(i) + '<span class=\"wc-am-pm\">' + self._amOrPm(i) + '</span></div>';
|
1144
|
+
}
|
1145
|
+
renderRow += '</div>';
|
1146
|
+
}
|
1147
|
+
renderRow += '</td>';
|
1148
|
+
|
1149
|
+
//now let's display events placeholders
|
1150
|
+
var _columnBaseClass = 'ui-state-default wc-day-column';
|
1151
|
+
for (var i = 1; i <= options.daysToShow; i++) {
|
1152
|
+
if (!showAsSeparatedUser) {
|
1153
|
+
renderRow += '<td class=\"' + _columnBaseClass + ' wc-day-column-first wc-day-column-last day-' + i + '\">';
|
1154
|
+
renderRow += '<div class=\"wc-full-height-column wc-day-column-inner day-' + i + '\"></div>';
|
1155
|
+
renderRow += '</td>';
|
1156
|
+
}
|
1157
|
+
else {
|
1158
|
+
var uLength = options.users.length;
|
1159
|
+
var columnclass;
|
1160
|
+
for (var j = 0; j < uLength; j++) {
|
1161
|
+
columnclass = [];
|
1162
|
+
if (j == 0) {
|
1163
|
+
columnclass.push('wc-day-column-first');
|
1164
|
+
}
|
1165
|
+
if (j == uLength - 1) {
|
1166
|
+
columnclass.push('wc-day-column-last');
|
1167
|
+
}
|
1168
|
+
if (!columnclass.length) {
|
1169
|
+
columnclass = 'wc-day-column-middle';
|
1170
|
+
}
|
1171
|
+
else {
|
1172
|
+
columnclass = columnclass.join(' ');
|
1173
|
+
}
|
1174
|
+
renderRow += '<td class=\"' + _columnBaseClass + ' ' + columnclass + ' day-' + i + '\">';
|
1175
|
+
renderRow += '<div class=\"wc-full-height-column wc-day-column-inner day-' + i;
|
1176
|
+
renderRow += ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
|
1177
|
+
renderRow += '</div>';
|
1178
|
+
renderRow += '</td>';
|
1179
|
+
}
|
1180
|
+
}
|
1181
|
+
}
|
1182
|
+
|
1183
|
+
renderRow += '</tr>';
|
1184
|
+
|
1185
|
+
$(renderRow).appendTo($calendarTableTbody);
|
1186
|
+
},
|
1187
|
+
|
1188
|
+
/*
|
1189
|
+
* setup mouse events for capturing new events
|
1190
|
+
*/
|
1191
|
+
_setupEventCreationForWeekDay: function($weekDay) {
|
1192
|
+
var self = this;
|
1193
|
+
var options = this.options;
|
1194
|
+
$weekDay.mousedown(function(event) {
|
1195
|
+
var $target = $(event.target);
|
1196
|
+
if ($target.hasClass('wc-day-column-inner')) {
|
1197
|
+
|
1198
|
+
var $newEvent = $('<div class=\"wc-cal-event wc-new-cal-event wc-new-cal-event-creating\"></div>');
|
1199
|
+
|
1200
|
+
$newEvent.css({lineHeight: (options.timeslotHeight - 2) + 'px', fontSize: (options.timeslotHeight / 2) + 'px'});
|
1201
|
+
$target.append($newEvent);
|
1202
|
+
|
1203
|
+
var columnOffset = $target.offset().top;
|
1204
|
+
var clickY = event.pageY - columnOffset;
|
1205
|
+
var clickYRounded = (clickY - (clickY % options.timeslotHeight)) / options.timeslotHeight;
|
1206
|
+
var topPosition = clickYRounded * options.timeslotHeight;
|
1207
|
+
$newEvent.css({top: topPosition});
|
1208
|
+
|
1209
|
+
if (!options.preventDragOnEventCreation) {
|
1210
|
+
$target.bind('mousemove.newevent', function(event) {
|
1211
|
+
$newEvent.show();
|
1212
|
+
$newEvent.addClass('ui-resizable-resizing');
|
1213
|
+
var height = Math.round(event.pageY - columnOffset - topPosition);
|
1214
|
+
var remainder = height % options.timeslotHeight;
|
1215
|
+
//snap to closest timeslot
|
1216
|
+
if (remainder < 0) {
|
1217
|
+
var useHeight = height - remainder;
|
1218
|
+
$newEvent.css('height', useHeight < options.timeslotHeight ? options.timeslotHeight : useHeight);
|
1219
|
+
} else {
|
1220
|
+
$newEvent.css('height', height + (options.timeslotHeight - remainder));
|
1221
|
+
}
|
1222
|
+
}).mouseup(function() {
|
1223
|
+
$target.unbind('mousemove.newevent');
|
1224
|
+
$newEvent.addClass('ui-corner-all');
|
1225
|
+
});
|
1226
|
+
}
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
}).mouseup(function(event) {
|
1230
|
+
var $target = $(event.target);
|
1231
|
+
|
1232
|
+
var $weekDay = $target.closest('.wc-day-column-inner');
|
1233
|
+
var $newEvent = $weekDay.find('.wc-new-cal-event-creating');
|
1234
|
+
|
1235
|
+
if ($newEvent.length) {
|
1236
|
+
var createdFromSingleClick = !$newEvent.hasClass('ui-resizable-resizing');
|
1237
|
+
|
1238
|
+
//if even created from a single click only, default height
|
1239
|
+
if (createdFromSingleClick) {
|
1240
|
+
$newEvent.css({height: options.timeslotHeight * options.defaultEventLength}).show();
|
1241
|
+
}
|
1242
|
+
var top = parseInt($newEvent.css('top'));
|
1243
|
+
var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $newEvent, top);
|
1244
|
+
|
1245
|
+
$newEvent.remove();
|
1246
|
+
var newCalEvent = {start: eventDuration.start, end: eventDuration.end, title: options.newEventText};
|
1247
|
+
var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
|
1248
|
+
|
1249
|
+
if (showAsSeparatedUser) {
|
1250
|
+
newCalEvent = self._setEventUserId(newCalEvent, $weekDay.data('wcUserId'));
|
1251
|
+
}
|
1252
|
+
else if (!options.showAsSeparateUsers && options.users && options.users.length == 1) {
|
1253
|
+
newCalEvent = self._setEventUserId(newCalEvent, self._getUserIdFromIndex(0));
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
var freeBusyManager = self.getFreeBusyManagerForEvent(newCalEvent);
|
1257
|
+
|
1258
|
+
var $renderedCalEvent = self._renderEvent(newCalEvent, $weekDay);
|
1259
|
+
|
1260
|
+
if (!options.allowCalEventOverlap) {
|
1261
|
+
self._adjustForEventCollisions($weekDay, $renderedCalEvent, newCalEvent, newCalEvent);
|
1262
|
+
self._positionEvent($weekDay, $renderedCalEvent);
|
1263
|
+
} else {
|
1264
|
+
self._adjustOverlappingEvents($weekDay);
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
var proceed = self._trigger('beforeEventNew', event, {
|
1268
|
+
'calEvent': newCalEvent,
|
1269
|
+
'createdFromSingleClick': createdFromSingleClick,
|
1270
|
+
'calendar': self.element
|
1271
|
+
});
|
1272
|
+
if (proceed) {
|
1273
|
+
options.eventNew(newCalEvent, $renderedCalEvent, freeBusyManager, self.element, event);
|
1274
|
+
}
|
1275
|
+
else {
|
1276
|
+
$($renderedCalEvent).remove();
|
1277
|
+
}
|
1278
|
+
}
|
1279
|
+
});
|
1280
|
+
},
|
1281
|
+
|
1282
|
+
/*
|
1283
|
+
* load calendar events for the week based on the date provided
|
1284
|
+
*/
|
1285
|
+
_loadCalEvents: function(dateWithinWeek) {
|
1286
|
+
|
1287
|
+
var date, weekStartDate, weekEndDate, $weekDayColumns;
|
1288
|
+
var self = this;
|
1289
|
+
var options = this.options;
|
1290
|
+
date = this._fixMinMaxDate(dateWithinWeek || options.date);
|
1291
|
+
// if date is not provided
|
1292
|
+
// or was not set
|
1293
|
+
// or is different than old one
|
1294
|
+
if ((!date || !date.getTime) ||
|
1295
|
+
(!options.date || !options.date.getTime) ||
|
1296
|
+
date.getTime() != options.date.getTime()
|
1297
|
+
) {
|
1298
|
+
// trigger the changedate event
|
1299
|
+
this._trigger('changedate', this.element, date);
|
1300
|
+
}
|
1301
|
+
this.options.date = date;
|
1302
|
+
weekStartDate = self._dateFirstDayOfWeek(date);
|
1303
|
+
weekEndDate = self._dateLastMilliOfWeek(date);
|
1304
|
+
|
1305
|
+
options.calendarBeforeLoad(self.element);
|
1306
|
+
|
1307
|
+
self.element.data('startDate', weekStartDate);
|
1308
|
+
self.element.data('endDate', weekEndDate);
|
1309
|
+
|
1310
|
+
$weekDayColumns = self.element.find('.wc-day-column-inner');
|
1311
|
+
|
1312
|
+
self._updateDayColumnHeader($weekDayColumns);
|
1313
|
+
|
1314
|
+
//load events by chosen means
|
1315
|
+
if (typeof options.data == 'string') {
|
1316
|
+
if (options.loading) {
|
1317
|
+
options.loading(true);
|
1318
|
+
}
|
1319
|
+
if (_currentAjaxCall) {
|
1320
|
+
// first abort current request.
|
1321
|
+
if (!_jQuery14OrLower) {
|
1322
|
+
_currentAjaxCall.abort();
|
1323
|
+
} else {
|
1324
|
+
// due to the fact that jquery 1.4 does not detect a request was
|
1325
|
+
// aborted, we need to replace the onreadystatechange and
|
1326
|
+
// execute the "complete" callback.
|
1327
|
+
_currentAjaxCall.onreadystatechange = null;
|
1328
|
+
_currentAjaxCall.abort();
|
1329
|
+
_currentAjaxCall = null;
|
1330
|
+
if (options.loading) {
|
1331
|
+
options.loading(false);
|
1332
|
+
}
|
1333
|
+
}
|
1334
|
+
}
|
1335
|
+
var jsonOptions = self._getJsonOptions();
|
1336
|
+
jsonOptions[options.startParam || 'start'] = Math.round(weekStartDate.getTime() / 1000);
|
1337
|
+
jsonOptions[options.endParam || 'end'] = Math.round(weekEndDate.getTime() / 1000);
|
1338
|
+
_currentAjaxCall = $.ajax({
|
1339
|
+
url: options.data,
|
1340
|
+
data: jsonOptions,
|
1341
|
+
dataType: 'json',
|
1342
|
+
error: function(XMLHttpRequest, textStatus, errorThrown) {
|
1343
|
+
// only prevent error with jQuery 1.5
|
1344
|
+
// see issue #34. thanks to dapplebeforedawn
|
1345
|
+
// (https://github.com/themouette/jquery-week-calendar/issues#issue/34)
|
1346
|
+
// for 1.5+, aborted request mean errorThrown == 'abort'
|
1347
|
+
// for prior version it means !errorThrown && !XMLHttpRequest.status
|
1348
|
+
// fixes #55
|
1349
|
+
if (errorThrown != 'abort' && XMLHttpRequest.status != 0) {
|
1350
|
+
alert('unable to get data, error:' + textStatus);
|
1351
|
+
}
|
1352
|
+
},
|
1353
|
+
success: function(data) {
|
1354
|
+
self._renderEvents(data, $weekDayColumns);
|
1355
|
+
},
|
1356
|
+
complete: function() {
|
1357
|
+
_currentAjaxCall = null;
|
1358
|
+
if (options.loading) {
|
1359
|
+
options.loading(false);
|
1360
|
+
}
|
1361
|
+
}
|
1362
|
+
});
|
1363
|
+
}
|
1364
|
+
else if ($.isFunction(options.data)) {
|
1365
|
+
options.data(weekStartDate, weekEndDate,
|
1366
|
+
function(data) {
|
1367
|
+
self._renderEvents(data, $weekDayColumns);
|
1368
|
+
});
|
1369
|
+
}
|
1370
|
+
else if (options.data) {
|
1371
|
+
self._renderEvents(options.data, $weekDayColumns);
|
1372
|
+
}
|
1373
|
+
|
1374
|
+
self._disableTextSelect($weekDayColumns);
|
1375
|
+
|
1376
|
+
|
1377
|
+
},
|
1378
|
+
|
1379
|
+
/*
|
1380
|
+
* update the display of each day column header based on the calendar week
|
1381
|
+
*/
|
1382
|
+
_updateDayColumnHeader: function($weekDayColumns) {
|
1383
|
+
var self = this;
|
1384
|
+
var options = this.options;
|
1385
|
+
var currentDay = self._cloneDate(self.element.data('startDate'));
|
1386
|
+
var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
|
1387
|
+
var todayClass = 'ui-state-active wc-today';
|
1388
|
+
|
1389
|
+
self.element.find('.wc-header td.wc-day-column-header').each(function(i, val) {
|
1390
|
+
$(this).html(self._getHeaderDate(currentDay));
|
1391
|
+
if (self._isToday(currentDay)) {
|
1392
|
+
$(this).addClass(todayClass);
|
1393
|
+
} else {
|
1394
|
+
$(this).removeClass(todayClass);
|
1395
|
+
}
|
1396
|
+
currentDay = self._addDays(currentDay, 1);
|
1397
|
+
|
1398
|
+
});
|
1399
|
+
|
1400
|
+
currentDay = self._cloneDate(self.element.data('startDate'));
|
1401
|
+
if (showAsSeparatedUser)
|
1402
|
+
{
|
1403
|
+
self.element.find('.wc-header td.wc-user-header').each(function(i, val) {
|
1404
|
+
if (self._isToday(currentDay)) {
|
1405
|
+
$(this).addClass(todayClass);
|
1406
|
+
} else {
|
1407
|
+
$(this).removeClass(todayClass);
|
1408
|
+
}
|
1409
|
+
currentDay = ((i + 1) % options.users.length) ? currentDay : self._addDays(currentDay, 1);
|
1410
|
+
});
|
1411
|
+
}
|
1412
|
+
|
1413
|
+
currentDay = self._cloneDate(self.element.data('startDate'));
|
1414
|
+
|
1415
|
+
$weekDayColumns.each(function(i, val) {
|
1416
|
+
|
1417
|
+
$(this).data('startDate', self._cloneDate(currentDay));
|
1418
|
+
$(this).data('endDate', new Date(currentDay.getTime() + (MILLIS_IN_DAY)));
|
1419
|
+
if (self._isToday(currentDay)) {
|
1420
|
+
$(this).parent()
|
1421
|
+
.addClass(todayClass)
|
1422
|
+
.removeClass('ui-state-default');
|
1423
|
+
} else {
|
1424
|
+
$(this).parent()
|
1425
|
+
.removeClass(todayClass)
|
1426
|
+
.addClass('ui-state-default');
|
1427
|
+
}
|
1428
|
+
|
1429
|
+
if (!showAsSeparatedUser || !((i + 1) % options.users.length)) {
|
1430
|
+
currentDay = self._addDays(currentDay, 1);
|
1431
|
+
}
|
1432
|
+
});
|
1433
|
+
|
1434
|
+
//now update the freeBusy placeholders
|
1435
|
+
if (options.displayFreeBusys) {
|
1436
|
+
currentDay = self._cloneDate(self.element.data('startDate'));
|
1437
|
+
self.element.find('.wc-grid-row-freebusy .wc-column-freebusy').each(function(i, val) {
|
1438
|
+
$(this).data('startDate', self._cloneDate(currentDay));
|
1439
|
+
$(this).data('endDate', new Date(currentDay.getTime() + (MILLIS_IN_DAY)));
|
1440
|
+
if (!showAsSeparatedUser || !((i + 1) % options.users.length)) {
|
1441
|
+
currentDay = self._addDays(currentDay, 1);
|
1442
|
+
}
|
1443
|
+
});
|
1444
|
+
}
|
1445
|
+
|
1446
|
+
//now update the calendar title
|
1447
|
+
if (this.options.title && this.options.title.length) {
|
1448
|
+
var _date = this.options.date,
|
1449
|
+
_start = self._cloneDate(self.element.data('startDate')),
|
1450
|
+
_end = self._dateLastDayOfWeek(new Date(this._cloneDate(self.element.data('endDate')).getTime() - (MILLIS_IN_DAY))),
|
1451
|
+
_title = this._getCalendarTitle();
|
1452
|
+
_title = _title.split('%start%').join(self._formatDate(_start, options.dateFormat));
|
1453
|
+
_title = _title.split('%end%').join(self._formatDate(_end, options.dateFormat));
|
1454
|
+
_title = _title.split('%date%').join(self._formatDate(_date, options.dateFormat));
|
1455
|
+
$('.wc-toolbar .wc-title', self.element).html(_title);
|
1456
|
+
}
|
1457
|
+
//self._clearFreeBusys();
|
1458
|
+
},
|
1459
|
+
|
1460
|
+
/*
|
1461
|
+
* gets the calendar title options
|
1462
|
+
*/
|
1463
|
+
_getCalendarTitle: function() {
|
1464
|
+
if ($.isFunction(this.options.title)) {
|
1465
|
+
return this.options.title(this.options.daysToShow);
|
1466
|
+
}
|
1467
|
+
return this.options.title;
|
1468
|
+
},
|
1469
|
+
|
1470
|
+
/*
|
1471
|
+
* Render the events into the calendar
|
1472
|
+
*/
|
1473
|
+
_renderEvents: function(data, $weekDayColumns) {
|
1474
|
+
var self = this;
|
1475
|
+
var options = this.options;
|
1476
|
+
var eventsToRender;
|
1477
|
+
|
1478
|
+
if (data.options) {
|
1479
|
+
var updateLayout = false;
|
1480
|
+
//update options
|
1481
|
+
$.each(data.options, function(key, value) {
|
1482
|
+
if (value !== options[key]) {
|
1483
|
+
options[key] = value;
|
1484
|
+
updateLayout = updateLayout || $.ui.weekCalendar.updateLayoutOptions[key];
|
1485
|
+
}
|
1486
|
+
});
|
1487
|
+
|
1488
|
+
self._computeOptions();
|
1489
|
+
|
1490
|
+
if (updateLayout) {
|
1491
|
+
var hour = self._getCurrentScrollHour();
|
1492
|
+
self.element.empty();
|
1493
|
+
self._renderCalendar();
|
1494
|
+
$weekDayColumns = self.element.find('.wc-time-slots .wc-day-column-inner');
|
1495
|
+
self._updateDayColumnHeader($weekDayColumns);
|
1496
|
+
self._resizeCalendar();
|
1497
|
+
self._scrollToHour(hour, false);
|
1498
|
+
}
|
1499
|
+
}
|
1500
|
+
this._clearCalendar();
|
1501
|
+
|
1502
|
+
if ($.isArray(data)) {
|
1503
|
+
eventsToRender = self._cleanEvents(data);
|
1504
|
+
} else if (data.events) {
|
1505
|
+
eventsToRender = self._cleanEvents(data.events);
|
1506
|
+
//render the freebusys
|
1507
|
+
self._renderFreeBusys(data);
|
1508
|
+
}
|
1509
|
+
$.each(eventsToRender, function(i, calEvent) {
|
1510
|
+
//render a multi day event as various event :
|
1511
|
+
//thanks to http://github.com/fbeauchamp/jquery-week-calendar
|
1512
|
+
var initialStart = new Date(calEvent.start);
|
1513
|
+
var initialEnd = new Date(calEvent.end);
|
1514
|
+
var maxHour = self.options.businessHours.limitDisplay ? self.options.businessHours.end : 24;
|
1515
|
+
var minHour = self.options.businessHours.limitDisplay ? self.options.businessHours.start : 0;
|
1516
|
+
var start = new Date(initialStart);
|
1517
|
+
var startDate = self._formatDate(start, 'Ymd');
|
1518
|
+
var endDate = self._formatDate(initialEnd, 'Ymd');
|
1519
|
+
var $weekDay;
|
1520
|
+
var isMultiday = false;
|
1521
|
+
|
1522
|
+
while (startDate < endDate) {
|
1523
|
+
calEvent.start = start;
|
1524
|
+
//end of this virual calEvent is set to the end of the day
|
1525
|
+
calEvent.end.setFullYear(start.getFullYear());
|
1526
|
+
calEvent.end.setDate(start.getDate());
|
1527
|
+
calEvent.end.setMonth(start.getMonth());
|
1528
|
+
calEvent.end.setHours(maxHour);
|
1529
|
+
calEvent.end.setMinutes(0);
|
1530
|
+
calEvent.end.setSeconds(0);
|
1531
|
+
if (($weekDay = self._findWeekDayForEvent(calEvent, $weekDayColumns))) {
|
1532
|
+
self._renderEvent(calEvent, $weekDay);
|
1533
|
+
}
|
1534
|
+
//start is set to the begin of the new day
|
1535
|
+
start.setDate(start.getDate() + 1);
|
1536
|
+
start.setHours(minHour);
|
1537
|
+
start.setMinutes(0);
|
1538
|
+
start.setSeconds(0);
|
1539
|
+
startDate = self._formatDate(start, 'Ymd');
|
1540
|
+
isMultiday = true;
|
1541
|
+
}
|
1542
|
+
if (start <= initialEnd) {
|
1543
|
+
calEvent.start = start;
|
1544
|
+
calEvent.end = initialEnd;
|
1545
|
+
if (((isMultiday && calEvent.start.getTime() != calEvent.end.getTime()) || !isMultiday) && ($weekDay = self._findWeekDayForEvent(calEvent, $weekDayColumns))) {
|
1546
|
+
self._renderEvent(calEvent, $weekDay);
|
1547
|
+
}
|
1548
|
+
}
|
1549
|
+
|
1550
|
+
//put back the initial start date
|
1551
|
+
calEvent.start = initialStart;
|
1552
|
+
});
|
1553
|
+
|
1554
|
+
$weekDayColumns.each(function() {
|
1555
|
+
self._adjustOverlappingEvents($(this));
|
1556
|
+
});
|
1557
|
+
|
1558
|
+
options.calendarAfterLoad(self.element);
|
1559
|
+
|
1560
|
+
if (!eventsToRender.length) {
|
1561
|
+
options.noEvents();
|
1562
|
+
}
|
1563
|
+
|
1564
|
+
},
|
1565
|
+
|
1566
|
+
/*
|
1567
|
+
* Render a specific event into the day provided. Assumes correct
|
1568
|
+
* day for calEvent date
|
1569
|
+
*/
|
1570
|
+
_renderEvent: function(calEvent, $weekDay) {
|
1571
|
+
var self = this;
|
1572
|
+
var options = this.options;
|
1573
|
+
if (calEvent.start.getTime() > calEvent.end.getTime()) {
|
1574
|
+
return; // can't render a negative height
|
1575
|
+
}
|
1576
|
+
|
1577
|
+
var eventClass, eventHtml, $calEventList, $modifiedEvent;
|
1578
|
+
|
1579
|
+
eventClass = calEvent.id ? 'wc-cal-event' : 'wc-cal-event wc-new-cal-event';
|
1580
|
+
eventHtml = '<div class=\"' + eventClass + ' ui-corner-all\">';
|
1581
|
+
eventHtml += '<div class=\"wc-time ui-corner-top\"></div>';
|
1582
|
+
eventHtml += '<div class=\"wc-title\"></div></div>';
|
1583
|
+
|
1584
|
+
$weekDay.each(function() {
|
1585
|
+
var $calEvent = $(eventHtml);
|
1586
|
+
$modifiedEvent = options.eventRender(calEvent, $calEvent);
|
1587
|
+
$calEvent = $modifiedEvent ? $modifiedEvent.appendTo($(this)) : $calEvent.appendTo($(this));
|
1588
|
+
$calEvent.css({lineHeight: (options.textSize + 2) + 'px', fontSize: options.textSize + 'px'});
|
1589
|
+
|
1590
|
+
self._refreshEventDetails(calEvent, $calEvent);
|
1591
|
+
self._positionEvent($(this), $calEvent);
|
1592
|
+
|
1593
|
+
//add to event list
|
1594
|
+
if ($calEventList) {
|
1595
|
+
$calEventList = $calEventList.add($calEvent);
|
1596
|
+
}
|
1597
|
+
else {
|
1598
|
+
$calEventList = $calEvent;
|
1599
|
+
}
|
1600
|
+
});
|
1601
|
+
$calEventList.show();
|
1602
|
+
|
1603
|
+
if (!options.readonly && options.resizable(calEvent, $calEventList)) {
|
1604
|
+
self._addResizableToCalEvent(calEvent, $calEventList, $weekDay);
|
1605
|
+
}
|
1606
|
+
if (!options.readonly && options.draggable(calEvent, $calEventList)) {
|
1607
|
+
self._addDraggableToCalEvent(calEvent, $calEventList);
|
1608
|
+
}
|
1609
|
+
options.eventAfterRender(calEvent, $calEventList);
|
1610
|
+
|
1611
|
+
return $calEventList;
|
1612
|
+
|
1613
|
+
},
|
1614
|
+
addEvent: function() {
|
1615
|
+
return this._renderEvent.apply(this, arguments);
|
1616
|
+
},
|
1617
|
+
|
1618
|
+
_adjustOverlappingEvents: function($weekDay) {
|
1619
|
+
var self = this;
|
1620
|
+
if (self.options.allowCalEventOverlap) {
|
1621
|
+
var groupsList = self._groupOverlappingEventElements($weekDay);
|
1622
|
+
$.each(groupsList, function() {
|
1623
|
+
var curGroups = this;
|
1624
|
+
$.each(curGroups, function(groupIndex) {
|
1625
|
+
var curGroup = this;
|
1626
|
+
|
1627
|
+
// do we want events to be displayed as overlapping
|
1628
|
+
if (self.options.overlapEventsSeparate) {
|
1629
|
+
var newWidth = self.options.totalEventsWidthPercentInOneColumn / curGroups.length;
|
1630
|
+
var newLeft = groupIndex * newWidth;
|
1631
|
+
} else {
|
1632
|
+
// TODO what happens when the group has more than 10 elements
|
1633
|
+
var newWidth = self.options.totalEventsWidthPercentInOneColumn - ((curGroups.length - 1) * 10);
|
1634
|
+
var newLeft = groupIndex * 10;
|
1635
|
+
}
|
1636
|
+
$.each(curGroup, function() {
|
1637
|
+
// bring mouseovered event to the front
|
1638
|
+
if (!self.options.overlapEventsSeparate) {
|
1639
|
+
$(this).bind('mouseover.z-index', function() {
|
1640
|
+
var $elem = $(this);
|
1641
|
+
$.each(curGroup, function() {
|
1642
|
+
$(this).css({'z-index': '1'});
|
1643
|
+
});
|
1644
|
+
$elem.css({'z-index': '3'});
|
1645
|
+
});
|
1646
|
+
}
|
1647
|
+
$(this).css({width: newWidth + '%', left: newLeft + '%', right: 0});
|
1648
|
+
});
|
1649
|
+
});
|
1650
|
+
});
|
1651
|
+
}
|
1652
|
+
},
|
1653
|
+
|
1654
|
+
|
1655
|
+
/*
|
1656
|
+
* Find groups of overlapping events
|
1657
|
+
*/
|
1658
|
+
_groupOverlappingEventElements: function($weekDay) {
|
1659
|
+
var $events = $weekDay.find('.wc-cal-event:visible');
|
1660
|
+
var sortedEvents = $events.sort(function(a, b) {
|
1661
|
+
return $(a).data('calEvent').start.getTime() - $(b).data('calEvent').start.getTime();
|
1662
|
+
});
|
1663
|
+
|
1664
|
+
var lastEndTime = new Date(0, 0, 0);
|
1665
|
+
var groups = [];
|
1666
|
+
var curGroups = [];
|
1667
|
+
var $curEvent;
|
1668
|
+
$.each(sortedEvents, function() {
|
1669
|
+
$curEvent = $(this);
|
1670
|
+
//checks, if the current group list is not empty, if the overlapping is finished
|
1671
|
+
if (curGroups.length > 0) {
|
1672
|
+
if (lastEndTime.getTime() <= $curEvent.data('calEvent').start.getTime()) {
|
1673
|
+
//finishes the current group list by adding it to the resulting list of groups and cleans it
|
1674
|
+
|
1675
|
+
groups.push(curGroups);
|
1676
|
+
curGroups = [];
|
1677
|
+
}
|
1678
|
+
}
|
1679
|
+
|
1680
|
+
//finds the first group to fill with the event
|
1681
|
+
for (var groupIndex = 0; groupIndex < curGroups.length; groupIndex++) {
|
1682
|
+
if (curGroups[groupIndex].length > 0) {
|
1683
|
+
//checks if the event starts after the end of the last event of the group
|
1684
|
+
if (curGroups[groupIndex][curGroups[groupIndex].length - 1].data('calEvent').end.getTime() <= $curEvent.data('calEvent').start.getTime()) {
|
1685
|
+
curGroups[groupIndex].push($curEvent);
|
1686
|
+
if (lastEndTime.getTime() < $curEvent.data('calEvent').end.getTime()) {
|
1687
|
+
lastEndTime = $curEvent.data('calEvent').end;
|
1688
|
+
}
|
1689
|
+
return;
|
1690
|
+
}
|
1691
|
+
}
|
1692
|
+
}
|
1693
|
+
//if not found, creates a new group
|
1694
|
+
curGroups.push([$curEvent]);
|
1695
|
+
if (lastEndTime.getTime() < $curEvent.data('calEvent').end.getTime()) {
|
1696
|
+
lastEndTime = $curEvent.data('calEvent').end;
|
1697
|
+
}
|
1698
|
+
});
|
1699
|
+
//adds the last groups in result
|
1700
|
+
if (curGroups.length > 0) {
|
1701
|
+
groups.push(curGroups);
|
1702
|
+
}
|
1703
|
+
return groups;
|
1704
|
+
},
|
1705
|
+
|
1706
|
+
|
1707
|
+
/*
|
1708
|
+
* find the weekday in the current calendar that the calEvent falls within
|
1709
|
+
*/
|
1710
|
+
_findWeekDayForEvent: function(calEvent, $weekDayColumns) {
|
1711
|
+
|
1712
|
+
var $weekDay,
|
1713
|
+
options = this.options,
|
1714
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
1715
|
+
user_ids = this._getEventUserId(calEvent);
|
1716
|
+
|
1717
|
+
if (!$.isArray(user_ids)) {
|
1718
|
+
user_ids = [user_ids];
|
1719
|
+
}
|
1720
|
+
|
1721
|
+
$weekDayColumns.each(function(index, curDay) {
|
1722
|
+
if ($(this).data('startDate').getTime() <= calEvent.start.getTime() &&
|
1723
|
+
$(this).data('endDate').getTime() >= calEvent.end.getTime() &&
|
1724
|
+
(!showAsSeparatedUser || $.inArray($(this).data('wcUserId'), user_ids) !== -1)
|
1725
|
+
) {
|
1726
|
+
if ($weekDay) {
|
1727
|
+
$weekDay = $weekDay.add($(curDay));
|
1728
|
+
}
|
1729
|
+
else {
|
1730
|
+
$weekDay = $(curDay);
|
1731
|
+
}
|
1732
|
+
}
|
1733
|
+
});
|
1734
|
+
|
1735
|
+
return $weekDay;
|
1736
|
+
},
|
1737
|
+
|
1738
|
+
/*
|
1739
|
+
* update the events rendering in the calendar. Add if does not yet exist.
|
1740
|
+
*/
|
1741
|
+
_updateEventInCalendar: function(calEvent) {
|
1742
|
+
var self = this;
|
1743
|
+
self._cleanEvent(calEvent);
|
1744
|
+
|
1745
|
+
if (calEvent.id) {
|
1746
|
+
self.element.find('.wc-cal-event').each(function() {
|
1747
|
+
if ($(this).data('calEvent').id === calEvent.id || $(this).hasClass('wc-new-cal-event')) {
|
1748
|
+
$(this).remove();
|
1749
|
+
// return false;
|
1750
|
+
}
|
1751
|
+
});
|
1752
|
+
}
|
1753
|
+
|
1754
|
+
var $weekDays = self._findWeekDayForEvent(calEvent, self.element.find('.wc-grid-row-events .wc-day-column-inner'));
|
1755
|
+
if ($weekDays) {
|
1756
|
+
$weekDays.each(function(index, weekDay) {
|
1757
|
+
var $weekDay = $(weekDay);
|
1758
|
+
var $calEvent = self._renderEvent(calEvent, $weekDay);
|
1759
|
+
self._adjustForEventCollisions($weekDay, $calEvent, calEvent, calEvent);
|
1760
|
+
self._refreshEventDetails(calEvent, $calEvent);
|
1761
|
+
self._positionEvent($weekDay, $calEvent);
|
1762
|
+
self._adjustOverlappingEvents($weekDay);
|
1763
|
+
});
|
1764
|
+
}
|
1765
|
+
},
|
1766
|
+
|
1767
|
+
/*
|
1768
|
+
* Position the event element within the weekday based on it's start / end dates.
|
1769
|
+
*/
|
1770
|
+
_positionEvent: function($weekDay, $calEvent) {
|
1771
|
+
var options = this.options;
|
1772
|
+
var calEvent = $calEvent.data('calEvent');
|
1773
|
+
var pxPerMillis = $weekDay.height() / options.millisToDisplay;
|
1774
|
+
var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
|
1775
|
+
var startMillis = this._getDSTdayShift(calEvent.start).getTime() - this._getDSTdayShift(new Date(calEvent.start.getFullYear(), calEvent.start.getMonth(), calEvent.start.getDate(), firstHourDisplayed)).getTime();
|
1776
|
+
var eventMillis = this._getDSTdayShift(calEvent.end).getTime() - this._getDSTdayShift(calEvent.start).getTime();
|
1777
|
+
var pxTop = pxPerMillis * startMillis;
|
1778
|
+
var pxHeight = pxPerMillis * eventMillis;
|
1779
|
+
//var pxHeightFallback = pxPerMillis * (60 / options.timeslotsPerHour) * 60 * 1000;
|
1780
|
+
$calEvent.css({top: pxTop, height: pxHeight || (pxPerMillis * 3600000 / options.timeslotsPerHour)});
|
1781
|
+
},
|
1782
|
+
|
1783
|
+
/*
|
1784
|
+
* Determine the actual start and end times of a calevent based on it's
|
1785
|
+
* relative position within the weekday column and the starting hour of the
|
1786
|
+
* displayed calendar.
|
1787
|
+
*/
|
1788
|
+
_getEventDurationFromPositionedEventElement: function($weekDay, $calEvent, top) {
|
1789
|
+
var options = this.options;
|
1790
|
+
var startOffsetMillis = options.businessHours.limitDisplay ? options.businessHours.start * 3600000 : 0;
|
1791
|
+
var start = new Date($weekDay.data('startDate').getTime() + startOffsetMillis + Math.round(top / options.timeslotHeight) * options.millisPerTimeslot);
|
1792
|
+
var end = new Date(start.getTime() + ($calEvent.height() / options.timeslotHeight) * options.millisPerTimeslot);
|
1793
|
+
return {start: this._getDSTdayShift(start, -1), end: this._getDSTdayShift(end, -1)};
|
1794
|
+
},
|
1795
|
+
|
1796
|
+
/*
|
1797
|
+
* If the calendar does not allow event overlap, adjust the start or end date if necessary to
|
1798
|
+
* avoid overlapping of events. Typically, shortens the resized / dropped event to it's max possible
|
1799
|
+
* duration based on the overlap. If no satisfactory adjustment can be made, the event is reverted to
|
1800
|
+
* it's original location.
|
1801
|
+
*/
|
1802
|
+
_adjustForEventCollisions: function($weekDay, $calEvent, newCalEvent, oldCalEvent, maintainEventDuration) {
|
1803
|
+
var options = this.options;
|
1804
|
+
|
1805
|
+
if (options.allowCalEventOverlap) {
|
1806
|
+
return;
|
1807
|
+
}
|
1808
|
+
var adjustedStart, adjustedEnd;
|
1809
|
+
var self = this;
|
1810
|
+
|
1811
|
+
$weekDay.find('.wc-cal-event').not($calEvent).each(function() {
|
1812
|
+
var currentCalEvent = $(this).data('calEvent');
|
1813
|
+
|
1814
|
+
//has been dropped onto existing event overlapping the end time
|
1815
|
+
if (newCalEvent.start.getTime() < currentCalEvent.end.getTime() &&
|
1816
|
+
newCalEvent.end.getTime() >= currentCalEvent.end.getTime()) {
|
1817
|
+
|
1818
|
+
adjustedStart = currentCalEvent.end;
|
1819
|
+
}
|
1820
|
+
|
1821
|
+
|
1822
|
+
//has been dropped onto existing event overlapping the start time
|
1823
|
+
if (newCalEvent.end.getTime() > currentCalEvent.start.getTime() &&
|
1824
|
+
newCalEvent.start.getTime() <= currentCalEvent.start.getTime()) {
|
1825
|
+
|
1826
|
+
adjustedEnd = currentCalEvent.start;
|
1827
|
+
}
|
1828
|
+
//has been dropped inside existing event with same or larger duration
|
1829
|
+
if (oldCalEvent.resizable == false ||
|
1830
|
+
(newCalEvent.end.getTime() <= currentCalEvent.end.getTime() &&
|
1831
|
+
newCalEvent.start.getTime() >= currentCalEvent.start.getTime())) {
|
1832
|
+
|
1833
|
+
adjustedStart = oldCalEvent.start;
|
1834
|
+
adjustedEnd = oldCalEvent.end;
|
1835
|
+
return false;
|
1836
|
+
}
|
1837
|
+
|
1838
|
+
});
|
1839
|
+
|
1840
|
+
|
1841
|
+
newCalEvent.start = adjustedStart || newCalEvent.start;
|
1842
|
+
|
1843
|
+
if (adjustedStart && maintainEventDuration) {
|
1844
|
+
newCalEvent.end = new Date(adjustedStart.getTime() + (oldCalEvent.end.getTime() - oldCalEvent.start.getTime()));
|
1845
|
+
self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, oldCalEvent);
|
1846
|
+
} else {
|
1847
|
+
newCalEvent.end = adjustedEnd || newCalEvent.end;
|
1848
|
+
}
|
1849
|
+
|
1850
|
+
|
1851
|
+
//reset if new cal event has been forced to zero size
|
1852
|
+
if (newCalEvent.start.getTime() >= newCalEvent.end.getTime()) {
|
1853
|
+
newCalEvent.start = oldCalEvent.start;
|
1854
|
+
newCalEvent.end = oldCalEvent.end;
|
1855
|
+
}
|
1856
|
+
|
1857
|
+
$calEvent.data('calEvent', newCalEvent);
|
1858
|
+
},
|
1859
|
+
|
1860
|
+
/*
|
1861
|
+
* Add draggable capabilities to an event
|
1862
|
+
*/
|
1863
|
+
_addDraggableToCalEvent: function(calEvent, $calEvent) {
|
1864
|
+
var options = this.options;
|
1865
|
+
$calEvent.draggable({
|
1866
|
+
handle: '.wc-time',
|
1867
|
+
containment: 'div.wc-time-slots',
|
1868
|
+
snap: '.wc-day-column-inner',
|
1869
|
+
snapMode: 'inner',
|
1870
|
+
snapTolerance: options.timeslotHeight - 1,
|
1871
|
+
revert: 'invalid',
|
1872
|
+
opacity: 0.5,
|
1873
|
+
grid: [$calEvent.outerWidth() + 1, options.timeslotHeight],
|
1874
|
+
start: function(event, ui) {
|
1875
|
+
var $calEvent = ui.draggable;
|
1876
|
+
options.eventDrag(calEvent, $calEvent);
|
1877
|
+
}
|
1878
|
+
});
|
1879
|
+
},
|
1880
|
+
|
1881
|
+
/*
|
1882
|
+
* Add droppable capabilites to weekdays to allow dropping of calEvents only
|
1883
|
+
*/
|
1884
|
+
_addDroppableToWeekDay: function($weekDay) {
|
1885
|
+
var self = this;
|
1886
|
+
var options = this.options;
|
1887
|
+
$weekDay.droppable({
|
1888
|
+
accept: '.wc-cal-event',
|
1889
|
+
drop: function(event, ui) {
|
1890
|
+
var $calEvent = ui.draggable;
|
1891
|
+
var top = Math.round(parseInt(ui.position.top));
|
1892
|
+
var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $calEvent, top);
|
1893
|
+
var calEvent = $calEvent.data('calEvent');
|
1894
|
+
var newCalEvent = $.extend(true, {}, calEvent, {start: eventDuration.start, end: eventDuration.end});
|
1895
|
+
var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
|
1896
|
+
if (showAsSeparatedUser) {
|
1897
|
+
// we may have dragged the event on column with a new user.
|
1898
|
+
// nice way to handle that is:
|
1899
|
+
// - get the newly dragged on user
|
1900
|
+
// - check if user is part of the event
|
1901
|
+
// - if yes, nothing changes, if not, find the old owner to remove it and add new one
|
1902
|
+
var newUserId = $weekDay.data('wcUserId');
|
1903
|
+
var userIdList = self._getEventUserId(calEvent);
|
1904
|
+
var oldUserId = $(ui.draggable.parents('.wc-day-column-inner').get(0)).data('wcUserId');
|
1905
|
+
if (!$.isArray(userIdList)) {
|
1906
|
+
userIdList = [userIdList];
|
1907
|
+
}
|
1908
|
+
if ($.inArray(newUserId, userIdList) == -1) {
|
1909
|
+
// remove old user
|
1910
|
+
var _index = $.inArray(oldUserId, userIdList);
|
1911
|
+
userIdList.splice(_index, 1);
|
1912
|
+
// add new user ?
|
1913
|
+
if ($.inArray(newUserId, userIdList) == -1) {
|
1914
|
+
userIdList.push(newUserId);
|
1915
|
+
}
|
1916
|
+
}
|
1917
|
+
newCalEvent = self._setEventUserId(newCalEvent, ((userIdList.length == 1) ? userIdList[0] : userIdList));
|
1918
|
+
}
|
1919
|
+
self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent, true);
|
1920
|
+
var $weekDayColumns = self.element.find('.wc-day-column-inner');
|
1921
|
+
|
1922
|
+
//trigger drop callback
|
1923
|
+
options.eventDrop(newCalEvent, calEvent, $calEvent);
|
1924
|
+
|
1925
|
+
var $newEvent = self._renderEvent(newCalEvent, self._findWeekDayForEvent(newCalEvent, $weekDayColumns));
|
1926
|
+
$calEvent.hide();
|
1927
|
+
|
1928
|
+
$calEvent.data('preventClick', true);
|
1929
|
+
|
1930
|
+
var $weekDayOld = self._findWeekDayForEvent($calEvent.data('calEvent'), self.element.find('.wc-time-slots .wc-day-column-inner'));
|
1931
|
+
|
1932
|
+
if ($weekDayOld.data('startDate') != $weekDay.data('startDate')) {
|
1933
|
+
self._adjustOverlappingEvents($weekDayOld);
|
1934
|
+
}
|
1935
|
+
self._adjustOverlappingEvents($weekDay);
|
1936
|
+
|
1937
|
+
setTimeout(function() {
|
1938
|
+
$calEvent.remove();
|
1939
|
+
}, 1000);
|
1940
|
+
|
1941
|
+
}
|
1942
|
+
});
|
1943
|
+
},
|
1944
|
+
|
1945
|
+
/*
|
1946
|
+
* Add resizable capabilities to a calEvent
|
1947
|
+
*/
|
1948
|
+
_addResizableToCalEvent: function(calEvent, $calEvent, $weekDay) {
|
1949
|
+
var self = this;
|
1950
|
+
var options = this.options;
|
1951
|
+
$calEvent.resizable({
|
1952
|
+
grid: options.timeslotHeight,
|
1953
|
+
containment: $weekDay,
|
1954
|
+
handles: 's',
|
1955
|
+
minHeight: options.timeslotHeight,
|
1956
|
+
stop: function(event, ui) {
|
1957
|
+
var $calEvent = ui.element;
|
1958
|
+
var newEnd = new Date($calEvent.data('calEvent').start.getTime() + Math.max(1, Math.round(ui.size.height / options.timeslotHeight)) * options.millisPerTimeslot);
|
1959
|
+
if (self._needDSTdayShift($calEvent.data('calEvent').start, newEnd))
|
1960
|
+
newEnd = self._getDSTdayShift(newEnd, -1);
|
1961
|
+
var newCalEvent = $.extend(true, {}, calEvent, {start: calEvent.start, end: newEnd});
|
1962
|
+
self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent);
|
1963
|
+
|
1964
|
+
self._refreshEventDetails(newCalEvent, $calEvent);
|
1965
|
+
self._positionEvent($weekDay, $calEvent);
|
1966
|
+
self._adjustOverlappingEvents($weekDay);
|
1967
|
+
//trigger resize callback
|
1968
|
+
options.eventResize(newCalEvent, calEvent, $calEvent);
|
1969
|
+
$calEvent.data('preventClick', true);
|
1970
|
+
setTimeout(function() {
|
1971
|
+
$calEvent.removeData('preventClick');
|
1972
|
+
}, 500);
|
1973
|
+
}
|
1974
|
+
});
|
1975
|
+
$('.ui-resizable-handle', $calEvent).text('=');
|
1976
|
+
},
|
1977
|
+
|
1978
|
+
/*
|
1979
|
+
* Refresh the displayed details of a calEvent in the calendar
|
1980
|
+
*/
|
1981
|
+
_refreshEventDetails: function(calEvent, $calEvent) {
|
1982
|
+
var suffix = '';
|
1983
|
+
if (!this.options.readonly &&
|
1984
|
+
this.options.allowEventDelete &&
|
1985
|
+
this.options.deletable(calEvent,$calEvent)) {
|
1986
|
+
suffix = '<div class="wc-cal-event-delete ui-icon ui-icon-close"></div>';
|
1987
|
+
}
|
1988
|
+
$calEvent.find('.wc-time').html(this.options.eventHeader(calEvent, this.element) + suffix);
|
1989
|
+
$calEvent.find('.wc-title').html(this.options.eventBody(calEvent, this.element));
|
1990
|
+
$calEvent.data('calEvent', calEvent);
|
1991
|
+
this.options.eventRefresh(calEvent, $calEvent);
|
1992
|
+
},
|
1993
|
+
|
1994
|
+
/*
|
1995
|
+
* Clear all cal events from the calendar
|
1996
|
+
*/
|
1997
|
+
_clearCalendar: function() {
|
1998
|
+
this.element.find('.wc-day-column-inner div').remove();
|
1999
|
+
this._clearFreeBusys();
|
2000
|
+
},
|
2001
|
+
|
2002
|
+
/*
|
2003
|
+
* Scroll the calendar to a specific hour
|
2004
|
+
*/
|
2005
|
+
_scrollToHour: function(hour, animate) {
|
2006
|
+
var self = this;
|
2007
|
+
var options = this.options;
|
2008
|
+
var $scrollable = this.element.find('.wc-scrollable-grid');
|
2009
|
+
var slot = hour;
|
2010
|
+
if (self.options.businessHours.limitDisplay) {
|
2011
|
+
if (hour <= self.options.businessHours.start) {
|
2012
|
+
slot = 0;
|
2013
|
+
} else if (hour >= self.options.businessHours.end) {
|
2014
|
+
slot = self.options.businessHours.end - self.options.businessHours.start - 1;
|
2015
|
+
} else {
|
2016
|
+
slot = hour - self.options.businessHours.start;
|
2017
|
+
}
|
2018
|
+
}
|
2019
|
+
|
2020
|
+
var $target = this.element.find('.wc-grid-timeslot-header .wc-hour-header:eq(' + slot + ')');
|
2021
|
+
|
2022
|
+
$scrollable.animate({scrollTop: 0}, 0, function() {
|
2023
|
+
var targetOffset = $target.offset().top;
|
2024
|
+
var scroll = targetOffset - $scrollable.offset().top - $target.outerHeight();
|
2025
|
+
if (animate) {
|
2026
|
+
$scrollable.animate({scrollTop: scroll}, options.scrollToHourMillis);
|
2027
|
+
}
|
2028
|
+
else {
|
2029
|
+
$scrollable.animate({scrollTop: scroll}, 0);
|
2030
|
+
}
|
2031
|
+
});
|
2032
|
+
},
|
2033
|
+
|
2034
|
+
/*
|
2035
|
+
* find the hour (12 hour day) for a given hour index
|
2036
|
+
*/
|
2037
|
+
_hourForIndex: function(index) {
|
2038
|
+
if (index === 0) { //midnight
|
2039
|
+
return 12;
|
2040
|
+
} else if (index < 13) { //am
|
2041
|
+
return index;
|
2042
|
+
} else { //pm
|
2043
|
+
return index - 12;
|
2044
|
+
}
|
2045
|
+
},
|
2046
|
+
|
2047
|
+
_24HourForIndex: function(index) {
|
2048
|
+
if (index === 0) { //midnight
|
2049
|
+
return '00:00';
|
2050
|
+
} else if (index < 10) {
|
2051
|
+
return '0' + index + ':00';
|
2052
|
+
} else {
|
2053
|
+
return index + ':00';
|
2054
|
+
}
|
2055
|
+
},
|
2056
|
+
|
2057
|
+
_amOrPm: function(hourOfDay) {
|
2058
|
+
return hourOfDay < 12 ? 'AM' : 'PM';
|
2059
|
+
},
|
2060
|
+
|
2061
|
+
_isToday: function(date) {
|
2062
|
+
var clonedDate = this._cloneDate(date);
|
2063
|
+
this._clearTime(clonedDate);
|
2064
|
+
var today = new Date();
|
2065
|
+
this._clearTime(today);
|
2066
|
+
return today.getTime() === clonedDate.getTime();
|
2067
|
+
},
|
2068
|
+
|
2069
|
+
/*
|
2070
|
+
* Clean events to ensure correct format
|
2071
|
+
*/
|
2072
|
+
_cleanEvents: function(events) {
|
2073
|
+
var self = this;
|
2074
|
+
$.each(events, function(i, event) {
|
2075
|
+
self._cleanEvent(event);
|
2076
|
+
});
|
2077
|
+
return events;
|
2078
|
+
},
|
2079
|
+
|
2080
|
+
/*
|
2081
|
+
* Clean specific event
|
2082
|
+
*/
|
2083
|
+
_cleanEvent: function(event) {
|
2084
|
+
if (event.date) {
|
2085
|
+
event.start = event.date;
|
2086
|
+
}
|
2087
|
+
event.start = this._cleanDate(event.start);
|
2088
|
+
event.end = this._cleanDate(event.end);
|
2089
|
+
if (!event.end) {
|
2090
|
+
event.end = this._addDays(this._cloneDate(event.start), 1);
|
2091
|
+
}
|
2092
|
+
},
|
2093
|
+
|
2094
|
+
/*
|
2095
|
+
* Disable text selection of the elements in different browsers
|
2096
|
+
*/
|
2097
|
+
_disableTextSelect: function($elements) {
|
2098
|
+
$elements.each(function() {
|
2099
|
+
if ($.browser.mozilla) {//Firefox
|
2100
|
+
$(this).css('MozUserSelect', 'none');
|
2101
|
+
} else if ($.browser.msie) {//IE
|
2102
|
+
$(this).bind('selectstart', function() {
|
2103
|
+
return false;
|
2104
|
+
});
|
2105
|
+
} else {//Opera, etc.
|
2106
|
+
$(this).mousedown(function() {
|
2107
|
+
return false;
|
2108
|
+
});
|
2109
|
+
}
|
2110
|
+
});
|
2111
|
+
},
|
2112
|
+
|
2113
|
+
/*
|
2114
|
+
* returns the date on the first millisecond of the week
|
2115
|
+
*/
|
2116
|
+
_dateFirstDayOfWeek: function(date) {
|
2117
|
+
var self = this;
|
2118
|
+
var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
2119
|
+
var adjustedDate = new Date(midnightCurrentDate);
|
2120
|
+
adjustedDate.setDate(adjustedDate.getDate() - self._getAdjustedDayIndex(midnightCurrentDate));
|
2121
|
+
|
2122
|
+
return adjustedDate;
|
2123
|
+
},
|
2124
|
+
|
2125
|
+
/*
|
2126
|
+
* returns the date on the first millisecond of the last day of the week
|
2127
|
+
*/
|
2128
|
+
_dateLastDayOfWeek: function(date) {
|
2129
|
+
var self = this;
|
2130
|
+
var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
2131
|
+
var adjustedDate = new Date(midnightCurrentDate);
|
2132
|
+
var daysToAdd = (self.options.daysToShow - 1 - self._getAdjustedDayIndex(midnightCurrentDate));
|
2133
|
+
adjustedDate.setDate(adjustedDate.getDate() + daysToAdd);
|
2134
|
+
|
2135
|
+
return adjustedDate;
|
2136
|
+
},
|
2137
|
+
|
2138
|
+
/**
|
2139
|
+
* fix the date if it is not within given options
|
2140
|
+
* minDate and maxDate
|
2141
|
+
*/
|
2142
|
+
_fixMinMaxDate: function(date) {
|
2143
|
+
var minDate, maxDate;
|
2144
|
+
date = this._cleanDate(date);
|
2145
|
+
|
2146
|
+
// not less than minDate
|
2147
|
+
if (this.options.minDate) {
|
2148
|
+
minDate = this._cleanDate(this.options.minDate);
|
2149
|
+
// midnight on minDate
|
2150
|
+
minDate = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate());
|
2151
|
+
if (date.getTime() < minDate.getTime()) {
|
2152
|
+
this._trigger('reachedmindate', this.element, date);
|
2153
|
+
}
|
2154
|
+
date = this._cleanDate(Math.max(date.getTime(), minDate.getTime()));
|
2155
|
+
}
|
2156
|
+
|
2157
|
+
// not more than maxDate
|
2158
|
+
if (this.options.maxDate) {
|
2159
|
+
maxDate = this._cleanDate(this.options.maxDate);
|
2160
|
+
// apply correction for max date if not startOnFirstDayOfWeek
|
2161
|
+
// to make sure no further date is displayed.
|
2162
|
+
// otherwise, the complement will still be shown
|
2163
|
+
if (!this._startOnFirstDayOfWeek()) {
|
2164
|
+
var day = maxDate.getDate() - this.options.daysToShow + 1;
|
2165
|
+
maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), day);
|
2166
|
+
}
|
2167
|
+
// microsecond before midnight on maxDate
|
2168
|
+
maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate(), 23, 59, 59, 999);
|
2169
|
+
if (date.getTime() > maxDate.getTime()) {
|
2170
|
+
this._trigger('reachedmaxdate', this.element, date);
|
2171
|
+
}
|
2172
|
+
date = this._cleanDate(Math.min(date.getTime(), maxDate.getTime()));
|
2173
|
+
}
|
2174
|
+
|
2175
|
+
return date;
|
2176
|
+
},
|
2177
|
+
|
2178
|
+
/*
|
2179
|
+
* gets the index of the current day adjusted based on options
|
2180
|
+
*/
|
2181
|
+
_getAdjustedDayIndex: function(date) {
|
2182
|
+
if (!this._startOnFirstDayOfWeek()) {
|
2183
|
+
return 0;
|
2184
|
+
}
|
2185
|
+
|
2186
|
+
var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
2187
|
+
var currentDayOfStandardWeek = midnightCurrentDate.getDay();
|
2188
|
+
var days = [0, 1, 2, 3, 4, 5, 6];
|
2189
|
+
this._rotate(days, this._firstDayOfWeek());
|
2190
|
+
return days[currentDayOfStandardWeek];
|
2191
|
+
},
|
2192
|
+
|
2193
|
+
_firstDayOfWeek: function() {
|
2194
|
+
if ($.isFunction(this.options.firstDayOfWeek)) {
|
2195
|
+
return this.options.firstDayOfWeek(this.element);
|
2196
|
+
}
|
2197
|
+
return this.options.firstDayOfWeek;
|
2198
|
+
},
|
2199
|
+
|
2200
|
+
/*
|
2201
|
+
* returns the date on the last millisecond of the week
|
2202
|
+
*/
|
2203
|
+
_dateLastMilliOfWeek: function(date) {
|
2204
|
+
var lastDayOfWeek = this._dateLastDayOfWeek(date);
|
2205
|
+
lastDayOfWeek = this._cloneDate(lastDayOfWeek);
|
2206
|
+
lastDayOfWeek.setDate(lastDayOfWeek.getDate() + 1);
|
2207
|
+
return lastDayOfWeek;
|
2208
|
+
|
2209
|
+
},
|
2210
|
+
|
2211
|
+
/*
|
2212
|
+
* Clear the time components of a date leaving the date
|
2213
|
+
* of the first milli of day
|
2214
|
+
*/
|
2215
|
+
_clearTime: function(d) {
|
2216
|
+
d.setHours(0);
|
2217
|
+
d.setMinutes(0);
|
2218
|
+
d.setSeconds(0);
|
2219
|
+
d.setMilliseconds(0);
|
2220
|
+
return d;
|
2221
|
+
},
|
2222
|
+
|
2223
|
+
/*
|
2224
|
+
* add specific number of days to date
|
2225
|
+
*/
|
2226
|
+
_addDays: function(d, n, keepTime) {
|
2227
|
+
d.setDate(d.getDate() + n);
|
2228
|
+
if (keepTime) {
|
2229
|
+
return d;
|
2230
|
+
}
|
2231
|
+
return this._clearTime(d);
|
2232
|
+
},
|
2233
|
+
|
2234
|
+
/*
|
2235
|
+
* Rotate an array by specified number of places.
|
2236
|
+
*/
|
2237
|
+
_rotate: function(a /*array*/, p /* integer, positive integer rotate to the right, negative to the left... */) {
|
2238
|
+
for (var l = a.length, p = (Math.abs(p) >= l && (p %= l), p < 0 && (p += l), p), i, x; p; p = (Math.ceil(l / p) - 1) * p - l + (l = p)) {
|
2239
|
+
for (i = l; i > p; x = a[--i], a[i] = a[i - p], a[i - p] = x) {}
|
2240
|
+
}
|
2241
|
+
return a;
|
2242
|
+
},
|
2243
|
+
|
2244
|
+
_cloneDate: function(d) {
|
2245
|
+
return new Date(d.getTime());
|
2246
|
+
},
|
2247
|
+
|
2248
|
+
/*
|
2249
|
+
* return a date for different representations
|
2250
|
+
*/
|
2251
|
+
_cleanDate: function(d) {
|
2252
|
+
if (typeof d == 'string') {
|
2253
|
+
// if is numeric
|
2254
|
+
if (!isNaN(parseFloat(d)) && isFinite()) {
|
2255
|
+
return this._cleanDate(parseInt(d, 10));
|
2256
|
+
}
|
2257
|
+
// this is a human readable date
|
2258
|
+
return Date.parse(d) || new Date(d);
|
2259
|
+
}
|
2260
|
+
if (typeof d == 'number') {
|
2261
|
+
return new Date(d);
|
2262
|
+
}
|
2263
|
+
return d;
|
2264
|
+
},
|
2265
|
+
|
2266
|
+
/*
|
2267
|
+
* date formatting is adapted from
|
2268
|
+
* http://jacwright.com/projects/javascript/date_format
|
2269
|
+
*/
|
2270
|
+
_formatDate: function(date, format) {
|
2271
|
+
var returnStr = '';
|
2272
|
+
for (var i = 0; i < format.length; i++) {
|
2273
|
+
var curChar = format.charAt(i);
|
2274
|
+
if (i != 0 && format.charAt(i - 1) == '\\') {
|
2275
|
+
returnStr += curChar;
|
2276
|
+
}
|
2277
|
+
else if (this._replaceChars[curChar]) {
|
2278
|
+
returnStr += this._replaceChars[curChar](date, this);
|
2279
|
+
} else if (curChar != '\\') {
|
2280
|
+
returnStr += curChar;
|
2281
|
+
}
|
2282
|
+
}
|
2283
|
+
return returnStr;
|
2284
|
+
},
|
2285
|
+
|
2286
|
+
_replaceChars: {
|
2287
|
+
// Day
|
2288
|
+
d: function(date) { return (date.getDate() < 10 ? '0' : '') + date.getDate(); },
|
2289
|
+
D: function(date, calendar) { return calendar.options.shortDays[date.getDay()]; },
|
2290
|
+
j: function(date) { return date.getDate(); },
|
2291
|
+
l: function(date, calendar) { return calendar.options.longDays[date.getDay()]; },
|
2292
|
+
N: function(date) { var _d = date.getDay(); return _d ? _d : 7; },
|
2293
|
+
S: function(date) { return (date.getDate() % 10 == 1 && date.getDate() != 11 ? 'st' : (date.getDate() % 10 == 2 && date.getDate() != 12 ? 'nd' : (date.getDate() % 10 == 3 && date.getDate() != 13 ? 'rd' : 'th'))); },
|
2294
|
+
w: function(date) { return date.getDay(); },
|
2295
|
+
z: function(date) { var d = new Date(date.getFullYear(), 0, 1); return Math.ceil((date - d) / 86400000); }, // Fixed now
|
2296
|
+
// Week
|
2297
|
+
W: function(date) { var d = new Date(date.getFullYear(), 0, 1); return Math.ceil((((date - d) / 86400000) + d.getDay() + 1) / 7); }, // Fixed now
|
2298
|
+
// Month
|
2299
|
+
F: function(date, calendar) { return calendar.options.longMonths[date.getMonth()]; },
|
2300
|
+
m: function(date) { return (date.getMonth() < 9 ? '0' : '') + (date.getMonth() + 1); },
|
2301
|
+
M: function(date, calendar) { return calendar.options.shortMonths[date.getMonth()]; },
|
2302
|
+
n: function(date) { return date.getMonth() + 1; },
|
2303
|
+
t: function(date) { var d = date; return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate() }, // Fixed now, gets #days of date
|
2304
|
+
// Year
|
2305
|
+
L: function(date) { var year = date.getFullYear(); return (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)); }, // Fixed now
|
2306
|
+
o: function(date) { var d = new Date(date.valueOf()); d.setDate(d.getDate() - ((date.getDay() + 6) % 7) + 3); return d.getFullYear();}, //Fixed now
|
2307
|
+
Y: function(date) { return date.getFullYear(); },
|
2308
|
+
y: function(date) { return ('' + date.getFullYear()).substr(2); },
|
2309
|
+
// Time
|
2310
|
+
a: function(date) { return date.getHours() < 12 ? 'am' : 'pm'; },
|
2311
|
+
A: function(date) { return date.getHours() < 12 ? 'AM' : 'PM'; },
|
2312
|
+
B: function(date) { return Math.floor((((date.getUTCHours() + 1) % 24) + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600) * 1000 / 24); }, // Fixed now
|
2313
|
+
g: function(date) { return date.getHours() % 12 || 12; },
|
2314
|
+
G: function(date) { return date.getHours(); },
|
2315
|
+
h: function(date) { return ((date.getHours() % 12 || 12) < 10 ? '0' : '') + (date.getHours() % 12 || 12); },
|
2316
|
+
H: function(date) { return (date.getHours() < 10 ? '0' : '') + date.getHours(); },
|
2317
|
+
i: function(date) { return (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); },
|
2318
|
+
s: function(date) { return (date.getSeconds() < 10 ? '0' : '') + date.getSeconds(); },
|
2319
|
+
u: function(date) { var m = date.getMilliseconds(); return (m < 10 ? '00' : (m < 100 ? '0' : '')) + m; },
|
2320
|
+
// Timezone
|
2321
|
+
e: function(date) { return 'Not Yet Supported'; },
|
2322
|
+
I: function(date) { return 'Not Yet Supported'; },
|
2323
|
+
O: function(date) { return (-date.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(date.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(date.getTimezoneOffset() / 60)) + '00'; },
|
2324
|
+
P: function(date) { return (-date.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(date.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(date.getTimezoneOffset() / 60)) + ':00'; }, // Fixed now
|
2325
|
+
T: function(date) { var m = date.getMonth(); date.setMonth(0); var result = date.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/, '$1'); date.setMonth(m); return result;},
|
2326
|
+
Z: function(date) { return -date.getTimezoneOffset() * 60; },
|
2327
|
+
// Full Date/Time
|
2328
|
+
c: function(date, calendar) { return calendar._formatDate(date, 'Y-m-d\\TH:i:sP'); }, // Fixed now
|
2329
|
+
r: function(date, calendar) { return calendar._formatDate(date, 'D, d M Y H:i:s O'); },
|
2330
|
+
U: function(date) { return date.getTime() / 1000; }
|
2331
|
+
},
|
2332
|
+
|
2333
|
+
/* USER MANAGEMENT FUNCTIONS */
|
2334
|
+
|
2335
|
+
getUserForId: function(id) {
|
2336
|
+
return $.extend({}, this.options.users[this._getUserIndexFromId(id)]);
|
2337
|
+
},
|
2338
|
+
|
2339
|
+
/**
|
2340
|
+
* return the user name for header
|
2341
|
+
*/
|
2342
|
+
_getUserName: function(index) {
|
2343
|
+
var self = this;
|
2344
|
+
var options = this.options;
|
2345
|
+
var user = options.users[index];
|
2346
|
+
if ($.isFunction(options.getUserName)) {
|
2347
|
+
return options.getUserName(user, index, self.element);
|
2348
|
+
}
|
2349
|
+
else {
|
2350
|
+
return user;
|
2351
|
+
}
|
2352
|
+
},
|
2353
|
+
/**
|
2354
|
+
* return the user id for given index
|
2355
|
+
*/
|
2356
|
+
_getUserIdFromIndex: function(index) {
|
2357
|
+
var self = this;
|
2358
|
+
var options = this.options;
|
2359
|
+
if ($.isFunction(options.getUserId)) {
|
2360
|
+
return options.getUserId(options.users[index], index, self.element);
|
2361
|
+
}
|
2362
|
+
return index;
|
2363
|
+
},
|
2364
|
+
/**
|
2365
|
+
* returns the associated user index for given ID
|
2366
|
+
*/
|
2367
|
+
_getUserIndexFromId: function(id) {
|
2368
|
+
var self = this;
|
2369
|
+
var options = this.options;
|
2370
|
+
for (var i = 0; i < options.users.length; i++) {
|
2371
|
+
if (self._getUserIdFromIndex(i) == id) {
|
2372
|
+
return i;
|
2373
|
+
}
|
2374
|
+
}
|
2375
|
+
return 0;
|
2376
|
+
},
|
2377
|
+
/**
|
2378
|
+
* return the user ids for given calEvent.
|
2379
|
+
* default is calEvent.userId field.
|
2380
|
+
*/
|
2381
|
+
_getEventUserId: function(calEvent) {
|
2382
|
+
var self = this;
|
2383
|
+
var options = this.options;
|
2384
|
+
if (options.showAsSeparateUsers && options.users && options.users.length) {
|
2385
|
+
if ($.isFunction(options.getEventUserId)) {
|
2386
|
+
return options.getEventUserId(calEvent, self.element);
|
2387
|
+
}
|
2388
|
+
return calEvent.userId;
|
2389
|
+
}
|
2390
|
+
return [];
|
2391
|
+
},
|
2392
|
+
/**
|
2393
|
+
* sets the event user id on given calEvent
|
2394
|
+
* default is calEvent.userId field.
|
2395
|
+
*/
|
2396
|
+
_setEventUserId: function(calEvent, userId) {
|
2397
|
+
var self = this;
|
2398
|
+
var options = this.options;
|
2399
|
+
if ($.isFunction(options.setEventUserId)) {
|
2400
|
+
return options.setEventUserId(userId, calEvent, self.element);
|
2401
|
+
}
|
2402
|
+
calEvent.userId = userId;
|
2403
|
+
return calEvent;
|
2404
|
+
},
|
2405
|
+
/**
|
2406
|
+
* return the user ids for given freeBusy.
|
2407
|
+
* default is freeBusy.userId field.
|
2408
|
+
*/
|
2409
|
+
_getFreeBusyUserId: function(freeBusy) {
|
2410
|
+
var self = this;
|
2411
|
+
var options = this.options;
|
2412
|
+
if ($.isFunction(options.getFreeBusyUserId)) {
|
2413
|
+
return options.getFreeBusyUserId(freeBusy.getOption(), self.element);
|
2414
|
+
}
|
2415
|
+
return freeBusy.getOption('userId');
|
2416
|
+
},
|
2417
|
+
|
2418
|
+
/* FREEBUSY MANAGEMENT */
|
2419
|
+
|
2420
|
+
/**
|
2421
|
+
* ckean the free busy managers and remove all the freeBusy
|
2422
|
+
*/
|
2423
|
+
_clearFreeBusys: function() {
|
2424
|
+
if (this.options.displayFreeBusys) {
|
2425
|
+
var self = this,
|
2426
|
+
options = this.options,
|
2427
|
+
$freeBusyPlaceholders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy');
|
2428
|
+
$freeBusyPlaceholders.each(function() {
|
2429
|
+
$(this).data('wcFreeBusyManager', new FreeBusyManager({
|
2430
|
+
start: self._cloneDate($(this).data('startDate')),
|
2431
|
+
end: self._cloneDate($(this).data('endDate')),
|
2432
|
+
defaultFreeBusy: options.defaultFreeBusy || {}
|
2433
|
+
}));
|
2434
|
+
});
|
2435
|
+
self.element.find('.wc-grid-row-freebusy .wc-freebusy').remove();
|
2436
|
+
}
|
2437
|
+
},
|
2438
|
+
/**
|
2439
|
+
* retrieve placeholders for given freebusy
|
2440
|
+
*/
|
2441
|
+
_findWeekDaysForFreeBusy: function(freeBusy, $weekDays) {
|
2442
|
+
var $returnWeekDays,
|
2443
|
+
options = this.options,
|
2444
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
2445
|
+
self = this,
|
2446
|
+
userList = self._getFreeBusyUserId(freeBusy);
|
2447
|
+
if (!$.isArray(userList)) {
|
2448
|
+
userList = userList != 'undefined' ? [userList] : [];
|
2449
|
+
}
|
2450
|
+
if (!$weekDays) {
|
2451
|
+
$weekDays = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy');
|
2452
|
+
}
|
2453
|
+
$weekDays.each(function() {
|
2454
|
+
var manager = $(this).data('wcFreeBusyManager'),
|
2455
|
+
has_overlap = manager.isWithin(freeBusy.getStart()) ||
|
2456
|
+
manager.isWithin(freeBusy.getEnd()) ||
|
2457
|
+
freeBusy.isWithin(manager.getStart()) ||
|
2458
|
+
freeBusy.isWithin(manager.getEnd()),
|
2459
|
+
userId = $(this).data('wcUserId');
|
2460
|
+
if (has_overlap && (!showAsSeparatedUser || ($.inArray(userId, userList) != -1))) {
|
2461
|
+
$returnWeekDays = $returnWeekDays ? $returnWeekDays.add($(this)) : $(this);
|
2462
|
+
}
|
2463
|
+
});
|
2464
|
+
return $returnWeekDays;
|
2465
|
+
},
|
2466
|
+
|
2467
|
+
/**
|
2468
|
+
* used to render all freeBusys
|
2469
|
+
*/
|
2470
|
+
_renderFreeBusys: function(freeBusys) {
|
2471
|
+
if (this.options.displayFreeBusys) {
|
2472
|
+
var self = this,
|
2473
|
+
$freeBusyPlaceholders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
|
2474
|
+
freebusysToRender;
|
2475
|
+
//insert freebusys to dedicated placeholders freebusy managers
|
2476
|
+
if ($.isArray(freeBusys)) {
|
2477
|
+
freebusysToRender = self._cleanFreeBusys(freeBusys);
|
2478
|
+
} else if (freeBusys.freebusys) {
|
2479
|
+
freebusysToRender = self._cleanFreeBusys(freeBusys.freebusys);
|
2480
|
+
}
|
2481
|
+
else {
|
2482
|
+
freebusysToRender = [];
|
2483
|
+
}
|
2484
|
+
|
2485
|
+
$.each(freebusysToRender, function(index, freebusy) {
|
2486
|
+
var $placeholders = self._findWeekDaysForFreeBusy(freebusy, $freeBusyPlaceholders);
|
2487
|
+
if ($placeholders) {
|
2488
|
+
$placeholders.each(function() {
|
2489
|
+
var manager = $(this).data('wcFreeBusyManager');
|
2490
|
+
manager.insertFreeBusy(new FreeBusy(freebusy.getOption()));
|
2491
|
+
$(this).data('wcFreeBusyManager', manager);
|
2492
|
+
});
|
2493
|
+
}
|
2494
|
+
});
|
2495
|
+
|
2496
|
+
//now display freebusys on place holders
|
2497
|
+
self._refreshFreeBusys($freeBusyPlaceholders);
|
2498
|
+
}
|
2499
|
+
},
|
2500
|
+
/**
|
2501
|
+
* refresh freebusys for given placeholders
|
2502
|
+
*/
|
2503
|
+
_refreshFreeBusys: function($freeBusyPlaceholders) {
|
2504
|
+
if (this.options.displayFreeBusys && $freeBusyPlaceholders) {
|
2505
|
+
var self = this,
|
2506
|
+
options = this.options,
|
2507
|
+
start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
|
2508
|
+
end = (options.businessHours.limitDisplay ? options.businessHours.end : 24);
|
2509
|
+
|
2510
|
+
$freeBusyPlaceholders.each(function() {
|
2511
|
+
var $placehoder = $(this);
|
2512
|
+
var s = self._cloneDate($placehoder.data('startDate')),
|
2513
|
+
e = self._cloneDate(s);
|
2514
|
+
s.setHours(start);
|
2515
|
+
e.setHours(end);
|
2516
|
+
$placehoder.find('.wc-freebusy').remove();
|
2517
|
+
$.each($placehoder.data('wcFreeBusyManager').getFreeBusys(s, e), function() {
|
2518
|
+
self._renderFreeBusy(this, $placehoder);
|
2519
|
+
});
|
2520
|
+
});
|
2521
|
+
}
|
2522
|
+
},
|
2523
|
+
/**
|
2524
|
+
* render a freebusy item on dedicated placeholders
|
2525
|
+
*/
|
2526
|
+
_renderFreeBusy: function(freeBusy, $freeBusyPlaceholder) {
|
2527
|
+
if (this.options.displayFreeBusys) {
|
2528
|
+
var self = this,
|
2529
|
+
options = this.options,
|
2530
|
+
freeBusyHtml = '<div class="wc-freebusy"></div>';
|
2531
|
+
|
2532
|
+
var $fb = $(freeBusyHtml);
|
2533
|
+
$fb.data('wcFreeBusy', new FreeBusy(freeBusy.getOption()));
|
2534
|
+
this._positionFreeBusy($freeBusyPlaceholder, $fb);
|
2535
|
+
$fb = options.freeBusyRender(freeBusy.getOption(), $fb, self.element);
|
2536
|
+
if ($fb) {
|
2537
|
+
$fb.appendTo($freeBusyPlaceholder);
|
2538
|
+
}
|
2539
|
+
}
|
2540
|
+
},
|
2541
|
+
/*
|
2542
|
+
* Position the freebusy element within the weekday based on it's start / end dates.
|
2543
|
+
*/
|
2544
|
+
_positionFreeBusy: function($placeholder, $freeBusy) {
|
2545
|
+
var options = this.options;
|
2546
|
+
var freeBusy = $freeBusy.data('wcFreeBusy');
|
2547
|
+
var pxPerMillis = $placeholder.height() / options.millisToDisplay;
|
2548
|
+
var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
|
2549
|
+
var startMillis = freeBusy.getStart().getTime() - new Date(freeBusy.getStart().getFullYear(), freeBusy.getStart().getMonth(), freeBusy.getStart().getDate(), firstHourDisplayed).getTime();
|
2550
|
+
var eventMillis = freeBusy.getEnd().getTime() - freeBusy.getStart().getTime();
|
2551
|
+
var pxTop = pxPerMillis * startMillis;
|
2552
|
+
var pxHeight = pxPerMillis * eventMillis;
|
2553
|
+
$freeBusy.css({top: pxTop, height: pxHeight});
|
2554
|
+
},
|
2555
|
+
/*
|
2556
|
+
* Clean freebusys to ensure correct format
|
2557
|
+
*/
|
2558
|
+
_cleanFreeBusys: function(freebusys) {
|
2559
|
+
var self = this,
|
2560
|
+
freeBusyToReturn = [];
|
2561
|
+
if (!$.isArray(freebusys)) {
|
2562
|
+
var freebusys = [freebusys];
|
2563
|
+
}
|
2564
|
+
$.each(freebusys, function(i, freebusy) {
|
2565
|
+
freeBusyToReturn.push(new FreeBusy(self._cleanFreeBusy(freebusy)));
|
2566
|
+
});
|
2567
|
+
return freeBusyToReturn;
|
2568
|
+
},
|
2569
|
+
|
2570
|
+
/*
|
2571
|
+
* Clean specific freebusy
|
2572
|
+
*/
|
2573
|
+
_cleanFreeBusy: function(freebusy) {
|
2574
|
+
if (freebusy.date) {
|
2575
|
+
freebusy.start = freebusy.date;
|
2576
|
+
}
|
2577
|
+
freebusy.start = this._cleanDate(freebusy.start);
|
2578
|
+
freebusy.end = this._cleanDate(freebusy.end);
|
2579
|
+
return freebusy;
|
2580
|
+
},
|
2581
|
+
|
2582
|
+
/**
|
2583
|
+
* retrives the first freebusy manager matching demand.
|
2584
|
+
*/
|
2585
|
+
getFreeBusyManagersFor: function(date, users) {
|
2586
|
+
var calEvent = {
|
2587
|
+
start: date,
|
2588
|
+
end: date
|
2589
|
+
};
|
2590
|
+
this._setEventUserId(calEvent, users);
|
2591
|
+
return this.getFreeBusyManagerForEvent(calEvent);
|
2592
|
+
},
|
2593
|
+
/**
|
2594
|
+
* retrives the first freebusy manager for given event.
|
2595
|
+
*/
|
2596
|
+
getFreeBusyManagerForEvent: function(newCalEvent) {
|
2597
|
+
var self = this,
|
2598
|
+
options = this.options,
|
2599
|
+
freeBusyManager;
|
2600
|
+
if (options.displayFreeBusys) {
|
2601
|
+
var $freeBusyPlaceHoders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
|
2602
|
+
freeBusy = new FreeBusy({start: newCalEvent.start, end: newCalEvent.end}),
|
2603
|
+
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
2604
|
+
userId = showAsSeparatedUser ? self._getEventUserId(newCalEvent) : null;
|
2605
|
+
if (!$.isArray(userId)) {
|
2606
|
+
userId = [userId];
|
2607
|
+
}
|
2608
|
+
$freeBusyPlaceHoders.each(function() {
|
2609
|
+
var manager = $(this).data('wcFreeBusyManager'),
|
2610
|
+
has_overlap = manager.isWithin(freeBusy.getEnd()) ||
|
2611
|
+
manager.isWithin(freeBusy.getEnd()) ||
|
2612
|
+
freeBusy.isWithin(manager.getStart()) ||
|
2613
|
+
freeBusy.isWithin(manager.getEnd());
|
2614
|
+
if (has_overlap && (!showAsSeparatedUser || $.inArray($(this).data('wcUserId'), userId) != -1)) {
|
2615
|
+
freeBusyManager = $(this).data('wcFreeBusyManager');
|
2616
|
+
return false;
|
2617
|
+
}
|
2618
|
+
});
|
2619
|
+
}
|
2620
|
+
return freeBusyManager;
|
2621
|
+
},
|
2622
|
+
/**
|
2623
|
+
* appends the freebusys to replace the old ones.
|
2624
|
+
* @param {array|object} freeBusys freebusy(s) to apply.
|
2625
|
+
*/
|
2626
|
+
updateFreeBusy: function(freeBusys) {
|
2627
|
+
var self = this,
|
2628
|
+
options = this.options;
|
2629
|
+
if (options.displayFreeBusys) {
|
2630
|
+
var $toRender,
|
2631
|
+
$freeBusyPlaceHoders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
|
2632
|
+
_freeBusys = self._cleanFreeBusys(freeBusys);
|
2633
|
+
|
2634
|
+
$.each(_freeBusys, function(index, _freeBusy) {
|
2635
|
+
|
2636
|
+
var $weekdays = self._findWeekDaysForFreeBusy(_freeBusy, $freeBusyPlaceHoders);
|
2637
|
+
//if freebusy has a placeholder
|
2638
|
+
if ($weekdays && $weekdays.length) {
|
2639
|
+
$weekdays.each(function(index, day) {
|
2640
|
+
var manager = $(day).data('wcFreeBusyManager');
|
2641
|
+
manager.insertFreeBusy(_freeBusy);
|
2642
|
+
$(day).data('wcFreeBusyManager', manager);
|
2643
|
+
});
|
2644
|
+
$toRender = $toRender ? $toRender.add($weekdays) : $weekdays;
|
2645
|
+
}
|
2646
|
+
});
|
2647
|
+
self._refreshFreeBusys($toRender);
|
2648
|
+
}
|
2649
|
+
},
|
2650
|
+
|
2651
|
+
/* NEW OPTIONS MANAGEMENT */
|
2652
|
+
|
2653
|
+
/**
|
2654
|
+
* checks wether or not the calendar should be displayed starting on first day of week
|
2655
|
+
*/
|
2656
|
+
_startOnFirstDayOfWeek: function() {
|
2657
|
+
return jQuery.isFunction(this.options.startOnFirstDayOfWeek) ? this.options.startOnFirstDayOfWeek(this.element) : this.options.startOnFirstDayOfWeek;
|
2658
|
+
},
|
2659
|
+
|
2660
|
+
/**
|
2661
|
+
* finds out the current scroll to apply it when changing the view
|
2662
|
+
*/
|
2663
|
+
_getCurrentScrollHour: function() {
|
2664
|
+
var self = this;
|
2665
|
+
var options = this.options;
|
2666
|
+
var $scrollable = this.element.find('.wc-scrollable-grid');
|
2667
|
+
var scroll = $scrollable.scrollTop();
|
2668
|
+
if (self.options.businessHours.limitDisplay) {
|
2669
|
+
scroll = scroll + options.businessHours.start * options.timeslotHeight * options.timeslotsPerHour;
|
2670
|
+
}
|
2671
|
+
return Math.round(scroll / (options.timeslotHeight * options.timeslotsPerHour)) + 1;
|
2672
|
+
},
|
2673
|
+
_getJsonOptions: function() {
|
2674
|
+
if ($.isFunction(this.options.jsonOptions)) {
|
2675
|
+
return $.extend({}, this.options.jsonOptions(this.element));
|
2676
|
+
}
|
2677
|
+
if ($.isPlainObject(this.options.jsonOptions)) {
|
2678
|
+
return $.extend({}, this.options.jsonOptions);
|
2679
|
+
}
|
2680
|
+
return {};
|
2681
|
+
},
|
2682
|
+
_getHeaderDate: function(date) {
|
2683
|
+
var options = this.options;
|
2684
|
+
if (options.getHeaderDate && $.isFunction(options.getHeaderDate))
|
2685
|
+
{
|
2686
|
+
return options.getHeaderDate(date, this.element);
|
2687
|
+
}
|
2688
|
+
var dayName = options.useShortDayNames ? options.shortDays[date.getDay()] : options.longDays[date.getDay()];
|
2689
|
+
return dayName + (options.headerSeparator) + this._formatDate(date, options.dateFormat);
|
2690
|
+
},
|
2691
|
+
|
2692
|
+
|
2693
|
+
|
2694
|
+
/**
|
2695
|
+
* returns corrected date related to DST problem
|
2696
|
+
*/
|
2697
|
+
_getDSTdayShift: function(date, shift) {
|
2698
|
+
var start = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0);
|
2699
|
+
var offset1 = start.getTimezoneOffset();
|
2700
|
+
var offset2 = date.getTimezoneOffset();
|
2701
|
+
if (offset1 == offset2)
|
2702
|
+
return date;
|
2703
|
+
shift = shift ? shift : 1;
|
2704
|
+
return new Date(date.getTime() - shift * (offset1 > offset2 ? -1 : 1) * (Math.max(offset1, offset2) - Math.min(offset1, offset2)) * 60000);
|
2705
|
+
},
|
2706
|
+
_needDSTdayShift: function(date1, date2) {
|
2707
|
+
return date1.getTimezoneOffset() != date2.getTimezoneOffset();
|
2708
|
+
}
|
2709
|
+
|
2710
|
+
|
2711
|
+
|
2712
|
+
}; // end of widget function return
|
2713
|
+
})() //end of widget function closure execution
|
2714
|
+
); // end of $.widget("ui.weekCalendar"...
|
2715
|
+
|
2716
|
+
$.extend($.ui.weekCalendar, {
|
2717
|
+
version: '2.0-dev',
|
2718
|
+
updateLayoutOptions: {
|
2719
|
+
startOnFirstDayOfWeek: true,
|
2720
|
+
firstDayOfWeek: true,
|
2721
|
+
daysToShow: true,
|
2722
|
+
displayOddEven: true,
|
2723
|
+
timeFormat: true,
|
2724
|
+
dateFormat: true,
|
2725
|
+
use24Hour: true,
|
2726
|
+
useShortDayNames: true,
|
2727
|
+
businessHours: true,
|
2728
|
+
timeslotHeight: true,
|
2729
|
+
timeslotsPerHour: true,
|
2730
|
+
buttonText: true,
|
2731
|
+
height: true,
|
2732
|
+
shortMonths: true,
|
2733
|
+
longMonths: true,
|
2734
|
+
shortDays: true,
|
2735
|
+
longDays: true,
|
2736
|
+
textSize: true,
|
2737
|
+
users: true,
|
2738
|
+
showAsSeparateUsers: true,
|
2739
|
+
displayFreeBusys: true
|
2740
|
+
}
|
2741
|
+
});
|
2742
|
+
|
2743
|
+
var MILLIS_IN_DAY = 86400000;
|
2744
|
+
var MILLIS_IN_WEEK = MILLIS_IN_DAY * 7;
|
2745
|
+
|
2746
|
+
/* FREE BUSY MANAGERS */
|
2747
|
+
var FreeBusyProto = {
|
2748
|
+
getStart: function() {return this.getOption('start')},
|
2749
|
+
getEnd: function() {return this.getOption('end')},
|
2750
|
+
getOption: function() {
|
2751
|
+
if (!arguments.length) { return this.options }
|
2752
|
+
if (typeof(this.options[arguments[0]]) !== 'undefined') {
|
2753
|
+
return this.options[arguments[0]];
|
2754
|
+
}
|
2755
|
+
else if (typeof(arguments[1]) !== 'undefined') {
|
2756
|
+
return arguments[1];
|
2757
|
+
}
|
2758
|
+
return null;
|
2759
|
+
},
|
2760
|
+
setOption: function(key, value) {
|
2761
|
+
if (arguments.length == 1) {
|
2762
|
+
$.extend(this.options, arguments[0]);
|
2763
|
+
return this;
|
2764
|
+
}
|
2765
|
+
this.options[key] = value;
|
2766
|
+
return this;
|
2767
|
+
},
|
2768
|
+
isWithin: function(dateTime) {return Math.floor(dateTime.getTime() / 1000) >= Math.floor(this.getStart().getTime() / 1000) && Math.floor(dateTime.getTime() / 1000) <= Math.floor(this.getEnd().getTime() / 1000)},
|
2769
|
+
isValid: function() {return this.getStart().getTime() < this.getEnd().getTime()}
|
2770
|
+
};
|
2771
|
+
|
2772
|
+
/**
|
2773
|
+
* @constructor
|
2774
|
+
* single user freebusy manager.
|
2775
|
+
*/
|
2776
|
+
var FreeBusy = function(options) {
|
2777
|
+
this.options = $.extend({}, options || {});
|
2778
|
+
};
|
2779
|
+
$.extend(FreeBusy.prototype, FreeBusyProto);
|
2780
|
+
|
2781
|
+
var FreeBusyManager = function(options) {
|
2782
|
+
this.options = $.extend({
|
2783
|
+
defaultFreeBusy: {}
|
2784
|
+
}, options || {});
|
2785
|
+
this.freeBusys = [];
|
2786
|
+
this.freeBusys.push(new FreeBusy($.extend({
|
2787
|
+
start: this.getStart(),
|
2788
|
+
end: this.getEnd()
|
2789
|
+
}, this.options.defaultFreeBusy)));
|
2790
|
+
};
|
2791
|
+
$.extend(FreeBusyManager.prototype, FreeBusyProto, {
|
2792
|
+
/**
|
2793
|
+
* return matching freeBusys.
|
2794
|
+
* if you do not pass any argument, returns all freebusys.
|
2795
|
+
* if you only pass a start date, only matchinf freebusy will be returned.
|
2796
|
+
* if you pass 2 arguments, then all freebusys available within the time period will be returned
|
2797
|
+
* @param {Date} start [optionnal] if you do not pass end date, will return the freeBusy within which this date falls.
|
2798
|
+
* @param {Date} end [optionnal] the date where to stop the search.
|
2799
|
+
* @return {Array} an array of FreeBusy matching arguments.
|
2800
|
+
*/
|
2801
|
+
getFreeBusys: function() {
|
2802
|
+
switch (arguments.length) {
|
2803
|
+
case 0:
|
2804
|
+
return this.freeBusys;
|
2805
|
+
case 1:
|
2806
|
+
var freeBusy = [];
|
2807
|
+
var start = arguments[0];
|
2808
|
+
if (!this.isWithin(start)) {
|
2809
|
+
return freeBusy;
|
2810
|
+
}
|
2811
|
+
$.each(this.freeBusys, function() {
|
2812
|
+
if (this.isWithin(start)) {
|
2813
|
+
freeBusy.push(this);
|
2814
|
+
}
|
2815
|
+
if (Math.floor(this.getEnd().getTime() / 1000) > Math.floor(start.getTime() / 1000)) {
|
2816
|
+
return false;
|
2817
|
+
}
|
2818
|
+
});
|
2819
|
+
return freeBusy;
|
2820
|
+
default:
|
2821
|
+
//we assume only 2 first args are revealants
|
2822
|
+
var freeBusy = [];
|
2823
|
+
var start = arguments[0], end = arguments[1];
|
2824
|
+
var tmpFreeBusy = new FreeBusy({start: start, end: end});
|
2825
|
+
if (end.getTime() < start.getTime() || this.getStart().getTime() > end.getTime() || this.getEnd().getTime() < start.getTime()) {
|
2826
|
+
return freeBusy;
|
2827
|
+
}
|
2828
|
+
$.each(this.freeBusys, function() {
|
2829
|
+
if (this.getStart().getTime() >= end.getTime()) {
|
2830
|
+
return false;
|
2831
|
+
}
|
2832
|
+
if (tmpFreeBusy.isWithin(this.getStart()) && tmpFreeBusy.isWithin(this.getEnd())) {
|
2833
|
+
freeBusy.push(this);
|
2834
|
+
}
|
2835
|
+
else if (this.isWithin(tmpFreeBusy.getStart()) && this.isWithin(tmpFreeBusy.getEnd())) {
|
2836
|
+
var _f = new FreeBusy(this.getOption());
|
2837
|
+
_f.setOption('end', tmpFreeBusy.getEnd());
|
2838
|
+
_f.setOption('start', tmpFreeBusy.getStart());
|
2839
|
+
freeBusy.push(_f);
|
2840
|
+
}
|
2841
|
+
else if (this.isWithin(tmpFreeBusy.getStart()) && this.getStart().getTime() < start.getTime()) {
|
2842
|
+
var _f = new FreeBusy(this.getOption());
|
2843
|
+
_f.setOption('start', tmpFreeBusy.getStart());
|
2844
|
+
freeBusy.push(_f);
|
2845
|
+
}
|
2846
|
+
else if (this.isWithin(tmpFreeBusy.getEnd()) && this.getEnd().getTime() > end.getTime()) {
|
2847
|
+
var _f = new FreeBusy(this.getOption());
|
2848
|
+
_f.setOption('end', tmpFreeBusy.getEnd());
|
2849
|
+
freeBusy.push(_f);
|
2850
|
+
}
|
2851
|
+
});
|
2852
|
+
return freeBusy;
|
2853
|
+
}
|
2854
|
+
},
|
2855
|
+
insertFreeBusy: function(freeBusy) {
|
2856
|
+
var freeBusy = new FreeBusy(freeBusy.getOption());
|
2857
|
+
//first, if inserted freebusy is bigger than manager
|
2858
|
+
if (freeBusy.getStart().getTime() < this.getStart().getTime()) {
|
2859
|
+
freeBusy.setOption('start', this.getStart());
|
2860
|
+
}
|
2861
|
+
if (freeBusy.getEnd().getTime() > this.getEnd().getTime()) {
|
2862
|
+
freeBusy.setOption('end', this.getEnd());
|
2863
|
+
}
|
2864
|
+
var start = freeBusy.getStart(), end = freeBusy.getEnd(),
|
2865
|
+
startIndex = 0, endIndex = this.freeBusys.length - 1,
|
2866
|
+
newFreeBusys = [];
|
2867
|
+
var pushNewFreeBusy = function(_f) {if (_f.isValid()) newFreeBusys.push(_f);};
|
2868
|
+
|
2869
|
+
$.each(this.freeBusys, function(index) {
|
2870
|
+
//within the loop, we have following vars:
|
2871
|
+
// curFreeBusyItem: the current iteration freeBusy, part of manager freeBusys list
|
2872
|
+
// start: the insterted freeBusy start
|
2873
|
+
// end: the inserted freebusy end
|
2874
|
+
var curFreeBusyItem = this;
|
2875
|
+
if (curFreeBusyItem.isWithin(start) && curFreeBusyItem.isWithin(end)) {
|
2876
|
+
/*
|
2877
|
+
we are in case where inserted freebusy fits in curFreeBusyItem:
|
2878
|
+
curFreeBusyItem: *-----------------------------*
|
2879
|
+
freeBusy: *-------------*
|
2880
|
+
obviously, start and end indexes are this item.
|
2881
|
+
*/
|
2882
|
+
startIndex = index;
|
2883
|
+
endIndex = index;
|
2884
|
+
if (start.getTime() == curFreeBusyItem.getStart().getTime() && end.getTime() == curFreeBusyItem.getEnd().getTime()) {
|
2885
|
+
/*
|
2886
|
+
in this case, inserted freebusy is exactly curFreeBusyItem:
|
2887
|
+
curFreeBusyItem: *-----------------------------*
|
2888
|
+
freeBusy: *-----------------------------*
|
2889
|
+
|
2890
|
+
just replace curFreeBusyItem with freeBusy.
|
2891
|
+
*/
|
2892
|
+
var _f1 = new FreeBusy(freeBusy.getOption());
|
2893
|
+
pushNewFreeBusy(_f1);
|
2894
|
+
}
|
2895
|
+
else if (start.getTime() == curFreeBusyItem.getStart().getTime()) {
|
2896
|
+
/*
|
2897
|
+
in this case inserted freebusy starts with curFreeBusyItem:
|
2898
|
+
curFreeBusyItem: *-----------------------------*
|
2899
|
+
freeBusy: *--------------*
|
2900
|
+
|
2901
|
+
just replace curFreeBusyItem with freeBusy AND the rest.
|
2902
|
+
*/
|
2903
|
+
var _f1 = new FreeBusy(freeBusy.getOption());
|
2904
|
+
var _f2 = new FreeBusy(curFreeBusyItem.getOption());
|
2905
|
+
_f2.setOption('start', end);
|
2906
|
+
pushNewFreeBusy(_f1);
|
2907
|
+
pushNewFreeBusy(_f2);
|
2908
|
+
}
|
2909
|
+
else if (end.getTime() == curFreeBusyItem.getEnd().getTime()) {
|
2910
|
+
/*
|
2911
|
+
in this case inserted freebusy ends with curFreeBusyItem:
|
2912
|
+
curFreeBusyItem: *-----------------------------*
|
2913
|
+
freeBusy: *--------------*
|
2914
|
+
|
2915
|
+
just replace curFreeBusyItem with before part AND freeBusy.
|
2916
|
+
*/
|
2917
|
+
var _f1 = new FreeBusy(curFreeBusyItem.getOption());
|
2918
|
+
_f1.setOption('end', start);
|
2919
|
+
var _f2 = new FreeBusy(freeBusy.getOption());
|
2920
|
+
pushNewFreeBusy(_f1);
|
2921
|
+
pushNewFreeBusy(_f2);
|
2922
|
+
}
|
2923
|
+
else {
|
2924
|
+
/*
|
2925
|
+
in this case inserted freebusy is within curFreeBusyItem:
|
2926
|
+
curFreeBusyItem: *-----------------------------*
|
2927
|
+
freeBusy: *--------------*
|
2928
|
+
|
2929
|
+
just replace curFreeBusyItem with before part AND freeBusy AND the rest.
|
2930
|
+
*/
|
2931
|
+
var _f1 = new FreeBusy(curFreeBusyItem.getOption());
|
2932
|
+
var _f2 = new FreeBusy(freeBusy.getOption());
|
2933
|
+
var _f3 = new FreeBusy(curFreeBusyItem.getOption());
|
2934
|
+
_f1.setOption('end', start);
|
2935
|
+
_f3.setOption('start', end);
|
2936
|
+
pushNewFreeBusy(_f1);
|
2937
|
+
pushNewFreeBusy(_f2);
|
2938
|
+
pushNewFreeBusy(_f3);
|
2939
|
+
}
|
2940
|
+
/*
|
2941
|
+
as work is done, no need to go further.
|
2942
|
+
return false
|
2943
|
+
*/
|
2944
|
+
return false;
|
2945
|
+
}
|
2946
|
+
else if (curFreeBusyItem.isWithin(start) && curFreeBusyItem.getEnd().getTime() != start.getTime()) {
|
2947
|
+
/*
|
2948
|
+
in this case, inserted freebusy starts within curFreeBusyItem:
|
2949
|
+
curFreeBusyItem: *----------*
|
2950
|
+
freeBusy: *-------------------*
|
2951
|
+
|
2952
|
+
set start index AND insert before part, we'll insert freebusy later
|
2953
|
+
*/
|
2954
|
+
if (curFreeBusyItem.getStart().getTime() != start.getTime()) {
|
2955
|
+
var _f1 = new FreeBusy(curFreeBusyItem.getOption());
|
2956
|
+
_f1.setOption('end', start);
|
2957
|
+
pushNewFreeBusy(_f1);
|
2958
|
+
}
|
2959
|
+
startIndex = index;
|
2960
|
+
}
|
2961
|
+
else if (curFreeBusyItem.isWithin(end) && curFreeBusyItem.getStart().getTime() != end.getTime()) {
|
2962
|
+
/*
|
2963
|
+
in this case, inserted freebusy starts within curFreeBusyItem:
|
2964
|
+
curFreeBusyItem: *----------*
|
2965
|
+
freeBusy: *-------------------*
|
2966
|
+
|
2967
|
+
set end index AND insert freebusy AND insert after part if needed
|
2968
|
+
*/
|
2969
|
+
pushNewFreeBusy(new FreeBusy(freeBusy.getOption()));
|
2970
|
+
if (end.getTime() < curFreeBusyItem.getEnd().getTime()) {
|
2971
|
+
var _f1 = new FreeBusy(curFreeBusyItem.getOption());
|
2972
|
+
_f1.setOption('start', end);
|
2973
|
+
pushNewFreeBusy(_f1);
|
2974
|
+
}
|
2975
|
+
endIndex = index;
|
2976
|
+
return false;
|
2977
|
+
}
|
2978
|
+
});
|
2979
|
+
//now compute arguments
|
2980
|
+
var tmpFB = this.freeBusys;
|
2981
|
+
this.freeBusys = [];
|
2982
|
+
|
2983
|
+
if (startIndex) {
|
2984
|
+
this.freeBusys = this.freeBusys.concat(tmpFB.slice(0, startIndex));
|
2985
|
+
}
|
2986
|
+
this.freeBusys = this.freeBusys.concat(newFreeBusys);
|
2987
|
+
if (endIndex < tmpFB.length) {
|
2988
|
+
this.freeBusys = this.freeBusys.concat(tmpFB.slice(endIndex + 1));
|
2989
|
+
}
|
2990
|
+
/* if(start.getDate() == 1){
|
2991
|
+
console.info('insert from '+freeBusy.getStart() +' to '+freeBusy.getEnd());
|
2992
|
+
console.log('index from '+ startIndex + ' to ' + endIndex);
|
2993
|
+
var str = [];
|
2994
|
+
$.each(tmpFB, function(i){str.push(i + ": " + this.getStart().getHours() + ' > ' + this.getEnd().getHours() + ' ' + (this.getOption('free') ? 'free' : 'busy'))});
|
2995
|
+
console.log(str.join('\n'));
|
2996
|
+
|
2997
|
+
console.log('insert');
|
2998
|
+
var str = [];
|
2999
|
+
$.each(newFreeBusys, function(i){str.push(this.getStart().getHours() + ' > ' + this.getEnd().getHours())});
|
3000
|
+
console.log(str.join(', '));
|
3001
|
+
|
3002
|
+
console.log('results');
|
3003
|
+
var str = [];
|
3004
|
+
$.each(this.freeBusys, function(i){str.push(i + ": " + this.getStart().getHours() + ' > ' + this.getEnd().getHours() + ' ' + (this.getOption('free') ? 'free' :'busy'))});
|
3005
|
+
console.log(str.join('\n'));
|
3006
|
+
}*/
|
3007
|
+
return this;
|
3008
|
+
}
|
3009
|
+
});
|
3010
|
+
|
3011
|
+
})(jQuery);
|