/* 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