/*
dhtmlxScheduler v.4.3.0 Stardard
This software is covered by GPL license. You also can obtain Commercial or Enterprise license to use it in non-GPL project - please contact sales@dhtmlx.com. Usage without proper license is prohibited.
(c) Dinamenta, UAB.
*/
scheduler.config.limit_start = null;
scheduler.config.limit_end = null;
scheduler.config.limit_view = false;
scheduler.config.check_limits = true;
scheduler.config.mark_now = true;
scheduler.config.display_marked_timespans = true;
scheduler._temp_limit_scope = function(){
var before = null;
var dhx_time_block = "dhx_time_block";
var default_timespan_type = "default";
var fix_options = function(options, days, zones) {
if (days instanceof Date && zones instanceof Date) {
options.start_date = days;
options.end_date = zones;
} else {
options.days = days;
options.zones = zones;
}
return options;
};
var get_resulting_options = function(days, zones, sections) {
var options = (typeof days == "object") ? days : { days: days };
options.type = dhx_time_block;
options.css = "";
if (zones) {
if (sections)
options.sections = sections;
options = fix_options(options, days, zones);
}
return options;
};
scheduler.blockTime = function(days, zones, sections){
var options = get_resulting_options(days, zones, sections);
return scheduler.addMarkedTimespan(options);
};
scheduler.unblockTime = function(days, zones, sections) {
zones = zones || "fullday";
var options = get_resulting_options(days, zones, sections);
return scheduler.deleteMarkedTimespan(options);
};
scheduler.attachEvent("onBeforeViewChange",function(om,od,nm,nd){
function isBlocked(date, mode){
var limit_start = scheduler.config.limit_start,
limit_end = scheduler.config.limit_end,
date_end = scheduler.date.add(date,1,mode);
return (date.valueOf() > limit_end.valueOf() || date_end <= limit_start.valueOf());
}
if (scheduler.config.limit_view){
nd = nd||od; nm = nm||om;
if (isBlocked(nd, nm) && !(od.valueOf() == nd.valueOf())){
setTimeout(function(){
var resetDate = !isBlocked(od, nm) ? od : scheduler.config.limit_start;
scheduler.setCurrentView(!isBlocked(resetDate, nm) ? resetDate : null, nm);
},1);
return false;
}
}
return true;
});
scheduler.checkInMarkedTimespan = function(ev, timespan_type, on_overlap){
timespan_type = timespan_type || default_timespan_type;
var res = true;
var temp_start_date = new Date(ev.start_date.valueOf());
var temp_end_date = scheduler.date.add(temp_start_date, 1, "day");
var timespans = scheduler._marked_timespans;
for (; temp_start_date < ev.end_date; temp_start_date = scheduler.date.date_part(temp_end_date), temp_end_date = scheduler.date.add(temp_start_date, 1, "day") ) {
var day_value = +scheduler.date.date_part( new Date(temp_start_date) ); // the first part of event not necessarily contains only date part
var day_index = temp_start_date.getDay();
var zones = getZones(ev, timespans, day_index, day_value, timespan_type);
if (zones){
for (var i = 0; i < zones.length; i+=2) {
// they may change for new event if it passes limit zone
var sm = scheduler._get_zone_minutes(temp_start_date);
var em = ( ev.end_date>temp_end_date || ev.end_date.getDate() != temp_start_date.getDate() ) ? 1440 : scheduler._get_zone_minutes(ev.end_date);
var sz = zones[i];
var ez = zones[i+1];
if (szsm) {
if(typeof on_overlap == "function"){
//handler allows to cancel overlapping
//actually needed only to keep default behavior of limits
res = on_overlap(ev, sm, em, sz, ez);//event object, event start/end minutes in 'zones' format, zone start/end minutes
}else{
res = false;
}
if(!res)
break;
}
}
}
}
return !res;
};
var blocker = scheduler.checkLimitViolation = function(event){
if(!event)
return true;
if (!scheduler.config.check_limits)
return true;
var s = scheduler;
var c = s.config;
var evs = [];
if (event.rec_type) {
var dates = scheduler.getRecDates(event);
for(var i=0; i < dates.length; i++){
var ev = scheduler._copy_event(event);
scheduler._lame_copy(ev, dates[i]);
evs.push(ev);
}
} else {
evs = [event];
}
var complete_res = true;
for (var p=0; p= c.limit_start.valueOf() && ev.end_date.valueOf() <= c.limit_end.valueOf()) : true;
if (res){
res = !scheduler.checkInMarkedTimespan(ev, dhx_time_block, function(ev, sm, em, sz, ez){
//try crop event to allow placing
var allow = true;
if (sm<=ez && sm >=sz){
if (ez == 24*60 || em=sz && em ez)){
if(ev._timed && s._drag_id && s._drag_mode == "new-size"){
ev.end_date.setHours(0);
ev.end_date.setMinutes(sz);
}
else {
allow = false;
}
}
return allow;
});
}
if (!res) {
res = (s.checkEvent("onLimitViolation")) ? s.callEvent("onLimitViolation",[ev.id, ev]) : res;
}
complete_res = complete_res && res;
}
if(!complete_res){
s._drag_id = null;
s._drag_mode = null;
}
return complete_res;
};
scheduler._get_blocked_zones = function(timespans, property, day_index, day_value, timespan_type){
var zones =[];
if (timespans && timespans[property]) {
var timeline_zones = timespans[property];
var blocked_timeline_zones = this._get_relevant_blocked_zones(day_index, day_value, timeline_zones, timespan_type);
for (var i=0; i= scheduler.config.limit_end.valueOf()) {
ev.start_date = this.date.add(scheduler.config.limit_end, -1, "day");
}
if (ev.end_date < scheduler.config.limit_start) {
ev.end_date = new Date(scheduler.config.limit_start);
}
if (ev.end_date.valueOf() >= scheduler.config.limit_end.valueOf()) {
ev.end_date = this.date.add(scheduler.config.limit_end, -1, "day");
}
if (ev.start_date.valueOf() >= ev.end_date.valueOf()) {
ev.end_date = this.date.add(ev.start_date, (this.config.event_duration||this.config.time_step), "minute");
}
ev._timed=this.isOneDayEvent(ev);
}
return true;
});
scheduler.attachEvent("onEventChanged",function(id){
if (!id) return true;
var ev = scheduler.getEvent(id);
if (!blocker(ev)){
if (!before) return false;
ev.start_date = before[0];
ev.end_date = before[1];
ev._timed=this.isOneDayEvent(ev);
}
return true;
});
scheduler.attachEvent("onBeforeEventChanged",function(ev, native_object, is_new){
return blocker(ev);
});
scheduler.attachEvent("onBeforeEventCreated", function(ev) { // native event
var start_date = scheduler.getActionData(ev).date;
var event = {
_timed: true,
start_date: start_date,
end_date: scheduler.date.add(start_date, scheduler.config.time_step, "minute")
};
return blocker(event);
});
scheduler.attachEvent("onViewChange", function(){
scheduler._mark_now();
});
scheduler.attachEvent("onSchedulerResize", function(){
window.setTimeout(function(){ scheduler._mark_now(); }, 1);
return true;
});
scheduler.attachEvent("onTemplatesReady", function() {
scheduler._mark_now_timer = window.setInterval(function() {
if(!scheduler._is_initialized())
return;
scheduler._mark_now();
}, 60000);
});
scheduler._mark_now = function(hide) {
// day, week, units views
var dhx_now_time = 'dhx_now_time';
if (!this._els[dhx_now_time]) {
this._els[dhx_now_time] = [];
}
var now = scheduler._currentDate();
var cfg = this.config;
scheduler._remove_mark_now(); // delete previous marks if they exist
if (!hide && cfg.mark_now && now < this._max_date && now > this._min_date && now.getHours() >= cfg.first_hour && now.getHours() config.start_date) || (config.days !== undefined && config.zones)) )
return r_configs; // incorrect config was provided
var min = 0;
var max = 24*60;
if (config.zones == "fullday")
config.zones = [min, max];
if (config.zones && config.invert_zones) {
config.zones = scheduler.invertZones(config.zones);
}
config.id = scheduler.uid();
config.css = config.css||"";
config.type = config.type||default_timespan_type;
var sections = config.sections;
if (sections) {
for (var view_key in sections) {
if (sections.hasOwnProperty(view_key)) {
var ids = sections[view_key];
if (!(ids instanceof Array))
ids = [ids];
for (var i=0; i t_sd) ? scheduler._get_zone_minutes(start_date) : min;
var zone_end = ( end_date>t_ed || end_date.getDate() != t_sd.getDate() ) ? max : scheduler._get_zone_minutes(end_date);
t_config.zones = [zone_start, zone_end];
r_configs.push(t_config);
t_sd = t_ed;
t_ed = scheduler.date.add(t_ed, 1, "day");
}
} else {
if (c_config.days instanceof Date)
c_config.days = (scheduler.date.date_part(c_config.days)).valueOf();
c_config.zones = config.zones.slice();
r_configs.push(c_config);
}
}
return r_configs;
};
scheduler._get_dates_by_index = function(index, start, end) {
var dates = [];
start = scheduler.date.date_part(new Date(start||scheduler._min_date));
end = new Date(end||scheduler._max_date);
var start_day = start.getDay();
var delta = (index-start_day >= 0) ? (index-start_day) : (7-start.getDay()+index);
var t_date = scheduler.date.add(start, delta, "day");
for (; t_date < end; t_date = scheduler.date.add(t_date, 1, "week")) {
dates.push(t_date);
}
return dates;
};
scheduler._get_css_classes_by_config = function(config) {
var css_classes = [];
if (config.type == dhx_time_block) {
css_classes.push(dhx_time_block);
if (config.css)
css_classes.push(dhx_time_block+"_reset");
}
css_classes.push("dhx_marked_timespan", config.css);
return css_classes.join(" ");
};
scheduler._get_block_by_config = function(config) {
var block = document.createElement("DIV");
if (config.html) {
if (typeof config.html == "string")
block.innerHTML = config.html;
else
block.appendChild(config.html);
}
return block;
};
scheduler._render_marked_timespan = function(options, area, day) {
var blocks = []; // resulting block which will be rendered and returned
var c = scheduler.config;
var min_date = this._min_date;
var max_date = this._max_date;
var day_value = false; // if timespan for specific date should be displayed
if (!c.display_marked_timespans)
return blocks;
// in case of markTimespan
if (!day && day !== 0) {
if (options.days < 7)
day = options.days;
else {
var date_to_display = new Date(options.days);
day_value = +date_to_display;
// in case of markTimespan date could be not in the viewing range, need to return
if ( !(+max_date > +date_to_display && +min_date <= +date_to_display) )
return blocks;
day = date_to_display.getDay();
}
// convert day default index (Sun - 0, Sat - 6) to index of hourscales (depends on week_start and config.start_on_monday)
var min_day = min_date.getDay();
if (min_day > day) {
day = 7 - (min_day-day);
} else {
day = day - min_day;
}
}
var zones = options.zones;
var css_classes = scheduler._get_css_classes_by_config(options);
if (scheduler._table_view && scheduler._mode == "month") {
var areas = [];
var days = [];
if (!area) {
days = (day_value) ? [day_value] : scheduler._get_dates_by_index(day);
for (var i=0; i < days.length; i++) {
areas.push( this._scales[days[i]] );
}
} else {
areas.push(area);
days.push(day);
}
for (var i=0; i < areas.length; i++) {
area = areas[i];
day = days[i];
var sweek = Math.floor((this._correct_shift(day,1)-min_date.valueOf())/(60*60*1000*24*this._cols.length)),
sday = this.locate_holder_day(day, false) % this._cols.length;
if(this._ignores[sday]) continue;
var block_proto = scheduler._get_block_by_config(options),
height = Math.max(area.offsetHeight - 1, 0), // 1 for bottom border
width = Math.max(area.offsetWidth - 1, 0), // 1 for left border
left = this._colsS[sday],
top = this._colsS.heights[sweek]+(this._colsS.height?(this.xy.month_scale_height+2):2)-1;
block_proto.className = css_classes;
block_proto.style.top = top + "px";
block_proto.style.lineHeight = block_proto.style.height = height + "px";
for (var k=0; k < zones.length; k+=2) {
var start = zones[i];
var end = zones[i+1];
if (end <= start)
return [];
var block = block_proto.cloneNode(true);
block.style.left = (left + Math.round( (start)/(24*60) * width)) + "px";
block.style.width = Math.round( (end-start)/(24*60) * width) + "px";
area.appendChild(block);
blocks.push(block);
}
}
} else {
var index = day;
if(this._ignores[this.locate_holder_day(day, false)]) return blocks;
if (this._props && this._props[this._mode] && options.sections && options.sections[this._mode]) {
var view = this._props[this._mode];
index = view.order[options.sections[this._mode]];
var inner_index = view.order[options.sections[this._mode]];
if(!(view.days > 1)){
index = inner_index;
if (view.size && (index > view.position+view.size)) {
index = 0;
}
}else{
var units_l =view.options.length;
index = index*units_l + inner_index;
}
}
area = area ? area : scheduler.locate_holder(index);
for (var i = 0; i < zones.length; i+=2){
var start = Math.max(zones[i], c.first_hour*60);
var end = Math.min(zones[i+1], c.last_hour*60);
if (end <= start) {
if (i+2 < zones.length)
continue;
else
return [];
}
var block = scheduler._get_block_by_config(options);
block.className = css_classes;
// +1 for working with section which really takes up whole height (as % would be == 0)
var all_hours_height = this.config.hour_size_px*24 + 1;
var hour_ms = 60*60*1000;
block.style.top = (Math.round((start*60*1000-this.config.first_hour*hour_ms)*this.config.hour_size_px/hour_ms) % all_hours_height) + "px";
block.style.lineHeight = block.style.height = Math.max((Math.round(((end-start)*60*1000)*this.config.hour_size_px/hour_ms)) % all_hours_height, 1)+"px";
area.appendChild(block);
blocks.push(block);
}
}
return blocks;
};
// just marks timespan, will be cleaned after refresh
scheduler.markTimespan = function(configuration) {
var configs = scheduler._prepare_timespan_options(configuration);
if (!configs.length)
return;
var divs = [];
for (var i=0; i c_zone_end && zone_start <= c_zone_end) || (zone_start < c_zone_start && zone_end >= c_zone_start)) {
resulting_zones[i] = Math.min(c_zone_start, zone_start);
resulting_zones[i+1] = Math.max(c_zone_end, zone_end);
i -= 2;
} else {
if (!isLast) // do nothing, maybe next current zone will match or will be last
continue;
var offset = (c_zone_start > zone_start)?0:2;
resulting_zones.splice(i+offset, 0, zone_start, zone_end); // last current zone, need to add another
}
zones.splice(k--,2); // zone was merged or added, need to exclude it
break;
}
}
return resulting_zones;
};
scheduler._subtract_timespan_zones = function(current_zones, zones) {
var resulting_zones = current_zones.slice();
for (var i=0; i c_zone_start && zone_start < c_zone_end) {
var is_modified = false;
if (c_zone_start >= zone_start && c_zone_end <= zone_end) {
resulting_zones.splice(i, 2);
}
if (c_zone_start < zone_start) {
resulting_zones.splice(i, 2, c_zone_start, zone_start);
is_modified = true;
}
if (c_zone_end > zone_end) {
resulting_zones.splice( (is_modified)?(i+2):i, (is_modified)?0:2, zone_end, c_zone_end);
}
i -= 2;
break;
} else {
continue;
}
}
}
return resulting_zones;
};
scheduler.invertZones = function(zones) {
return scheduler._subtract_timespan_zones([0, 1440], zones.slice());
};
scheduler._delete_marked_timespan_by_id = function(id) {
var configs = scheduler._marked_timespans_ids[id];
if (configs) {
for (var i=0; i 1)){
day = scheduler.date.date_part(new Date(this._date)); // for units view actually only 1 day is displayed yet the day variable will change, need to use this._date for all calls
}else{
var dx = 24*60*60*1000;
var day_ind = Math.floor((day - scheduler._min_date)/dx);
day = scheduler.date.add(scheduler._min_date, Math.floor(day_ind/units.length), "day"); // to the "same" day for all sections
day = scheduler.date.date_part(day);
}
day_index = day.getDay();
day_value = day.valueOf();
if (timespans[mode] && timespans[mode][unit.key]) {
var unit_zones = timespans[mode][unit.key];
var unit_types = scheduler._get_types_to_render(unit_zones[day_index], unit_zones[day_value]);
r_configs.push.apply(r_configs, scheduler._get_configs_to_render(unit_types));
}
}
var global_data = timespans["global"];
var day_types = global_data[day_value]||global_data[day_index];
r_configs.push.apply(r_configs, scheduler._get_configs_to_render(day_types));
for (var i=0; i