/*
Product Name: dhtmlxSuite
Version: 4.0.3
Edition: Professional
License: content of this file is covered by DHTMLX Commercial or Enterprise license. Usage without proper license is prohibited. To obtain it contact sales@dhtmlx.com
Copyright UAB Dinamenta http://www.dhtmlx.com
*/
/*
Copyright DHTMLX LTD. http://www.dhtmlx.com
You allowed to use this component or parts of it under GPL terms
To use it on other terms or get Professional edition of the component please contact us at sales@dhtmlx.com
*/
/*
2014 March 19
*/
/* DHX DEPEND FROM FILE 'assert.js'*/
if (!window.dhtmlx)
dhtmlx={};
//check some rule, show message as error if rule is not correct
dhtmlx.assert = function(test, message){
if (!test) dhtmlx.error(message);
};
dhtmlx.assert_enabled=function(){ return false; };
//register names of event, which can be triggered by the object
dhtmlx.assert_event = function(obj, evs){
if (!obj._event_check){
obj._event_check = {};
obj._event_check_size = {};
}
for (var a in evs){
obj._event_check[a.toLowerCase()]=evs[a];
var count=-1; for (var t in evs[a]) count++;
obj._event_check_size[a.toLowerCase()]=count;
}
};
dhtmlx.assert_method_info=function(obj, name, descr, rules){
var args = [];
for (var i=0; i < rules.length; i++) {
args.push(rules[i][0]+" : "+rules[i][1]+"\n "+rules[i][2].describe()+(rules[i][3]?"; optional":""));
}
return obj.name+"."+name+"\n"+descr+"\n Arguments:\n - "+args.join("\n - ");
};
dhtmlx.assert_method = function(obj, config){
for (var key in config)
dhtmlx.assert_method_process(obj, key, config[key].descr, config[key].args, (config[key].min||99), config[key].skip);
};
dhtmlx.assert_method_process = function (obj, name, descr, rules, min, skip){
var old = obj[name];
if (!skip)
obj[name] = function(){
if (arguments.length != rules.length && arguments.length < min)
dhtmlx.log("warn","Incorrect count of parameters\n"+obj[name].describe()+"\n\nExpecting "+rules.length+" but have only "+arguments.length);
else
for (var i=0; i= 0) return true;
return false;
};
dhtmlx.assert_rule_dimension.describe=function(){
return "{Integer} value must be a positive number";
};
dhtmlx.assert_rule_number=function(check){
if (typeof check == "number") return true;
return false;
};
dhtmlx.assert_rule_number.describe=function(){
return "{Integer} value must be a number";
};
dhtmlx.assert_rule_function=function(check){
if (typeof check == "function") return true;
return false;
};
dhtmlx.assert_rule_function.describe=function(){
return "{Function} value must be a custom function";
};
dhtmlx.assert_rule_any=function(check){
return true;
};
dhtmlx.assert_rule_any.describe=function(){
return "Any value";
};
dhtmlx.assert_rule_mix=function(a,b){
var t = function(check){
if (a(check)||b(check)) return true;
return false;
};
t.describe = function(){
return a.describe();
};
return t;
};
}
/* DHX DEPEND FROM FILE 'dhtmlx.js'*/
/*DHX:Depend assert.js*/
/*
Common helpers
*/
dhtmlx.version="3.0";
dhtmlx.codebase="./";
//coding helpers
dhtmlx.copy = function(source){
var f = dhtmlx.copy._function;
f.prototype = source;
return new f();
};
dhtmlx.copy._function = function(){};
//copies methods and properties from source to the target
dhtmlx.extend = function(target, source){
for (var method in source)
target[method] = source[method];
//applying asserts
if (dhtmlx.assert_enabled() && source._assert){
target._assert();
target._assert=null;
}
dhtmlx.assert(target,"Invalid nesting target");
dhtmlx.assert(source,"Invalid nesting source");
//if source object has init code - call init against target
if (source._init)
target._init();
return target;
};
dhtmlx.proto_extend = function(){
var origins = arguments;
var compilation = origins[0];
var construct = [];
for (var i=origins.length-1; i>0; i--) {
if (typeof origins[i]== "function")
origins[i]=origins[i].prototype;
for (var key in origins[i]){
if (key == "_init")
construct.push(origins[i][key]);
else if (!compilation[key])
compilation[key] = origins[i][key];
}
};
if (origins[0]._init)
construct.push(origins[0]._init);
compilation._init = function(){
for (var i=0; i handler
this._handlers = {}; //hash of event handlers, ID => handler
this._map = {};
},
//temporary block event triggering
block : function(){
this._events._block = true;
},
//re-enable event triggering
unblock : function(){
this._events._block = false;
},
mapEvent:function(map){
dhtmlx.extend(this._map, map);
},
//trigger event
callEvent:function(type,params){
if (this._events._block) return true;
type = type.toLowerCase();
dhtmlx.assert_event_call(this, type, params);
var event_stack =this._events[type.toLowerCase()]; //all events for provided name
var return_value = true;
if (dhtmlx.debug) //can slowdown a lot
dhtmlx.log("info","["+this.name+"] event:"+type,params);
if (event_stack)
for(var i=0; i=0) this.splice(pos,(len||1));
},
//find element in collection and remove it
remove:function(value){
this.removeAt(this.find(value));
},
//add element to collection at specific position
insertAt:function(data,pos){
if (!pos && pos!==0) //add to the end by default
this.push(data);
else {
var b = this.splice(pos,(this.length-pos));
this[pos] = data;
this.push.apply(this,b); //reconstruct array without loosing this pointer
}
},
//return index of element, -1 if it doesn't exists
find:function(data){
for (i=0; ito){ //can be in case of backward shift-selection
var a=to; to=from; from=a;
}
return this.getIndexRange(from,to);
},
//converts range of indexes to array of all IDs between them
getIndexRange:function(from,to){
to=Math.min((to||Infinity),this.dataCount()-1);
var ret=dhtmlx.toArray(); //result of method is rich-array
for (var i=(from||0); i <= to; i++)
ret.push(this.item(this.order[i]));
return ret;
},
//returns total count of elements
dataCount:function(){
return this.order.length;
},
//returns truy if item with such ID exists
exists:function(id){
return !!(this.pull[id]);
},
//nextmethod is not visible on component level, check DataMove.move
//moves item from source index to the target index
move:function(sindex,tindex){
if (sindex<0 || tindex<0){
dhtmlx.error("DataStore::move","Incorrect indexes");
return;
}
var id = this.idByIndex(sindex);
var obj = this.item(id);
this.order.removeAt(sindex); //remove at old position
//if (sindex data_size){
dhtmlx.log("Warning","DataStore:add","Index of out of bounds");
index = Math.min(this.order.length,index);
}
if (this.callEvent("onBeforeAdd", [id, obj, index]) === false) return false;
if (this.exists(id)) return dhtmlx.error("Not unique ID");
this.pull[id]=obj;
this.order.insertAt(id,index);
if (this._filter_order){ //adding during filtering
//we can't know the location of new item in full dataset, making suggestion
//put at end by default
var original_index = this._filter_order.length;
//put at start only if adding to the start and some data exists
if (!index && this.order.length)
original_index = 0;
this._filter_order.insertAt(id,original_index);
}
this.callEvent("onafterAdd",[id,index]);
//repaint signal
this.callEvent("onStoreUpdated",[id,obj,"add"]);
return id;
},
//removes element from datastore
remove:function(id){
//id can be an array of IDs - result of getSelect, for example
if (id instanceof Array){
for (var i=0; i < id.length; i++)
this.remove(id[i]);
return;
}
if (this.callEvent("onBeforeDelete",[id]) === false) return false;
if (!this.exists(id)) return dhtmlx.error("Not existing ID",id);
var obj = this.item(id); //save for later event
//clear from collections
this.order.remove(id);
if (this._filter_order)
this._filter_order.remove(id);
delete this.pull[id];
this.callEvent("onafterdelete",[id]);
//repaint signal
this.callEvent("onStoreUpdated",[id,obj,"delete"]);
},
//deletes all records in datastore
clearAll:function(){
//instead of deleting one by one - just reset inner collections
this.pull = {};
this.order = dhtmlx.toArray();
this.feed = null;
this._filter_order = null;
this.callEvent("onClearAll",[]);
this.refresh();
},
//converts id to index
idByIndex:function(index){
if (index>=this.order.length || index<0)
dhtmlx.log("Warning","DataStore::idByIndex Incorrect index");
return this.order[index];
},
//converts index to id
indexById:function(id){
var res = this.order.find(id); //slower than idByIndex
//if (!this.pull[id])
// dhtmlx.log("Warning","DataStore::indexById Non-existing ID: "+ id);
return res;
},
//returns ID of next element
next:function(id,step){
return this.order[this.indexById(id)+(step||1)];
},
//returns ID of first element
first:function(){
return this.order[0];
},
//returns ID of last element
last:function(){
return this.order[this.order.length-1];
},
//returns ID of previous element
previous:function(id,step){
return this.order[this.indexById(id)-(step||1)];
},
/*
sort data in collection
by - settings of sorting
or
by - sorting function
dir - "asc" or "desc"
or
by - property
dir - "asc" or "desc"
as - type of sortings
Sorting function will accept 2 parameters and must return 1,0,-1, based on desired order
*/
sort:function(by, dir, as){
var sort = by;
if (typeof by == "function")
sort = {as:by, dir:dir};
else if (typeof by == "string")
sort = {by:by, dir:dir, as:as};
var parameters = [sort.by, sort.dir, sort.as];
if (!this.callEvent("onbeforesort",parameters)) return;
if (this.order.length){
var sorter = dhtmlx.sort.create(sort);
//get array of IDs
var neworder = this.getRange(this.first(), this.last());
neworder.sort(sorter);
this.order = neworder.map(function(obj){ return this.id(obj); },this);
}
//repaint self
this.refresh();
this.callEvent("onaftersort",parameters);
},
/*
Filter datasource
text - property, by which filter
value - filter mask
or
text - filter method
Filter method will receive data object and must return true or false
*/
filter:function(text,value){
if (!this.callEvent("onBeforeFilter", [text, value])) return;
//remove previous filtering , if any
if (this._filter_order){
this.order = this._filter_order;
delete this._filter_order;
}
if (!this.order.length) return;
//if text not define -just unfilter previous state and exit
if (text){
var filter = text;
value = value||"";
if (typeof text == "string"){
text = dhtmlx.Template.fromHTML(text);
value = value.toString().toLowerCase();
filter = function(obj,value){ //default filter - string start from, case in-sensitive
return text(obj).toLowerCase().indexOf(value)!=-1;
};
}
var neworder = dhtmlx.toArray();
for (var i=0; i < this.order.length; i++){
var id = this.order[i];
if (filter(this.item(id),value))
neworder.push(id);
}
//set new order of items, store original
this._filter_order = this.order;
this.order = neworder;
}
//repaint self
this.refresh();
this.callEvent("onAfterFilter", []);
},
/*
Iterate through collection
*/
each:function(method,master){
for (var i=0; ib?1:(ab?1:(ab?1:(a value
// {obj.attr} => named attribute or value of sub-tag in case of xml
// {obj.attr?some:other} conditional output
// {-obj => sub-template
str=(str||"").toString();
str=str.replace(/[\r\n]+/g,"\\n");
str=str.replace(/\{obj\.([^}?]+)\?([^:]*):([^}]*)\}/g,"\"+(obj.$1?\"$2\":\"$3\")+\"");
str=str.replace(/\{common\.([^}\(]*)\}/g,"\"+common.$1+\"");
str=str.replace(/\{common\.([^\}\(]*)\(\)\}/g,"\"+(common.$1?common.$1(obj):\"\")+\"");
str=str.replace(/\{obj\.([^}]*)\}/g,"\"+obj.$1+\"");
str=str.replace(/#([a-z0-9_]+)#/gi,"\"+obj.$1+\"");
str=str.replace(/\{obj\}/g,"\"+obj+\"");
str=str.replace(/\{-obj/g,"{obj");
str=str.replace(/\{-common/g,"{common");
str="return \""+str+"\";";
return this._cache[str]= Function("obj","common",str);
}
};
dhtmlx.Type={
/*
adds new template-type
obj - object to which template will be added
data - properties of template
*/
add:function(obj, data){
//auto switch to prototype, if name of class was provided
if (!obj.types && obj.prototype.types)
obj = obj.prototype;
//if (typeof data == "string")
// data = { template:data };
if (dhtmlx.assert_enabled())
this.assert_event(data);
var name = data.name||"default";
//predefined templates - autoprocessing
this._template(data);
this._template(data,"edit");
this._template(data,"loading");
obj.types[name]=dhtmlx.extend(dhtmlx.extend({},(obj.types[name]||this._default)),data);
return name;
},
//default template value - basically empty box with 5px margin
_default:{
css:"default",
template:function(){ return ""; },
template_edit:function(){ return ""; },
template_loading:function(){ return "..."; },
width:150,
height:80,
margin:5,
padding:0
},
//template creation helper
_template:function(obj,name){
name = "template"+(name?("_"+name):"");
var data = obj[name];
//if template is a string - check is it plain string or reference to external content
if (data && (typeof data == "string")){
if (data.indexOf("->")!=-1){
data = data.split("->");
switch(data[0]){
case "html": //load from some container on the page
data = dhtmlx.html.getValue(data[1]).replace(/\"/g,"\\\"");
break;
case "http": //load from external file
data = new dhtmlx.ajax().sync().get(data[1],{uid:(new Date()).valueOf()}).responseText;
break;
default:
//do nothing, will use template as is
break;
}
}
obj[name] = dhtmlx.Template.fromHTML(data);
}
}
};
/* DHX DEPEND FROM FILE 'single_render.js'*/
/*
REnders single item.
Can be used for elements without datastore, or with complex custom rendering logic
@export
render
*/
/*DHX:Depend template.js*/
dhtmlx.SingleRender={
_init:function(){
},
//convert item to the HTML text
_toHTML:function(obj){
/*
this one doesn't support per-item-$template
it has not sense, because we have only single item per object
*/
return this.type._item_start(obj,this.type)+this.type.template(obj,this.type)+this.type._item_end;
},
//render self, by templating data object
render:function(){
if (!this.callEvent || this.callEvent("onBeforeRender",[this.data])){
if (this.data)
this._dataobj.innerHTML = this._toHTML(this.data);
if (this.callEvent) this.callEvent("onAfterRender",[]);
}
}
};
/* DHX DEPEND FROM FILE 'tooltip.js'*/
/*
UI: Tooltip
@export
show
hide
*/
/*DHX:Depend tooltip.css*/
/*DHX:Depend template.js*/
/*DHX:Depend single_render.js*/
dhtmlx.ui.Tooltip=function(container){
this.name = "Tooltip";
this.version = "3.0";
if (dhtmlx.assert_enabled()) this._assert();
if (typeof container == "string"){
container = { template:container };
}
dhtmlx.extend(this, dhtmlx.Settings);
dhtmlx.extend(this, dhtmlx.SingleRender);
this._parseSettings(container,{
type:"default",
dy:0,
dx:20
});
//create container for future tooltip
this._dataobj = this._obj = document.createElement("DIV");
this._obj.className="dhx_tooltip";
dhtmlx.html.insertBefore(this._obj,document.body.firstChild);
};
dhtmlx.ui.Tooltip.prototype = {
//show tooptip
//pos - object, pos.x - left, pox.y - top
show:function(data,pos){
if (this._disabled) return;
//render sefl only if new data was provided
if (this.data!=data){
this.data=data;
this.render(data);
}
//show at specified position
this._obj.style.top = pos.y+this._settings.dy+"px";
this._obj.style.left = pos.x+this._settings.dx+"px";
this._obj.style.display="block";
},
//hide tooltip
hide:function(){
this.data=null; //nulify, to be sure that on next show it will be fresh-rendered
this._obj.style.display="none";
},
disable:function(){
this._disabled = true;
},
enable:function(){
this._disabled = false;
},
types:{
"default":dhtmlx.Template.fromHTML("{obj.id}")
},
template_item_start:dhtmlx.Template.empty,
template_item_end:dhtmlx.Template.empty
};
/* DHX DEPEND FROM FILE 'autotooltip.js'*/
/*
Behavior: AutoTooltip - links tooltip to data driven item
*/
/*DHX:Depend tooltip.js*/
dhtmlx.AutoTooltip = {
tooltip_setter:function(value){
var t = new dhtmlx.ui.Tooltip(value);
this.attachEvent("onMouseMove",function(id,e){ //show tooltip on mousemove
t.show(this.get(id),dhtmlx.html.pos(e));
});
this.attachEvent("onMouseOut",function(id,e){ //hide tooltip on mouseout
t.hide();
});
this.attachEvent("onMouseMoving",function(id,e){ //hide tooltip just after moving start
t.hide();
});
return t;
}
};
/* DHX DEPEND FROM FILE 'compatibility.js'*/
/*
Collection of compatibility hacks
*/
/*DHX:Depend dhtmlx.js*/
dhtmlx.compat=function(name, obj){
//check if name hash present, and applies it when necessary
if (dhtmlx.compat[name])
dhtmlx.compat[name](obj);
};
(function(){
if (!window.dhtmlxError){
//dhtmlxcommon is not included
//create fake error tracker for connectors
var dummy = function(){};
window.dhtmlxError={ catchError:dummy, throwError:dummy };
//helpers instead of ones from dhtmlxcommon
window.convertStringToBoolean=function(value){
return !!value;
};
window.dhtmlxEventable = function(node){
dhtmlx.extend(node,dhtmlx.EventSystem);
};
//imitate ajax layer of dhtmlxcommon
var loader = {
getXMLTopNode:function(name){
},
doXPath:function(path){
return dhtmlx.DataDriver.xml.xpath(this.xml,path);
},
xmlDoc:{
responseXML:true
}
};
//wrap ajax methods of dataprocessor
dhtmlx.compat.dataProcessor=function(obj){
//FIXME
//this is pretty ugly solution - we replace whole method , so changes in dataprocessor need to be reflected here
var sendData = "_sendData";
var in_progress = "_in_progress";
var tMode = "_tMode";
var waitMode = "_waitMode";
obj[sendData]=function(a1,rowId){
if (!a1) return; //nothing to send
if (rowId)
this[in_progress][rowId]=(new Date()).valueOf();
if (!this.callEvent("onBeforeDataSending",rowId?[rowId,this.getState(rowId)]:[])) return false;
var a2 = this;
var a3=this.serverProcessor;
if (this[tMode]!="POST")
//use dhtmlx.ajax instead of old ajax layer
dhtmlx.ajax().get(a3+((a3.indexOf("?")!=-1)?"&":"?")+this.serialize(a1,rowId),"",function(t,x,xml){
loader.xml = dhtmlx.DataDriver.xml.checkResponse(t,x);
a2.afterUpdate(a2, null, null, null, loader);
});
else
dhtmlx.ajax().post(a3,this.serialize(a1,rowId),function(t,x,xml){
loader.xml = dhtmlx.DataDriver.xml.checkResponse(t,x);
a2.afterUpdate(a2, null, null, null, loader);
});
this[waitMode]++;
};
};
}
})();
/* DHX DEPEND FROM FILE 'compatibility_layout.js'*/
/*DHX:Depend dhtmlx.js*/
/*DHX:Depend compatibility.js*/
if (!dhtmlx.attaches)
dhtmlx.attaches = {};
dhtmlx.attaches.attachAbstract=function(name, conf){
var obj = document.createElement("DIV");
obj.id = "CustomObject_"+dhtmlx.uid();
obj.style.width = "100%";
obj.style.height = "100%";
obj.cmp = "grid";
document.body.appendChild(obj);
this.attachObject(obj.id);
conf.container = obj.id;
var that = this.vs[this.av];
that.grid = new window[name](conf);
that.gridId = obj.id;
that.gridObj = obj;
that.grid.setSizes = function(){
if (this.resize) this.resize();
else this.render();
};
var method_name="_viewRestore";
return this.vs[this[method_name]()].grid;
};
dhtmlx.attaches.attachDataView = function(conf){
return this.attachAbstract("dhtmlXDataView",conf);
};
dhtmlx.attaches.attachChart = function(conf){
return this.attachAbstract("dhtmlXChart",conf);
};
dhtmlx.compat.layout = function(){};