summaryrefslogtreecommitdiffstats
path: root/codebase/sources/dhtmlxscheduler.js
diff options
context:
space:
mode:
Diffstat (limited to 'codebase/sources/dhtmlxscheduler.js')
-rw-r--r--codebase/sources/dhtmlxscheduler.js1378
1 files changed, 1159 insertions, 219 deletions
diff --git a/codebase/sources/dhtmlxscheduler.js b/codebase/sources/dhtmlxscheduler.js
index cfb1c48..2282a28 100644
--- a/codebase/sources/dhtmlxscheduler.js
+++ b/codebase/sources/dhtmlxscheduler.js
@@ -1,12 +1,12 @@
/*
@license
-dhtmlxScheduler v.4.3.1
+dhtmlxScheduler v.4.4.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.
*/
-window.dhtmlXScheduler = window.scheduler = { version: "4.3.1" };
+window.dhtmlXScheduler = window.scheduler = { version: "4.4.0" };
if (!window.dhtmlx) {
dhtmlx = function(obj){
@@ -975,32 +975,144 @@ dhtmlxEventable=function(obj){
};
obj = null;
};
+scheduler.event = window.dhtmlxEvent;
+
+scheduler.eventRemove = function(el, event, handler){
+ if (el.removeEventListener)
+ el.removeEventListener(event, handler, false);
+
+ else if (el.detachEvent)
+ el.detachEvent("on"+event, handler);
+};
+
+(function(){
+ function isVisible(node){
+ var display = false,
+ visibility = false;
+ if(window.getComputedStyle){
+ var style = window.getComputedStyle(node, null);
+ display = style["display"];
+ visibility = style["visibility"];
+ }else if(node.currentStyle){
+ display = node.currentStyle["display"];
+ visibility = node.currentStyle["visibility"];
+ }
+
+ var hiddenSection = false;
+ var recurringSection = scheduler._locate_css({target:node}, "dhx_form_repeat", false);
+ if(recurringSection){
+ hiddenSection = !!(recurringSection.style.height == "0px");
+ }
+ hiddenSection = hiddenSection || !(node.offsetHeight);
+
+ return (display != "none" && visibility != "hidden" && !hiddenSection);
+ }
+
+ function hasNonNegativeTabIndex(node){
+ return !isNaN(node.getAttribute("tabindex")) && (node.getAttribute("tabindex")*1 >= 0);
+ }
+
+ function hasHref(node){
+ var canHaveHref = {"a": true, "area": true};
+ if(canHaveHref[node.nodeName.loLowerCase()]){
+ return !!node.getAttribute("href");
+ }
+ return true;
+ }
+
+ function isEnabled(node){
+ var canDisable = {"input":true, "select":true, "textarea":true, "button":true, "object":true};
+ if(canDisable[node.nodeName.toLowerCase()]){
+ return !node.hasAttribute("disabled");
+ }
+
+ return true;
+ }
+
+
+ scheduler._getFocusableNodes = function getFocusableNodes(root){
+ var nodes = root.querySelectorAll([
+ "a[href]",
+ "area[href]",
+ "input",
+ "select",
+ "textarea",
+ "button",
+ "iframe",
+ "object",
+ "embed",
+ "[tabindex]",
+ "[contenteditable]"
+ ].join(", "));
+
+ var nodesArray = Array.prototype.slice.call(nodes, 0);
+ for(var i = 0; i < nodesArray.length; i++){
+ var node = nodesArray[i];
+ var isValid = (hasNonNegativeTabIndex(node) || isEnabled(node) || hasHref(node)) && isVisible(node);
+ if(!isValid){
+ nodesArray.splice(i, 1);
+ i--;
+ }
+ }
+ return nodesArray;
+ };
+})();
+
+scheduler._trim = function(str){
+ var func = String.prototype.trim || function(){ return this.replace(/^\s+|\s+$/g, ""); };
+ return func.apply(str);
+};
if(!window.dhtmlx)
window.dhtmlx = {};
(function(){
var _dhx_msg_cfg = null;
function callback(config, result){
+ setTimeout(function(){
+ if(!config.box) return;
+
var usercall = config.callback;
modality(false);
config.box.parentNode.removeChild(config.box);
+ dhtmlx.callEvent("onAfterMessagePopup", [config.box]);
_dhx_msg_cfg = config.box = null;
+
if (usercall)
usercall(result);
+ },1);
}
+
function modal_key(e){
if (_dhx_msg_cfg){
e = e||event;
var code = e.which||event.keyCode;
+ var preventDefault = false;
+
if (dhtmlx.message.keyboard){
- if (code == 13 || code == 32)
- callback(_dhx_msg_cfg, true);
- if (code == 27)
+ if (code == 13 || code == 32){
+ // default behavior is to confirm/submit popup on space/enter
+ // if browser focus is set on button element - do button click instead of default behavior
+ var target = e.target || e.srcElement;
+ if(scheduler._getClassName(target).indexOf("dhtmlx_popup_button") > -1 && target.click){
+ target.click();
+ }else{
+ callback(_dhx_msg_cfg, true);
+ preventDefault = true;
+ }
+ }
+
+ if (code == 27){
callback(_dhx_msg_cfg, false);
+ preventDefault = true;
+ }
}
- if (e.preventDefault)
- e.preventDefault();
- return !(e.cancelBubble = true);
+
+ if(preventDefault){
+ if (e.preventDefault)
+ e.preventDefault();
+ return !(e.cancelBubble = true);
+ }
+ return;
}
}
if (document.attachEvent)
@@ -1021,10 +1133,11 @@ if(!window.dhtmlx)
}
function button(text, result, css){
+ var buttonAriaAttrs = scheduler._waiAria.messageButtonAttrString(text);
// css - for locale-independent class name
var className = css ? css : (text || "");
var button_css = "dhtmlx_"+(className).toLowerCase().replace(/ /g, "_")+"_button"; // dhtmlx_ok_button, dhtmlx_click_me_button
- return "<div class='dhtmlx_popup_button "+button_css+"' result='"+result+"' ><div>"+text+"</div></div>";
+ return "<div "+buttonAriaAttrs+"class='dhtmlx_popup_button "+button_css+"' result='"+result+"' ><div>"+text+"</div></div>";
}
function info(text){
@@ -1044,6 +1157,8 @@ if(!window.dhtmlx)
text = null;
};
+ scheduler._waiAria.messageInfoAttr(message);
+
if (t.position == "bottom" && t.area.firstChild)
t.area.insertBefore(message,t.area.firstChild);
else
@@ -1063,16 +1178,23 @@ if(!window.dhtmlx)
var box = document.createElement("DIV");
box.className = " dhtmlx_modal_box dhtmlx-"+config.type;
box.setAttribute("dhxbox", 1);
-
+
+ var contentId = scheduler.uid();
+ scheduler._waiAria.messageModalAttr(box, contentId);
+
var inner = '';
+ var hasTitle = false;
if (config.width)
box.style.width = config.width;
if (config.height)
box.style.height = config.height;
- if (config.title)
- inner+='<div class="dhtmlx_popup_title">'+config.title+'</div>';
- inner+='<div class="dhtmlx_popup_text"><span>'+(config.content?'':config.text)+'</span></div><div class="dhtmlx_popup_controls">';
+ if (config.title) {
+ inner += '<div class="dhtmlx_popup_title" id="'+contentId+'">' + config.title + '</div>';
+ hasTitle = true;
+ }
+
+ inner+='<div class="dhtmlx_popup_text" '+(!hasTitle ? ' id="'+contentId+'" ' : "")+'><span>'+(config.content?'':config.text)+'</span></div><div class="dhtmlx_popup_controls">';
if (ok){
var ok_text = (config.ok || scheduler.locale.labels.message_ok);
//default value for compatibility with custom locales some people have
@@ -1103,16 +1225,20 @@ if(!window.dhtmlx)
box.onclick = function(e){
e = e ||event;
var source = e.target || e.srcElement;
- if (!source.className) source = source.parentNode;
- if (source.className.split(" ")[0] == "dhtmlx_popup_button"){
+ var className = scheduler._getClassName(source);
+ if (!className) source = source.parentNode;
+
+ className = scheduler._getClassName(source);
+
+ if (className.split(" ")[0] == "dhtmlx_popup_button"){
var result = source.getAttribute("result");
result = (result == "true")||(result == "false"?false:result);
callback(config, result);
}
};
config.box = box;
- if (ok||cancel)
- _dhx_msg_cfg = config;
+ //if (ok||cancel)
+ _dhx_msg_cfg = config;
return box;
}
@@ -1132,10 +1258,12 @@ if(!window.dhtmlx)
//necessary for IE only
box.onkeydown = modal_key;
- box.focus();
+ dhtmlx.modalbox.focus(box);
+
if (config.hidden)
dhtmlx.modalbox.hide(box);
+ dhtmlx.callEvent("onMessagePopup", [box]);
return box;
}
@@ -1188,6 +1316,16 @@ if(!window.dhtmlx)
modality(false);
}
};
+
+ dhtmlx.modalbox.focus = function(node){
+ setTimeout(function(){
+ var focusable = scheduler._getFocusableNodes(node);
+ if(focusable.length){
+ if(focusable[0].focus) focusable[0].focus();
+ }
+ }, 1);
+ };
+
var t = dhtmlx.message = function(text, type, expire, id){
text = params.apply(this, arguments);
text.type = text.type||"info";
@@ -1232,6 +1370,9 @@ if(!window.dhtmlx)
}
};
})();
+if(!dhtmlx.attachEvent){
+ dhtmlxEventable(dhtmlx);
+}
/**
* @desc: constructor, data processor object
* @param: serverProcessorURL - url used for update
@@ -1633,7 +1774,7 @@ dataProcessor.prototype={
case "delete":
case "deleted":
this.obj.setUserData(sid, this.action_param, "true_deleted");
- this.obj[this._methods[3]](sid);
+ this.obj[this._methods[3]](sid, tid);
delete this._in_progress[marker];
return this.callEvent("onAfterUpdate", [sid, action, tid, btag]);
}
@@ -1832,9 +1973,16 @@ dataProcessor.prototype={
var url = this.serverProcessor+getUrlSymbol(this.serverProcessor)+["dhx_user="+this._user,"dhx_version="+version].join("&");
url = url.replace("editing=true&","");
this.getUpdates(url, function(){
- var vers = self._loader.doXPath("//userdata");
- self.obj.setUserData(0,"version",self._v(vers[0]));
-
+ var vers;
+ try {
+ vers = self._loader.doXPath("//userdata");
+ }
+ catch(ex) {
+ self._update_busy = false;
+ return;
+ }
+
+ self.obj.setUserData(0, "version", self._v(vers[0]));
var upds = self._loader.doXPath("//update");
if (upds.length){
self._silent_mode = true;
@@ -1893,6 +2041,377 @@ dhtmlxError.catchError("LoadXML", function(a, b, c){
}
});
+(function(){
+
+ var htmlTags = new RegExp("<(?:.|\n)*?>", "gm");
+ var extraSpaces = new RegExp(" +", "gm");
+
+ function stripHTMLLite(htmlText){
+ return (htmlText + "")
+ .replace(htmlTags, " ").
+ replace(extraSpaces, " ");
+ }
+
+ var singleQuotes = new RegExp("'", "gm");
+ function escapeQuotes(text){
+ return (text + "").replace(singleQuotes, "&#39;");
+ }
+
+ scheduler._waiAria = {
+ getAttributeString: function(attr){
+ var attributes = [" "];
+ for(var i in attr){
+ if(typeof attr[i] != "function" && typeof attr[i] != "object") {
+ var text = escapeQuotes(stripHTMLLite(attr[i]));
+ attributes.push(i + "='" + text + "'");
+ }
+ }
+ attributes.push(" ");
+ return attributes.join(" ");
+ },
+ setAttributes: function(div, values){
+ for(var i in values){
+ div.setAttribute(i, stripHTMLLite(values[i]));
+ }
+ return div;
+ },
+
+ labelAttr: function(div, content){
+ return this.setAttributes(div, {"aria-label": content});
+ },
+ label: function(label){
+ return scheduler._waiAria.getAttributeString({"aria-label": label});
+ },
+
+ // day/week/units
+
+ hourScaleAttr: function(div, content){
+ this.labelAttr(div, content);
+
+ },
+ monthCellAttr: function(div, date){
+ this.labelAttr(div, scheduler.templates.day_date(date));
+ },
+
+ navBarDateAttr: function(div, content){
+ this.labelAttr(div, content);
+ },
+ dayHeaderAttr: function(div, content){
+ this.labelAttr(div, content);
+ },
+
+ dayColumnAttr: function(div, date){
+ this.dayHeaderAttr(div, scheduler.templates.day_date(date));
+ },
+
+ headerButtonsAttributes: function(div, label){
+ return this.setAttributes(div, {"role":"button", "aria-label":label});
+ },
+
+ headerToggleState: function(div, isActive){
+ return this.setAttributes(div, {"aria-pressed": isActive ? "true" : "false"});
+ },
+
+
+ getHeaderCellAttr:function(dateString){
+
+ return scheduler._waiAria.getAttributeString({"aria-label": dateString});
+ },
+
+
+ eventAttr: function(event, div){
+ if(!scheduler.config.readonly && scheduler.config.drag_move){
+ if(event.id != scheduler.getState().drag_id){
+ div.setAttribute("aria-grabbed", false);
+ }else{
+ div.setAttribute("aria-grabbed", true);
+ }
+ }
+
+ this._eventCommonAttr(event, div);
+ },
+
+
+ _eventCommonAttr: function(event, div){
+ div.setAttribute("aria-label", stripHTMLLite(scheduler.templates.tooltip_text(event.start_date, event.end_date, event)));
+
+ if(scheduler.config.readonly){
+ div.setAttribute("aria-readonly", true);
+
+ }
+
+ if(event.$dataprocessor_class){
+ div.setAttribute("aria-busy", true);
+ }
+
+
+ div.setAttribute("aria-selected",
+ (scheduler.getState().select_id == event.id) ? "true" : "false");
+ },
+
+ setEventBarAttr: function(event, div){
+ this._eventCommonAttr(event, div);
+
+ if(!scheduler.config.readonly && scheduler.config.drag_move){
+ if(event.id != scheduler.getState().drag_id){
+ div.setAttribute("aria-grabbed", false);
+ }else{
+ div.setAttribute("aria-grabbed", true);
+ }
+ }
+ },
+
+ _getAttributes: function(attributeSetter, arg){
+ var result = {
+ setAttribute:function(name, value){
+ this[name] = value;
+ }
+ };
+
+ attributeSetter.apply(this, [arg, result]);
+ return result;
+
+ },
+
+ eventBarAttrString: function(event){
+ return this.getAttributeString(this._getAttributes(this.setEventBarAttr, event));
+ },
+
+
+
+ agendaHeadAttrString :function(){
+ return this.getAttributeString({role: "row"});
+ },
+ agendaHeadDateString :function(label){
+ return this.getAttributeString({role: "columnheader", "aria-label": label});
+ },
+ agendaHeadDescriptionString :function(label){
+ return this.agendaHeadDateString(label);
+ },
+ agendaDataAttrString: function(){
+ return this.getAttributeString({role: "grid"});
+ },
+ agendaEventAttrString: function(event){
+ var attrs = this._getAttributes(this._eventCommonAttr, event);
+
+ attrs["role"] = "row";
+
+ return this.getAttributeString(attrs);
+
+ },
+ agendaDetailsBtnString: function(){
+ return this.getAttributeString({"role":"button", "aria-label":scheduler.locale.labels.icon_details});
+ },
+
+
+ gridAttrString: function(){
+ return this.getAttributeString({role: "grid"});
+ },
+
+ gridRowAttrString: function(event){
+ return this.agendaEventAttrString(event);
+ },
+
+ gridCellAttrString: function(event, column, value){
+ return this.getAttributeString({"role":"gridcell", "aria-label": [
+ (column.label === undefined ? column.id : column.label),
+ ": ",
+ value
+ ]});
+ },
+
+ mapAttrString: function(){
+ return this.gridAttrString();
+ },
+ mapRowAttrString: function(event){
+ return this.gridRowAttrString(event);
+ },
+ mapDetailsBtnString: function(){
+ return this.agendaDetailsBtnString();
+ },
+
+ minicalHeader: function(div, headerId){
+ this.setAttributes(div, {
+ "id":headerId+"",
+ "aria-live":"assertice",
+ "aria-atomic":"true"
+
+ });
+ },
+ minicalGrid: function(div, headerId){
+ this.setAttributes(div, {
+ "aria-labelledby":headerId+"",
+ "role":"grid"
+ });
+ },
+ minicalRow: function(div){
+ this.setAttributes(div, {
+ "role":"row"
+ });
+ },
+ minicalDayCell: function(div, date){
+ var selected = (date.valueOf() < scheduler._max_date.valueOf() && date.valueOf() >= scheduler._min_date.valueOf());
+ this.setAttributes(div, {
+ "role":"gridcell",
+ "aria-label": scheduler.templates.day_date(date),
+ "aria-selected": selected ? "true" : "false"
+ });
+ },
+ minicalHeadCell: function(div){
+ this.setAttributes(div, {
+ "role":"columnheader"
+ });
+ },
+
+
+ weekAgendaDayCell: function(div, date){
+ var header = div.querySelector(".dhx_wa_scale_bar");
+ var content = div.querySelector(".dhx_wa_day_data");
+ var headerId = scheduler.uid() + "";
+ this.setAttributes(header, { "id": headerId});
+ this.setAttributes(content, { "aria-labelledby": headerId});
+
+ },
+ weekAgendaEvent: function(div, event){
+ this.eventAttr(event, div);
+ },
+
+ lightboxHiddenAttr: function(div){
+ div.setAttribute("aria-hidden", "true");
+ },
+
+ lightboxVisibleAttr: function(div){
+ div.setAttribute("aria-hidden", "false");
+ },
+
+ lightboxSectionButtonAttrString: function(label){
+ return this.getAttributeString({"role":"button", "aria-label":label, "tabindex":"0"});
+ },
+
+ yearHeader: function(div, headerId){
+ this.setAttributes(div, {
+ "id":headerId+""
+ });
+ },
+ yearGrid: function(div, headerId){
+ this.minicalGrid(div, headerId);
+ },
+ yearHeadCell: function(div){
+ return this.minicalHeadCell(div);
+ },
+ yearRow: function(div){
+ return this.minicalRow(div);
+ },
+ yearDayCell: function(div){
+ this.setAttributes(div, {
+ "role":"gridcell"
+ });
+ },
+
+ lightboxAttr: function(div){
+ div.setAttribute("role", "dialog");
+ div.setAttribute("aria-hidden", "true");
+ div.firstChild.setAttribute("role", "heading");
+ },
+
+ lightboxButtonAttrString:function(buttonName){
+ return this.getAttributeString({"role":"button", "aria-label":scheduler.locale.labels[buttonName], "tabindex":"0"});
+ },
+ eventMenuAttrString: function(iconName){
+ return this.getAttributeString({"role":"button", "aria-label":scheduler.locale.labels[iconName]});
+ },
+ lightboxHeader: function(div, headerText){
+ div.setAttribute("aria-label", headerText);
+ },
+
+ lightboxSelectAttrString: function(time_option){
+ var label = "";
+
+ switch (time_option) {
+ case "%Y":
+ label = scheduler.locale.labels.year;
+ break;
+ case "%m":
+ label = scheduler.locale.labels.month;
+ break;
+ case "%d":
+ label = scheduler.locale.labels.day;
+ break;
+ case "%H:%i":
+ label = scheduler.locale.labels.hour + " " + scheduler.locale.labels.minute;
+ break;
+ default:
+ break;
+ }
+
+ return scheduler._waiAria.getAttributeString({"aria-label": label});
+ },
+
+
+ messageButtonAttrString: function(buttonLabel){
+ return "tabindex='0' role='button' aria-label='"+buttonLabel+"'";
+ },
+
+ messageInfoAttr: function(div){
+ div.setAttribute("role", "alert");
+ //div.setAttribute("tabindex", "-1");
+ },
+
+ messageModalAttr: function(div, uid){
+ div.setAttribute("role", "dialog");
+ if(uid){
+ div.setAttribute("aria-labelledby", uid);
+ }
+
+ // div.setAttribute("tabindex", "-1");
+ },
+
+ quickInfoAttr: function(div){
+ div.setAttribute("role", "dialog");
+ },
+
+ quickInfoHeaderAttrString: function(){
+ return " role='heading' ";
+ },
+
+ quickInfoHeader: function(div, header){
+ div.setAttribute("aria-label", header);
+ },
+
+ quickInfoButtonAttrString: function(label){
+ return scheduler._waiAria.getAttributeString({"role":"button", "aria-label":label, "tabindex":"0"});
+ },
+
+ tooltipAttr: function(div){
+ div.setAttribute("role", "tooltip");
+ },
+
+ tooltipVisibleAttr: function(div){
+ div.setAttribute("aria-hidden", "false");
+ },
+
+ tooltipHiddenAttr: function(div){
+ div.setAttribute("aria-hidden", "true");
+ }
+ };
+
+ function isDisabled(){
+ return !scheduler.config.wai_aria_attributes;
+ }
+
+ for(var i in scheduler._waiAria){
+ scheduler._waiAria[i] = (function(payload){
+ return function(){
+ if(isDisabled()){
+ return "";
+ }
+ return payload.apply(this, arguments);
+ };
+ })(scheduler._waiAria[i]);
+ }
+
+
+})();
dhtmlxEventable(scheduler);
@@ -1908,23 +2427,40 @@ scheduler._detachDomEvent = function(el, event, handler){
scheduler._init_once = function(){
var oldSize = getWindowSize();
- dhtmlxEvent(window,"resize",function(){
- var newSize = getWindowSize();
-
- // ie7-8 triggers "resize" when window's elements are resized, it messes container-autoresize extension
- // check if it's actually resized
- if(!equals(oldSize, newSize)){
- window.clearTimeout(scheduler._resize_timer);
- scheduler._resize_timer=window.setTimeout(function(){
- if (scheduler.callEvent("onSchedulerResize",[])) {
+ dhtmlxEvent(window,"resize",function() {
+ if (!isAttachedNode(scheduler._obj))
+ return;
+
+ window.clearTimeout(scheduler._resize_timer);
+ scheduler._resize_timer = window.setTimeout(function () {
+ var newSize = getWindowSize();
+
+ // ie7-8 triggers "resize" when window's elements are resized, it messes container-autoresize extension
+ // check if it's actually resized
+ if (!equals(oldSize, newSize)) {
+ if (!isAttachedNode(scheduler._obj))
+ return;
+
+ if (scheduler.callEvent("onSchedulerResize", [])) {
scheduler.update_view();
scheduler.callEvent("onAfterSchedulerResize", []);
}
- }, 100);
- }
- oldSize = newSize;
+ }
+ oldSize = newSize;
+ }, 20);
});
+
+ function isAttachedNode(container){
+ var root = document.body;
+
+ while(container && container != root){
+ container = container.parentNode;
+ }
+
+ return !!(root == container);
+ }
+
function getWindowSize(){
return {
w : window.innerWidth || document.documentElement.clientWidth,
@@ -1946,6 +2482,7 @@ scheduler.init=function(id,date,mode){
}
this._obj=(typeof id == "string")?document.getElementById(id):id;
+ this.$container = this._obj;
//hook for terrace skin
if (this._skin_init)
@@ -2017,7 +2554,7 @@ scheduler.get_elements=function(){
//get all child elements as named hash
var els=this._obj.getElementsByTagName("DIV");
for (var i=0; i < els.length; i++){
- var class_name=els[i].className || "";
+ var class_name= scheduler._getClassName(els[i]);
var attr_value = els[i].getAttribute("name") || "";
if (class_name) class_name = class_name.split(" ")[0];
if (!this._els[class_name]) this._els[class_name]=[];
@@ -2027,8 +2564,10 @@ scheduler.get_elements=function(){
var label = scheduler.locale.labels[attr_value||class_name];
if (typeof label !== "string" && attr_value && !els[i].innerHTML)
label = attr_value.split("_")[0];
- if (label)
- els[i].innerHTML= label;
+ if (label) {
+ this._waiAria.labelAttr(els[i], label);
+ els[i].innerHTML = label;
+ }
}
};
@@ -2127,7 +2666,7 @@ scheduler._click={
if (id && scheduler.config.select) {
scheduler.select(id);
- var mask = trg.className;
+ var mask = scheduler._getClassName(trg);
if (mask.indexOf("_icon")!=-1)
scheduler._click.buttons[mask.split(" ")[1].replace("icon_","")](id);
} else{
@@ -2206,21 +2745,22 @@ scheduler.addEventNow=function(start,end,e){
base.start_date = base.start_date||start_date;
base.end_date = base.end_date||end_date;
base.text = base.text||this.locale.labels.new_event;
- base.id = this._drag_id = this.uid();
+ base.id = this._drag_id = base.id || this.uid();
this._drag_mode="new-size";
this._loading=true;
- this.addEvent(base);
+ var eventId = this.addEvent(base);
this.callEvent("onEventCreated",[this._drag_id,e]);
this._loading=false;
this._drag_event={}; //dummy , to trigger correct event updating logic
- this._on_mouse_up(e);
+ this._on_mouse_up(e);
+ return eventId;
};
scheduler._on_dbl_click=function(e,src){
src = src||(e.target||e.srcElement);
if (this.config.readonly) return;
- var name = (src.className||"").split(" ")[0];
+ var name = scheduler._getClassName(src).split(" ")[0];
switch(name){
case "dhx_scale_holder":
case "dhx_scale_holder_now":
@@ -2263,20 +2803,24 @@ scheduler._get_column_index = function(x_pos){
if (this._cols){
var width = 0;
- for(var i=0; i < this._cols.length && !width; i++){
- width = this._cols[i];
- }
- if(width){
- column = x_pos / width;
- }else{
- column = 0;
+ var i = 0;
+ while (width + this._cols[i] < x_pos && i < this._cols.length){
+ width += this._cols[i];
+ i++;
}
- if (this._ignores)
- for (var i=0; i<=column; i++)
- if (this._ignores[i])
- column++;
+ column = i + (this._cols[column] ? ((x_pos - width)/ this._cols[column]) : 0);
+
+ if (this._ignores){
+
+ if(column >= this._cols.length){
+ while(column >= 1 && this._ignores[Math.floor(column)]){
+ column--;
+ }
+ }
+
+ }
}
return column;
};
@@ -2311,38 +2855,41 @@ scheduler._mouse_coords=function(ev){
pos.ev = ev;
var handler = this["mouse_"+this._mode];
- if (handler)
- return handler.call(this,pos);
-
-
- //transform to date
- if (!this._table_view) {
- pos = this._week_indexes_from_pos(pos);
- } else {
- var column = this._get_column_index(pos.x);
- if (!this._cols || !this._colsS) // agenda/map views
- return pos;
- var dy=0;
- for (dy=1; dy < this._colsS.heights.length; dy++)
- if (this._colsS.heights[dy]>pos.y) break;
-
- pos.y=Math.ceil( (Math.max(0, column)+Math.max(0,dy-1)*7)*24*60/this.config.time_step );
-
- if (scheduler._drag_mode || this._mode == "month")
- pos.y=(Math.max(0,Math.ceil(column)-1)+Math.max(0,dy-1)*7)*24*60/this.config.time_step;
-
- //we care about ignored days only during event moving in month view
- if (this._drag_mode == "move"){
- if (scheduler._ignores_detected && scheduler.config.preserve_length){
- pos._ignores = true;
- //get real lengtn of event
- if (!this._drag_event._event_length)
- this._drag_event._event_length = this._get_real_event_length(this._drag_event.start_date, this._drag_event.end_date, { x_step:1, x_unit:"day"});
+ if (handler){
+ pos = handler.call(this,pos);
+ }else{
+ //transform to date
+ if (!this._table_view) {
+ pos = this._week_indexes_from_pos(pos);
+ } else {
+ var column = this._get_column_index(pos.x);
+ if (!this._cols || !this._colsS) // agenda/map views
+ return pos;
+ var dy=0;
+ for (dy=1; dy < this._colsS.heights.length; dy++)
+ if (this._colsS.heights[dy]>pos.y) break;
+
+ pos.y=Math.ceil( (Math.max(0, column)+Math.max(0,dy-1)*7)*24*60/this.config.time_step );
+
+ if (scheduler._drag_mode || this._mode == "month")
+ pos.y=(Math.max(0,Math.ceil(column)-1)+Math.max(0,dy-1)*7)*24*60/this.config.time_step;
+
+ //we care about ignored days only during event moving in month view
+ if (this._drag_mode == "move"){
+ if (scheduler._ignores_detected && scheduler.config.preserve_length){
+ pos._ignores = true;
+ //get real lengtn of event
+ if (!this._drag_event._event_length)
+ this._drag_event._event_length = this._get_real_event_length(this._drag_event.start_date, this._drag_event.end_date, { x_step:1, x_unit:"day"});
+ }
}
- }
- pos.x=0;
+ pos.x=0;
+ }
}
+
+ pos.timestamp = +new Date();
+
return pos;
};
scheduler._close_not_saved=function(){
@@ -2371,13 +2918,36 @@ scheduler._is_pos_changed = function(old_pos, new_pos){
d_pos = 5;
// start drag only if passed some time since mouse down, or if mouse position changed sufficiently
- return !!(!this._drag_pos.start || (+new Date() - this._drag_pos.start > delay) || diff(old_pos.x, new_pos.x, d_pos) || diff(old_pos.y, new_pos.y, d_pos));
+ return !!(this._drag_pos.has_moved || !this._drag_pos.timestamp || (new_pos.timestamp - this._drag_pos.timestamp > delay) || diff(old_pos.ev.clientX, new_pos.ev.clientX, d_pos) || diff(old_pos.ev.clientY, new_pos.ev.clientY, d_pos));
+};
+
+scheduler._correct_drag_start_date = function(start){
+ var obj;
+ if (scheduler.matrix)
+ obj = scheduler.matrix[scheduler._mode];
+ obj = obj || { x_step:1, x_unit:"day" };
+
+ start = new Date(start);
+ var len = 1;
+ if(obj._start_correction || obj._end_correction)
+ len = (obj.last_hour||0)*60 - (start.getHours()*60+start.getMinutes()) || 1;
+
+ return start*1 + (scheduler._get_fictional_event_length(start, len, obj) - len);
+};
+scheduler._correct_drag_end_date = function(start, duration){
+ var obj;
+ if (scheduler.matrix)
+ obj = scheduler.matrix[scheduler._mode];
+ obj = obj || { x_step:1, x_unit:"day" };
+
+ var end = start*1 + scheduler._get_fictional_event_length(start, duration, obj);
+ return new Date(end*1 - (scheduler._get_fictional_event_length(end, -1, obj, -1) + 1));
};
scheduler._on_mouse_move=function(e){
if (this._drag_mode){
var pos=this._mouse_coords(e);
- if (pos.force_redraw || this._is_pos_changed(this._drag_pos, pos)){
+ if (this._is_pos_changed(this._drag_pos, pos)){
var start, end;
if (this._edit_id!=this._drag_id)
this._close_not_saved();
@@ -2397,10 +2967,13 @@ scheduler._on_mouse_move=function(e){
if (!this._drag_start) {
var res = this.callEvent("onBeforeEventCreated", [e, this._drag_id]);
- if (!res)
+ if (!res){
+ this._loading=false;
return;
+ }
+ this._loading=false;
this._drag_start=start;
return;
}
@@ -2425,10 +2998,14 @@ scheduler._on_mouse_move=function(e){
this._loading=false;
this._drag_mode="new-size";
- }
+ }
+
var ev=this.getEvent(this._drag_id);
var obj;
+ if (scheduler.matrix)
+ obj = scheduler.matrix[scheduler._mode];
+ obj = obj || { x_step:1, x_unit:"day" };
if (this._drag_mode=="move"){
start = this._min_date.valueOf()+(pos.y*this.config.time_step+pos.x*24*60 -(scheduler._move_pos_shift||0) )*60000;
@@ -2436,10 +3013,10 @@ scheduler._on_mouse_move=function(e){
start = this._correct_shift(start);
if (pos._ignores && this.config.preserve_length && this._table_view){
- if (this.matrix)
- obj = this.matrix[this._mode];
- obj = obj || { x_step:1, x_unit:"day" };
- end = start*1 + this._get_fictional_event_length(start, this._drag_event._event_length, obj);
+
+ start = scheduler._correct_drag_start_date(start);
+ end = scheduler._correct_drag_end_date(start,this._drag_event._event_length);
+
} else
end = ev.end_date.valueOf()-(ev.start_date.valueOf()-start);
} else { // resize
@@ -2457,13 +3034,18 @@ scheduler._on_mouse_move=function(e){
end = resize_date;
}
} else {
- if (pos.resize_from_start)
- start = resize_date;
- else
- end = resize_date;
+ if (pos.resize_from_start){
+ start = scheduler._correct_drag_start_date(resize_date);
+ }else{
+ end = scheduler._correct_drag_end_date(resize_date, 0);
+ }
}
} else {
- end = this.date.date_part(new Date(ev.end_date.valueOf() - 1)).valueOf()+pos.y*this.config.time_step*60000;
+ var end_day_start = this.date.date_part(new Date(ev.end_date.valueOf() - 1)).valueOf();
+ var end_day_date = new Date(end_day_start);
+
+ end = end_day_start + pos.y*this.config.time_step*60000;
+ end = end + ((new Date(end)).getTimezoneOffset() - end_day_date.getTimezoneOffset()) * 60000;
this._els["dhx_cal_data"][0].style.cursor="s-resize";
if (this._mode == "week" || this._mode == "day")
end = this._correct_shift(end);
@@ -2484,17 +3066,49 @@ scheduler._on_mouse_move=function(e){
var new_end = new Date(end-1);
var new_start = new Date(start);
//deny drag out of visible scheduler scale in timeline view
- if(scheduler.config.limit_drag_out &&
+ if(this._drag_mode=="move" && scheduler.config.limit_drag_out &&
(+new_start < +scheduler._min_date || +end > +scheduler._max_date)){
+
+ if(+ev.start_date < +scheduler._min_date || +ev.end_date > +scheduler._max_date){
+ // not move event if it's already outside time scale
+ new_start = new Date(ev.start_date);
+ end = new Date(ev.end_date);
+ }else{
+
var duration = end - new_start;
+
if(+new_start < +scheduler._min_date){
new_start = new Date(scheduler._min_date);
- end = new Date(+new_start + duration);
+ if (pos._ignores && this.config.preserve_length && this._table_view){
+ new_start = new Date(scheduler._correct_drag_start_date(new_start));
+ if(obj._start_correction)
+ new_start = new Date(new_start.valueOf() + obj._start_correction);
+ end = new Date(new_start*1 + this._get_fictional_event_length(new_start, this._drag_event._event_length, obj));
+ }else{
+ end = new Date(+new_start + duration);
+ }
}else{
end = new Date(scheduler._max_date);
- new_start = new Date(+end - duration);
+
+ if (pos._ignores && this.config.preserve_length && this._table_view){
+ if(obj._end_correction)
+ end = new Date(end.valueOf() - obj._end_correction);
+ end = new Date(end*1 - this._get_fictional_event_length(end, 0, obj, true));
+ new_start = new Date(end*1 - this._get_fictional_event_length(end, this._drag_event._event_length, obj, true));
+ if(this._ignores_detected){
+ new_start = scheduler.date.add(new_start, obj.x_step, obj.x_unit);
+ end = new Date(end*1 - this._get_fictional_event_length(end, 0, obj, true));
+ end = scheduler.date.add(end, obj.x_step, obj.x_unit);
+ }
+
+ }else{
+ new_start = new Date(+end - duration);
+ }
+
}
- var new_end = new Date(end-1);
+
+ }
+ var new_end = new Date(end-1);
}
@@ -2548,7 +3162,7 @@ scheduler._on_mouse_down=function(e,src) {
if (this.config.readonly || this._drag_mode) return;
src = src||(e.target||e.srcElement);
- var classname = src.className && src.className.split(" ")[0];
+ var classname = scheduler._getClassName(src).split(" ")[0];
switch (classname) {
case "dhx_cal_event_line":
@@ -2562,7 +3176,8 @@ scheduler._on_mouse_down=function(e,src) {
break;
case "dhx_event_resize":
this._drag_mode="resize";
- if((src.className||"").indexOf("dhx_event_resize_end") < 0){
+ var fullClass = scheduler._getClassName(src);
+ if((fullClass).indexOf("dhx_event_resize_end") < 0){
scheduler._drag_from_start = true;
}else{
scheduler._drag_from_start = false;
@@ -2603,7 +3218,6 @@ scheduler._on_mouse_down=function(e,src) {
this._drag_event = scheduler._lame_clone(this.getEvent(this._drag_id) || {});
this._drag_pos = this._mouse_coords(e);
- this._drag_pos.start = +new Date();
}
}
this._drag_start=null;
@@ -2660,7 +3274,7 @@ scheduler._on_mouse_up=function(e){
this.unselect();
this._new_event=new Date();//timestamp of creation
//if selection disabled - force lightbox usage
- if (this._table_view || this.config.details_on_create || !this.config.select) {
+ if (this._table_view || this.config.details_on_create || !this.config.select || !this.isOneDayEvent(this.getEvent(drag_id))) {
scheduler.callEvent("onDragEnd", [drag_id, mode, e]);
return this.showLightbox(drag_id);
}
@@ -2672,7 +3286,10 @@ scheduler._on_mouse_up=function(e){
}
}
}
- if (this._drag_pos && (this._drag_pos.has_moved || this._drag_pos === true)) this.render_view_data(); //redraw even if there is no real changes - necessary for correct positioning item after drag
+ if (this._drag_pos && (this._drag_pos.has_moved || this._drag_pos === true)) {
+ this._drag_id = this._drag_mode = null; // set null to prevent _sorder recalculation for drag event
+ this.render_view_data(); //redraw even if there is no real changes - necessary for correct positioning item after drag
+ }
scheduler.callEvent("onDragEnd", [drag_id, mode, e]);
}
this._drag_id = null;
@@ -2689,6 +3306,8 @@ scheduler._trigger_dyn_loading = function(){
}
};
scheduler.update_view=function(){
+ this._reset_ignores();
+
var view = this[this._mode + "_view"];
if(view){
view(true);
@@ -2707,14 +3326,41 @@ scheduler.isViewExists = function(mode){
(scheduler.date[mode+ "_start"] && scheduler.templates[mode+ "_date"] && scheduler.templates[mode+ "_scale_date"]));
};
+scheduler._set_aria_buttons_attrs = function(){
+ var buttonGroups = ["dhx_cal_next_button", "dhx_cal_prev_button", "dhx_cal_tab", "dhx_cal_today_button"];
+ for(var i = 0; i < buttonGroups.length; i++){
+ var group = this._els[buttonGroups[i]];
+ for(var j = 0; group && j < group.length; j++ ){
+ var name = group[j].getAttribute("name");
+ var label = this.locale.labels[buttonGroups[i]];
+ if(name){
+ label = this.locale.labels[name] || label;
+
+
+ }
+ if(buttonGroups[i] == "dhx_cal_next_button"){
+ label = this.locale.labels.next;
+ }else if(buttonGroups[i] == "dhx_cal_prev_button"){
+ label = this.locale.labels.prev;
+ }
+ this._waiAria.headerButtonsAttributes(group[j], label || "");
+ }
+ }
+};
+
scheduler.updateView = function(date, mode) {
date = date || this._date;
mode = mode || this._mode;
var dhx_cal_data = 'dhx_cal_data';
- if (!this._mode)
- this._obj.className += " dhx_scheduler_" + mode; else {
- this._obj.className = this._obj.className.replace("dhx_scheduler_" + this._mode, "dhx_scheduler_" + mode);
+ var container = this._obj;
+ var oldClass = "dhx_scheduler_" + this._mode;
+ var newClass = "dhx_scheduler_" + mode;
+
+ if (!this._mode || (container.className.indexOf(oldClass) == -1)){
+ container.className += " " + newClass;
+ } else {
+ container.className = container.className.replace(oldClass, newClass);
}
var prev_scroll = (this._mode == mode && this.config.preserve_scroll) ? this._els[dhx_cal_data][0].scrollTop : false; // saving current scroll
@@ -2737,14 +3383,24 @@ scheduler.updateView = function(date, mode) {
this._dy_shift = 0;//correction for multiday section in week/day views
+
+ this._set_aria_buttons_attrs();
+
var tabs = this._els["dhx_cal_tab"];
if(tabs){//calendar can work without view tabs
for (var i = 0; i < tabs.length; i++) {
- var name = tabs[i].className;
+ var tab = tabs[i];
+
+ var name = tab.className;
name = name.replace(/ active/g, "");
- if (tabs[i].getAttribute("name") == this._mode + "_tab")
+ if (tab.getAttribute("name") == this._mode + "_tab"){
name = name + " active";
- tabs[i].className = name;
+ this._waiAria.headerToggleState(tab, true);
+ }else{
+ this._waiAria.headerToggleState(tab, false);
+ }
+
+ tab.className = name;
}
}
//show new view
@@ -2776,7 +3432,12 @@ scheduler._render_x_header = function(i,left,d,h, offset_top){
left = left+1;
}
this.set_xy(head, width, this.xy.scale_height-2, left, offset_top);//-1 for border
- head.innerHTML=this.templates[this._mode+"_scale_date"](d,this._mode); //TODO - move in separate method
+
+ var columnHeaderText = this.templates[this._mode+"_scale_date"](d,this._mode); //TODO - move in separate method
+ head.innerHTML = columnHeaderText;
+
+ this._waiAria.dayHeaderAttr(head, columnHeaderText);
+
h.appendChild(head);
};
@@ -2857,7 +3518,7 @@ scheduler._render_scales = function(header, data_area){
}
scales.className = cls+" "+this.templates.week_date_class(d,today);
-
+ this._waiAria.dayColumnAttr(scales, d);
this._set_scale_col_size(scales, this._cols[i], left);
data_area.appendChild(scales);
@@ -2901,7 +3562,11 @@ scheduler._reset_scale=function(){
this._min_date=d;
- this._els["dhx_cal_date"][0].innerHTML=this.templates[this._mode+"_date"](dd,ed,this._mode);
+
+ var navBarDateStr = this.templates[this._mode+"_date"](dd,ed,this._mode);
+ this._els["dhx_cal_date"][0].innerHTML = navBarDateStr;
+ this._waiAria.navBarDateAttr(this._els["dhx_cal_date"][0] ,navBarDateStr);
+
this._max_date = ed;
scheduler._render_scales(h, data_area);
@@ -2946,15 +3611,17 @@ scheduler._reset_hours_scale=function(b,dd,sd){
for (var i=this.config.first_hour*1; i < this.config.last_hour; i++) {
var cc=document.createElement("DIV");
cc.className="dhx_scale_hour";
- cc.style.height=this.config.hour_size_px-(this._quirks?0:1)+"px";
+ cc.style.height=this.config.hour_size_px+"px";
var width = this.xy.scale_width;
if (this.config.left_border) {
- width = width - 1;
cc.className += " dhx_scale_hour_border";
}
cc.style.width = width + "px";
- cc.innerHTML=scheduler.templates.hour_scale(date);
-
+
+ var content = scheduler.templates.hour_scale(date);
+ cc.innerHTML = content;
+ this._waiAria.hourScaleAttr(cc, content);
+
c.appendChild(cc);
date=this.date.add(date,1,"hour");
}
@@ -2970,9 +3637,13 @@ scheduler._currentDate = function(){
return new Date();
};
-scheduler._process_ignores = function(sd, n, mode, step, preserve){
+scheduler._reset_ignores = function(){
this._ignores={};
this._ignores_detected = 0;
+};
+
+scheduler._process_ignores = function(sd, n, mode, step, preserve){
+ this._reset_ignores();
var ignore = scheduler["ignore_"+this._mode];
if (ignore){
@@ -2991,7 +3662,7 @@ scheduler._process_ignores = function(sd, n, mode, step, preserve){
}
};
-scheduler._render_month_scale = function(div, dd/*month start*/, sd/*view start*/ ){
+scheduler._render_month_scale = function(div, dd/*month start*/, sd/*view start*/, rows ){
//renders month view layout
var ed=scheduler.date.add(dd,1,"month"),
@@ -3000,15 +3671,15 @@ scheduler._render_month_scale = function(div, dd/*month start*/, sd/*view start*
this.date.date_part(cd);
this.date.date_part(sd);
- var rows=Math.ceil(Math.round((ed.valueOf()-sd.valueOf()) / (60*60*24*1000) ) / 7);
- var tdcss=[];
+ rows = rows || Math.ceil(Math.round((ed.valueOf()-sd.valueOf()) / (60*60*24*1000) ) / 7);
+ var tdwidths=[];
for (var i=0; i<=7; i++) {
var cell_width = ((this._cols[i]||0)-1);
if (i === 0 && this.config.left_border) {
cell_width = cell_width - 1;
}
- tdcss[i]=" style='width:"+cell_width+"px;";
+ tdwidths[i] = cell_width + "px";
}
function getCellHeight(row){
@@ -3022,13 +3693,21 @@ scheduler._render_month_scale = function(div, dd/*month start*/, sd/*view start*
var cellheight = 0;
- var html="<table cellpadding='0' cellspacing='0'>";
+ var table = document.createElement("table");
+ table.setAttribute("cellpadding", "0");
+ table.setAttribute("cellspacing", "0");
+
+ var tableBody = document.createElement("tbody");
+ table.appendChild(tableBody);
+
var rendered_dates = [];
for (var i=0; i<rows; i++){
- html+="<tr>";
+ var row = document.createElement("tr");
+ tableBody.appendChild(row);
var row_height = Math.max(getCellHeight(i) - scheduler.xy.month_head_height, 0);
for (var j=0; j<7; j++) {
- html+="<td";
+ var cell = document.createElement("td");
+ row.appendChild(cell);
var cls = "";
if (sd<dd)
@@ -3042,7 +3721,8 @@ scheduler._render_month_scale = function(div, dd/*month start*/, sd/*view start*
cls += " dhx_scale_ignore";
}
- html+=" class='"+cls+" "+this.templates.month_date_class(sd,cd)+"' >";
+ cell.className = cls + " " + this.templates.month_date_class(sd, cd);
+
var body_class = "dhx_month_body";
var head_class = "dhx_month_head";
if (j === 0 && this.config.left_border) {
@@ -3050,10 +3730,23 @@ scheduler._render_month_scale = function(div, dd/*month start*/, sd/*view start*
head_class += " dhx_month_head_border";
}
if (!this._ignores_detected || !this._ignores[j]){
- html+="<div class='"+head_class+"'>"+this.templates.month_day(sd)+"</div>";
- html+="<div class='"+body_class+"' "+tdcss[j] + ";height:"+row_height + "px;'></div></td>";
+
+ this._waiAria.monthCellAttr(cell, sd);
+
+ var cellHead = document.createElement("DIV");
+ cellHead.className = head_class;
+ cellHead.innerHTML = this.templates.month_day(sd);
+ cell.appendChild(cellHead);
+
+ var cellBody = document.createElement("DIV");
+ cellBody.className = body_class;
+ cellBody.style.height = row_height + "px";
+ cellBody.style.width = tdwidths[j];
+ cell.appendChild(cellBody);
+
} else {
- html+="<div></div><div></div>";
+ cell.appendChild(document.createElement("div"));
+ cell.appendChild(document.createElement("div"));
}
rendered_dates.push(sd);
var bf1 = sd.getDate();
@@ -3061,17 +3754,16 @@ scheduler._render_month_scale = function(div, dd/*month start*/, sd/*view start*
if (sd.getDate() - bf1 > 1)
sd = new Date(sd.getFullYear(), sd.getMonth(), bf1 + 1, 12, 0);
}
- html+="</tr>";
scheduler._colsS.heights[i] = cellheight;
cellheight += getCellHeight(i);
}
- html+="</table>";
this._min_date = view_start;
this._max_date = sd;
- div.innerHTML=html;
+ div.innerHTML = "";
+ div.appendChild(table);
this._scales = {};
var divs = div.getElementsByTagName('div');
@@ -3090,7 +3782,7 @@ scheduler._render_month_scale = function(div, dd/*month start*/, sd/*view start*
return this._max_date;
};
-scheduler._reset_month_scale=function(b,dd,sd){
+scheduler._reset_month_scale=function(b,dd,sd,rows){
//recalculates rows height and redraws month layout
var ed=scheduler.date.add(dd,1,"month");
@@ -3099,14 +3791,14 @@ scheduler._reset_month_scale=function(b,dd,sd){
this.date.date_part(cd);
this.date.date_part(sd);
- var rows=Math.ceil(Math.round((ed.valueOf()-sd.valueOf()) / (60*60*24*1000) ) / 7);
+ rows = rows || Math.ceil(Math.round((ed.valueOf()-sd.valueOf()) / (60*60*24*1000) ) / 7);
var height = (Math.floor(b.clientHeight/rows) - this.xy.month_head_height);
this._colsS.height = height + this.xy.month_head_height;
this._colsS.heights = [];
- return scheduler._render_month_scale(b, dd, sd);
+ return scheduler._render_month_scale(b, dd, sd, rows);
};
scheduler.getLabel = function(property, key) {
@@ -3179,9 +3871,9 @@ scheduler.getActionData = function(n_ev) {
scheduler._focus = function(node, select){
if (node && node.focus){
if (this.config.touch){
- window.setTimeout(function(){
+ window.setTimeout(function(){
node.focus();
- },100);
+ },10);
} else {
if (select && node.select) node.select();
node.focus();
@@ -3204,12 +3896,17 @@ scheduler._get_real_event_length=function(sd, fd, obj){
end_slot = Math.round(ev_length/60/60/1000/24);
}
+ var last_column = true;
while (start_slot < end_slot){
var check = scheduler.date.add(fd, -obj.x_step, obj.x_unit);
- if (ignore && ignore(fd))
+ if (ignore && ignore(fd) && (!last_column || (last_column && ignore(check) ))){
ev_length -= (fd-check);
- else
+
+ }else{
+ last_column = false;
ev_length -= hours;
+ }
+
fd = check;
end_slot--;
@@ -3229,6 +3926,7 @@ scheduler._get_fictional_event_length=function(end_date, ev_length, obj, back){
today = (obj.last_hour||0)*60 - (sd.getHours()*60+sd.getMinutes());
var per_day = (obj.last_hour - obj.first_hour)*60;
var days = Math.ceil( (ev_length / (60*1000) - today ) / per_day);
+ if(days < 0) days = 0;
ev_length += days * (24*60 - per_day) * 60 * 1000;
}
@@ -3284,6 +3982,19 @@ scheduler._is_lightbox_open = function(){
var state = this.getState();
return state.lightbox_id !== null && state.lightbox_id !== undefined;
};
+
+scheduler._getClassName = function(node){
+ if(!node) return "";
+
+ var className = node.className || "";
+ if(className.baseVal)//'className' exist but not a string - IE svg element in DOM
+ className = className.baseVal;
+
+ if(!className.indexOf)
+ className = '';
+
+ return className || "";
+};
scheduler.date={
init:function(){
var s = scheduler.locale.date.month_short;
@@ -3333,10 +4044,21 @@ scheduler.date={
var ndate = new Date(date.valueOf());
ndate.setDate(ndate.getDate() + inc);
+
+ // Workaround for Safari/iOS timezone bug, ref:OKZ-149693
+ if(inc == Math.round(inc) && inc > 0){
+ var datesDiff = +ndate - +date,
+ rest = datesDiff % (24*60*60*1000);
+ if(rest && date.getTimezoneOffset() == ndate.getTimezoneOffset()){
+ var hours = rest / (60* 60 * 1000);
+ ndate.setTime(ndate.getTime() + (24 - hours) * 60 * 60 * 1000);
+ }
+ }
+
if (inc >= 0 && (!date.getHours() && ndate.getHours()) &&//shift to yesterday on dst
(ndate.getDate() < date.getDate() || ndate.getMonth() < date.getMonth() || ndate.getFullYear() < date.getFullYear()) )
ndate.setTime(ndate.getTime() + 60 * 60 * 1000 * (24 - ndate.getHours()));
- return ndate;
+ return ndate;
},
add:function(date,inc,mode){
var ndate=new Date(date.valueOf());
@@ -3442,6 +4164,7 @@ scheduler.date={
},
getISOWeek: function(ndate) {
if(!ndate) return false;
+ ndate = this.date_part(new Date(ndate));
var nday = ndate.getDay();
if (nday === 0) {
nday = 7;
@@ -3512,7 +4235,16 @@ scheduler.locale = {
/* dhtmlx message default buttons */
message_ok:"OK",
- message_cancel:"Cancel"
+ message_cancel:"Cancel",
+
+ /* wai aria labels for non-text controls */
+ next: "Next",
+ prev: "Previous",
+ year: "Year",
+ month: "Month",
+ day: "Day",
+ hour:"Hour",
+ minute: "Minute"
}
};
@@ -3594,7 +4326,9 @@ scheduler.config={
left_border: false,
ajax_error: "alert",//"ignore"|"console"
- delay_render: 0
+ delay_render: 0,
+ timeline_swap_resize: true,
+ wai_aria_attributes: true
};
scheduler.templates={};
scheduler.init_templates=function(){
@@ -3661,6 +4395,13 @@ scheduler.init_templates=function(){
this.callEvent("onTemplatesReady",[]);
};
+/* Could be redifined */
+scheduler.templates.tooltip_date_format = scheduler.date.date_to_str("%Y-%m-%d %H:%i");
+
+scheduler.templates.tooltip_text = function(start, end, event) {
+ return "<b>Event:</b> " + event.text + "<br/><b>Start date:</b> " + scheduler.templates.tooltip_date_format(start) + "<br/><b>End date:</b> " + scheduler.templates.tooltip_date_format(end);
+};
+
scheduler.uid = function() {
@@ -3782,13 +4523,17 @@ scheduler.event_updated = function(ev, force) {
};
scheduler.is_visible_events = function(ev) {
//if in displayed dates
- var in_visible_range = (ev.start_date < this._max_date && this._min_date < ev.end_date);
+ var in_visible_range = (ev.start_date.valueOf() < this._max_date.valueOf() && this._min_date.valueOf() < ev.end_date.valueOf());
if(in_visible_range){
//end dates are not between last/first hours
- var end_dates_visible = (this._table_view || ((ev.end_date.getHours() >= this.config.first_hour && ev.end_date.getHours() < this.config.last_hour) ||
- (ev.start_date.getHours() >= this.config.first_hour && ev.start_date.getHours() < this.config.last_hour))) ;
+ var evFirstHour = ev.start_date.getHours(),
+ evLastHour = ev.end_date.getHours() + (ev.end_date.getMinutes()/60),
+ lastHour = this.config.last_hour,
+ firstHour = this.config.first_hour;
+
+ var end_dates_visible = (this._table_view || !((evLastHour > lastHour || evLastHour < firstHour) && (evFirstHour >= lastHour || evFirstHour < firstHour)));
if(end_dates_visible){
return true;
@@ -3798,7 +4543,7 @@ scheduler.is_visible_events = function(ev) {
var event_duration = (ev.end_date.valueOf() - ev.start_date.valueOf()) / (1000*60*60),//hours
hidden_duration = 24 - (this.config.last_hour - this.config.first_hour);
- return (event_duration > hidden_duration);
+ return !!((event_duration > hidden_duration) || (evFirstHour < lastHour && evLastHour >= firstHour));
}
}else{
@@ -3836,7 +4581,9 @@ scheduler._is_main_area_event = function(ev){
return !!ev._timed;
};
scheduler.render_view_data = function(evs, hold) {
+ var full = false;
if (!evs) {
+ full = true;
if (this._not_render) {
this._render_wait = true;
return;
@@ -3876,6 +4623,10 @@ scheduler.render_view_data = function(evs, hold) {
this._rendered_location = this._els['dhx_cal_data'][0];
this.render_data(evs, hold);
}
+
+ if(full){
+ this.callEvent("onDataRender", []);
+ }
};
@@ -4077,7 +4828,10 @@ scheduler._pre_render_events = function(evs, hold) {
return evs;
};
scheduler._get_event_sday = function(ev) {
- return Math.floor((ev.start_date.valueOf() - this._min_date.valueOf()) / (24 * 60 * 60 * 1000));
+ // get day in current view
+ // use rounding for 23 or 25 hour days on DST
+ var datePart = this.date.day_start(new Date(ev.start_date));
+ return Math.round((datePart.valueOf() - this._min_date.valueOf()) / (24 * 60 * 60 * 1000));
};
scheduler._get_event_mapped_end_date = function(ev) {
var end_date = ev.end_date;
@@ -4420,7 +5174,7 @@ scheduler.render_event = function(ev) {
}
var d = this._render_v_bar(ev, menu_offset + left, top, width, height, ev._text_style, scheduler.templates.event_header(ev.start_date, ev.end_date, ev), scheduler.templates.event_text(ev.start_date, ev.end_date, ev));
-
+ this._waiAria.eventAttr(ev, d);
this._rendered.push(d);
parent.appendChild(d);
@@ -4432,6 +5186,10 @@ scheduler.render_event = function(ev) {
width = Math.max(width - 4, scheduler.xy.editor_width);
d = document.createElement("DIV");
d.setAttribute("event_id", ev.id);
+
+
+ this._waiAria.eventAttr(ev, d);
+
this.set_xy(d, width, height - 20, left, top + 14);
d.className = "dhx_cal_event dhx_cal_editor";
@@ -4472,8 +5230,12 @@ scheduler.render_event = function(ev) {
var icons_str = "";
var bg_color = (ev.color ? ("background-color: " + ev.color + ";") : "");
var color = (ev.textColor ? ("color: " + ev.textColor + ";") : "");
- for (var i = 0; i < icons.length; i++)
- icons_str += "<div class='dhx_menu_icon " + icons[i] + "' style='" + bg_color + "" + color + "' title='" + this.locale.labels[icons[i]] + "'></div>";
+
+ var ariaAttr;
+ for (var i = 0; i < icons.length; i++) {
+ ariaAttr = this._waiAria.eventMenuAttrString(icons[i]);
+ icons_str += "<div class='dhx_menu_icon " + icons[i] + "' style='" + bg_color + "" + color + "' title='" + this.locale.labels[icons[i]] + "'"+ariaAttr+"></div>";
+ }
var obj = this._render_v_bar(ev, left - menu + 1, top, menu, icons.length * 20 + 26 - 2, "", "<div style='" + bg_color + "" + color + "' class='dhx_menu_head'></div>", icons_str, true);
obj.style.left = left - menu + 1;
this._els["dhx_cal_data"][0].appendChild(obj);
@@ -4628,7 +5390,7 @@ scheduler.render_event_bar = function (ev) {
(ev._text_style || "")
].join(";");
- var html = '<div event_id="' + ev.id + '" class="' + cs + '" style="'+style_text+'">';
+ var html = "<div event_id='" + ev.id + "' class='"+ cs + "' style='"+style_text+"'"+this._waiAria.eventBarAttrString(ev)+">";
if (resizable) {
html += resize_handle;
}
@@ -4656,6 +5418,36 @@ scheduler._locate_event = function(node) {
return id;
};
+scheduler._locate_css = function(e, classname, strict){
+ if(strict === undefined)
+ strict = true;
+
+ var trg = e.target || e.srcElement;
+ var css = '';
+
+ while (trg){
+ css = scheduler._getClassName(trg);
+
+ if(css){
+ var ind = css.indexOf(classname);
+ if (ind >= 0){
+ if (!strict)
+ return trg;
+
+ //check that we have exact match
+ var left = (ind === 0) || (!scheduler._trim(css.charAt(ind - 1)));
+ var right = ((ind + classname.length >= css.length)) || (!scheduler._trim(css.charAt(ind + classname.length)));
+
+ if (left && right)
+ return trg;
+ }
+ }
+
+ trg=trg.parentNode;
+ }
+ return null;
+};
+
scheduler.edit = function(id) {
if (this._edit_id == id) return;
this.editStop(false, id);
@@ -4737,7 +5529,9 @@ scheduler.showEvent = function(id, mode) {
scheduler.config.preserve_scroll = preserve_scroll;
if (scheduler.matrix && scheduler.matrix[mode]) {
- scheduler._els.dhx_cal_data[0].scrollTop = getAbsoluteTop(scheduler.getRenderedEvent(ev.id)) - getAbsoluteTop(scheduler._els.dhx_cal_data[0]) - 20;
+ var rendered_event = scheduler.getRenderedEvent(ev.id);
+ if(rendered_event)
+ scheduler._els.dhx_cal_data[0].scrollTop = getAbsoluteTop(rendered_event) - getAbsoluteTop(scheduler._els.dhx_cal_data[0]) - 20;
}
scheduler.callEvent("onAfterEventDisplay", [ev, mode]);
@@ -4748,10 +5542,13 @@ scheduler._append_drag_marker = function(m){
var zone = scheduler._els["dhx_cal_data"][0];
var scale = zone.lastChild;
- if(scale.className && scale.className.indexOf("dhx_scale_holder") < 0 && scale.previousSibling){
+ var className = scheduler._getClassName(scale);
+ if(className.indexOf("dhx_scale_holder") < 0 && scale.previousSibling){
scale = scale.previousSibling;
}
- if (scale && scale.className.indexOf("dhx_scale_holder") === 0) {
+
+ className = scheduler._getClassName(scale);
+ if (scale && className.indexOf("dhx_scale_holder") === 0) {
scale.appendChild(m);
}
};
@@ -4880,7 +5677,12 @@ scheduler._init_date = function(date){
scheduler.json = {};
scheduler.json.parse = function(data) {
if (typeof data == "string") {
- scheduler._temp = eval("(" + data + ")");
+ if(window.JSON){
+ scheduler._temp = JSON.parse(data);
+ }else{
+ scheduler._temp = eval("(" + data + ")");
+ }
+
data = (scheduler._temp) ? scheduler._temp.data || scheduler._temp.d || scheduler._temp : [];
}
@@ -5162,13 +5964,17 @@ scheduler.form_blocks={
return "<div class='dhx_cal_ltext' style='height:"+height+";'><textarea></textarea></div>";
},
set_value:function(node,value,ev){
- node.firstChild.value=value||"";
+ scheduler.form_blocks.textarea._get_input(node).value=value||"";
},
get_value:function(node,ev){
- return node.firstChild.value;
+ return scheduler.form_blocks.textarea._get_input(node).value;
},
focus:function(node){
- var a=node.firstChild; scheduler._focus(a, true);
+ var a = scheduler.form_blocks.textarea._get_input(node);
+ scheduler._focus(a, true);
+ },
+ _get_input: function(node){
+ return node.getElementsByTagName("textarea")[0];
}
},
select:{
@@ -5224,52 +6030,51 @@ scheduler.form_blocks={
if (p > 0) {
html += " ";
}
-
+ var options = "";
switch (time_option) {
case "%Y":
sns._time_format_order[3] = p;
//year
- html+="<select>";
var year = dt.getFullYear()-5; //maybe take from config?
for (var i=0; i < 10; i++)
- html+="<option value='"+(year+i)+"'>"+(year+i)+"</option>";
- html+="</select> ";
+ options+="<option value='"+(year+i)+"'>"+(year+i)+"</option>";
break;
case "%m":
sns._time_format_order[2] = p;
//month
- html+="<select>";
for (var i=0; i < 12; i++)
- html+="<option value='"+i+"'>"+this.locale.date.month_full[i]+"</option>";
- html += "</select>";
+ options+="<option value='"+i+"'>"+this.locale.date.month_full[i]+"</option>";
break;
case "%d":
sns._time_format_order[1] = p;
//days
- html+="<select>";
for (var i=1; i < 32; i++)
- html+="<option value='"+i+"'>"+i+"</option>";
- html += "</select>";
+ options+="<option value='"+i+"'>"+i+"</option>";
break;
case "%H:%i":
sns._time_format_order[0] = p;
//hours
- html += "<select>";
var i = first;
var tdate = dt.getDate();
sns._time_values = [];
while(i<last){
var time=this.templates.time_picker(dt);
- html+="<option value='"+i+"'>"+time+"</option>";
+ options+="<option value='"+i+"'>"+time+"</option>";
sns._time_values.push(i);
dt.setTime(dt.valueOf()+this.config.time_step*60*1000);
var diff = (dt.getDate()!=tdate)?1:0; // moved or not to the next day
i=diff*24*60+dt.getHours()*60+dt.getMinutes();
}
- html += "</select>";
break;
}
+
+ if(options){
+
+ var ariaAttrs = scheduler._waiAria.lightboxSelectAttrString(time_option);
+ var readonly = sns.readonly ? "disabled='disabled'" : "";
+ html += "<select "+readonly + ariaAttrs+">"+options+"</select> ";
+ }
}
return "<div style='height:30px;padding-top:0px;font-size:inherit;' class='dhx_section_time'>"+html+"<span style='font-weight:normal; font-size:10pt;'> &nbsp;&ndash;&nbsp; </span>"+html+"</div>";
@@ -5415,19 +6220,32 @@ scheduler.showLightbox=function(id){
var box = this.getLightbox();
this.showCover(box);
this._fill_lightbox(id,box);
+ this._waiAria.lightboxVisibleAttr(box);
this.callEvent("onLightbox",[id]);
};
scheduler._fill_lightbox = function(id, box) {
var ev = this.getEvent(id);
var s = box.getElementsByTagName("span");
+ var lightboxHeader = [];
+
if (scheduler.templates.lightbox_header) {
+ lightboxHeader.push("");
+ var headerContent = scheduler.templates.lightbox_header(ev.start_date, ev.end_date, ev);
+ lightboxHeader.push(headerContent);
s[1].innerHTML = "";
- s[2].innerHTML = scheduler.templates.lightbox_header(ev.start_date, ev.end_date, ev);
+ s[2].innerHTML = headerContent;
} else {
- s[1].innerHTML = this.templates.event_header(ev.start_date, ev.end_date, ev);
- s[2].innerHTML = (this.templates.event_bar_text(ev.start_date, ev.end_date, ev) || "").substr(0, 70); //IE6 fix
+ var headerDate = this.templates.event_header(ev.start_date, ev.end_date, ev);
+ var headerTitle = (this.templates.event_bar_text(ev.start_date, ev.end_date, ev) || "").substr(0, 70); //IE6 fix;
+
+ lightboxHeader.push(headerDate);
+ lightboxHeader.push(headerTitle);
+ s[1].innerHTML = headerDate;
+ s[2].innerHTML = headerTitle;
}
+ this._waiAria.lightboxHeader(box, lightboxHeader.join(" "));
+
var sns = this.config.lightbox.sections;
for (var i = 0; i < sns.length; i++) {
var current_sns = sns[i];
@@ -5465,7 +6283,9 @@ scheduler._empty_lightbox=function(data){
this.render_view_data();
};
scheduler.hide_lightbox=function(id){
- this.hideCover(this.getLightbox());
+ var box = this.getLightbox();
+ this.hideCover(box);
+ this._waiAria.lightboxHiddenAttr(box);
this._lightbox_id = null;
this.callEvent("onAfterLightbox",[]);
};
@@ -5530,8 +6350,11 @@ scheduler._init_lightbox_events=function(){
this.getLightbox().onclick=function(e){
var src=e?e.target:event.srcElement;
if (!src.className) src=src.previousSibling;
- if (src && src.className)
- switch(src.className){
+
+ var className = scheduler._getClassName(src);
+
+ if (src && className)
+ switch(className){
case "dhx_save_btn":
scheduler.save_lightbox();
break;
@@ -5551,11 +6374,11 @@ scheduler._init_lightbox_events=function(){
default:
if (src.getAttribute("dhx_button")) {
- scheduler.callEvent("onLightboxButton", [src.className, src, e]);
+ scheduler.callEvent("onLightboxButton", [className, src, e]);
} else {
var index, block, sec;
- if (src.className.indexOf("dhx_custom_button") != -1) {
- if (src.className.indexOf("dhx_custom_button_") != -1) {
+ if (className.indexOf("dhx_custom_button") != -1) {
+ if (className.indexOf("dhx_custom_button_") != -1) {
index = src.parentNode.getAttribute("index");
sec = src.parentNode.parentNode;
} else {
@@ -5573,10 +6396,29 @@ scheduler._init_lightbox_events=function(){
}
};
this.getLightbox().onkeydown=function(e){
+ var event = e || window.event;
+ var target = e.target || e.srcElement;
+ var buttonTarget = target.querySelector("[dhx_button]");
+
+ if(!buttonTarget){
+ buttonTarget = target.parentNode.querySelector(".dhx_custom_button, .dhx_readonly");
+ }
+
switch((e||event).keyCode){
+ case 32:{//space
+ if ((e||event).shiftKey) return;
+ if(buttonTarget && buttonTarget.click){
+ buttonTarget.click();
+ }
+ break;
+ }
case scheduler.keys.edit_save:
if ((e||event).shiftKey) return;
- scheduler.save_lightbox();
+ if(buttonTarget && buttonTarget.click){
+ buttonTarget.click();
+ }else{
+ scheduler.save_lightbox();
+ }
break;
case scheduler.keys.edit_cancel:
scheduler.cancel_lightbox();
@@ -5584,6 +6426,7 @@ scheduler._init_lightbox_events=function(){
default:
break;
}
+
};
};
scheduler.setLightboxSize=function(){
@@ -5641,12 +6484,18 @@ scheduler.getLightbox=function(){ //scheduler.config.wide_form=true;
var html = this._lightbox_template;
var buttons = this.config.buttons_left;
- for (var i = 0; i < buttons.length; i++)
- html+="<div class='dhx_btn_set dhx_left_btn_set "+buttons[i]+"_set'><div dhx_button='1' class='"+buttons[i]+"'></div><div>"+scheduler.locale.labels[buttons[i]]+"</div></div>";
+
+ var ariaAttr = "";
+ for (var i = 0; i < buttons.length; i++) {
+ ariaAttr = this._waiAria.lightboxButtonAttrString(buttons[i]);
+ html += "<div "+ariaAttr+" class='dhx_btn_set dhx_left_btn_set " + buttons[i] + "_set'><div dhx_button='1' class='" + buttons[i] + "'></div><div>" + scheduler.locale.labels[buttons[i]] + "</div></div>";
+ }
buttons = this.config.buttons_right;
- for (var i = 0; i < buttons.length; i++)
- html+="<div class='dhx_btn_set dhx_right_btn_set "+buttons[i]+"_set' style='float:right;'><div dhx_button='1' class='"+buttons[i]+"'></div><div>"+scheduler.locale.labels[buttons[i]]+"</div></div>";
+ for (var i = 0; i < buttons.length; i++) {
+ ariaAttr = this._waiAria.lightboxButtonAttrString(buttons[i]);
+ html += "<div "+ariaAttr+" class='dhx_btn_set dhx_right_btn_set " + buttons[i] + "_set' style='float:right;'><div dhx_button='1' class='" + buttons[i] + "'></div><div>" + scheduler.locale.labels[buttons[i]] + "</div></div>";
+ }
html+="</div>";
d.innerHTML=html;
@@ -5657,6 +6506,9 @@ scheduler.getLightbox=function(){ //scheduler.config.wide_form=true;
scheduler._init_dnd_events();
}
+
+ this._waiAria.lightboxAttr(d);
+
document.body.insertBefore(d,document.body.firstChild);
this._lightbox=d;
@@ -5668,7 +6520,8 @@ scheduler.getLightbox=function(){ //scheduler.config.wide_form=true;
sns[i].id="area_"+this.uid();
var button = "";
if (sns[i].button){
- button = "<div class='dhx_custom_button' index='"+i+"'><div class='dhx_custom_button_"+sns[i].button+"'></div><div>"+this.locale.labels["button_"+sns[i].button]+"</div></div>";
+ var ariaAttr = scheduler._waiAria.lightboxSectionButtonAttrString(this.locale.labels["button_"+sns[i].button]);
+ button = "<div "+ariaAttr+" class='dhx_custom_button' index='"+i+"'><div class='dhx_custom_button_"+sns[i].button+"'></div><div>"+this.locale.labels["button_"+sns[i].button]+"</div></div>";
}
if (this.config.wide_form){
@@ -5679,19 +6532,42 @@ scheduler.getLightbox=function(){ //scheduler.config.wide_form=true;
if(typeof label_name !== "string"){
label_name = sns[i].name;
}
- html+="<div id='"+sns[i].id+"' class='dhx_cal_lsection'>"+button+label_name+"</div>"+block.render.call(this,sns[i]);
+ html+="<div id='"+sns[i].id+"' class='dhx_cal_lsection'>"+button+ "<label>"+label_name+"</label></div>"+block.render.call(this,sns[i]);
html+="</div>";
}
var ds=d.getElementsByTagName("div");
for (var i=0; i<ds.length; i++) {
var t_ds = ds[i];
- if (t_ds.className == "dhx_cal_larea") {
+ var className = scheduler._getClassName(t_ds);
+ if (className == "dhx_cal_larea") {
t_ds.innerHTML = html;
break;
}
}
+ // bind labels to lightbox inputs
+ for(var i = 0; i < sns.length; i++){
+ var section = sns[i];
+ if(!section.id || !document.getElementById(section.id))
+ continue;
+
+ var labelBlock = document.getElementById(section.id);
+ var label = labelBlock.querySelector("label");
+ var inputBlock = labelBlock.nextSibling;
+ if(!inputBlock)
+ continue;
+
+ var input = inputBlock.querySelector("input, select, textarea");
+ if(input){
+ section.inputId = input.id || "input_" + scheduler.uid();
+ if(!input.id)
+ input.id = section.inputId;
+
+ label.setAttribute("for", section.inputId);
+ }
+ }
+
//sizes
this.setLightboxSize();
@@ -5724,17 +6600,17 @@ scheduler._init_touch_events = function(){
if (ev.pointerType == ev.MSPOINTER_TYPE_MOUSE ) return null;
return ev;
}, function(ev){
- return (!ev || ev.pointerType == ev.MSPOINTER_TYPE_MOUSE);
+ return (!ev || ev.pointerType == ev.MSPOINTER_TYPE_MOUSE || (scheduler._pointerDragId && scheduler._pointerDragId != ev.pointerId));
});
this._obj.ondblclick = function(){};
} else
this._touch_events(["touchmove", "touchstart", "touchend"], function(ev){
if (ev.touches && ev.touches.length > 1) return null;
- if (ev.touches[0])
+ if (ev.touches && ev.touches[0])
return { target:ev.target, pageX:ev.touches[0].pageX, pageY:ev.touches[0].pageY };
else
return ev;
- }, function(){ return false; });
+ }, function(ev){ return !!(ev.touches && ev.touches.length > 1); });
}
};
@@ -5810,11 +6686,15 @@ scheduler._touch_events = function(names, accessor, ignore){
scheduler.render_view_data = original_render;
}
}
+
+ // touchmove
attachTouchEvent(document.body, names[0], function(e){
if (ignore(e)) return;
+ var acc = accessor(e);
+ if(!acc) return;
if (drag_mode){
- doMouseMove(accessor(e));
+ doMouseMove(acc);
scheduler._update_global_tip();
if (e.preventDefault)
e.preventDefault();
@@ -5855,9 +6735,12 @@ scheduler._touch_events = function(names, accessor, ignore){
return false;
}
});
- attachTouchEvent(this._els["dhx_cal_data"][0], names[1], function(e){
+
+ // touchstart
+ attachTouchEvent(this._obj, names[1], function(e){
if (ignore(e)) return;
-
+ scheduler._pointerDragId = e.pointerId;
+
var fake_event;
drag_mode = scroll_mode = false;
action_mode = true;
@@ -5875,6 +6758,7 @@ scheduler._touch_events = function(names, accessor, ignore){
if (!scroll_mode && !drag_mode && now - dblclicktime < 250){
scheduler._click.dhx_cal_data(fake_event);
window.setTimeout(function(){
+ fake_event.type = "dblclick";
scheduler._on_dbl_click(fake_event);
}, 50);
@@ -5912,7 +6796,8 @@ scheduler._touch_events = function(names, accessor, ignore){
drag_mode = true;
var target = source.target;
- if (target && target.className && target.className.indexOf("dhx_body") != -1)
+ var className = scheduler._getClassName(target);
+ if (target && className.indexOf("dhx_body") != -1)
target = target.previousSibling;
scheduler._on_mouse_down(source, target);
@@ -5931,7 +6816,7 @@ scheduler._touch_events = function(names, accessor, ignore){
if (scheduler.config.touch_tip)
scheduler._show_global_tip();
- scheduler._on_mouse_move(source);
+ scheduler.updateEvent(scheduler._drag_id);
},scheduler.config.touch_drag);
source = fake_event;
@@ -5945,11 +6830,13 @@ scheduler._touch_events = function(names, accessor, ignore){
scheduler._drag_id = null;
scheduler._drag_mode=null;
scheduler._drag_pos=null;
-
+ scheduler._pointerDragId = null;
clearTimeout(timer);
drag_mode = action_mode = false;
scroll_mode = true;
}
+
+ // touch end
attachTouchEvent(this._els["dhx_cal_data"][0], names[2], function(e){
if (ignore(e)) return;
@@ -5993,9 +6880,9 @@ scheduler._update_global_tip = function(init){
}
if (scheduler._drag_mode == "create" || scheduler._drag_mode == "new-size")
- toptip.innerHTML = (scheduler.locale.drag_to_create || "Drag to create")+time;
+ toptip.innerHTML = (scheduler.locale.labels.drag_to_create || "Drag to create")+time;
else
- toptip.innerHTML = (scheduler.locale.drag_to_move || "Drag to move")+time;
+ toptip.innerHTML = (scheduler.locale.labels.drag_to_move || "Drag to move")+time;
}
};
scheduler._hide_global_tip = function(){
@@ -6007,10 +6894,26 @@ scheduler._hide_global_tip = function(){
};
scheduler._dp_init=function(dp){
- dp._methods=["_set_event_text_style","","changeEventId","_dp_hook_delete"];
-
- this._dp_hook_delete = function(id){
- return this.deleteEvent(id, true);
+ dp._methods=["_set_event_text_style","","_dp_change_event_id","_dp_hook_delete"];
+
+ this._dp_change_event_id = function(id, new_id){
+ if(!scheduler.getEvent(id))
+ return;
+
+ scheduler.changeEventId(id, new_id);
+ };
+
+ this._dp_hook_delete = function(id, new_id){
+ if(!scheduler.getEvent(id))
+ return;
+
+ if(id != new_id){
+ if(this.getUserData(id, dp.action_param) == "true_deleted")
+ this.setUserData(id, dp.action_param, "updated");
+
+ this.changeEventId(id, new_id);
+ }
+ return this.deleteEvent(new_id, true);
};
this.attachEvent("onEventAdded",function(id){
if (!this._loading && this._validId(id))
@@ -6031,28 +6934,47 @@ scheduler._dp_init=function(dp){
if (!this._loading && this._validId(id))
dp.setUpdated(id,true,"updated");
});
-
- dp._getRowData=function(id,pref){
- var ev=this.obj.getEvent(id);
- var data = {};
+
+ scheduler.attachEvent("onClearAll", function(){
+ // clear dataprocessor state when scheduler is reset
+ dp._in_progress={};
+ dp._invalid={};
+ dp.updatedRows = [];
+ dp._waitMode = 0;
+ });
+
+ dp._objToJson = function(obj, data, prefix){
+ prefix = prefix || "";
+ data = data || {};
- for (var a in ev){
+ for (var a in obj){
if (a.indexOf("_") === 0) continue;
- if (ev[a] && ev[a].getUTCFullYear) //not very good, but will work
- data[a] = this.obj.templates.xml_format(ev[a]);
- else
- data[a] = ev[a];
+ if (obj[a] && obj[a].getUTCFullYear) //not very good, but will work
+ data[prefix+a] = this.obj.templates.xml_format(obj[a]);
+ else {
+ if (obj[a] && typeof obj[a] == "object")
+ dp._objToJson(obj[a], data, prefix+a+".");
+ else
+ data[prefix+a] = obj[a];
+ }
}
return data;
};
+ dp._getRowData=function(id,pref){
+ var ev=this.obj.getEvent(id);
+ return this._objToJson(ev);
+ };
dp._clearUpdateFlag=function(){};
dp.attachEvent("insertCallback", scheduler._update_callback);
dp.attachEvent("updateCallback", scheduler._update_callback);
dp.attachEvent("deleteCallback", function(upd, id) {
- this.obj.setUserData(id, this.action_param, "true_deleted");
- this.obj.deleteEvent(id);
+ if (this.obj.getEvent(id)){
+ this.obj.setUserData(id, this.action_param, "true_deleted");
+ this.obj.deleteEvent(id);
+ } else if (this.obj._add_rec_marker)
+ this.obj._update_callback(upd, id);
});
};
@@ -6062,15 +6984,28 @@ scheduler._validId=function(id){
};
scheduler.setUserData=function(id,name,value){
- if (id)
- this.getEvent(id)[name]=value;
- else
+ if (id){
+ var ev = this.getEvent(id);
+ if(ev) ev[name]=value;
+ }else{
this._userdata[name]=value;
+ }
};
scheduler.getUserData=function(id,name){
- return id?this.getEvent(id)[name]:this._userdata[name];
+ if (id){
+ var ev = this.getEvent(id);
+ if(ev)
+ return ev[name];
+ else
+ return null;
+ }else{
+ return this._userdata[name];
+ }
};
scheduler._set_event_text_style=function(id,style){
+ if(!scheduler.getEvent(id))
+ return;
+
this.for_rendered(id,function(r){
r.style.cssText+=";"+style;
});
@@ -6081,11 +7016,16 @@ scheduler._set_event_text_style=function(id,style){
scheduler._update_callback = function(upd,id){
var data = scheduler._xmlNodeToJSON(upd.firstChild);
+
+ //fix for updates of recurring events
+ if (data.rec_type == "none") data.rec_pattern = "none";
data.text = data.text||data._tagvalue;
data.start_date = scheduler.templates.xml_date(data.start_date);
data.end_date = scheduler.templates.xml_date(data.end_date);
scheduler.addEvent(data);
+ if (scheduler._add_rec_marker)
+ scheduler.setCurrentView();
};
scheduler._skin_settings = {
fix_tab_position: [1,0],
@@ -6165,7 +7105,7 @@ scheduler._skin_init = function(){
if (date.getDate() == 1) {
label = scheduler.locale.date.month_full[date.getMonth()] + " " + label;
}
- if (+date == +scheduler.date.date_part(new Date())) {
+ if (+date == +scheduler.date.date_part(this._currentDate())) {
label = scheduler.locale.labels.dhx_cal_today_button + " " + label;
}
return label;