/*
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
*/
/**
* @desc: constructor, data processor object
* @param: serverProcessorURL - url used for update
* @type: public
*/
function dataProcessor(serverProcessorURL){
this.serverProcessor = serverProcessorURL;
this.action_param="!nativeeditor_status";
this.object = null;
this.updatedRows = []; //ids of updated rows
this.autoUpdate = true;
this.updateMode = "cell";
this._tMode="GET";
this._headers = null;
this._payload = null;
this.post_delim = "_";
this._waitMode=0;
this._in_progress={};//?
this._invalid={};
this.mandatoryFields=[];
this.messages=[];
this.styles={
updated:"font-weight:bold;",
inserted:"font-weight:bold;",
deleted:"text-decoration : line-through;",
invalid:"background-color:FFE0E0;",
invalid_cell:"border-bottom:2px solid red;",
error:"color:red;",
clear:"font-weight:normal;text-decoration:none;"
};
this.enableUTFencoding(true);
dhx4._eventable(this);
if (this.connector_init){
this.setTransactionMode("POST",true);
this.serverProcessor+=(this.serverProcessor.indexOf("?")!=-1?"&":"?")+"editing=true";
};
return this;
}
dataProcessor.prototype={
url:function(str){
if (str.indexOf("?") != -1)
return "&";
else
return "?";
},
setTransactionMode:function(mode,total){
if (typeof mode == "object"){
this._tMode = mode.mode || this._tMode;
this._headers = this._headers || mode.headers;
this._payload = this._payload || mode.payload;
} else {
this._tMode=mode;
this._tSend=total;
}
if (this._tMode == "REST"){
this._tSend = false;
this._endnm = true;
}
if (this._tMode == "JSON"){
this._tSend = false;
this._endnm = true;
this._headers = this._headers || {};
this._headers["Content-type"] = "application/json";
}
},
escape:function(data){
if (this._utf)
return encodeURIComponent(data);
else
return escape(data);
},
/**
* @desc: allows to set escaping mode
* @param: true - utf based escaping, simple - use current page encoding
* @type: public
*/
enableUTFencoding:function(mode){
this._utf=dhx4.s2b(mode);
},
/**
* @desc: allows to define, which column may trigger update
* @param: val - array or list of true/false values
* @type: public
*/
setDataColumns:function(val){
this._columns=(typeof val == "string")?val.split(","):val;
},
/**
* @desc: get state of updating
* @returns: true - all in sync with server, false - some items not updated yet.
* @type: public
*/
getSyncState:function(){
return !this.updatedRows.length;
},
/**
* @desc: enable/disable named field for data syncing, will use column ids for grid
* @param: mode - true/false
* @type: public
*/
enableDataNames:function(mode){
this._endnm=dhx4.s2b(mode);
},
/**
* @desc: enable/disable mode , when only changed fields and row id send to the server side, instead of all fields in default mode
* @param: mode - true/false
* @type: public
*/
enablePartialDataSend:function(mode){
this._changed=dhx4.s2b(mode);
},
/**
* @desc: set if rows should be send to server automaticaly
* @param: mode - "row" - based on row selection changed, "cell" - based on cell editing finished, "off" - manual data sending
* @type: public
*/
setUpdateMode:function(mode,dnd){
this.autoUpdate = (mode=="cell");
this.updateMode = mode;
this.dnd=dnd;
},
ignore:function(code,master){
this._silent_mode=true;
code.call(master||window);
this._silent_mode=false;
},
/**
* @desc: mark row as updated/normal. check mandatory fields,initiate autoupdate (if turned on)
* @param: rowId - id of row to set update-status for
* @param: state - true for "updated", false for "not updated"
* @param: mode - update mode name
* @type: public
*/
setUpdated:function(rowId,state,mode){
this._log("item "+rowId+" "+(state?"marked":"unmarked")+" ["+(mode||"updated")+"]");
if (this._silent_mode) return;
var ind=this.findRow(rowId);
mode=mode||"updated";
var existing = this.obj.getUserData(rowId,this.action_param);
if (existing && mode == "updated") mode=existing;
if (state){
this.set_invalid(rowId,false); //clear previous error flag
this.updatedRows[ind]=rowId;
this.obj.setUserData(rowId,this.action_param,mode);
if (this._in_progress[rowId])
this._in_progress[rowId]="wait";
} else{
if (!this.is_invalid(rowId)){
this.updatedRows.splice(ind,1);
this.obj.setUserData(rowId,this.action_param,"");
}
}
//clear changed flag
if (!state)
this._clearUpdateFlag(rowId);
this.markRow(rowId,state,mode);
if (state && this.autoUpdate) this.sendData(rowId);
},
_clearUpdateFlag:function(id){},
markRow:function(id,state,mode){
var str="";
var invalid=this.is_invalid(id);
if (invalid){
str=this.styles[invalid];
state=true;
}
if (this.callEvent("onRowMark",[id,state,mode,invalid])){
//default logic
str=this.styles[state?mode:"clear"]+str;
this.obj[this._methods[0]](id,str);
if (invalid && invalid.details){
str+=this.styles[invalid+"_cell"];
for (var i=0; i < invalid.details.length; i++)
if (invalid.details[i])
this.obj[this._methods[1]](id,i,str);
}
}
},
getState:function(id){
return this.obj.getUserData(id,this.action_param);
},
is_invalid:function(id){
return this._invalid[id];
},
set_invalid:function(id,mode,details){
if (details) mode={value:mode, details:details, toString:function(){ return this.value.toString(); }};
this._invalid[id]=mode;
},
/**
* @desc: check mandatory fields and varify values of cells, initiate update (if specified)
* @param: rowId - id of row to set update-status for
* @type: public
*/
checkBeforeUpdate:function(rowId){
return true;
},
/**
* @desc: send row(s) values to server
* @param: rowId - id of row which data to send. If not specified, then all "updated" rows will be send
* @type: public
*/
sendData:function(rowId){
if (rowId)
this._log("Sending: "+rowId);
if (this._waitMode && (this.obj.mytype=="tree" || this.obj._h2)) return;
if (this.obj.editStop) this.obj.editStop();
if(typeof rowId == "undefined" || this._tSend) return this.sendAllData();
if (this._in_progress[rowId]) return false;
this.messages=[];
if (this.getState(rowId) !== "deleted")
if (!this.checkBeforeUpdate(rowId) && this.callEvent("onValidationError",[rowId,this.messages])) return false;
this._beforeSendData(this._getRowData(rowId),rowId);
},
_beforeSendData:function(data,rowId){
if (!this.callEvent("onBeforeUpdate",[rowId,this.getState(rowId),data])) return false;
this._sendData(data,rowId);
},
serialize:function(data, id){
if (typeof data == "string")
return data;
if (typeof id != "undefined")
return this.serialize_one(data,"");
else{
var stack = [];
var keys = [];
for (var key in data)
if (data.hasOwnProperty(key)){
stack.push(this.serialize_one(data[key],key+this.post_delim));
keys.push(key);
}
stack.push("ids="+this.escape(keys.join(",")));
if (window.dhtmlx && dhtmlx.security_key)
stack.push("dhx_security="+dhtmlx.security_key);
return stack.join("&");
}
},
serialize_one:function(data, pref){
if (typeof data == "string")
return data;
var stack = [];
for (var key in data)
if (data.hasOwnProperty(key)){
if ((key == "id" || key == this.action_param) && this._tMode == "REST") continue;
stack.push(this.escape((pref||"")+key)+"="+this.escape(data[key]));
}
return stack.join("&");
},
_applyPayload:function(url){
if (this._payload)
for (var key in this._payload)
url = url + (url.indexOf("?") === -1 ? "?" : "&" ) + this.escape(key) + "=" + this.escape(this._payload[key]);
return url;
},
_sendData:function(a1,rowId){
this._log("url: "+this.serverProcessor);
this._log(a1)
if (!a1) return; //nothing to send
if (!this.callEvent("onBeforeDataSending",rowId?[rowId,this.getState(rowId),a1]:[null, null, a1])) return false;
if (rowId)
this._in_progress[rowId]=(new Date()).valueOf();
var that = this;
var back = function(xml){
var ids = [];
if (rowId)
ids.push(rowId);
else if (a1)
for (var key in a1)
ids.push(key);
return that.afterUpdate(that,xml,ids);
};
var a3 = this.serverProcessor+(this._user?(this.url(this.serverProcessor)+["dhx_user="+this._user,"dhx_version="+this.obj.getUserData(0,"version")].join("&")):"");
var a4 = this._applyPayload(a3);
if (this._tMode=="GET"){
dhx4.ajax.query({
url:a4+((a4.indexOf("?")!=-1)?"&":"?")+this.serialize(a1,rowId),
method:"GET",
headers:this._headers,
callback:back
});
}
else if (this._tMode == "POST"){
dhx4.ajax.query({
url:a4,
method:"POST",
headers:this._headers,
callback:back,
data:this.serialize(a1,rowId)
});
}
else if (this._tMode == "JSON"){
var action = a1[this.action_param];
var data = {};
for (var key in a1) data[key] = a1[key];
delete data[this.action_param];
delete data.id;
delete data.gr_id;
dhx4.ajax.query({
url:a4,
method:"POST",
headers:this._headers,
callback:back,
data:JSON.stringify({
id: rowId,
action: action,
data: data
})
});
}
else if (this._tMode == "REST"){
var state = this.getState(rowId);
var url = a3.replace(/(\&|\?)editing\=true/,"");
var parts = url.split("?");
if (parts[1])
parts[1] = "?"+parts[1];
var data = "";
var method = "POST";
if (state == "inserted"){
data = this.serialize(a1, rowId);
} else if (state == "deleted"){
method = "DELETE";
url = parts[0]+rowId+(parts[1]||"");
} else {
method = "PUT";
data = this.serialize(a1, rowId);
url = parts[0]+rowId+(parts[1]||"");
}
this._applyPayload(url);
dhx4.ajax.query({
url:url,
method:method,
headers:this._headers,
data:data,
callback:back
});
}
this._waitMode++;
},
sendAllData:function(){
this._log("Sending all updated items");
if (!this.updatedRows.length) return;
this.messages=[]; var valid=true;
for (var i=0; i