/* Product Name: dhtmlxSuite Version: 5.2.0 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 */ (function(){ var dhx = {}; //check some rule, show message as error if rule is not correct dhx.assert = function(test, message){ if (!test){ dhx.assert_error(message); } }; dhx.assert_error = function(message){ dhx.log("error",message); if (dhx.message && typeof message == "string") dhx.message({ type:"debug", text:message, expire:-1 }); if (dhx.debug !== false) eval("debugger;"); }; //entry point for analitic scripts dhx.assert_core_ready = function(){ if (window.dhx_on_core_ready) dhx_on_core_ready(); }; /* Common helpers */ dhx.codebase="./"; dhx.name = "Core"; //coding helpers dhx.clone = function(source){ var f = dhx.clone._function; f.prototype = source; return new f(); }; dhx.clone._function = function(){}; //copies methods and properties from source to the target dhx.extend = function(base, source, force){ dhx.assert(base,"Invalid mixing target"); dhx.assert(source,"Invalid mixing source"); if (base._dhx_proto_wait){ dhx.PowerArray.insertAt.call(base._dhx_proto_wait, source,1); return base; } //copy methods, overwrite existing ones in case of conflict for (var method in source) if (!base[method] || force) base[method] = source[method]; //in case of defaults - preffer top one if (source.defaults) dhx.extend(base.defaults, source.defaults); //if source object has init code - call init against target if (source.$init) source.$init.call(base); return base; }; //copies methods and properties from source to the target from all levels dhx.copy = function(source){ dhx.assert(source,"Invalid mixing target"); if(arguments.length>1){ var target = arguments[0]; source = arguments[1]; } else var target = (dhx.isArray(source)?[]:{}); for (var method in source){ if(source[method] && typeof source[method] == "object" && !dhx.isDate(source[method])){ target[method] = (dhx.isArray(source[method])?[]:{}); dhx.copy(target[method],source[method]); }else{ target[method] = source[method]; } } return target; }; dhx.single = function(source){ var instance = null; var t = function(config){ if (!instance) instance = new source({}); if (instance._reinit) instance._reinit.apply(instance, arguments); return instance; }; return t; }; dhx.protoUI = function(){ if (dhx.debug_proto) dhx.log("UI registered: "+arguments[0].name); var origins = arguments; var selfname = origins[0].name; var t = function(data){ if (!t) return dhx.ui[selfname].prototype; var origins = t._dhx_proto_wait; if (origins){ var params = [origins[0]]; for (var i=1; i < origins.length; i++){ params[i] = origins[i]; if (params[i]._dhx_proto_wait) params[i] = params[i].call(dhx, params[i].name); if (params[i].prototype && params[i].prototype.name) dhx.ui[params[i].prototype.name] = params[i]; } dhx.ui[selfname] = dhx.proto.apply(dhx, params); if (t._dhx_type_wait) for (var i=0; i < t._dhx_type_wait.length; i++) dhx.Type(dhx.ui[selfname], t._dhx_type_wait[i]); t = origins = null; } if (this != dhx) return new dhx.ui[selfname](data); else return dhx.ui[selfname]; }; t._dhx_proto_wait = Array.prototype.slice.call(arguments, 0); return dhx.ui[selfname]=t; }; dhx.proto = function(){ if (dhx.debug_proto) dhx.log("Proto chain:"+arguments[0].name+"["+arguments.length+"]"); var origins = arguments; var compilation = origins[0]; var has_constructor = !!compilation.$init; var construct = []; dhx.assert(compilation,"Invalid mixing target"); for (var i=origins.length-1; i>0; i--) { dhx.assert(origins[i],"Invalid mixing source"); if (typeof origins[i]== "function") origins[i]=origins[i].prototype; if (origins[i].$init) construct.push(origins[i].$init); if (origins[i].defaults){ var defaults = origins[i].defaults; if (!compilation.defaults) compilation.defaults = {}; for (var def in defaults) if (dhx.isUndefined(compilation.defaults[def])) compilation.defaults[def] = defaults[def]; } if (origins[i].type && compilation.type){ for (var def in origins[i].type) if (!compilation.type[def]) compilation.type[def] = origins[i].type[def]; } for (var key in origins[i]){ if (!compilation[key]) compilation[key] = origins[i][key]; } } if (has_constructor) construct.push(compilation.$init); compilation.$init = function(){ for (var i=0; i handler this._evs_handlers = {}; //hash of event handlers, ID => handler this._evs_map = {}; } }, //temporary block event triggering blockEvent : function(){ this._evs_events._block = true; }, //re-enable event triggering unblockEvent : function(){ this._evs_events._block = false; }, mapEvent:function(map){ dhx.extend(this._evs_map, map, true); }, on_setter:function(config){ if(config){ for(var i in config){ if(typeof config[i] == 'function') this.attachEvent(i, config[i]); } } }, //trigger event callEvent:function(type,params){ if (this._evs_events._block) return true; type = type.toLowerCase(); var event_stack =this._evs_events[type.toLowerCase()]; //all events for provided name var return_value = true; if (dhx.debug) //can slowdown a lot dhx.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 (var i=0; i")!=-1){ str = str.split("->"); switch(str[0]){ case "html": //load from some container on the page str = dhx.html.getValue(str[1]); break; default: //do nothing, will use template as is break; } } //supported idioms // {obj.attr} => named attribute or value of sub-tag in case of xml str=(str||"").toString(); str=str.replace(newlines,"\\n"); str=str.replace(quotes,"\\\""); 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.apply(this, arguments):\"\")+\""); str=str.replace(/\{obj\.([^}]*)\}/g,"\"+(obj.$1)+\""); str=str.replace("{obj}","\"+obj+\""); str=str.replace(/#([^#'";, ]+)#/gi,"\"+(obj.$1)+\""); try { _cache[str] = Function("obj","common","return \""+str+"\";"); } catch(e){ dhx.assert_error("Invalid template:"+str); } return _cache[str]; }; dhx.Template.empty=function(){ return ""; }; dhx.Template.bind =function(value){ return dhx.bind(dhx.Template(value),this); }; /* adds new template-type obj - object to which template will be added data - properties of template */ dhx.Type=function(obj, data){ if (obj._dhx_proto_wait){ if (!obj._dhx_type_wait) obj._dhx_type_wait = []; obj._dhx_type_wait.push(data); return; } //auto switch to prototype, if name of class was provided if (typeof obj == "function") obj = obj.prototype; if (!obj.types){ obj.types = { "default" : obj.type }; obj.type.name = "default"; } var name = data.name; var type = obj.type; if (name) type = obj.types[name] = dhx.clone(data.baseType?obj.types[data.baseType]:obj.type); for(var key in data){ if (key.indexOf("template")===0) type[key] = dhx.Template(data[key]); else type[key]=data[key]; } return name; }; })(); /*DHX:Depend core/dhx.js*/ dhx.Settings={ $init:function(){ /* property can be accessed as this.config.some in same time for inner call it have sense to use _settings because it will be minified in final version */ this._settings = this.config= {}; }, define:function(property, value){ if (typeof property == "object") return this._parseSeetingColl(property); return this._define(property, value); }, _define:function(property,value){ //method with name {prop}_setter will be used as property setter //setter is optional var setter = this[property+"_setter"]; return this._settings[property]=setter?setter.call(this,value,property):value; }, //process configuration object _parseSeetingColl:function(coll){ if (coll){ for (var a in coll) //for each setting this._define(a,coll[a]); //set value through config } }, //helper for object initialization _parseSettings:function(obj,initial){ //initial - set of default values var settings = {}; if (initial) settings = dhx.extend(settings,initial); //code below will copy all properties over default one if (typeof obj == "object" && !obj.tagName) dhx.extend(settings,obj, true); //call config for each setting this._parseSeetingColl(settings); }, _mergeSettings:function(config, defaults){ for (var key in defaults) switch(typeof config[key]){ case "object": config[key] = this._mergeSettings((config[key]||{}), defaults[key]); break; case "undefined": config[key] = defaults[key]; break; default: //do nothing break; } return config; }, debug_freid_c_id:true, debug_freid_a_name:true }; /*DHX:Depend core/datastore.js*/ /*DHX:Depend core/load.js*/ /* ajax operations can be used for direct loading as dhx.ajax(ulr, callback) or dhx.ajax().item(url) dhx.ajax().post(url) */ /*DHX:Depend core/dhx.js*/ dhx.ajax = function(url,call,master){ //if parameters was provided - made fast call if (arguments.length!==0){ var http_request = new dhx.ajax(); if (master) http_request.master=master; return http_request.get(url,null,call); } if (!this.getXHR) return new dhx.ajax(); //allow to create new instance without direct new declaration return this; }; dhx.ajax.count = 0; dhx.ajax.prototype={ master:null, //creates xmlHTTP object getXHR:function(){ if (dhx.env.isIE) return new ActiveXObject("Microsoft.xmlHTTP"); else return new XMLHttpRequest(); }, /* send data to the server params - hash of properties which will be added to the url call - callback, can be an array of functions */ send:function(url,params,call){ var x=this.getXHR(); if (!dhx.isArray(call)) call = [call]; //add extra params to the url if (typeof params == "object"){ var t=[]; for (var a in params){ var value = params[a]; if (value === null || value === dhx.undefined) value = ""; t.push(a+"="+encodeURIComponent(value));// utf-8 escaping } params=t.join("&"); } if (params && this.request==='GET'){ url=url+(url.indexOf("?")!=-1 ? "&" : "?")+params; params=null; } x.open(this.request,url,!this._sync); if (this.request === 'POST') x.setRequestHeader('Content-type','application/x-www-form-urlencoded'); //async mode, define loading callback var self=this; x.onreadystatechange= function(){ if (!x.readyState || x.readyState == 4){ if (dhx.debug_time) dhx.log_full_time("data_loading"); //log rendering time dhx.ajax.count++; if (call && self){ for (var i=0; i < call.length; i++) //there can be multiple callbacks if (call[i]){ var method = (call[i].success||call[i]); if (x.status >= 400 || (!x.status && !x.responseText)) method = call[i].error; if (method) method.call((self.master||self),x.responseText,x.responseXML,x); } } if (self) self.master=null; call=self=null; //anti-leak } }; x.send(params||null); return x; //return XHR, which can be used in case of sync. mode }, //GET request get:function(url,params,call){ if (arguments.length == 2){ call = params; params = null; } this.request='GET'; return this.send(url,params,call); }, //POST request post:function(url,params,call){ this.request='POST'; return this.send(url,params,call); }, //PUT request put:function(url,params,call){ this.request='PUT'; return this.send(url,params,call); }, //POST request del:function(url,params,call){ this.request='DELETE'; return this.send(url,params,call); }, sync:function(){ this._sync = true; return this; }, bind:function(master){ this.master = master; return this; } }; /*submits values*/ dhx.send = function(url, values, method, target){ var form = dhx.html.create("FORM",{ "target":(target||"_self"), "action":url, "method":(method||"POST") },""); for (var k in values) { var field = dhx.html.create("INPUT",{"type":"hidden","name": k,"value": values[k]},""); form.appendChild(field); } form.style.display = "none"; document.body.appendChild(form); form.submit(); document.body.removeChild(form); }; dhx.AtomDataLoader={ $init:function(config){ //prepare data store this.data = {}; if (config){ this._settings.datatype = config.datatype||"json"; this.$ready.push(this._load_when_ready); } }, _load_when_ready:function(){ this._ready_for_data = true; if (this._settings.url) this.url_setter(this._settings.url); if (this._settings.data) this.data_setter(this._settings.data); }, url_setter:function(value){ if (!this._ready_for_data) return value; this.load(value, this._settings.datatype); return value; }, data_setter:function(value){ if (!this._ready_for_data) return value; this.parse(value, this._settings.datatype); return true; }, debug_freid_c_datatype:true, debug_freid_c_dataFeed:true, //loads data from external URL load:function(url,call){ if (url.$proxy) { url.load(this, typeof call == "string" ? call : "json"); return; } this.callEvent("onXLS",[]); if (typeof call == "string"){ //second parameter can be a loading type or callback //we are not using setDriver as data may be a non-datastore here this.data.driver = dhx.DataDriver[call]; call = arguments[2]; } else if (!this.data.driver) this.data.driver = dhx.DataDriver.json; //load data by async ajax call //loading_key - can be set by component, to ignore data from old async requests var callback = [{ success: this._onLoad, error: this._onLoadError }]; if (call){ if (dhx.isArray(call)) callback.push.apply(callback,call); else callback.push(call); } return dhx.ajax(url,callback,this); }, //loads data from object parse:function(data,type){ this.callEvent("onXLS",[]); this.data.driver = dhx.DataDriver[type||"json"]; this._onLoad(data,null); }, //default after loading callback _onLoad:function(text,xml,loader,key){ var driver = this.data.driver; var data = driver.toObject(text,xml); if (data){ var top = driver.getRecords(data)[0]; this.data=(driver?driver.getDetails(top):text); } else this._onLoadError(text,xml,loader); this.callEvent("onXLE",[]); }, _onLoadError:function(text, xml, xhttp){ this.callEvent("onXLE",[]); this.callEvent("onLoadError",arguments); dhx4.callEvent("onLoadError", [text, xml, xhttp, this]); }, _check_data_feed:function(data){ if (!this._settings.dataFeed || this._ignore_feed || !data) return true; var url = this._settings.dataFeed; if (typeof url == "function") return url.call(this, (data.id||data), data); url = url+(url.indexOf("?")==-1?"?":"&")+"action=get&id="+encodeURIComponent(data.id||data); this.callEvent("onXLS",[]); dhx.ajax(url, function(text,xml,loader){ this._ignore_feed=true; var data = dhx.DataDriver.toObject(text, xml); if (data) this.setValues(data.getDetails(data.getRecords()[0])); else this._onLoadError(text,xml,loader); this._ignore_feed=false; this.callEvent("onXLE",[]); }, this); return false; } }; /* Abstraction layer for different data types */ dhx.DataDriver={}; dhx.DataDriver.json={ //convert json string to json object if necessary toObject:function(data){ if (!data) data="[]"; if (typeof data == "string"){ try{ eval ("dhx.temp="+data); } catch(e){ dhx.assert_error(e); return null; } data = dhx.temp; } if (data.data){ var t = data.data.config = {}; for (var key in data) if (key!="data") t[key] = data[key]; data = data.data; } return data; }, //get array of records getRecords:function(data){ if (data && !dhx.isArray(data)) return [data]; return data; }, //get hash of properties for single record getDetails:function(data){ if (typeof data == "string") return { id:dhx.uid(), value:data }; return data; }, //get count of data and position at which new data need to be inserted getInfo:function(data){ var cfg = data.config; if (!cfg) return {}; return { _size:(cfg.total_count||0), _from:(cfg.pos||0), _parent:(cfg.parent||0), _config:(cfg.config), _key:(cfg.dhx_security) }; }, child:"data" }; dhx.DataDriver.html={ /* incoming data can be - collection of nodes - ID of parent container - HTML text */ toObject:function(data){ if (typeof data == "string"){ var t=null; if (data.indexOf("<")==-1) //if no tags inside - probably its an ID t = dhx.toNode(data); if (!t){ t=document.createElement("DIV"); t.innerHTML = data; } return t.getElementsByTagName(this.tag); } return data; }, //get array of records getRecords:function(node){ var data = []; for (var i=0; i= count + from )) return true; } return false; }, //default after loading callback _onLoad:function(text,xml,loader){ //ignore data loading command if data was reloaded this._ajax_queue.remove(loader); var data = this.data.driver.toObject(text,xml); if (data) this.data._parse(data); else return this._onLoadError(text, xml, loader); //data loaded, view rendered, call onready handler this._call_onready(); this.callEvent("onXLE",[]); }, removeMissed_setter:function(value){ return this.data._removeMissed = value; }, scheme_setter:function(value){ this.data.scheme(value); }, dataFeed_setter:function(value){ this.data.attachEvent("onBeforeFilter", dhx.bind(function(text, value){ if (this._settings.dataFeed){ var filter = {}; if (!text && !value) return; if (typeof text == "function"){ if (!value) return; text(value, filter); } else filter = { text:value }; this.clearAll(); var url = this._settings.dataFeed; var urldata = []; if (typeof url == "function") return url.call(this, value, filter); for (var key in filter) urldata.push("dhx_filter["+key+"]="+encodeURIComponent(filter[key])); this.load(url+(url.indexOf("?")<0?"?":"&")+urldata.join("&"), this._settings.datatype); return false; } },this)); return value; }, debug_freid_c_ready:true, debug_freid_c_datathrottle:true, _call_onready:function(){ if (this._settings.ready && !this._ready_was_used){ var code = dhx.toFunctor(this._settings.ready); if (code) dhx.delay(code, this, arguments); this._ready_was_used = true; } }, _call_onclearall:function(){ for (var i = 0; i < this._ajax_queue.length; i++) this._ajax_queue[i].abort(); this._ajax_queue = dhx.toArray(); }, _call_on_config:function(config){ this._parseSeetingColl(config); } },dhx.AtomDataLoader); /* DataStore is not a behavior, it standalone object, which represents collection of data. Call provideAPI to map data API @export exists idByIndex indexById get set refresh dataCount sort filter next previous clearAll first last */ dhx.DataStore = function(){ this.name = "DataStore"; dhx.extend(this, dhx.EventSystem); this.setDriver("json"); //default data source is an this.pull = {}; //hash of IDs this.order = dhx.toArray(); //order of IDs this._marks = {}; }; dhx.DataStore.prototype={ //defines type of used data driver //data driver is an abstraction other different data formats - xml, json, csv, etc. setDriver:function(type){ dhx.assert(dhx.DataDriver[type],"incorrect DataDriver"); this.driver = dhx.DataDriver[type]; }, //process incoming raw data _parse:function(data,master){ this.callEvent("onParse", [this.driver, data]); if (this._filter_order) this.filter(); //get size and position of data var info = this.driver.getInfo(data); if (info._key) dhx.securityKey = info._key; if (info._config) this.callEvent("onServerConfig",[info._config]); //get array of records var recs = this.driver.getRecords(data); this._inner_parse(info, recs); //in case of tree store we may want to group data if (this._scheme_group && this._group_processing) this._group_processing(this._scheme_group); //optional data sorting if (this._scheme_sort){ this.blockEvent(); this.sort(this._scheme_sort); this.unblockEvent(); } this.callEvent("onStoreLoad",[this.driver, data]); //repaint self after data loading this.refresh(); }, _inner_parse:function(info, recs){ var from = (info._from||0)*1; var subload = true; var marks = false; if (from === 0 && this.order[0]){ //update mode if (this._removeMissed){ //update mode, create kill list marks = {}; for (var 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=dhx.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){ dhx.assert(sindex>=0 && tindex>=0, "DataStore::move","Incorrect indexes"); var id = this.idByIndex(sindex); var obj = this.item(id); this.order.removeAt(sindex); //remove at old position //if (sindex data_size){ dhx.log("Warning","DataStore:add","Index of out of bounds"); index = Math.min(order.length,index); } if (this.callEvent("onBeforeAdd", [id, obj, index]) === false) return false; dhx.assert(!this.exists(id), "Not unique ID"); this.pull[id]=obj; 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 (dhx.isArray(id)){ for (var i=0; i < id.length; i++) this.remove(id[i]); return; } if (this.callEvent("onBeforeDelete",[id]) === false) return false; dhx.assert(this.exists(id), "Not existing ID in remove command"+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]; if (this._marks[id]) delete this._marks[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 = dhx.toArray(); //this.feed = null; this._filter_order = this.url = null; this.callEvent("onClearAll",[]); this.refresh(); }, //converts id to index idByIndex:function(index){ if (index>=this.order.length || index<0) dhx.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]) dhx.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.replace(/#/g,""), dir:dir, as:as}; var parameters = [sort.by, sort.dir, sort.as]; if (!this.callEvent("onBeforeSort",parameters)) return; this._sort_core(sort); //repaint self this.refresh(); this.callEvent("onAfterSort",parameters); }, _sort_core:function(sort){ if (this.order.length){ var sorter = this._sort._create(sort); //get array of IDs var neworder = this.getRange(this.first(), this.last()); neworder.sort(sorter); this.order = neworder.map(function(obj){ dhx.assert(obj, "Client sorting can't be used with dynamic loading"); return this.id(obj); },this); } }, /* 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_reset:function(preserve){ //remove previous filtering , if any if (this._filter_order && !preserve){ this.order = this._filter_order; delete this._filter_order; } }, _filter_core:function(filter, value, preserve){ var neworder = dhx.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 if (!preserve || !this._filter_order) this._filter_order = this.order; this.order = neworder; }, filter:function(text,value,preserve){ if (!this.callEvent("onBeforeFilter", [text, value])) return; this._filter_reset(preserve); 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 = text.replace(/#/g,""); if (typeof value == "function") filter = function(obj){ return value(obj[text]); }; else{ value = value.toString().toLowerCase(); filter = function(obj,value){ //default filter - string start from, case in-sensitive dhx.assert(obj, "Client side filtering can't be used with dynamic loading"); return (obj[text]||"").toString().toLowerCase().indexOf(value)!=-1; }; } } this._filter_core(filter, value, preserve, this._filterMode); } //repaint self this.refresh(); this.callEvent("onAfterFilter", []); }, /* Iterate through collection */ each:function(method,master){ for (var i=0; ib?1:(ab?1:(ab?1:(ab?1:(a "+target.name+"@"+target._settings.id); this._bind_update(target, this._bind_hash[key][0], this._bind_hash[key][1]); //trigger component specific updating logic if (update && target.filter) target.refresh(); } }, //add one more bind target addBind:function(source, rule, format){ this._bind_hash[source] = [rule, format]; }, removeBind:function(source){ delete this._bind_hash[source]; delete this._bind_updated[source]; delete this._ignore_binds[source]; }, //returns true if object belong to "collection" type _bind_specific_rules:function(obj){ if (obj.filter) dhx.extend(this, dhx.CollectionBind); else if (obj.setValue) dhx.extend(this, dhx.ValueBind); else dhx.extend(this, dhx.RecordBind); }, //inform all binded objects, that source data was updated _update_binds:function(){ if (!this._do_not_update_binds) for (var key in this._bind_hash){ if (this._ignore_binds[key]) continue; this._bind_updated[key] = false; this.getBindData(key, true); } }, //copy data from source to the target _bind_update_common:function(target, rule, data){ if (target.setValue) target.setValue(data?data[rule]:data); else if (!target.filter){ if (!data && target.clear) target.clear(true); else { if (target._check_data_feed(data)) target.setValues(dhx.clone(data)); } } else { target.data.silent(function(){ this.filter(rule,data); }); } target.callEvent("onBindApply", [data,rule,this]); } }; //pure data objects dhx.DataValue = dhx.proto({ name:"DataValue", isVisible:function(){ return true; }, $init:function(config){ this.data = ""||config; var id = (config&&config.id)?config.id:dhx.uid(); this._settings = { id:id }; dhx.ui.views[id] = this; }, setValue:function(value){ this.data = value; this.callEvent("onChange", [value]); }, getValue:function(){ return this.data; }, refresh:function(){ this.callEvent("onBindRequest"); } }, dhx.EventSystem, dhx.BaseBind); dhx.DataRecord = dhx.proto({ name:"DataRecord", isVisible:function(){ return true; }, $init:function(config){ this.data = config||{}; var id = (config&&config.id)?config.id:dhx.uid(); this._settings = { id:id }; dhx.ui.views[id] = this; }, getValues:function(){ return this.data; }, setValues:function(data){ this.data = data; this.callEvent("onChange", [data]); }, refresh:function(){ this.callEvent("onBindRequest"); } }, dhx.EventSystem, dhx.BaseBind, dhx.AtomDataLoader, dhx.Settings); dhx.DataCollection = dhx.proto({ name:"DataCollection", isVisible:function(){ if (!this.data.order.length && !this.data._filter_order && !this._settings.dataFeed) return false; return true; }, $init:function(config){ this.data.provideApi(this, true); var id = (config&&config.id)?config.id:dhx.uid(); this._settings.id =id; dhx.ui.views[id] = this; this.data.attachEvent("onStoreLoad", dhx.bind(function(){ this.callEvent("onBindRequest",[]); }, this)); }, refresh:function(){ this.callEvent("onBindRequest",[]); } }, dhx.DataLoader, dhx.EventSystem, dhx.BaseBind, dhx.Settings); dhx.ValueBind={ $init:function(){ this.attachEvent("onChange", this._update_binds); }, _bind_update:function(target, rule, format){ var data = this.getValue()||""; if (format) data = format(data); if (target.setValue) target.setValue(data); else if (!target.filter){ var pod = {}; pod[rule] = data; if (target._check_data_feed(data)) target.setValues(pod); } else{ target.data.silent(function(){ this.filter(rule,data); }); } target.callEvent("onBindApply", [data,rule,this]); } }; dhx.RecordBind={ $init:function(){ this.attachEvent("onChange", this._update_binds); }, _bind_update:function(target, rule){ var data = this.getValues()||null; this._bind_update_common(target, rule, data); } }; dhx.CollectionBind={ $init:function(){ this._cursor = null; this.attachEvent("onSelectChange", function(data){ var sel = this.getSelected(); this.setCursor(sel?(sel.id||sel):null); }); this.attachEvent("onAfterCursorChange", this._update_binds); this.data.attachEvent("onStoreUpdated", dhx.bind(function(id, data, mode){ if (id && id == this.getCursor() && mode != "paint") this._update_binds(); },this)); this.data.attachEvent("onClearAll", dhx.bind(function(){ this._cursor = null; },this)); this.data.attachEvent("onIdChange", dhx.bind(function(oldid, newid){ if (this._cursor == oldid) this._cursor = newid; },this)); }, setCursor:function(id){ if (id == this._cursor || (id !== null && !this.item(id))) return; this.callEvent("onBeforeCursorChange", [this._cursor]); this._cursor = id; this.callEvent("onAfterCursorChange",[id]); }, getCursor:function(){ return this._cursor; }, _bind_update:function(target, rule){ var data = this.item(this.getCursor())|| this._settings.defaultData || null; this._bind_update_common(target, rule, data); } }; /*DHX:Depend core/legacy_bind.js*/ /*DHX:Depend core/dhx.js*/ /*DHX:Depend core/bind.js*/ /*jsl:ignore*/ if (!dhx.ui) dhx.ui = {}; if (!dhx.ui.views){ dhx.ui.views = {}; dhx.ui.get = function(id){ if (id._settings) return id; return dhx.ui.views[id]; }; } if (window.dhtmlx) dhtmlx.BaseBind = dhx.BaseBind; dhtmlXDataStore = function(config){ var obj = new dhx.DataCollection(config); var name = "_dp_init"; obj[name]=function(dp){ //map methods var varname = "_methods"; dp[varname]=["dummy","dummy","changeId","dummy"]; this.data._old_names = { "add":"inserted", "update":"updated", "delete":"deleted" }; this.data.attachEvent("onStoreUpdated",function(id,data,mode){ if (id && !dp._silent) dp.setUpdated(id,true,this._old_names[mode]); }); varname = "_getRowData"; //serialize item's data in URL dp[varname]=function(id,pref){ var ev=this.obj.data.item(id); var data = { id:id }; data[this.action_param] = this.obj.getUserData(id); if (ev) for (var a in ev){ data[a]=ev[a]; } return data; }; this.changeId = function(oldid, newid){ this.data.changeId(oldid, newid); dp._silent = true; this.data.callEvent("onStoreUpdated", [newid, this.item(newid), "update"]); dp._silent = false; }; varname = "_clearUpdateFlag"; dp[varname]=function(){}; this._userdata = {}; }; obj.dummy = function(){}; obj.setUserData=function(id,name,value){ this._userdata[id]=value; }; obj.getUserData=function(id,name){ return this._userdata[id]; }; obj.dataFeed=function(obj){ this.define("dataFeed", obj); }; dhx.extend(obj, dhx.BindSource); return obj; }; if (window.dhtmlXDataView) dhtmlXDataView.prototype._initBindSource=function(){ this.isVisible = function(){ if (!this.data.order.length && !this.data._filter_order && !this._settings.dataFeed) return false; return true; }; var settings = "_settings"; this._settings = this._settings || this[settings]; if (!this._settings.id) this._settings.id = dhx.uid(); this.unbind = dhx.BaseBind.unbind; this.unsync = dhx.BaseBind.unsync; dhx.ui.views[this._settings.id] = this; }; if (window.dhtmlXChart) dhtmlXChart.prototype._initBindSource=function(){ this.isVisible = function(){ if (!this.data.order.length && !this.data._filtered_state && !this._settings.dataFeed) return false; return true; }; var settings = "_settings"; this._settings = this._settings || this[settings]; if (!this._settings.id) this._settings.id = dhx.uid(); this.unbind = dhx.BaseBind.unbind; this.unsync = dhx.BaseBind.unsync; dhx.ui.views[this._settings.id] = this; }; dhx.BaseBind.unsync = function(target){ return dhx.BaseBind._unbind.call(this, target); } dhx.BaseBind.unbind = function(target){ return dhx.BaseBind._unbind.call(this, target); } dhx.BaseBind.legacyBind = function(){ return dhx.BaseBind.bind.apply(this, arguments); }; dhx.BaseBind.legacySync = function(source, rule){ if (this._initBindSource) this._initBindSource(); if (source._initBindSource) source._initBindSource(); this.attachEvent("onAfterEditStop", function(id){ this.save(id); return true; }); this.attachEvent("onDataRequest", function(start, count){ for (var i=start; i