Dhtmlx_Scheduler分析

Dhtmlx Scheduller(以下简称ds)代码其实分成了很多内容,主要包括了四个对象

Dthmlx

dhtmlxAjax

dhmltxGridObject

Scheduler

以及很多其他方法包括jquery兼容性处理,_CreatBox()为首的一些列创建窗口的方法,button(),callback(),getofferSetSum(),geturlSymbol()等一系列特性方法。

我们需要关注其中的scheduler对象。

最简单的范例

  JS代码

scheduler.config.xml_date="%Y-%m-%d %H:%i";

scheduler.init('scheduler_here',new Date(2010,0,10),"week");

scheduler.load("./data/events.xml");

      Html代码

<div id="scheduler_here" class="dhx_cal_container" style='width:100%; height:100%;'>

<div class="dhx_cal_navline">

<div class="dhx_cal_prev_button">&nbsp;</div>

<div class="dhx_cal_next_button">&nbsp;</div>

<div class="dhx_cal_today_button"></div>

<div class="dhx_cal_date"></div>

<div class="dhx_cal_tab" name="day_tab" style="right:204px;"></div>

<div class="dhx_cal_tab" name="week_tab" style="right:140px;"></div>

<div class="dhx_cal_tab" name="month_tab" style="right:76px;"></div>

</div>

<div class="dhx_cal_header">

</div>

<div class="dhx_cal_data">

</div>

</div>

 

 

从scheduler.init()开始

所有代码都是从scheduler.init开始的,从这个入口开机我们可以看到scheduler主要调用了如下几个方法

 

clip_image001

本来看dthmlx源码只有一个目的:我要为月视图上的任务条创建一个垂直工具条。

现在好,小半天下来,除了想看的没看明白,不想看的全看明白了。既然看了这么多了,还是直接总结一下备用。学习本来就有两种方式,一种是循序渐进稳扎稳大,一种是直奔主题,根据目的来驱动。

init方法最终会调用setCurrentView,setCurrentView又回去调用updateView最终生成了所有页面event元素, now我们知道了,核心方法是updateView。

接下来根据单个功能点来看代码吧,要不然功能太庞大了

对于单击evnent元素(周视图的event块元素和月视图event bar元素),执行流程又是如下的:

event和event menu元素的生成顺序

image

 

 

 

其实可以看出来week视图和month视图生成元素的顺序基本上是一致的,只是到了renderdate方法的时候走了一下分支:

  • 如果是月视图,则调用reder_event_bar方法;
  • 如果是周视图,则调用render_event方法。

月视图通过render_event方法生成了块状事件区域,然后继续调用_render_v_bar生成了垂直工具条。

但是对于月视图而言只是生成了任务bar,没有生成工具栏,原因就是缺少了_render_v_bar方法。但是想要为其生成工具栏的话,_render_v_bar方法不能够直接在此处调用,需要做一些定制化的改造

 

 

Week视图生成event区域/event_menu代码

scheduler.render_event = function(ev) {

var menu = scheduler.xy.menu_width;

var menu_offset = (this.config.use_select_menu_space) ? 0 : menu;

if (ev._sday < 0) return; //can occur in case of recurring event during time shift

var parent = scheduler.locate_holder(ev._sday);       

if (!parent) return; //attempt to render non-visible event

var sm = ev.start_date.getHours() * 60 + ev.start_date.getMinutes();

var em = (ev.end_date.getHours() * 60 + ev.end_date.getMinutes()) || (scheduler.config.last_hour * 60);

var ev_count = ev._count || 1;

var ev_sorder = ev._sorder || 0;

var top = (Math.round((sm * 60 * 1000 - this.config.first_hour * 60 * 60 * 1000) * this.config.hour_size_px / (60 * 60 * 1000))) % (this.config.hour_size_px * 24); //42px/hour

var height = Math.max(scheduler.xy.min_event_height, (em - sm) * this.config.hour_size_px / 60); //42px/hour

var width = Math.floor((parent.clientWidth - menu_offset) / ev_count);

var left = ev_sorder * width + 1;

if (!ev._inner) width = width * (ev_count - ev_sorder);

if (this.config.cascade_event_display) {

var limit = this.config.cascade_event_count;

var margin = this.config.cascade_event_margin;

left = ev_sorder % limit * margin;

var right = (ev._inner) ? (ev_count - ev_sorder - 1) % limit * margin / 2 : 0;

width = Math.floor(parent.clientWidth - menu_offset - left - right);

}

//生成了event区域

var d = this._render_v_bar(ev.id, 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._rendered.push(d);

parent.appendChild(d);

left = left + parseInt(parent.style.left, 10) + menu_offset;

if (this._edit_id == ev.id) {

d.style.zIndex = 1; //fix overlapping issue

width = Math.max(width - 4, scheduler.xy.editor_width);

d = document.createElement("DIV");

d.setAttribute("event_id", ev.id);

this.set_xy(d, width, height - 20, left, top + 14);

d.className = "dhx_cal_editor";

var d2 = document.createElement("DIV");

this.set_xy(d2, width - 6, height - 26);

d2.style.cssText += ";margin:2px 2px 2px 2px;overflow:hidden;";

//生成了编辑区域

d.appendChild(d2);

this._els["dhx_cal_data"][0].appendChild(d);

this._rendered.push(d);

d2.innerHTML = "<textarea class='dhx_cal_editor'>" + ev.text + "</textarea>";

if (this._quirks7) d2.firstChild.style.height = height - 12 + "px"; //IEFIX

this._editor = d2.firstChild;

this._editor.onkeydown = function(e) {

if ((e || event).shiftKey) return true;

var code = (e || event).keyCode;

if (code == scheduler.keys.edit_save) scheduler.editStop(true);

if (code == scheduler.keys.edit_cancel) scheduler.editStop(false);

};

this._editor.onselectstart = function (e) {

return (e || event).cancelBubble = true;

};

scheduler._focus(d2.firstChild, true);

//IE and opera can add x-scroll during focusing

this._els["dhx_cal_data"][0].scrollLeft = 0;

}

if (this.xy.menu_width !== 0 && this._select_id == ev.id) {

if (this.config.cascade_event_display && this._drag_mode)

d.style.zIndex = 1; //fix overlapping issue for cascade view in case of dnd of selected event

var icons = this.config["icons_" + ((this._edit_id == ev.id) ? "edit" : "select")];

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 obj = this._render_v_bar(ev.id, 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);

this._rendered.push(obj);

}

};

 

生成元素的时候会调用如下方法在外部保存一层元素。其实本质上就是生成了一个悬浮元素  

scheduler._render_v_bar = function (id, x, y, w, h, style, contentA, contentB, bottom) {

var d = document.createElement("DIV");

var ev = this.getEvent(id);

var cs = (bottom) ? "dhx_cal_event dhx_cal_select_menu" : "dhx_cal_event";

var cse = scheduler.templates.event_class(ev.start_date, ev.end_date, ev);

if (cse) cs = cs + " " + cse;

var bg_color = (ev.color ? ("background:" + ev.color + ";") : "");

var color = (ev.textColor ? ("color:" + ev.textColor + ";") : "");

var html = '<div event_id="' + id + '" class="' + cs + '" style="position:absolute; top:' + y + 'px; left:' + x + 'px; width:' + (w - 4) + 'px; height:' + h + 'px;' + (style || "") + '"></div>';

d.innerHTML = html;

var container = d.cloneNode(true).firstChild;

if (!bottom && scheduler.renderEvent(container, ev)) {

return container;

} else {

container = d.firstChild;

var inner_html = '<div class="dhx_event_move dhx_header" style=" width:' + (w - 6) + 'px;' + bg_color + '" >&nbsp;</div>';

inner_html += '<div class="dhx_event_move dhx_title" style="' + bg_color + '' + color + '">' + contentA + '</div>';

inner_html += '<div class="dhx_body" style=" width:' + (w - (this._quirks ? 4 : 14)) + 'px; height:' + (h - (this._quirks ? 20 : 30) + 1) + 'px;' + bg_color + '' + color + '">' + contentB + '</div>'; // +2 css specific, moved from render_event

var footer_class = "dhx_event_resize dhx_footer";

if (bottom)

footer_class = "dhx_resize_denied " + footer_class;

inner_html += '<div class="' + footer_class + '" style=" width:' + (w - 8) + 'px;' + (bottom ? ' margin-top:-1px;' : '') + '' + bg_color + '' + color + '" ></div>';

container.innerHTML = inner_html;

}

return container;

};

 

 

month视图生成event区域代码

  

scheduler.render_event_bar = function (ev) {

var parent = this._rendered_location;

var pos = this._get_event_bar_pos(ev);

var y = pos.y;

var x = pos.x;

var x2 = pos.x2;

//events in ignored dates

if (!x2) return;

var d = document.createElement("DIV");

var cs = "dhx_cal_event_clear";

if (!ev._timed) {

cs = "dhx_cal_event_line";

if (ev.hasOwnProperty("_first_chunk") && ev._first_chunk)

cs += " dhx_cal_event_line_start";

if (ev.hasOwnProperty("_last_chunk") && ev._last_chunk)

cs += " dhx_cal_event_line_end";

}

var cse = scheduler.templates.event_class(ev.start_date, ev.end_date, ev);

if (cse) cs = cs + " " + cse;

var bg_color = (ev.color ? ("background:" + ev.color + ";") : "");

var color = (ev.textColor ? ("color:" + ev.textColor + ";") : "");

var html = '<div event_id="' + ev.id + '" class="' + cs + '" style="position:absolute; top:' + y + 'px; left:' + x + 'px; width:' + (x2 - x - 15) + 'px;' + color + '' + bg_color + '' + (ev._text_style || "") + '">';

ev = scheduler.getEvent(ev.id); // ev at this point could be a part of a larged event

if (ev._timed)

html += scheduler.templates.event_bar_date(ev.start_date, ev.end_date, ev);

html += scheduler.templates.event_bar_text(ev.start_date, ev.end_date, ev) + '</div>';

html += '</div>';

d.innerHTML = html;

this._rendered.push(d.firstChild);

parent.appendChild(d.firstChild);

//其实增加了如下的代码就可以生成元素了

debugger;

if (this.xy.menu_width !== 0 && this._select_id == ev.id) {

if (this.config.cascade_event_display && this._drag_mode)

d.style.zIndex = 1; //fix overlapping issue for cascade view in case of dnd of selected event

var icons = this.config["icons_" + ((this._edit_id == ev.id) ? "edit" : "select")];

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 obj = this._render_v_bar(ev.id, 100, 100,300, 100, "", "<div style='" + bg_color + "" + color + "' class='dhx_menu_head'></div>", icons_str, true);

obj.style.left = 200 + 1;

this._els["dhx_cal_data"][0].appendChild(obj);

this._rendered.push(obj);

}

};

 

 

至此,我们就实现了生成工具条的目标。

 

 Dhtmlx还是一个非常强大的控件,里面可以复用的内容非常多,包括图标,弹出元素样式。后续继续跟踪形成一个系列来写,这不是结果

 

 

posted @ 2013-11-17 19:23  shall we  阅读(1208)  评论(0编辑  收藏  举报