Seasonal rec_type

Hi, I’m in need of a rec_type that allows for seasonal tasks, so it would be repeated at a specified interval (day, week, month) but only for the selected season (or perhaps 2 or 3 seasons):
Summer (Dec-Feb)
Autumn (March to May)
Winter (June-August)
Spring (September-November)

How difficult would it be to implement this? And is it only the recurring.js that I would be needing to modify to allow for this new rec_type?

Only recurring.js and it is quite complicated.

a) recurring form need to be customized and related js logic to get|set repeating mode.
b) custom repeater function need to be created ( while it not so complex, there is no any documentation or samples )

You can try to use the alternative approach. Create “monthly” recurring event, and after that delete all instances ( create recurring exceptions ) for month in which event must not occur. So it will be a normal recurring event with a lot of exceptions.

I’ve finally got some time to try and implement the seasonal rec_type now.

Ive so far constructed the interface, the rec_type saves correctly, When I open up the event it only rechecks the first month. If there is more than 1 day of the week selected the entire event vanishes from the scheduler as well.

The seasonal rec_type allows the user to specify the number of weeks between each recurrence then using checkboxes, check the days of the week and the months that the event should repeat on/during.

However when it comes to showing the next event in the recurrence I’m having some trouble in trying to get the calculations to work. Based on what I’ve learnt so far the function scheduler.transpose_type now has a case of “seasonal” added, the way I thought it might work is through combining the week and month rec_types, as such the function scheduler.transponse_size I set “seasonal” to be “7” for the week, but within the actual case the sections for months instead of using “e” I set it to be “1” the same as month.

The rec_type that is creates is formatted along the following rules:
seasonal_x_a,b__x,y,z#
seasonal - for the rec_type.
x - the number of weeks before the next recurrence.
a,b - the number for the months that have been selected, e.g. Jan & Feb would be 0,1 or Mar, May, Aug would be 2,4,7
x,y,z - the days of the week that have been selected, this is handled the same way as the week rec_type.

Is there anyway I could get some help with how to correctly construct the scheduler.transpose_type case of “seasonal” and to fix the issue with rechecking the months after saving along with multiple days selected causing the event to vanish, I’ve spent around 5hrs so far to no avail, I’ve included the dhtmlxscheduler_recurring.js file below.

[code]/*
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License

to use it in non-GPL project. Please contact sales@dhtmlx.com for details
/
scheduler.config.occurrence_timestamp_in_utc=!1;
scheduler.form_blocks.recurring={
render:function(){
return scheduler.__recurring_template
},ds:{},init_set_value:function(a,b,c){
function d(a){
for(var b=0;b<a.length;b++){
var c=a[b];
c.type==“checkbox”||c.type==“radio”?(g[c.name]||(g[c.name]=[]),g[c.name].push©):g[c.name]=c
}
}
function f(a){
for(var b=g[a],c=0;c<b.length;c++)
if(b[c].checked)
return b[c].value
}
function e(){
m(“dhx_repeat_day”).style.display=“none”;
m(“dhx_repeat_week”).style.display=“none”;
m(“dhx_repeat_month”).style.display=“none”;
m(“dhx_repeat_year”).style.display=“none”;
m(“dhx_repeat_seasonal”).style.display=“none”;
m("dhx_repeat
"+this.value).style.display=“block”;
if (this.value == “seasonal”) {
$("#repeatForm").height(240);
$("#leftDivider").height(240);
$("#rightDivider").height(240);
} else {
$("#repeatForm").height(140);
$("#leftDivider").height(140);
$("#rightDivider").height(140);
}
}
function h(a){
var b=[f(“repeat”)];
for(qb[0];b.length<5;)
b.push("");
var c="";
if(g.end[0].checked)
a.end=new Date(9999,1,1),c=“no”;
else if(g.end[2].checked)
a.end=j(g.date_of_end.value);
else{
scheduler.transpose_type(b.join("
"));
var c=Math.max(1,g.occurences_count.value),e=b[0]==“week”&&b[4]&&b[4].toString().indexOf(scheduler.config.start_on_monday?1:0)==-1?1:0;
a.end=scheduler.date.add(new Date(a.start),c+e,b.join(""))
}
return b.join("
")+"#"+c
}
function i(a,b){
var c=a.split("#"),a=c[0].split("_");
ra[0];
var e=g.repeat[{day:0,week:1,month:2,year:3,seasonal:4}[a[0]]];
switch(c[1]){
case “no”:
g.end[0].checked=!0;
break;
case “”:
g.end[2].checked=!0;
g.date_of_end.value=l(b.end);
break;
default:
g.end[1].checked=!0,g.occurences_count.value=c[1]
}
e.checked=!0;
e.onclick()
}
scheduler.form_blocks.recurring._ds={
start:c.start_date,end:c._end_date
};
var k=scheduler.date.str_to_date(scheduler.config.repeat_date),j=function(a){
var b=k(a);
scheduler.config.include_end_by&&(b=scheduler.date.add(b,1,“day”));
return b
},l=scheduler.date.date_to_str(scheduler.config.repeat_date),n=a.getElementsByTagName(“FORM”)[0],g=[];
d(n.getElementsByTagName(“INPUT”));
d(n.getElementsByTagName(“SELECT”));
if(!scheduler.config.repeat_date_of_end){
var s=scheduler.date.date_to_str(scheduler.config.repeat_date);
scheduler.config.repeat_date_of_end=s(scheduler.date.add(scheduler._currentDate(),30,“day”))
}
g.date_of_end.value=scheduler.config.repeat_date_of_end;
var m=function(a){
return document.getElementById(a)
};
scheduler.form_blocks.recurring._get_repeat_code=h;
var q={
month:function(a,b){
f(“month_type”)==“d”?(a.push(Math.max(1,g.month_count.value)),b.start.setDate(g.month_day.value)):(a.push(Math.max(1,g.month_count2.value)),a.push(g.month_day2.value),a.push(Math.max(1,g.month_week2.value)),b.start.setDate(1));
b._start=!0
},week:function(a,b){
a.push(Math.max(1,g.week_count.value));
a.push("");
a.push("");
for(var c=[],e=g.week_day,d=0;d<e.length;d++)
e[d].checked&&c.push(e[d].value);
c.length||c.push(b.start.getDay());
b.start=scheduler.date.week_start(b.start);
b._start=!0;
a.push(c.sort().join(","))
},day:function(a){
f(“day_type”)==“d”?a.push(Math.max(1,g.day_count.value)):(a.push(“week”),a.push(1),a.push(""),a.push(""),a.push(“1,2,3,4,5”),a.splice(0,1))
},year:function(a,b){
f(“year_type”)==“d”?(a.push(“1”),b.start.setMonth(0),b.start.setDate(g.year_day.value),b.start.setMonth(g.year_month.value)):(a.push(“1”),a.push(g.year_day2.value),a.push(g.year_week2.value),b.start.setDate(1),b.start.setMonth(g.year_month2.value));
b._start=!0
},seasonal:function(a,b) {
a.push(Math.max(1,g.week2_count.value));
for(var c=[],e=g.month3_day,d=0;d<e.length;d++)
e[d].checked&&c.push(e[d].value);
c.length||c.push(b.start.getDay());
a.push(c.sort().join(","));
a.push("");
for(var c=[],e=g.week2_day,d=0;d<e.length;d++)
e[d].checked&&c.push(e[d].value);
c.length||c.push(b.start.getDay());
b.start=scheduler.date.week_start(b.start);
b._start=!0;
a.push(c.sort().join(","))
}
},r={
week:function(a){
g.week_count.value=a[1];
for(var b=g.week_day,c=a[4].split(","),e={},d=0;d<c.length;d++)
e[c[d]]=!0;
for(d=0;d<b.length;d++)
b[d].checked=!!e[b[d].value]
},month:function(a,b){
a[2]==""?(g.month_type[0].checked=!0,g.month_count.value=a[1],g.month_day.value=b.start.getDate()):(g.month_type[1].checked=!0,g.month_count2.value=a[1],g.month_week2.value=a[3],g.month_day2.value=a[2])
},day:function(a){
g.day_type[0].checked=!0;g.day_count.value=a[1]
},year:function(a,b){
a[2]==""?(g.year_type[0].checked=!0,g.year_day.value=b.start.getDate(),g.year_month.value=b.start.getMonth()):(g.year_type[1].checked=!0,g.year_week2.value=a[3],g.year_day2.value=a[2],g.year_month2.value=b.start.getMonth())
},seasonal:function(a){
g.week2_count.value=a[1];
for(var b=g.week2_day,c=a[4].split(","),e={},d=0;d<c.length;d++)
e[c[d]]=!0;
for(d=0;d<b.length;d++)
b[d].checked=!!e[b[d].value];
for(var b=g.month3_day,c=a[4].split(","),e={},d=0;d<c.length;d++)
e[c[d]]=!0;
for(d=0;d<b.length;d++)
b[d].checked=!!e[b[d].value];
}
};
scheduler.form_blocks.recurring._set_repeat_code=i;
for(var o=0;o<n.elements.length;o++){
var p=n.elements[o];
switch(p.name){
case “repeat”:
p.onclick=e
}
}
scheduler._lightbox._rec_init_done=!0
},set_value:function(a,b,c){
var d=scheduler.form_blocks.recurring;
scheduler._lightbox._rec_init_done||d._init_set_value(a,b,c);
a.open=!c.rec_type;
a.blocked=c.event_pid&&c.event_pid!=“0”?!0:!1;
var f=d._ds;
f.start=c.start_date;
f.end=c._end_date;
d.button_click(0,a.previousSibling.firstChild.firstChild,a,a);
b&&d._set_repeat_code(b,f)
},get_value:function(a,b){
if(a.open){
var c=scheduler.form_blocks.recurring._ds,d={};
this.formSection(“time”).getValue(d);
c.start=d.start_date;
b.rec_type=scheduler.form_blocks.recurring._get_repeat_code©;
c._start?(b.start_date=new Date(c.start),b._start_date=new Date(c.start),c._start=!1):b._start_date=null;
b._end_date=c.end;
b.rec_pattern=b.rec_type.split("#")[0]
}else
b.rec_type=b.rec_pattern="",b._end_date=b.end_date;
return b.rec_type
},focus:function(){},button_click:function(a,b,c,d){
!d.open&&!d.blocked?(d.style.height=“140px”,b.style.backgroundPosition="-5px 0px",b.nextSibling.innerHTML=scheduler.locale.labels.button_recurring_open):(d.style.height=“0px”,b.style.backgroundPosition="-5px 20px",b.nextSibling.innerHTML=scheduler.locale.labels.button_recurring);
d.open=!d.open;scheduler.setLightboxSize()
}
};
scheduler._rec_markers={};
scheduler._rec_markers_pull={};
scheduler._add_rec_marker=function(a,b){
a._pid_time=b;
this._rec_markers[a.id]=a;
this._rec_markers_pull[a.event_pid]||(this._rec_markers_pull[a.event_pid]={});
this._rec_markers_pull[a.event_pid][b]=a
};
scheduler._get_rec_marker=function(a,b){
var c=this._rec_markers_pull[b];
return c?c[a]:null
};
scheduler._get_rec_markers=function(a){
return this._rec_markers_pull[a]||[]
};
scheduler._rec_temp=[];
(function(){
var a=scheduler.addEvent;
scheduler.addEvent=function(b,c,d,f,e){
var h=a.apply(this,arguments);
if(h){
var i=scheduler.getEvent(h);
i.event_pid!=0&&scheduler._add_rec_marker(i,i.event_length
1E3);
if(i.rec_type)
i.rec_pattern=i.rec_type.split("#")[0]
}
}
})();
scheduler.attachEvent(“onEventIdChange”,function(a,b){if(!this._ignore_call){this._ignore_call=!0;for(var c=0;c<this._rec_temp.length;c++){var d=this._rec_temp[c];if(d.event_pid==a)d.event_pid=b,this.changeEventId(d.id,b+"#"+d.id.split("#")[1])}delete this._ignore_call}});
scheduler.attachEvent(“onBeforeEventDelete”,function(a){var b=this.getEvent(a);if(a.toString().indexOf("#")!=-1||b.event_pid&&b.event_pid!=“0”&&b.rec_type&&b.rec_type!=“none”){var a=a.split("#"),c=this.uid(),d=a[1]?a[1]:b._pid_time/1E3,f=this._copy_event(b);f.id=c;f.event_pid=b.event_pid||a[0];var e=d;f.event_length=e;f.rec_type=f.rec_pattern=“none”;this.addEvent(f);this._add_rec_marker(f,e1E3)}else{b.rec_type&&this._lightbox_id&&this._roll_back_dates(b);var h=this._get_rec_markers(a),i;for(i in h)if(h.hasOwnProperty(i))a=
h[i].id,this.getEvent(a)&&this.deleteEvent(a,!0)}return!0});
scheduler.attachEvent(“onEventChanged”,function(a){if(this._loading)return!0;var b=this.getEvent(a);if(a.toString().indexOf("#")!=-1){var a=a.split("#"),c=this.uid();this._not_render=!0;var d=this._copy_event(b);d.id=c;d.event_pid=a[0];var f=a[1];d.event_length=f;d.rec_type=d.rec_pattern="";this._add_rec_marker(d,f
1E3);this.addEvent(d);this._not_render=!1}else{b.rec_type&&this._lightbox_id&&this._roll_back_dates(b);var e=this._get_rec_markers(a),h;for(h in e)e.hasOwnProperty(h)&&(delete this._rec_markers[e[h].id],
this.deleteEvent(e[h].id,!0));delete this._rec_markers_pull[a];for(var i=!1,k=0;k<this._rendered.length;k++)this._rendered[k].getAttribute(“event_id”)==a&&(i=!0);if(!i)this._select_id=null}return!0});scheduler.attachEvent(“onEventAdded”,function(a){if(!this._loading){var b=this.getEvent(a);b.rec_type&&!b.event_length&&this._roll_back_dates(b)}return!0});
scheduler.attachEvent(“onEventSave”,function(a,b){
var c=this.getEvent(a);
if(!c.rec_type&&b.rec_type&&(a+"").indexOf("#")==-1)
this._select_id=null;
return!0
});
scheduler.attachEvent(“onEventCreated”,function(a){
var b=this.getEvent(a);
if(!b.rec_type)
b.rec_type=b.rec_pattern=b.event_length=b.event_pid="";
return!0
});
scheduler.attachEvent(“onEventCancel”,function(a){
var b=this.getEvent(a);
b.rec_type&&(this._roll_back_dates(b),this.render_view_data())
});
scheduler._roll_back_dates=function(a){a.event_length=(a.end_date.valueOf()-a.start_date.valueOf())/1E3;a.end_date=a._end_date;a._start_date&&(a.start_date.setMonth(0),a.start_date.setDate(a._start_date.getDate()),a.start_date.setMonth(a._start_date.getMonth()),a.start_date.setFullYear(a._start_date.getFullYear()))};scheduler.validId=function(a){return a.toString().indexOf("#")==-1};scheduler.showLightbox_rec=scheduler.showLightbox;
scheduler.showLightbox=function(a){
var b=this.locale,c=scheduler.config.lightbox_recurring,d=this.getEvent(a),f=d.event_pid,e=a.toString().indexOf("#")!=-1;
e&&(f=a.split("#")[0]);
var h=function(a){
var b=scheduler.getEvent(a);
b._end_date=b.end_date;
b.end_date=new Date(b.start_date.valueOf()+b.event_length1E3);
return scheduler.showLightbox_rec(a)
};
if((f||f==0)&&d.rec_type)
return h(a);
if(!f||f==0||!b.labels.confirm_recurring||c==“instance”||c==“series”&&!e)
return this.showLightbox_rec(a);
if(c==“ask”){
var i=this;
dhtmlx.modalbox({
text:b.labels.confirm_recurring,
title:b.labels.title_confirm_recurring,width:“500px”,
position:“middle”,
buttons:[b.labels.button_edit_series,b.labels.button_edit_occurrence,b.labels.icon_cancel],
callback:function(b){
switch(+b){
case 0:
return h(f);
case 1:
return i.showLightbox_rec(a)
}
}
})
}else
h(f)
};
scheduler.get_visible_events_rec=scheduler.get_visible_events;
scheduler.get_visible_events=function(a){for(var b=0;b<this._rec_temp.length;b++)delete this.events[this.rec_temp[b].id];this.rec_temp=[];for(var c=this.get_visible_events_rec(a),d=[],b=0;b<c.length;b++)c[b].rec_type?c[b].rec_pattern!=“none”&&this.repeat_date(c[b],d):d.push(c[b]);return d};
(function(){var a=scheduler.is_one_day_event;scheduler.is_one_day_event=function(b){return b.rec_type?!0:a.call(this,b)};var b=scheduler.updateEvent;scheduler.updateEvent=function(a){var d=scheduler.getEvent(a);d&&d.rec_type&&a.toString().indexOf("#")===-1?scheduler.update_view():b.call(this,a)}})();
scheduler.transponse_size={
day:1,week:7,month:1,year:12,seasonal:7
};
scheduler.date.day_week=function(a,b,c){
a.setDate(1);
var c=(c-1)7,d=a.getDay(),f=b1+c-d+1;
a.setDate(f<=c?f+7:f)
};
scheduler.transpose_day_week=function(a,b,c,d,f){
for(var e=(a.getDay()||(scheduler.config.start_on_monday?7:0))-c,h=0;h<b.length;h++)
if(b[h]>e)
return a.setDate(a.getDate()+b[h]*1-e-(d?c:f));
this.transpose_day_week(a,b,c+d,null,c)
};
scheduler.transpose_type=function(a){
var b="transpose
"+a;
if(!this.date[b]){
var c=a.split("
"),d=864E5,f="add
"+a,e=this.transponse_size[c[0]]c[1];
if(c[0]==“day”||c[0]==“week”){
var h=null;
if(c[4]&&(h=c[4].split(","),scheduler.config.start_on_monday)){
for(var i=0;i<h.length;i++)
h[i]=h[i]1||7;
h.sort()
}
this.date[b]=function(a,b){
var c=Math.floor((b.valueOf()-a.valueOf())/(d
e));
c>0&&a.setDate(a.getDate()+c
e);
h&&scheduler.transpose_day_week(a,h,1,e)
};
this.date[f]=function(a,b){
var c=new Date(a.valueOf());
if(h)
for(var d=0;d<b;d++)
scheduler.transpose_day_week(c,h,0,e);
else
c.setDate(c.getDate()+b
e);
return c
}
}else if(c[0]==“month”||c[0]==“year”)
this.date[b]=function(a,b){
var d=Math.ceil((b.getFullYear()12+b.getMonth()1-(a.getFullYear()12+a.getMonth()1))/e);
d>=0&&a.setMonth(a.getMonth()+d
e);
c[3]&&scheduler.date.day_week(a,c[2],c[3])
},this.date[f]=function(a,b){
var d=new Date(a.valueOf());
d.setMonth(d.getMonth()+b
e);
c[3]&&scheduler.date.day_week(d,c[2],c[3]);
return d
}
else if (c[0]==“seasonal”) {
var h=null;
if(c[4]&&(h=c[4].split(","),scheduler.config.start_on_monday)){
for(var i=0;i<h.length;i++) {
h[i]=h[i]1||7;
}
h.sort()
}
this.date[b]=function(a,b){
var c=Math.floor((b.valueOf()-a.valueOf())/(d
e));
c>0&&a.setDate(a.getDate()+c
e);
var d=Math.ceil((b.getFullYear()12+b.getMonth()1-(a.getFullYear()12+a.getMonth()1))/1);
d>=0&&a.setMonth(a.getMonth()+d
1);
h&&scheduler.transpose_day_week(a,h,1,e)
};
this.date[f]=function(a,b){
var c=new Date(a.valueOf());
c.setMonth(c.getMonth()+b
e);
if(h)
for(var d=0;d<b;d++)
scheduler.transpose_day_week(c,h,0,e);
else
c.setDate(c.getDate()+b
e);
return c
}
}
}
};
scheduler.repeat_date=function(a,b,c,d,f){
var d=d||this._min_date,f=f||this._max_date,e=new Date(a.start_date.valueOf());
if(!a.rec_pattern&&a.rec_type)
a.rec_pattern=a.rec_type.split("#")[0];
this.transpose_type(a.rec_pattern);
for(scheduler.date"transpose_"+a.rec_pattern;e<a.start_date||scheduler._fix_daylight_saving_date(e,d,a,e,new Date(e.valueOf()+a.event_length
1E3)).valueOf()<=d.valueOf()||e.valueOf()+a.event_length
1E3<=d.valueOf():wink:
e=this.date.add(e,1,a.rec_pattern);
for(;e<f&&e<a.end_date;){
var h=scheduler.config.occurrence_timestamp_in_utc?Date.UTC(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds()):e.valueOf(),i=this._get_rec_marker(h,a.id);
if(i)
c&&b.push(i);
else{
var k=new Date(e.valueOf()+a.event_length1E3),j=this._copy_event(a);
j.text=a.text;
j.start_date=e;
j.event_pid=a.id;
j.id=a.id+"#"+Math.ceil(h/1E3);
j.end_date=k;
j.end_date=scheduler._fix_daylight_saving_date(j.start_date,j.end_date,a,e,j.end_date);
j._timed=this.is_one_day_event(j);
if(!j._timed&&!this._table_view&&!this.config.multi_day)
break;
b.push(j);
c||(this._events[j.id]=j,this._rec_temp.push(j))
}
e=this.date.add(e,1,a.rec_pattern)
}
};
scheduler._fix_daylight_saving_date=function(a,b,c,d,f){
var e=a.getTimezoneOffset()-b.getTimezoneOffset();
return e?e>0?new Date(d.valueOf()+c.event_length
1E3-e6E4):new Date(b.valueOf()-e6E4):new Date(f.valueOf())
};
scheduler.getRecDates=function(a,b){
var c=typeof a==“object”?a:scheduler.getEvent(a),d=0,f=[],b=b||100,e=new Date(c.start_date.valueOf()),h=new Date(e.valueOf());
if(!c.rec_type)
return[{start_date:c.start_date,end_date:c.end_date}];
if(c.rec_type==“none”)
return[];
this.transpose_type(c.rec_pattern);
for(scheduler.date"transpose_"+c.rec_pattern;e<c.start_date||e.valueOf()+c.event_length1E3<=h.valueOf():wink:
e=this.date.add(e,1,c.rec_pattern);
for(;e<c.end_date;){
var i=this._get_rec_marker(e.valueOf(),c.id),k=!0;
if (new Date(e).getTime() > new Date().getTime()) {
if(i)
i.rec_type==“none”?k=!1:f.push({start_date:i.start_date,end_date:i.end_date});
else{
var j=new Date(e),l=new Date(e.valueOf()+c.event_length
1E3),l=scheduler._fix_daylight_saving_date(j,l,c,e,l);
f.push({start_date:j,end_date:l})
}
e=this.date.add(e,1,c.rec_pattern);
if(k&&(d++,d==b))
break
} else
e=this.date.add(e,1,c.rec_pattern);
}
return f
};
scheduler.getEvents=function(a,b){
var c=[],d;
for(d in this._events){
var f=this._events[d];
if(f&&f.start_date<b&&f.end_date>a)
if(f.rec_pattern){
if(f.rec_pattern!=“none”){
var e=[];
this.repeat_date(f,e,!0,a,b);
for(var h=0;h<e.length;h++)
!e[h].rec_pattern&&e[h].start_date<b&&e[h].end_date>a&&!this._rec_markers[e[h].id]&&c.push(e[h])
}
}else
f.id.toString().indexOf("#")==-1&&c.push(f)
}
return c
};
scheduler.config.repeat_date="%m.%d.%Y";
scheduler.config.lightbox.sections=[
{name:“description”,height:130,map_to:“text”,type:“textarea”,focus:!0},
{name:“recurring”,type:“recurring”,map_to:“rec_type”,button:“recurring”},
{name:“time”,height:72,type:“time”,map_to:“auto”}
];
scheduler._copy_dummy=function(){
var a=new Date(this.start_date),b=new Date(this.end_date);
this.start_date=a;
this.end_date=b;
this.event_length=this.event_pid=this.rec_pattern=this.rec_type=null
};
scheduler.config.include_end_by=!1;
scheduler.config.lightbox_recurring=“ask”;
scheduler.attachEvent(“onClearAll”,function(){
scheduler._rec_markers={};
scheduler._rec_markers_pull={};
scheduler._rec_temp=[]
});
scheduler.__recurring_template=’

’+
‘’+
’+
‘’+
‘Daily’+

'+
‘’+
‘Weekly’+

'+
‘’+
‘Monthly’+

'+
‘’+
‘Yearly’+

'+
‘’+
‘Seasonal’+
‘’+
’+
’+
’+
’+
‘’+
‘Every’+
‘’+
‘day’+

'+
‘’+
‘Every workday’+
‘’+
’+
’+
'Repeat everyweek next days:
'+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
’+
‘’+
‘Monday’+

'+
‘’+
‘Thursday’+
‘’+
’+
‘’+
‘Tuesday’+

'+
‘’+
‘Friday’+
‘’+
’+
‘’+
‘Wednesday’+

'+
‘’+
‘Saturday’+
‘’+
’+
‘’+
‘Sunday’+

'+

’+
’+
’+
‘’+
‘Repeat every’+
‘’+
‘day of every’+
'month
'+
‘’+
‘On every’+
‘’+
‘’+
‘’+
‘Monday’+
‘Tuesday’+
‘Wednesday’+
‘Thursday’+
‘Friday’+
‘Saturday’+
‘Sunday’+
‘’+
'of everymonth
'+
’+
’+
‘’+
‘Every’+
‘’+
'day of '+
‘’+
‘January’+
‘February’+
‘March’+
‘April’+
‘May’+
‘June’+
‘July’+
‘August’+
‘September’+
‘October’+
‘November’+
‘December’+
‘’+
'month
'+
‘’+
‘On’+
‘’+
‘’+
‘’+
‘Monday’+
‘Tuesday’+
‘Wednesday’+
‘Thursday’+
‘Friday’+
‘Saturday’+
‘Sunday’+
‘’+
‘of’+
‘’+
‘January’+
‘February’+
‘March’+
‘April’+
‘May’+
‘June’+
‘July’+
‘August’+
‘September’+
‘October’+
‘November’+
‘December’+

'+
’+
’+
'Repeat everyweek on days:
'+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
’+
‘’+
‘Monday’+

'+
‘’+
‘Thursday’+
‘’+
’+
‘’+
‘Tuesday’+

'+
‘’+
‘Friday’+
‘’+
’+
‘’+
‘Wednesday’+

'+
‘’+
‘Saturday’+
‘’+
’+
‘’+
‘Sunday’+

'+


'+
'During the months:
'+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
’+
‘’+
‘January’+

'+
‘’+
‘May’+

'+
‘’+
‘September’+
‘’+
’+
‘’+
‘February’+

'+
‘’+
‘June’+

'+
‘’+
‘October’+
‘’+
’+
‘’+
‘March’+

'+
‘’+
‘July’+

'+
‘’+
‘November’+
‘’+
’+
‘’+
‘April’+

'+
‘’+
‘August’+

'+
‘’+
‘December’+
‘’+
’+
’+
’+
’+
’+
‘’+
‘No end date’+

'+
‘’+
‘End after’+
‘’+
'occurrences
'+
‘’+
‘End by’+
‘’+

'+
’+
‘’+
’+
';[/code]

UPDATE: I’ve fixed the issue with not checking all the months, the issue with not displaying on multiple days was actually the event being hidden by another, which I fixed now too. so all that remains is the recurrence as only the first of the series ever shows.

Updated code:

[code]/*
This software is allowed to use under GPL or you need to obtain Commercial or Enterise License

to use it in non-GPL project. Please contact sales@dhtmlx.com for details
/
scheduler.config.occurrence_timestamp_in_utc=!1;
scheduler.form_blocks.recurring={
render:function(){
return scheduler.__recurring_template
},ds:{},init_set_value:function(a,b,c){
function d(a){
for(var b=0;b<a.length;b++){
var c=a[b];
c.type==“checkbox”||c.type==“radio”?(g[c.name]||(g[c.name]=[]),g[c.name].push©):g[c.name]=c
}
}
function f(a){
for(var b=g[a],c=0;c<b.length;c++)
if(b[c].checked)
return b[c].value
}
function e(){
m(“dhx_repeat_day”).style.display=“none”;
m(“dhx_repeat_week”).style.display=“none”;
m(“dhx_repeat_month”).style.display=“none”;
m(“dhx_repeat_year”).style.display=“none”;
m(“dhx_repeat_seasonal”).style.display=“none”;
m("dhx_repeat
"+this.value).style.display=“block”;
if (this.value == “seasonal”) {
$("#repeatForm").height(240);
$("#leftDivider").height(240);
$("#rightDivider").height(240);
} else {
$("#repeatForm").height(140);
$("#leftDivider").height(140);
$("#rightDivider").height(140);
}
}
function h(a){
var b=[f(“repeat”)];
for(qb[0];b.length<5;)
b.push("");
var c="";
if(g.end[0].checked)
a.end=new Date(9999,1,1),c=“no”;
else if(g.end[2].checked)
a.end=j(g.date_of_end.value);
else{
scheduler.transpose_type(b.join("
"));
var c=Math.max(1,g.occurences_count.value),e=b[0]==“week”&&b[4]&&b[4].toString().indexOf(scheduler.config.start_on_monday?1:0)==-1?1:0;
a.end=scheduler.date.add(new Date(a.start),c+e,b.join(""))
}
return b.join("
")+"#"+c
}
function i(a,b){
var c=a.split("#"),a=c[0].split("_");
ra[0];
var e=g.repeat[{day:0,week:1,month:2,year:3,seasonal:4}[a[0]]];
switch(c[1]){
case “no”:
g.end[0].checked=!0;
break;
case “”:
g.end[2].checked=!0;
g.date_of_end.value=l(b.end);
break;
default:
g.end[1].checked=!0,g.occurences_count.value=c[1]
}
e.checked=!0;
e.onclick()
}
scheduler.form_blocks.recurring._ds={
start:c.start_date,end:c._end_date
};
var k=scheduler.date.str_to_date(scheduler.config.repeat_date),j=function(a){
var b=k(a);
scheduler.config.include_end_by&&(b=scheduler.date.add(b,1,“day”));
return b
},l=scheduler.date.date_to_str(scheduler.config.repeat_date),n=a.getElementsByTagName(“FORM”)[0],g=[];
d(n.getElementsByTagName(“INPUT”));
d(n.getElementsByTagName(“SELECT”));
if(!scheduler.config.repeat_date_of_end){
var s=scheduler.date.date_to_str(scheduler.config.repeat_date);
scheduler.config.repeat_date_of_end=s(scheduler.date.add(scheduler._currentDate(),30,“day”))
}
g.date_of_end.value=scheduler.config.repeat_date_of_end;
var m=function(a){
return document.getElementById(a)
};
scheduler.form_blocks.recurring._get_repeat_code=h;
var q={
month:function(a,b){
f(“month_type”)==“d”?(a.push(Math.max(1,g.month_count.value)),b.start.setDate(g.month_day.value)):(a.push(Math.max(1,g.month_count2.value)),a.push(g.month_day2.value),a.push(Math.max(1,g.month_week2.value)),b.start.setDate(1));
b._start=!0
},week:function(a,b){
a.push(Math.max(1,g.week_count.value));
a.push("");
a.push("");
for(var c=[],e=g.week_day,d=0;d<e.length;d++)
e[d].checked&&c.push(e[d].value);
c.length||c.push(b.start.getDay());
b.start=scheduler.date.week_start(b.start);
b._start=!0;
a.push(c.sort().join(","))
},day:function(a){
f(“day_type”)==“d”?a.push(Math.max(1,g.day_count.value)):(a.push(“week”),a.push(1),a.push(""),a.push(""),a.push(“1,2,3,4,5”),a.splice(0,1))
},year:function(a,b){
f(“year_type”)==“d”?(a.push(“1”),b.start.setMonth(0),b.start.setDate(g.year_day.value),b.start.setMonth(g.year_month.value)):(a.push(“1”),a.push(g.year_day2.value),a.push(g.year_week2.value),b.start.setDate(1),b.start.setMonth(g.year_month2.value));
b._start=!0
},seasonal:function(a,b) {
a.push(Math.max(1,g.week2_count.value));
for(var c=[],e=g.month3_day,d=0;d<e.length;d++)
e[d].checked&&c.push(e[d].value);
c.length||c.push(b.start.getDay());
a.push(c.sort().join(","));
a.push("");
for(var c=[],e=g.week2_day,d=0;d<e.length;d++)
e[d].checked&&c.push(e[d].value);
c.length||c.push(b.start.getDay());
b.start=scheduler.date.week_start(b.start);
b._start=!0;
a.push(c.sort().join(","))
}
},r={
week:function(a){
g.week_count.value=a[1];
for(var b=g.week_day,c=a[4].split(","),e={},d=0;d<c.length;d++)
e[c[d]]=!0;
for(d=0;d<b.length;d++)
b[d].checked=!!e[b[d].value]
},month:function(a,b){
a[2]==""?(g.month_type[0].checked=!0,g.month_count.value=a[1],g.month_day.value=b.start.getDate()):(g.month_type[1].checked=!0,g.month_count2.value=a[1],g.month_week2.value=a[3],g.month_day2.value=a[2])
},day:function(a){
g.day_type[0].checked=!0;g.day_count.value=a[1]
},year:function(a,b){
a[2]==""?(g.year_type[0].checked=!0,g.year_day.value=b.start.getDate(),g.year_month.value=b.start.getMonth()):(g.year_type[1].checked=!0,g.year_week2.value=a[3],g.year_day2.value=a[2],g.year_month2.value=b.start.getMonth())
},seasonal:function(a){
g.week2_count.value=a[1];
for(var b=g.week2_day,c=a[4].split(","),e={},d=0;d<c.length;d++)
e[c[d]]=!0;
for(d=0;d<b.length;d++)
b[d].checked=!!e[b[d].value];
for(var b=g.month3_day,c=a[2].split(","),e={},d=0;d<c.length;d++)
e[c[d]]=!0;
for(d=0;d<b.length;d++)
b[d].checked=!!e[b[d].value];
}
};
scheduler.form_blocks.recurring._set_repeat_code=i;
for(var o=0;o<n.elements.length;o++){
var p=n.elements[o];
switch(p.name){
case “repeat”:
p.onclick=e
}
}
scheduler._lightbox._rec_init_done=!0
},set_value:function(a,b,c){
var d=scheduler.form_blocks.recurring;
scheduler._lightbox._rec_init_done||d._init_set_value(a,b,c);
a.open=!c.rec_type;
a.blocked=c.event_pid&&c.event_pid!=“0”?!0:!1;
var f=d._ds;
f.start=c.start_date;
f.end=c._end_date;
d.button_click(0,a.previousSibling.firstChild.firstChild,a,a);
b&&d._set_repeat_code(b,f)
},get_value:function(a,b){
if(a.open){
var c=scheduler.form_blocks.recurring._ds,d={};
this.formSection(“time”).getValue(d);
c.start=d.start_date;
b.rec_type=scheduler.form_blocks.recurring._get_repeat_code©;
c._start?(b.start_date=new Date(c.start),b._start_date=new Date(c.start),c._start=!1):b._start_date=null;
b._end_date=c.end;
b.rec_pattern=b.rec_type.split("#")[0]
}else
b.rec_type=b.rec_pattern="",b._end_date=b.end_date;
return b.rec_type
},focus:function(){},button_click:function(a,b,c,d){
!d.open&&!d.blocked?(d.style.height=“140px”,b.style.backgroundPosition="-5px 0px",b.nextSibling.innerHTML=scheduler.locale.labels.button_recurring_open):(d.style.height=“0px”,b.style.backgroundPosition="-5px 20px",b.nextSibling.innerHTML=scheduler.locale.labels.button_recurring);
d.open=!d.open;scheduler.setLightboxSize()
}
};
scheduler._rec_markers={};
scheduler._rec_markers_pull={};
scheduler._add_rec_marker=function(a,b){
a._pid_time=b;
this._rec_markers[a.id]=a;
this._rec_markers_pull[a.event_pid]||(this._rec_markers_pull[a.event_pid]={});
this._rec_markers_pull[a.event_pid][b]=a
};
scheduler._get_rec_marker=function(a,b){
var c=this._rec_markers_pull[b];
return c?c[a]:null
};
scheduler._get_rec_markers=function(a){
return this._rec_markers_pull[a]||[]
};
scheduler._rec_temp=[];
(function(){
var a=scheduler.addEvent;
scheduler.addEvent=function(b,c,d,f,e){
var h=a.apply(this,arguments);
if(h){
var i=scheduler.getEvent(h);
i.event_pid!=0&&scheduler._add_rec_marker(i,i.event_length
1E3);
if(i.rec_type)
i.rec_pattern=i.rec_type.split("#")[0]
}
}
})();
scheduler.attachEvent(“onEventIdChange”,function(a,b){if(!this._ignore_call){this._ignore_call=!0;for(var c=0;c<this._rec_temp.length;c++){var d=this._rec_temp[c];if(d.event_pid==a)d.event_pid=b,this.changeEventId(d.id,b+"#"+d.id.split("#")[1])}delete this._ignore_call}});
scheduler.attachEvent(“onBeforeEventDelete”,function(a){var b=this.getEvent(a);if(a.toString().indexOf("#")!=-1||b.event_pid&&b.event_pid!=“0”&&b.rec_type&&b.rec_type!=“none”){var a=a.split("#"),c=this.uid(),d=a[1]?a[1]:b._pid_time/1E3,f=this._copy_event(b);f.id=c;f.event_pid=b.event_pid||a[0];var e=d;f.event_length=e;f.rec_type=f.rec_pattern=“none”;this.addEvent(f);this._add_rec_marker(f,e1E3)}else{b.rec_type&&this._lightbox_id&&this._roll_back_dates(b);var h=this._get_rec_markers(a),i;for(i in h)if(h.hasOwnProperty(i))a=
h[i].id,this.getEvent(a)&&this.deleteEvent(a,!0)}return!0});
scheduler.attachEvent(“onEventChanged”,function(a){if(this._loading)return!0;var b=this.getEvent(a);if(a.toString().indexOf("#")!=-1){var a=a.split("#"),c=this.uid();this._not_render=!0;var d=this._copy_event(b);d.id=c;d.event_pid=a[0];var f=a[1];d.event_length=f;d.rec_type=d.rec_pattern="";this._add_rec_marker(d,f
1E3);this.addEvent(d);this._not_render=!1}else{b.rec_type&&this._lightbox_id&&this._roll_back_dates(b);var e=this._get_rec_markers(a),h;for(h in e)e.hasOwnProperty(h)&&(delete this._rec_markers[e[h].id],
this.deleteEvent(e[h].id,!0));delete this._rec_markers_pull[a];for(var i=!1,k=0;k<this._rendered.length;k++)this._rendered[k].getAttribute(“event_id”)==a&&(i=!0);if(!i)this._select_id=null}return!0});scheduler.attachEvent(“onEventAdded”,function(a){if(!this._loading){var b=this.getEvent(a);b.rec_type&&!b.event_length&&this._roll_back_dates(b)}return!0});
scheduler.attachEvent(“onEventSave”,function(a,b){
var c=this.getEvent(a);
if(!c.rec_type&&b.rec_type&&(a+"").indexOf("#")==-1)
this._select_id=null;
return!0
});
scheduler.attachEvent(“onEventCreated”,function(a){
var b=this.getEvent(a);
if(!b.rec_type)
b.rec_type=b.rec_pattern=b.event_length=b.event_pid="";
return!0
});
scheduler.attachEvent(“onEventCancel”,function(a){
var b=this.getEvent(a);
b.rec_type&&(this._roll_back_dates(b),this.render_view_data())
});
scheduler._roll_back_dates=function(a){a.event_length=(a.end_date.valueOf()-a.start_date.valueOf())/1E3;a.end_date=a._end_date;a._start_date&&(a.start_date.setMonth(0),a.start_date.setDate(a._start_date.getDate()),a.start_date.setMonth(a._start_date.getMonth()),a.start_date.setFullYear(a._start_date.getFullYear()))};scheduler.validId=function(a){return a.toString().indexOf("#")==-1};scheduler.showLightbox_rec=scheduler.showLightbox;
scheduler.showLightbox=function(a){
var b=this.locale,c=scheduler.config.lightbox_recurring,d=this.getEvent(a),f=d.event_pid,e=a.toString().indexOf("#")!=-1;
e&&(f=a.split("#")[0]);
var h=function(a){
var b=scheduler.getEvent(a);
b._end_date=b.end_date;
b.end_date=new Date(b.start_date.valueOf()+b.event_length1E3);
return scheduler.showLightbox_rec(a)
};
if((f||f==0)&&d.rec_type)
return h(a);
if(!f||f==0||!b.labels.confirm_recurring||c==“instance”||c==“series”&&!e)
return this.showLightbox_rec(a);
if(c==“ask”){
var i=this;
dhtmlx.modalbox({
text:b.labels.confirm_recurring,
title:b.labels.title_confirm_recurring,width:“500px”,
position:“middle”,
buttons:[b.labels.button_edit_series,b.labels.button_edit_occurrence,b.labels.icon_cancel],
callback:function(b){
switch(+b){
case 0:
return h(f);
case 1:
return i.showLightbox_rec(a)
}
}
})
}else
h(f)
};
scheduler.get_visible_events_rec=scheduler.get_visible_events;
scheduler.get_visible_events=function(a){for(var b=0;b<this._rec_temp.length;b++)delete this.events[this.rec_temp[b].id];this.rec_temp=[];for(var c=this.get_visible_events_rec(a),d=[],b=0;b<c.length;b++)c[b].rec_type?c[b].rec_pattern!=“none”&&this.repeat_date(c[b],d):d.push(c[b]);return d};
(function(){var a=scheduler.is_one_day_event;scheduler.is_one_day_event=function(b){return b.rec_type?!0:a.call(this,b)};var b=scheduler.updateEvent;scheduler.updateEvent=function(a){var d=scheduler.getEvent(a);d&&d.rec_type&&a.toString().indexOf("#")===-1?scheduler.update_view():b.call(this,a)}})();
scheduler.transponse_size={
day:1,week:7,month:1,year:12,seasonal:7
};
scheduler.date.day_week=function(a,b,c){
a.setDate(1);
var c=(c-1)7,d=a.getDay(),f=b1+c-d+1;
a.setDate(f<=c?f+7:f)
};
scheduler.transpose_day_week=function(a,b,c,d,f){
for(var e=(a.getDay()||(scheduler.config.start_on_monday?7:0))-c,h=0;h<b.length;h++)
if(b[h]>e)
return a.setDate(a.getDate()+b[h]*1-e-(d?c:f));
this.transpose_day_week(a,b,c+d,null,c)
};
scheduler.transpose_type=function(a){
var b="transpose
"+a;
if(!this.date[b]){
var c=a.split("
"),d=864E5,f="add
"+a,e=this.transponse_size[c[0]]c[1];
if(c[0]==“day”||c[0]==“week”){
var h=null;
if(c[4]&&(h=c[4].split(","),scheduler.config.start_on_monday)){
for(var i=0;i<h.length;i++)
h[i]=h[i]1||7;
h.sort()
}
this.date[b]=function(a,b){
var c=Math.floor((b.valueOf()-a.valueOf())/(d
e));
c>0&&a.setDate(a.getDate()+c
e);
h&&scheduler.transpose_day_week(a,h,1,e)
};
this.date[f]=function(a,b){
var c=new Date(a.valueOf());
if(h)
for(var d=0;d<b;d++)
scheduler.transpose_day_week(c,h,0,e);
else
c.setDate(c.getDate()+b
e);
return c
}
}else if(c[0]==“month”||c[0]==“year”)
this.date[b]=function(a,b){
var d=Math.ceil((b.getFullYear()12+b.getMonth()1-(a.getFullYear()12+a.getMonth()1))/e);
d>=0&&a.setMonth(a.getMonth()+d
e);
c[3]&&scheduler.date.day_week(a,c[2],c[3])
},this.date[f]=function(a,b){
var d=new Date(a.valueOf());
d.setMonth(d.getMonth()+b
e);
c[3]&&scheduler.date.day_week(d,c[2],c[3]);
return d
}
else if (c[0]==“seasonal”) {
var h=null;
if(c[4]&&(h=c[4].split(","),scheduler.config.start_on_monday)){
for(var i=0;i<h.length;i++) {
h[i]=h[i]1||7;
}
h.sort()
}
this.date[b]=function(a,b){
var c=Math.floor((b.valueOf()-a.valueOf())/(d
e));
c>0&&a.setDate(a.getDate()+c
e);
var d=Math.ceil((b.getFullYear()12+b.getMonth()1-(a.getFullYear()12+a.getMonth()1))/1);
d>=0&&a.setMonth(a.getMonth()+d
1);
h&&scheduler.transpose_day_week(a,h,1,e)
};
this.date[f]=function(a,b){
var c=new Date(a.valueOf());
c.setMonth(c.getMonth()+b
e);
if(h)
for(var d=0;d<b;d++)
scheduler.transpose_day_week(c,h,0,e);
else
c.setDate(c.getDate()+b
e);
return c
}
}
}
};
scheduler.repeat_date=function(a,b,c,d,f){
var d=d||this._min_date,f=f||this._max_date,e=new Date(a.start_date.valueOf());
if(!a.rec_pattern&&a.rec_type)
a.rec_pattern=a.rec_type.split("#")[0];
this.transpose_type(a.rec_pattern);
for(scheduler.date"transpose_"+a.rec_pattern;e<a.start_date||scheduler._fix_daylight_saving_date(e,d,a,e,new Date(e.valueOf()+a.event_length
1E3)).valueOf()<=d.valueOf()||e.valueOf()+a.event_length
1E3<=d.valueOf():wink:
e=this.date.add(e,1,a.rec_pattern);
for(;e<f&&e<a.end_date;){
var h=scheduler.config.occurrence_timestamp_in_utc?Date.UTC(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours(),e.getMinutes(),e.getSeconds()):e.valueOf(),i=this._get_rec_marker(h,a.id);
if(i)
c&&b.push(i);
else{
var k=new Date(e.valueOf()+a.event_length1E3),j=this._copy_event(a);
j.text=a.text;
j.start_date=e;
j.event_pid=a.id;
j.id=a.id+"#"+Math.ceil(h/1E3);
j.end_date=k;
j.end_date=scheduler._fix_daylight_saving_date(j.start_date,j.end_date,a,e,j.end_date);
j._timed=this.is_one_day_event(j);
if(!j._timed&&!this._table_view&&!this.config.multi_day)
break;
b.push(j);
c||(this._events[j.id]=j,this._rec_temp.push(j))
}
e=this.date.add(e,1,a.rec_pattern)
}
};
scheduler._fix_daylight_saving_date=function(a,b,c,d,f){
var e=a.getTimezoneOffset()-b.getTimezoneOffset();
return e?e>0?new Date(d.valueOf()+c.event_length
1E3-e6E4):new Date(b.valueOf()-e6E4):new Date(f.valueOf())
};
scheduler.getRecDates=function(a,b){
var c=typeof a==“object”?a:scheduler.getEvent(a),d=0,f=[],b=b||100,e=new Date(c.start_date.valueOf()),h=new Date(e.valueOf());
if(!c.rec_type)
return[{start_date:c.start_date,end_date:c.end_date}];
if(c.rec_type==“none”)
return[];
this.transpose_type(c.rec_pattern);
for(scheduler.date"transpose_"+c.rec_pattern;e<c.start_date||e.valueOf()+c.event_length1E3<=h.valueOf():wink:
e=this.date.add(e,1,c.rec_pattern);
for(;e<c.end_date;){
var i=this._get_rec_marker(e.valueOf(),c.id),k=!0;
if (new Date(e).getTime() > new Date().getTime()) {
if(i)
i.rec_type==“none”?k=!1:f.push({start_date:i.start_date,end_date:i.end_date});
else{
var j=new Date(e),l=new Date(e.valueOf()+c.event_length
1E3),l=scheduler._fix_daylight_saving_date(j,l,c,e,l);
f.push({start_date:j,end_date:l})
}
e=this.date.add(e,1,c.rec_pattern);
if(k&&(d++,d==b))
break
} else
e=this.date.add(e,1,c.rec_pattern);
}
return f
};
scheduler.getEvents=function(a,b){
var c=[],d;
for(d in this._events){
var f=this._events[d];
if(f&&f.start_date<b&&f.end_date>a)
if(f.rec_pattern){
if(f.rec_pattern!=“none”){
var e=[];
this.repeat_date(f,e,!0,a,b);
for(var h=0;h<e.length;h++)
!e[h].rec_pattern&&e[h].start_date<b&&e[h].end_date>a&&!this._rec_markers[e[h].id]&&c.push(e[h])
}
}else
f.id.toString().indexOf("#")==-1&&c.push(f)
}
return c
};
scheduler.config.repeat_date="%m.%d.%Y";
scheduler.config.lightbox.sections=[
{name:“description”,height:130,map_to:“text”,type:“textarea”,focus:!0},
{name:“recurring”,type:“recurring”,map_to:“rec_type”,button:“recurring”},
{name:“time”,height:72,type:“time”,map_to:“auto”}
];
scheduler._copy_dummy=function(){
var a=new Date(this.start_date),b=new Date(this.end_date);
this.start_date=a;
this.end_date=b;
this.event_length=this.event_pid=this.rec_pattern=this.rec_type=null
};
scheduler.config.include_end_by=!1;
scheduler.config.lightbox_recurring=“ask”;
scheduler.attachEvent(“onClearAll”,function(){
scheduler._rec_markers={};
scheduler._rec_markers_pull={};
scheduler._rec_temp=[]
});
scheduler.__recurring_template=’

’+
‘’+
’+
‘’+
‘Daily’+

'+
‘’+
‘Weekly’+

'+
‘’+
‘Monthly’+

'+
‘’+
‘Yearly’+

'+
‘’+
‘Seasonal’+
‘’+
’+
’+
’+
’+
‘’+
‘Every’+
‘’+
‘day’+

'+
‘’+
‘Every workday’+
‘’+
’+
’+
'Repeat everyweek next days:
'+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
’+
‘’+
‘Monday’+

'+
‘’+
‘Thursday’+
‘’+
’+
‘’+
‘Tuesday’+

'+
‘’+
‘Friday’+
‘’+
’+
‘’+
‘Wednesday’+

'+
‘’+
‘Saturday’+
‘’+
’+
‘’+
‘Sunday’+

'+

’+
’+
’+
‘’+
‘Repeat every’+
‘’+
‘day of every’+
'month
'+
‘’+
‘On every’+
‘’+
‘’+
‘’+
‘Monday’+
‘Tuesday’+
‘Wednesday’+
‘Thursday’+
‘Friday’+
‘Saturday’+
‘Sunday’+
‘’+
'of everymonth
'+
’+
’+
‘’+
‘Every’+
‘’+
'day of '+
‘’+
‘January’+
‘February’+
‘March’+
‘April’+
‘May’+
‘June’+
‘July’+
‘August’+
‘September’+
‘October’+
‘November’+
‘December’+
‘’+
'month
'+
‘’+
‘On’+
‘’+
‘’+
‘’+
‘Monday’+
‘Tuesday’+
‘Wednesday’+
‘Thursday’+
‘Friday’+
‘Saturday’+
‘Sunday’+
‘’+
‘of’+
‘’+
‘January’+
‘February’+
‘March’+
‘April’+
‘May’+
‘June’+
‘July’+
‘August’+
‘September’+
‘October’+
‘November’+
‘December’+

'+
’+
’+
'Repeat everyweek on days:
'+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
’+
‘’+
‘Monday’+

'+
‘’+
‘Thursday’+
‘’+
’+
‘’+
‘Tuesday’+

'+
‘’+
‘Friday’+
‘’+
’+
‘’+
‘Wednesday’+

'+
‘’+
‘Saturday’+
‘’+
’+
‘’+
‘Sunday’+

'+


'+
'During the months:
'+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
‘’+
’+
‘’+
‘January’+

'+
‘’+
‘May’+

'+
‘’+
‘September’+
‘’+
’+
‘’+
‘February’+

'+
‘’+
‘June’+

'+
‘’+
‘October’+
‘’+
’+
‘’+
‘March’+

'+
‘’+
‘July’+

'+
‘’+
‘November’+
‘’+
’+
‘’+
‘April’+

'+
‘’+
‘August’+

'+
‘’+
‘December’+
‘’+
’+
’+
’+
’+
’+
‘’+
‘No end date’+

'+
‘’+
‘End after’+
‘’+
'occurrences
'+
‘’+
‘End by’+
‘’+

'+
’+
‘’+
’+
';[/code]

In sources folder, there is a not compressed version of dhtmlxscheduler and all extensions, working with not compressed names is a more convenient than working with abstract a,b,c variables.

There are two methods created for each repeat type

scheduler.date.transpose_{type}
scheduler.date.add_{type}

first one is necessary to set the date to the nearest instance of recurring event
second is necessary to locate the next recurring event

If you want to limit the month is which event can occurs, code can be modified like next

[code]
this.date[gf] = function(sd, inc) {
var nd = new Date(sd.valueOf());
if (days) {
for (var count = 0; count < inc; count++)
scheduler.transpose_day_week(nd, days, 0, step);
} else
nd.setDate(nd.getDate() + inc * step);

			if (!check_valid_month(nd.getMonth()))
                                     return scheduler.date[gf](nd, inc);

			return nd;
	};[/code]

Above code checks is new instance date is in valid month ( check_valid_month - custom function ), and if not - checks the next day in the serie.

Thanks so much :smiley:, using the code you posted as a basis I’ve now got it displaying the seasonal recurrence, who’d have thought it’d be as simple as

if (!check_valid_month(c.getMonth(),g)) return scheduler.date[f](c,b);

I’ve been working with the compressed files for a long time now, I didn’t realise there was versions of the uncompressed code. If I swapped to the uncompressed versions now it’d probably take far too much time to work out all the changes I’ve made to each file to suit my needs.

My next question is how much and what do I need to change within SchedulerHelper.php to allow for this new rec_type, as I use SchedulerHelper to generate all the next occurrences so they can be used in a search?

I’m just guessing here, but I’d need to edit the transpositor, date_generator and get_correct_date functions.
The get_correct_date function would need it’s case to go before the line:

} elseif (($this->coun2 != '')&&($this->day != '')) {

As I’m storing the months in the position that the coun2 variable is normally used.

date_generator would have a third case within the while loop for if $this->type == ‘seasonal’

As for transpositor I’m not too sure when I’d even want to start, do I make a third case before the else or do I place another if statement within the else, to specify how $this->type == ‘seasonal’ should be handled?

You can try the next ( not quite sure, but most probably will work )

In transpositor, just add before the end of method something like

if (!is_allowed_month($this->start_date)) $this->start_date = set_nearest_allowed_month($this->start_date);

The whole purpose of this method is to locate first possible date which match recurring rule.

In get_correct_date, you can check $cur_date at start, and if it is in wrong month - just exit the function. The code is purposed to set correct date in the month, so the check at the start will cover all cases

Thanks for your help so far the new rec_type is almost working perfectly. I’ve so far managed to get 2 out of the 3 different search methods working with the new recurrence type (Next Occurrence and Today’s Events), however the third method, Events this month, I can’t seem to get working. I’ve attached the SchedulerHelper file that handles the “Events this month” search, a month is selected by navigating left or right then all results are displayed on my own custom mini calendar and additionally as text, the text only showing the next occurrence which works fine with the few tests I’ve done.

If I have an event repeating every 2 weeks on Wednesday during August, September & October. The 2-3 times Wednesday occurs during September across the years returns fine, however nothing is ever shown in October, at most 1 event is shown on the last Wednesday of August, and sometimes the last Wednesday of July is given an event.

I can’t work out why it isn’t returning the correct dates for seasonal, but still works fine for any of the other rec_types. SchedulerHelper’s get_event is being called with the id of the event, the first of the month being searched and the 1st of the next month, so it should only be able to search for events between these two dates (theoretically).

[code]<?php

class SchedulerDate {
public $ev_id;
public $start_date;
public $end_date;
public $text;
public $ev_pid;
public $service;
public $address;
public $abn;
public $rec_type;
public $event_length;
public $type;
public $coun;
public $coun2;
public $day;
public $days;
public $result;
public $updates;
public $updates_time;
public $date_start_general;

function __construct($data, $updates, $date_start_general) {
	$start_date = date_parse($data['start_date']);
	$this->start_date = mktime($start_date['hour'], $start_date['minute'], $start_date['second'], $start_date['month'], $start_date['day'], $start_date['year']);
	$end_date = date_parse($data['end_date']);
	$this->end_date = mktime($end_date['hour'], $end_date['minute'], $end_date['second'], $end_date['month'], $end_date['day'], $end_date['year']);
	$this->date_start_general = $date_start_general;
	if ($this->end_date == false) {
		$this->end_date = mktime(0, 0, 0, 1, 1, 2038);
	}
	$this->text = $data['text'];
	$this->rec_type = $data['rec_type'];
	$this->event_length = $data['event_length'];
	$this->ev_id = $data['tasks_id'];
	$this->ev_pid = $data['event_pid'];
	$this->service = $data['service'];
	$this->address = $data['address'];
	$this->abn = $data['abn'];
	$this->orig_event = $data;
	if ($this->rec_type != '') {
		list($this->type, $this->coun, $this->coun2, $this->day, $this->days, $this->extra) = preg_split("/(_|#)/", $this->rec_type);
	}
	$this->days = preg_split("/,/",$this->days);

	if ($this->days[0] == '') {
		$this->days = array();
	}

	$this->updates = $updates;
}


function get_day_of_week($time_stamp) {
	$week_day = getdate($time_stamp);
	$week_day = $week_day['wday'];
	return $week_day;
}


function get_updates($cur_date) {
	if (isset($this->updates[$cur_date])) {
		if ($this->updates[$cur_date]['event_pid'] == $this->ev_id) {
			if ($this->updates[$cur_date]['rec_type'] == 'none') {
				return 1;
			}
			if ($this->updates[$cur_date]['rec_type'] == '') {
				return array('tasks_id' => $this->updates[$cur_date]['tasks_id'], 'start_date' => $this->updates[$cur_date]['start_date'], 'end_date' => $this->updates[$cur_date]['end_date'], 'text' => $this->updates[$cur_date]['text'], 'rec_type' => $this->rec_type,  'event_pid' => $this->updates[$cur_date]['event_pid'], 'event_length' => $this->event_length );
			}
			return 0;
		}
	} else {
		return 0;
	}
}


function get_days($cur_date, $date_start, $date_end) {
	$day = 60*60*24;
	for ($j = 0; $j<7; $j++) {
		$week_day = $this->get_day_of_week($cur_date);
		if (in_array($week_day, $this->days)) {
			if (($cur_date > $date_start)&&($cur_date < $date_end)) {
				$changes = $this->get_updates($cur_date);
				if ($changes == 0) {
					if ($cur_date > $this->start_date) {
						$this->result[] = array('tasks_id' => $this->ev_id, 'start_date' => date("Y-m-d H:i:s", $cur_date), 'end_date' => date("Y-m-d H:i:s", $cur_date + $this->event_length), 'text' => $this->text, 'rec_type' => $this->rec_type,  'event_pid' => $this->ev_pid, 'event_length' => $this->event_length, 'service' => $this->service, 'address' => $this->address, 'abn' => $this->abn );
					}
				} elseif ($changes != 1) {
					$this->result[] = $changes;
				}
			}
		}
		$cur_date += $day;
	}
	return $cur_date;
}

function get_day($cur_date, $date_start, $date_end) {
	$cur_date = mktime(date("H", $cur_date), date("i", $cur_date), date("s", $cur_date), date("m", $cur_date), 1, date("Y", $cur_date));
	$coun = ($this->day - 1)*7;
	$cday = $this->get_day_of_week($cur_date);
	$nday = $this->coun2*1 + $coun - $cday + 1;
	if ($nday <= $coun) {
		$cur_date = mktime(date("H", $cur_date), date("i", $cur_date), date("s", $cur_date), date("m", $cur_date), $nday+7, date("Y", $cur_date));
	} else {
		$cur_date = mktime(date("H", $cur_date), date("i", $cur_date), date("s", $cur_date), date("m", $cur_date), $nday, date("Y", $cur_date));
	}
	if (($cur_date > $date_start)&&($cur_date < $date_end)) {
		$changes = $this->get_updates($cur_date);
		if ($changes == 0) {
			if (date("Y-m-d H:i:s", $cur_date) > $this->date_start_general) {
				$this->result[] = array('tasks_id' => $this->ev_id, 'start_date' => date("Y-m-d H:i:s", $cur_date), 'end_date' => date("Y-m-d H:i:s", $cur_date + $this->event_length), 'text' => $this->text, 'rec_type' => $this->rec_type,  'event_pid' => $this->ev_pid, 'event_length' => $this->event_length, 'service' => $this->service, 'address' => $this->address, 'abn' => $this->abn );
			}
		} elseif ($changes != 1) {
			$this->result[] = $changes;
		}
	}
	return $cur_date;
}

function transpositor($date_start) {
	$step = 1;
	$day = 60*60*24;
	
	if (!$this->coun) {
		return;
	}
	
	if (($this->type == 'day')||($this->type == 'week')) {
		if ($this->type == 'week') {
			$step = 7;
		}
		$diff = $date_start - $this->start_date;
		$diff = floor($diff/$day);
		$delta = floor($diff/($this->coun*$step));
		if ($delta>=0) {
			$this->start_date = mktime(date("H", $this->start_date), date("i", $this->start_date), date("s", $this->start_date), date("m", $this->start_date), date("d", $this->start_date) + $delta*$step*$this->coun, date("Y", $this->start_date));
		}
	} else {
		if ($this->type == 'year')
			$step = 12;
		$delta = ceil(((date("Y", $date_start)*12 + date("m", $date_start)*1) - (date("Y", $this->start_date)*12 + date("m", $this->start_date)*1))/($step*$this->coun));
		if ($delta>=0) {
			$this->start_date = mktime(date("H", $this->start_date), date("i", $this->start_date), date("s", $this->start_date), date("m", $this->start_date)+$delta*$step*$this->coun, date("d", $this->start_date), date("Y", $this->start_date));
		}
	}
	if (!$this->is_allowed_month($this->start_date) && $this->type == 'seasonal')
		$this->start_date = $this->set_nearest_allowed_month($this->start_date,$date_start);
}

function is_allowed_month($date_start) {
	$months = explode(",",$this->coun2);
	if (in_array(date("n",strtotime($date_start)),$months))
		return true;
	else
		return false;
}

function set_nearest_allowed_month($s, $s2) {
	$months = explode(",",$this->coun2);
	$l = 1;
	$m = date("n",$s);
	for ($i=0;$i<count($months);$i++) {
		if ($months[$i] >= $m) {
			$l = $months[$i];
			$i = count($months);
		}
	}
	if ($l == 0)
		$l = $months[0];
	if ($l < 10)
		$l = "0".$l;
	
	$day = 60*60*24;
	$step = 7;
	$diff = $s2 - $this->start_date;
	$diff = floor($diff/$day);
	$delta = floor($diff/($this->coun*$step));
	if ($delta>=0) {
	   return mktime(date("H", $this->start_date), date("i", $this->start_date), date("s", $this->start_date), $l, date("d", $this->start_date) + $delta*$step*$this->coun, date("Y", $this->start_date));
	} else {
	   return mktime(date("H", $this->start_date), date("i", $this->start_date), date("s", $this->start_date), $l, date("d", $this->start_date), date("Y", $this->start_date));
	}
}

function date_generator($date_start, $date_end) {
	$final = array();
	$day = 60*60*24;
	$cur_date = $this->start_date;
	$this->result = array();
	$i = 0;
	while (($date_end > $cur_date)&&($this->end_date > $cur_date)) {
		$cur_date = $this->start_date;
		if (($this->type == 'day')||($this->type == 'week')||($this->type == 'seasonal')) {
			$st = 1;
			if ($this->type == 'week' || $this->type == 'seasonal') {
				$st = 7;
			}
			$step = $st*$i*$this->coun;
			$cur_date += $step*$day;
		} elseif (($this->type == 'month')||($this->type == 'year')) {
			$st = 1;
			if ($this->type == 'year') {
				$st = 12;
			}
			$step = $st*$i*$this->coun;
			$cur_date = mktime(date("H", $cur_date), date("i", $cur_date), date("s", $cur_date),date("m", $cur_date) + $step, date("d", $cur_date), date("Y", $cur_date));
		}
		$this->get_correct_date($cur_date, $date_start, $date_end);
		$i++;
		if ($this->type == '')
			break;
	}
	return $this->result;
}


function get_correct_date($cur_date, $date_start, $date_end) {
	$final = array();
	$day = 60*60*24;
	if ($this->type == "seasonal") {
		$months = explode(",",$this->coun2);
		if (!in_array(date("n",$cur_date), $months)){
			return;
		}
	}

	if (count($this->days)) {
		$week_day = $this->get_day_of_week($cur_date);
		$cur_date -= ((--$week_day)*$day);
		$cur_date = $this->get_days($cur_date, $date_start, $date_end);
	} elseif (($this->coun2 != '')&&($this->day != '')) {
			$cur_date = $this->get_day($cur_date, $date_start, $date_end);
	} else {
		if (($cur_date > $date_start)&&($cur_date < $date_end)) {
			$changes = $this->get_updates($cur_date);
			if ($changes == 0) {
				if (date("Y-m-d H:i:s", $cur_date) > $this->date_start_general) {
					$ev = $this->orig_event;
					$ev['start_date'] = date("Y-m-d H:i:s", $cur_date);
					$ev['end_date'] = date("Y-m-d H:i:s", $cur_date + $this->event_length);
					$this->result[] = $ev;
				}
			} elseif ($changes != 1) {
				$this->result[] = $changes;
			}
		}
	}
}

}

class SchedulerHelper
{
public $date_start;
public $date_end;
public $date_start_ts;
public $date_end_ts;
public $connect;
public $table_name;
public $field_start;
public $field_end;

function __construct($connect, $table_name, $fields="start_date,end_date") {
	$this->connect = $connect;
	$this->table_name = $table_name;
	list($this->field_start, $this->field_end) = explode(",", $fields);
	$this->field_start = trim($this->field_start);
	$this->field_end = trim($this->field_end);
}

function get_event($id, $date_start = "1970-01-01", $date_end = "2038-01-01") {
    $this->date_start = $date_start;
    $this->date_end = $date_end;
    $date_start = date_parse($date_start);
    $this->date_start_ts = mktime($date_start['hour'], $date_start['minute'], $date_start['second'], $date_start['month'], $date_start['day'], $date_start['year']);
    $date_end = date_parse($date_end);
    $this->date_end_ts = mktime($date_end['hour'], $date_end['minute'], $date_end['second'], $date_end['month'], $date_end['day'], $date_end['year']);

    $final = array();
    $updates = Array();
    $query = "SELECT * FROM ".$this->table_name." WHERE `rec_type`='none' OR (`rec_type`='' AND `event_length`!='0')";
    $res = mysql_query($query, $this->connect);
    for ($i = 0; $i < mysql_num_rows($res); $i++) {
        $event = mysql_fetch_assoc($res);
        $updates[mysql_result($res, $i, 'event_length')] = $event;
    }

    $query = "SELECT * FROM ".$this->table_name." WHERE (`start_date`<='".($this->date_end)."' AND `end_date`>='".($this->date_start)."') AND tasks_id='".$id."'";
    $res = mysql_query($query, $this->connect);

    while ($data = mysql_fetch_assoc($res)) {
        $event_cur = new SchedulerDate($data, $updates, $this->date_start);
        $event_cur->transpositor($this->date_start_ts);
        $final_temp = $event_cur->date_generator($this->date_start_ts, $this->date_end_ts);
        foreach ($final_temp as $v) {
            $final[] = $v;
        }
    }
    return $final;
}

}

?>[/code]

Turns out the search doesn’t work in all cases for the “Next Occurrence” search (and I assume the “Today’s events” as well). In fact SchedulerHelper seems to start looking for dates from the 1st of each month, not relative to the first event in the series for the seasonal event type.

Any ideas why this happens?

I’m pretty sure I’ve solved the problem now, instead of setting the next month i should have been incrementing by weeks until a valid month was reached.

Hi freddy

But this code not filtering updated events from recurring types.can u post your new ScheduleHelper

Hi silumca,

I can share the SchedulerHelper file, but I can’t share my current dhtmlxscheduler file (it’s an advanced hybrid of all the features I wanted to implement from the various versions that have been released and has php, some database calls, jquery and ajax scattered throughout it and links with a bunch of other highly customised pages).

Here’s my SchedulerHelper code (also make sure to read through it, I’ve customised this file beyond just adding in the seasonal recurrence type so that it refers to some specific database columns for additional returned data):

[code]<?php

class SchedulerDate2 {
public $ev_id;
public $start_date;
public $end_date;
public $text;
public $ev_pid;
public $service;
public $address;
public $abn;
public $rec_type;
public $event_length;
public $type;
public $coun;
public $coun2;
public $day;
public $days;
public $result;
public $updates;
public $updates_time;
public $date_start_general;

function __construct($data, $updates, $date_start_general) {
	$start_date = date_parse($data['start_date']);
	$this->start_date = mktime($start_date['hour'], $start_date['minute'], $start_date['second'], $start_date['month'], $start_date['day'], $start_date['year']);
	$end_date = date_parse($data['end_date']);
	$this->end_date = mktime($end_date['hour'], $end_date['minute'], $end_date['second'], $end_date['month'], $end_date['day'], $end_date['year']);
	$this->date_start_general = $date_start_general;
	if ($this->end_date == false) {
		$this->end_date = mktime(0, 0, 0, 1, 1, 2038);
	}
	$this->text = $data['text'];
	$this->rec_type = $data['rec_type'];
	$this->event_length = $data['event_length'];
	$this->ev_id = $data['tasks_id'];
	$this->ev_pid = $data['event_pid'];
	$this->service = $data['service'];
	$this->address = $data['address'];
	$this->abn = $data['abn'];
	$this->orig_event = $data;
	if ($this->rec_type != '') {
		list($this->type, $this->coun, $this->coun2, $this->day, $this->days, $this->extra) = preg_split("/(_|#)/", $this->rec_type);
	}
	$this->days = preg_split("/,/",$this->days);

	if ($this->days[0] == '') {
		$this->days = array();
	}

	$this->updates = $updates;
}


function get_day_of_week($time_stamp) {
	$week_day = getdate($time_stamp);
	$week_day = $week_day['wday'];
	return $week_day;
}


function get_updates($cur_date) {
	if (isset($this->updates[$cur_date])) {
		if ($this->updates[$cur_date]['event_pid'] == $this->ev_id) {
			if ($this->updates[$cur_date]['rec_type'] == 'none') {
				return 1;
			}
			if ($this->updates[$cur_date]['rec_type'] == '') {
				return array('tasks_id' => $this->updates[$cur_date]['tasks_id'], 'start_date' => $this->updates[$cur_date]['start_date'], 'end_date' => $this->updates[$cur_date]['end_date'], 'text' => $this->updates[$cur_date]['text'], 'rec_type' => $this->rec_type,  'event_pid' => $this->updates[$cur_date]['event_pid'], 'event_length' => $this->event_length );
			}
			return 0;
		}
	} else {
		return 0;
	}
}


function get_days($cur_date, $date_start, $date_end) {
	$day = 60*60*24;
	for ($j = 0; $j<7; $j++) {
		$week_day = $this->get_day_of_week($cur_date);
		if (in_array($week_day, $this->days)) {
			if (($cur_date > $date_start)&&($cur_date < $date_end)) {
				$changes = $this->get_updates($cur_date);
				if ($changes == 0) {
					if ($cur_date > $this->start_date) {
						$this->result[] = array('tasks_id' => $this->ev_id, 'start_date' => date("Y-m-d H:i:s", $cur_date), 'end_date' => date("Y-m-d H:i:s", $cur_date + $this->event_length), 'text' => $this->text, 'rec_type' => $this->rec_type,  'event_pid' => $this->ev_pid, 'event_length' => $this->event_length, 'service' => $this->service, 'address' => $this->address, 'abn' => $this->abn );
					}
				} elseif ($changes != 1) {
					$this->result[] = $changes;
				}
			}
		}
		$cur_date += $day;
	}
	return $cur_date;
}

function get_day($cur_date, $date_start, $date_end) {
	$cur_date = mktime(date("H", $cur_date), date("i", $cur_date), date("s", $cur_date), date("m", $cur_date), 1, date("Y", $cur_date));
	$coun = ($this->day - 1)*7;
	$cday = $this->get_day_of_week($cur_date);
	$nday = $this->coun2*1 + $coun - $cday + 1;
	if ($nday <= $coun) {
		$cur_date = mktime(date("H", $cur_date), date("i", $cur_date), date("s", $cur_date), date("m", $cur_date), $nday+7, date("Y", $cur_date));
	} else {
		$cur_date = mktime(date("H", $cur_date), date("i", $cur_date), date("s", $cur_date), date("m", $cur_date), $nday, date("Y", $cur_date));
	}
	if (($cur_date > $date_start)&&($cur_date < $date_end)) {
		$changes = $this->get_updates($cur_date);
		if ($changes == 0) {
			if (date("Y-m-d H:i:s", $cur_date) > $this->date_start_general) {
				$this->result[] = array('tasks_id' => $this->ev_id, 'start_date' => date("Y-m-d H:i:s", $cur_date), 'end_date' => date("Y-m-d H:i:s", $cur_date + $this->event_length), 'text' => $this->text, 'rec_type' => $this->rec_type,  'event_pid' => $this->ev_pid, 'event_length' => $this->event_length, 'service' => $this->service, 'address' => $this->address, 'abn' => $this->abn );
			}
		} elseif ($changes != 1) {
			$this->result[] = $changes;
		}
	}
	return $cur_date;
}

function transpositor($date_start) {
	$step = 1;
	$day = 60*60*24;
	$t = $this->type;
	if (!$this->coun) {
		return;
	}
	
	if ($this->type == 'seasonal'){
		if (!$this->is_allowed_month($this->start_date))
			$this->start_date = $this->set_nearest_allowed_month($this->start_date);
	} else if (($this->type == 'day')||($this->type == 'week')) {
		if ($this->type == 'week') {
			$step = 7;
		}
		$diff = $date_start - $this->start_date;
		$diff = floor($diff/$day);
		$delta = floor($diff/($this->coun*$step));
		if ($delta>=0) {
			$this->start_date = mktime(date("H", $this->start_date), date("i", $this->start_date), date("s", $this->start_date), date("m", $this->start_date), date("d", $this->start_date) + $delta*$step*$this->coun, date("Y", $this->start_date));
		}
	} else {
		if ($this->type == 'year')
			$step = 12;
		$delta = ceil(((date("Y", $date_start)*12 + date("m", $date_start)*1) - (date("Y", $this->start_date)*12 + date("m", $this->start_date)*1))/($step*$this->coun));
		if ($delta>=0) {
			$this->start_date = mktime(date("H", $this->start_date), date("i", $this->start_date), date("s", $this->start_date), date("m", $this->start_date)+$delta*$step*$this->coun, date("d", $this->start_date), date("Y", $this->start_date));
		}
	}
}

function is_allowed_month($date_start) {
	$months = explode(",",$this->coun2);
	if (in_array(date("n",strtotime($date_start)-1),$months))
		return true;
	else
		return false;
}

function set_nearest_allowed_month($s) {
	$months = explode(",",$this->coun2);
	$l = 14;
	//Find month between current month and end of year
	for($i = 0; $i < count($months); $i++){
		if ($months[$i] >= (date("n")-1) && $months[$i] < $l)
			$l = $months[$i];
	}
	//If month wasn't matched, set to the lowest month
	if ($l == 14) {
		for($i = 0; $i < count($months); $i++){
			if ($months[$i] < $l)
				$l = $months[$i];
		}
	}
	$day = 60*60*24;
	$step = $day*7*$this->coun;
	while((date("n", $s)-1) != $l) {
		$s += $step;
	}
	return ($s-$step);
}

function date_generator($date_start, $date_end) {
	$final = array();
	$day = 60*60*24;
	$cur_date = $this->start_date;
	$this->result = array();
	$i = 0;
	while (($date_end > $cur_date)&&($this->end_date > $cur_date)) {
		$cur_date = $this->start_date;
		if (($this->type == 'day')||($this->type == 'week')||($this->type == 'seasonal')) {
			$st = 1;
			if ($this->type == 'week' || $this->type == 'seasonal') {
				$st = 7;
			}
			$step = $st*$i*$this->coun;
			$cur_date += $step*$day;
		} elseif (($this->type == 'month')||($this->type == 'year')) {
			$st = 1;
			if ($this->type == 'year') {
				$st = 12;
			}
			$step = $st*$i*$this->coun;
			$cur_date = mktime(date("H", $cur_date), date("i", $cur_date), date("s", $cur_date),date("m", $cur_date) + $step, date("d", $cur_date), date("Y", $cur_date));
		}
		$this->get_correct_date($cur_date, $date_start, $date_end);
		$i++;
		if ($this->type == '')
			break;
	}
	return $this->result;
}


function get_correct_date($cur_date, $date_start, $date_end) {
	$final = array();
	$day = 60*60*24;
	if ($this->type == "seasonal") {
		$months = explode(",",$this->coun2);
		if (!in_array(date("n",$cur_date)-1, $months)){
			return;
		}
	}
	if (count($this->days)) {
		$week_day = $this->get_day_of_week($cur_date);
		$cur_date -= ((--$week_day)*$day);
		$cur_date = $this->get_days($cur_date, $date_start, $date_end);
		if (date("Y-m-d H:i:s", $cur_date) > $this->date_start_general) {
			$ev = $this->orig_event;
			$ev['start_date'] = date("Y-m-d H:i:s", $cur_date);
			$ev['end_date'] = date("Y-m-d H:i:s", $cur_date + $this->event_length);
			$this->result[] = $ev;
		}
	} elseif (($this->coun2 != '')&&($this->day != '')) {
			$cur_date = $this->get_day($cur_date, $date_start, $date_end);
	} else {
		if (($cur_date > $date_start)&&($cur_date < $date_end)) {
			$changes = $this->get_updates($cur_date);
			if ($changes == 0) {
				if (date("Y-m-d H:i:s", $cur_date) > $this->date_start_general) {
					$ev = $this->orig_event;
					$ev['start_date'] = date("Y-m-d H:i:s", $cur_date);
					$ev['end_date'] = date("Y-m-d H:i:s", $cur_date + $this->event_length);
					$this->result[] = $ev;
				}
			} elseif ($changes != 1) {
				$this->result[] = $changes;
			}
		}
	}
}

}

class SchedulerHelper2
{
public $date_start;
public $date_end;
public $date_start_ts;
public $date_end_ts;
public $connect;
public $table_name;
public $field_start;
public $field_end;

function __construct($connect, $table_name, $fields="start_date,end_date") {
	$this->connect = $connect;
	$this->table_name = $table_name;
	list($this->field_start, $this->field_end) = explode(",", $fields);
	$this->field_start = trim($this->field_start);
	$this->field_end = trim($this->field_end);
}


function get_dates($date_start, $date_end) {
	$this->date_start = $date_start;
	$this->date_end = $date_end;
	$date_start = date_parse($date_start);
	$this->date_start_ts = mktime($date_start['hour'], $date_start['minute'], $date_start['second'], $date_start['month'], $date_start['day'], $date_start['year']);
	$date_end = date_parse($date_end);
	$this->date_end_ts = mktime($date_end['hour'], $date_end['minute'], $date_end['second'], $date_end['month'], $date_end['day'], $date_end['year']);

	$final = array();
	$updates = Array();
	$query = "SELECT * FROM ".$this->table_name." WHERE `rec_type`='none' OR (`rec_type`='' AND `event_length`!='0')";
	$res = mysql_query($query, $this->connect);
	for ($i = 0; $i < mysql_num_rows($res); $i++) {
		$event = mysql_fetch_assoc($res);
		$updates[mysql_result($res, $i, 'event_length')] = $event;
	}

	$query = "SELECT * FROM ".$this->table_name." WHERE (`start_date`<='".($this->date_end)."' AND `end_date`>='".($this->date_start)."')";
	$res = mysql_query($query, $this->connect);

	while ($data = mysql_fetch_assoc($res)) {
		$event_cur = new SchedulerDate2($data, $updates, $this->date_start);
		$event_cur->transpositor($this->date_start_ts);
		$final_temp = $event_cur->date_generator($this->date_start_ts, $this->date_end_ts);
		foreach ($final_temp as $v) {
			$final[] = $v;
		}
	}
	return $final;
}


function get_event($id, $date_start = "1970-01-01", $date_end = "2038-01-01") {
    $this->date_start = $date_start;
    $this->date_end = $date_end;
    $date_start = date_parse($date_start);
    $this->date_start_ts = mktime($date_start['hour'], $date_start['minute'], $date_start['second'], $date_start['month'], $date_start['day'], $date_start['year']);
    $date_end = date_parse($date_end);
    $this->date_end_ts = mktime($date_end['hour'], $date_end['minute'], $date_end['second'], $date_end['month'], $date_end['day'], $date_end['year']);

    $final = array();
    $updates = Array();
    $query = "SELECT * FROM ".$this->table_name." WHERE (`rec_type`='none' OR (`rec_type`='' AND `event_length`!='0') AND (`start_date`<='".($this->date_end)."' AND `end_date`>='".($this->date_start)."')) AND (tasks_id = '$id' OR event_pid = '$id')";
    $res = mysql_query($query, $this->connect);
    for ($i = 0; $i < mysql_num_rows($res); $i++) {
        $event = mysql_fetch_assoc($res);
        $updates[mysql_result($res, $i, 'event_length')] = $event;
    }

    $query = "SELECT * FROM ".$this->table_name." WHERE (`start_date`<='".($this->date_end)."' AND `end_date`>='".($this->date_start)."') AND tasks_id='".$id."'";
    $res = mysql_query($query, $this->connect);
    while ($data = mysql_fetch_assoc($res)) {
        $event_cur = new SchedulerDate2($data, $updates, $this->date_start);
        $event_cur->transpositor($this->date_start_ts);
        $final_temp = $event_cur->date_generator($this->date_start_ts, $this->date_end_ts);
        foreach ($final_temp as $v) {
            $final[] = $v;
        }
    }
    return $final;
}

 function get_rosterevent($id, $date_start = "1970-01-01", $date_end = "2038-01-01") {
    $this->date_start = $date_start;
    $this->date_end = $date_end;
    $date_start = date_parse($date_start);
    $this->date_start_ts = mktime($date_start['hour'], $date_start['minute'], $date_start['second'], $date_start['month'], $date_start['day'], $date_start['year']);
    $date_end = date_parse($date_end);
    $this->date_end_ts = mktime($date_end['hour'], $date_end['minute'], $date_end['second'], $date_end['month'], $date_end['day'], $date_end['year']);

    $final = array();
    $updates = Array();
    $query = "SELECT * FROM ".$this->table_name." WHERE `rec_type`='none' OR (`rec_type`='' AND `event_length`!='0') AND (`start_date`<='".($this->date_end)."' AND `end_date`>='".($this->date_start)."')";
    $res = mysql_query($query, $this->connect);
    for ($i = 0; $i < mysql_num_rows($res); $i++) {
        $event = mysql_fetch_assoc($res);
        $updates[mysql_result($res, $i, 'event_length')] = $event;
    }

    $query = "SELECT * FROM ".$this->table_name." WHERE (`start_date`<='".($this->date_end)."' AND `end_date`>='".($this->date_start)."') AND id='".$id."'";
    $res = mysql_query($query, $this->connect);

    while ($data = mysql_fetch_assoc($res)) {
        $event_cur = new SchedulerDate2($data, $updates, $this->date_start);
        $event_cur->transpositor($this->date_start_ts);
        $final_temp = $event_cur->date_generator($this->date_start_ts, $this->date_end_ts);
        foreach ($final_temp as $v) {
            $final[] = $v;
        }
    }
    return $final;
}

}

?>[/code]

Hi freddy,
Thanks for your reply

  1. but this helper cant able to filter rec_type=“none” events and when i m passing exact start time and endtime between a date resulting empty array.
  2. when i updated a recurring event,its displaying old event and new one too.
    My table struture is
    id start_date end_date text rec_type event_pid event_length
    1 2014-06-25 10:00:00 2014-06-25 12:25:00 New 0 0
    2 2014-06-01 10:10:00 2015-02-01 00:00:00 New month_1_1_1_#no 0 6900
    3 2014-06-01 10:15:00 2014-11-03 10:15:00 New month_1_1_1_#5 0 2400
    4 2014-06-23 16:55:00 2015-02-01 00:00:00 New week_1___0,2,3#no 0 7200
    5 2014-07-02 14:40:00 2014-07-02 16:40:00 New 4 1404300300
    6 2014-06-25 16:55:00 2014-06-25 18:55:00 New event none 4 1403695500

Actually there are 7 events are there between 2nd Jun14 to 2nd July 14 but its displaying 11 events(without record no 6)
and empty records with record no 6

its not able to filter updated and deleted records can u please :exclamation: post a Helper which will filter updated and deleted events too

Thanks a lot

The rec_type = ‘none’ and updates are already handled in the calling class of SchedulerHelper2 (see the bottom of the code). As I said I’ve heavily modified this code and you will need to change any database variable names in that bottom class, along with adding in and changing related variable names throughout the SchedulerDate2 class at the top. This code does work as a standalone (at least on my website) as I use it in a number of places outside of the scheduler to generate the date an event is next on.

I can’t say I’ve encountered that bug about the start and end date being equal, but then I always set end date to be at least 1 day after the start date. This particular function should be used with +1 year date range though if you want a proper search of all events (including the default rec_types i.e. Day, Week, Month, Year, and not just my custom seasonal one).

Hi Freedy,

Actually i tried with one month duration gap not same date 2nd jun to 2nd july which have 7 events but its displaying 11 using your Helper,

I checked its displaying both recurring dates and updated dates too instead of merging updated events.

Any way thanks for help

Oh ok, sorry I can’t be of more help, it might just be that I’ve got it handling differently to you in the rest of my code too. You can see a functional demo of seasonal I’ve set up at https://samepage.com.au/ (just ignore the warning about it being untrusted, my SSL cert has run out and I don’t plan on renewing it until I’ve got everything to an exceptional state and ready for sale).

Hi freddy,

   Thats fine i too have no problem with calendar view, in Calendar view its displaying all actual dates and events properly.But problem with displaying a report without using calendar.bcoz for a recurring event its only storing single event in DB,and i tried to use Schedulehelper to get those events by passing startdate and enddate.