/* 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