You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
600 lines
17 KiB
600 lines
17 KiB
/* |
|
DynAPI Distribution |
|
DataSource Class |
|
|
|
The DynAPI Distribution is distributed under the terms of the GNU LGPL license. |
|
|
|
requires: dynapi.util.IOElement |
|
*/ |
|
|
|
DataSource = function(url,method,ioelement){ |
|
|
|
this.EventObject=EventObject; |
|
this.EventObject(); |
|
|
|
this.clsid=dynapi.functions.getGUID(); |
|
DataSource.all[this.clsid]=this; |
|
|
|
this.src=null; |
|
this.dataobjects={}; |
|
|
|
this._resetProperties(); |
|
|
|
this.setSource(url,method,ioelement); |
|
}; |
|
|
|
/* Prototype */ |
|
var p = dynapi.setPrototype('DataSource','EventObject'); |
|
|
|
// Private Methods |
|
p._boundObject = function(o,f){ |
|
if(!f || !o) return; |
|
if(!o._clsid) o._clsid=DataSource.increment(); |
|
this.dataobjects[o._clsid]=f; |
|
o.__iDataSource=this; |
|
DataSource.allDataObjects[o._clsid]=o; |
|
}; |
|
p._fieldManager = function(mode,fld,value){ |
|
var i,rt,con,fldname; |
|
// set or get field values from local recordset or bound object |
|
if(mode=='GET' && !this._modRec && this.record) return this.record[fld]; |
|
else { |
|
if(mode=='SET' && this.record) this.record[fld]=value; |
|
for(i in this.dataobjects){ |
|
if (!fld||fld==this.dataobjects[i]){ |
|
fldname=this.dataobjects[i]; |
|
con=DataSource.allDataObjects[i]; |
|
if(con) { |
|
if(mode=='SET' && con._setDSValue) { |
|
con._setDSValue(value,fldname); |
|
}else if(mode=='GET' && con._getDSValue) { |
|
return con._getDSValue(); |
|
} |
|
|
|
} |
|
} |
|
} |
|
} |
|
}; |
|
p._resetProperties=function(){ |
|
this.record=null; |
|
this.recordSet=[]; |
|
this.rowCount=0; // total records |
|
this.rowIndex=-1; // current record index(0 to rowCount) |
|
this.pageSize=1; // number of recordSet per page |
|
this.pageCount=0; // total pages |
|
this.pageNumber=0; // current page number (1 to pageCount) |
|
this.pageRIS=-1; // starting index for a page |
|
this.pageRIE=-1; // ending index for a page |
|
this.isConnected=false; |
|
}; |
|
p._send = function(act,data,params){ |
|
var r,fn,cargo={id:this.clsid,action:act,data:data};; |
|
params =(params)? params:{}; |
|
if(!this.src||!this.isConnected) { |
|
this.invokeEvent('alert',null,'DataSource: Connection failed.'); |
|
return; |
|
} |
|
this.invokeEvent('request'); |
|
if(this.webservice && !this.wsSync) { |
|
// Web Service - Async |
|
fn=DataSource.fnSODAResponse; |
|
if(this._ticket) this.ioelement.cancel(this._ticket); // cancel any previous requests |
|
if(act=='fetchpage') this._ticket=this.webservice.call(act,[this.pageNumber,this.pageSize,params.pageType],fn,cargo); |
|
else this._ticket=this.webservice.call(act,[this.rowIndex,data],fn,cargo); |
|
} |
|
else if(this.webservice && this.wsSync) { |
|
// Web Service - Sync |
|
if(act=='fetchpage') r=this.webservice.call(act,[this.pageNumber,this.pageSize,params.pageType],false); |
|
else r=this.webservice.call(act,[this.rowIndex,data],false); |
|
if(r.error) this.invokeEvent('alert',null,'DataSource: '+r.error.text); |
|
else { |
|
data=r.value; |
|
if(!data) return; |
|
DataSource.fnProcessResponse(cargo,data); |
|
} |
|
} |
|
else { |
|
// HTTP GET & POST - Async |
|
fn=DataSource.fnGETPOSTResponse; |
|
data=(data)? data:{}; |
|
data.dataAction = act; |
|
if(act!='fetchpage') data.dataRowIndex=this.rowIndex; |
|
else { |
|
data.pageSize = this.pageSize; |
|
data.pageNumber = this.pageNumber; |
|
data.pageType=params.pageType; |
|
} |
|
if(this._ticket) this.ioelement.cancel(this._ticket); // cancel any previous requests |
|
if(this.method=='get') this._ticket=this.ioelement.get(this.src,data,fn,cargo); |
|
else this._ticket=this.ioelement.post(this.src,data,fn,cargo); |
|
} |
|
}; |
|
p._unboundObject = function(o){ |
|
if(!o._clsid) return; |
|
delete this.dataobjects[o._clsid]; |
|
delete DataSource.allDataObjects[o._clsid]; |
|
}; |
|
|
|
|
|
// Public Methods ------------------------------- |
|
|
|
p.addRecord = function(){ |
|
this._modRec=true; |
|
this._oldRowIndex=this.rowIndex; |
|
this._send('addrow'); |
|
}; |
|
p.cancelAction = function(norefresh){ |
|
if (this._cancelAct=='waiting') this._cancelAct=true; // cancel submit() |
|
else { |
|
// cancel either editRecord() or addRecord() operation |
|
this._cancelAct=true; |
|
if (this._modRec && this._oldRowIndex!=this.rowIndex) this.rowIndex=this._oldRowIndex; |
|
this._oldRowIndex=null; |
|
this._modRec=false; |
|
if(!norefresh) this.refresh(); |
|
} |
|
}; |
|
p.connect = function(fn,useWebService,useSync,uid,pwd){ // connects to the data source using the SODA web service |
|
this.ws_uid=uid; this.ws_pwd=pwd; |
|
this.wsSync=useSync; |
|
this._resetProperties(); |
|
if(!useWebService) { |
|
if(typeof(fn)!='function') return; |
|
this.isConnected=true; |
|
fn(this,true); |
|
}else if(IOElement.SODA){ |
|
this._callback=fn; |
|
if(typeof(useWebService)=='string') { |
|
// use an existing web service |
|
var s,et; |
|
this.webservice=this.ioelement[useWebService]; |
|
if (this.webservice && this.webservice.isConnected) { |
|
this.isConnected=true; |
|
s=true; et=''; |
|
}else{ |
|
this.webservice=null; |
|
s=false; et='Service not found'; |
|
} |
|
this._callback(this,s,et); |
|
}else{ |
|
// create a new web service |
|
var me=this; |
|
var cbFn=function(ws,s,et){ |
|
if(s==true) { |
|
me.webservice=ws; |
|
me.isConnected=true; |
|
} |
|
// notify caller of connection |
|
me._callback(me,s,et); |
|
} |
|
this.ioelement.createWebService(this.clsid,this.src,cbFn,useSync,uid,pwd,this.method); |
|
} |
|
} |
|
}; |
|
p.deleteRecord=function(){ |
|
this._send('deleterow'); |
|
}; |
|
p.editRecord = function(){ |
|
if(this._modRec) return; |
|
this._modRec=true; |
|
this._oldRowIndex=this.rowIndex; |
|
}; |
|
p.getField = function(fld){return this._fieldManager('GET',fld)}; |
|
p.getAbsolutePage = function() {return this.pageNumber}; |
|
p.getRecordPosition = function(){return this.rowIndex}; |
|
p.getPageCount = function() {return this.pageCount}; |
|
p.getPageSize = function() {return this.pageSize}; |
|
p.getPageStart = function(){return this.pageRIS}; |
|
p.getPageEnd = function(){return this.pageRIE}; |
|
p.getRecordCount = function(){return this.rowCount}; |
|
p.getRecord = function(n){ |
|
var i, data={}; |
|
if(!this._modRec || (n!=null && n!=this.rowIndex)) data=(n==null)?this.record:this.recordSet[n]; |
|
else { |
|
for (i in this.dataobjects){ |
|
f=this.dataobjects[i]; |
|
con=DataSource.allDataObjects[i]; |
|
data[f]=con._getDSValue(); |
|
} |
|
} |
|
return data; |
|
}; |
|
p.isEditMode = function(){return this._modRec}; |
|
p.moveFirst = function(){ |
|
if(this._modRec) this.cancelAction(true); |
|
if(this.pageSize<=1) this._send('movefirst'); |
|
else{ |
|
var r,cp=this.pageNumber; //current page |
|
var fetch=(cp!=1 || !this.recordSet.length); |
|
this.rowIndex=0; |
|
this.pageNumber=1; |
|
if (fetch) this._send('fetchpage',null,{pageType:'firstpage'}); |
|
else { |
|
r=this.recordSet[0]; |
|
this.setRecord(r); |
|
} |
|
} |
|
}; |
|
p.moveLast = function(){ |
|
if(this._modRec) this.cancelAction(true); |
|
if(this.pageSize<=1) this._send('movelast'); |
|
else{ |
|
var cp=this.pageNumber; //current page |
|
var lp=this.pageCount; // last page |
|
var fetch=(lp!=cp || !this.recordSet.length); |
|
this.pageNumber=lp; |
|
this.rowIndex=this.rowCount-1; |
|
if (fetch) { |
|
this.rowIndex=-2; // force rowIndex to be set to pageRIE |
|
this._send('fetchpage',null,{pageType:'lastpage'}); |
|
}else { |
|
r=this.recordSet[this.rowIndex]; |
|
this.setRecord(r); |
|
} |
|
} |
|
}; |
|
p.moveNext = function(){ |
|
if(this._modRec) this.cancelAction(true); |
|
this._modRec=false; |
|
if(this.pageSize<=1) this._send('movenext'); |
|
else{ |
|
var ps,cp,np,fetch; |
|
var r=(this.rowIndex+1); |
|
ps=this.pageSize; |
|
cp=this.pageNumber; //current page |
|
if(r<1) np=1; // new page |
|
else np=this.pageNumber=parseInt(r/ps)+1; |
|
fetch=(np!=cp || np>this.pageCount || !this.recordSet.length); |
|
if(r>=this.rowCount) {r=this.rowCount-1; fetch=true;} |
|
this.rowIndex=r; |
|
if (fetch) this._send('fetchpage',null,{pageType:'normalpage'}); |
|
else { |
|
r=this.recordSet[r]; |
|
this.setRecord(r); |
|
} |
|
} |
|
}; |
|
p.movePrev = function(){ |
|
if(this._modRec) this.cancelAction(true); |
|
if(this.pageSize<=1) this._send('moveprev'); |
|
else{ |
|
var ps,cp,np,fetch; |
|
var r=(this.rowIndex-1); |
|
ps=this.pageSize; |
|
cp=this.pageNumber; //current page |
|
if(r<1) np=1; // new page |
|
else np=this.pageNumber=parseInt(r/ps)+1; |
|
fetch=(np!=cp || np<1 || !this.recordSet.length); |
|
if(r<0) {r=0; fetch=true;} |
|
this.rowIndex=r; |
|
if (fetch) this._send('fetchpage',null,{pageType:'normalpage'}); |
|
else { |
|
r=this.recordSet[r]; |
|
this.setRecord(r); |
|
} |
|
} |
|
}; |
|
p.retry = function() { |
|
if(this._ticket) this.ioelement.retry(this._ticket); |
|
else if(!this.isConnected) this.ioelement.retry(); |
|
}; |
|
p.refresh = function(fld){ |
|
var record=this.record; |
|
if(!fld||!record) this.setRecordPosition(this.rowIndex); |
|
else if(record){ |
|
// refresh field from local cached data record |
|
this._fieldManager('SET',fld,record[fld]); |
|
} |
|
}; |
|
p.setAbsolutePage = function(n) { |
|
var cp=this.pageNumber; |
|
var np=parseInt(n); |
|
if(np>0 && np!=cp) { |
|
this.rowIndex=-1; // force rowIndex to be set on the new page |
|
this.pageNumber=np; |
|
this._send('fetchpage'); |
|
} |
|
}; |
|
p.setField = function(fld,value){ |
|
this._fieldManager('SET',fld,value); |
|
}; |
|
p.setPageSize = function(n) { |
|
this.pageSize=parseInt(n); |
|
if(this.pageSize<1) this.pageSize=1; |
|
this.pageNumber=0; // this will force moveFirst() to reload page |
|
this.moveFirst(); |
|
}; |
|
p.setRecord = function(data){ |
|
var vl,con,i,fld; |
|
if(!data) return; |
|
this.recordSet[this.rowIndex] = this.record = data; |
|
for(i in this.dataobjects){ |
|
fld=this.dataobjects[i]; |
|
con=DataSource.allDataObjects[i]; |
|
if(con){ |
|
vl=data[fld]; |
|
con._setDSValue(vl); |
|
} |
|
}; |
|
this.invokeEvent('recordchange'); |
|
}; |
|
p.setRecordPosition = function(n) { |
|
this.rowIndex=parseInt(n); |
|
if(this._modRec) this.cancelAction(true); |
|
if(this.pageSize<=1) this._send('moveto'); |
|
else { |
|
var ps,cp,np,fetch; |
|
var r=this.rowIndex; |
|
ps=this.pageSize; |
|
cp=this.pageNumber; //current page |
|
if(r<1) np=1; // new page |
|
else np=this.pageNumber=parseInt(r/ps)+1; |
|
fetch=(np!=cp || np>this.pageCount || !this.recordSet.length); |
|
if(r>=this.rowCount) {r=this.rowCount-1; fetch=true;} |
|
this.rowIndex=r; |
|
if (fetch) this._send('fetchpage',null,{pageType:'normalpage'}); |
|
else { |
|
r=this.recordSet[r]; |
|
this.setRecord(r); |
|
} |
|
} |
|
}; |
|
p.setSource = function(url,method,ioelement){ |
|
this.src=url; |
|
if(method) method=(method+'').toLowerCase(); |
|
if(method || !this.method) this.method=(method=='post'||method=='get')? method:'post'; |
|
if(ioelement) this.ioelement=ioelement; |
|
else if(!this.ioelement) this.ioelement=IOElement.getSharedIO(); |
|
}; |
|
p.submit = function(){ |
|
if (!this._modRec) this.invokeEvent('alert',null,'DataSource: Submit action canceled'); |
|
else { |
|
var data = this.getRecord(); |
|
this._cancelAct='waiting'; |
|
this.invokeEvent('validate',null,data); |
|
if(this._cancelAct==true) return; |
|
this._cancelAct=false; |
|
this._send('submitrow',data); |
|
} |
|
}; |
|
|
|
|
|
/* Non-Prototype */ |
|
DataSource._cnt=0; |
|
DataSource.all={}; |
|
DataSource.allDataObjects={}; |
|
DataSource.increment = function(){return 'dsObject'+(this._cnt++)}; |
|
DataSource._getFORMInput = function(){return this.value}; |
|
DataSource._setFORMInput = function(d){this.value=d}; |
|
DataSource._getFORMImage = function(){return this.src}; |
|
DataSource._setFORMImage = function(d){if(this.src) this.src=d;}; |
|
DataSource._getFORMSelect = function(){ |
|
var i,d=[]; |
|
for(i=0;i<this.options.length;i++) { |
|
if(this.options[i].selected) d[d.length]=this.options[i].value; |
|
}; |
|
return d.join(','); |
|
}; |
|
DataSource._setFORMSelect = function(d){ |
|
var i,a,o,ov={}; |
|
if (typeof(d)=='object'){ |
|
// clear <select> menu and display name/value pairs |
|
while(this.length>0) this.remove(0); |
|
for(i in d){ |
|
this.add(new Option(i,d[i])); |
|
} |
|
}else { |
|
// select values from <select> menu |
|
a=(d+'').split(','); |
|
for(i=0;i<a.length;i++) ov[a[i]]=true; |
|
for(i=0;i<this.options.length;i++) { |
|
o=this.options[i]; |
|
if(ov[o.value]) o.selected=true; |
|
else o.selected=false; |
|
}; |
|
} |
|
}; |
|
DataSource._getFORMCheckBox = function(){ |
|
if (!this.length) { |
|
if(this.checked) return this.value; |
|
}else { |
|
var i,chkv=[]; |
|
for(i=0;i<this.length;i++) { |
|
if(this[i].checked) chkv[chkv.length]=this[i].value; |
|
}; |
|
return chkv.join(','); |
|
} |
|
}; |
|
DataSource._setFORMCheckBox = function(d){ |
|
if (!this.length) { |
|
if(d==this.value) this.checked=true; |
|
else this.checked=false; |
|
}else { |
|
var i,chk,chkv={}; |
|
var a=(d+'').split(','); |
|
for(i=0;i<a.length;i++) chkv[a[i]]=true; |
|
for(i=0;i<this.length;i++) { |
|
chk=this[i]; |
|
if(chkv[chk.value]) chk.checked=true; |
|
else chk.checked=false; |
|
}; |
|
} |
|
}; |
|
DataSource._getFORMRadio= function(){ |
|
if (!this.length) { |
|
if(this.checked) return this.value; |
|
}else { |
|
for(var i=0;i<this.length;i++) { |
|
if(this[i].checked) return this[i].value; |
|
}; |
|
} |
|
}; |
|
DataSource._setFORMRadio= function(d){ |
|
if (!this.length) { |
|
if(d==this.value) this.checked=true; |
|
else this.checked=false; |
|
}else{ |
|
var i,rb; |
|
for(i=0;i<this.length;i++) { |
|
rb=this[i]; |
|
if(d==rb.value) rb.checked=true; |
|
else rb.checked=false; |
|
}; |
|
} |
|
}; |
|
DataSource._GetDataSource = function(){ return this.__iDataSource}; |
|
DataSource._SetDataSource = function(ds,field){ |
|
if(ds && ds._boundObject) ds._boundObject(this,field); |
|
}; |
|
DataSource.IsFormElm=function(o){ |
|
var ot,type=(o && o.type)? o.type+'':''; |
|
ot=type.replace(/hidden|textarea|text|button|submit|image|select|checkbox|radio/,''); |
|
if(type && ot!=type) return true; |
|
else return false; |
|
}; |
|
DataSource.createBoundObject = function(o,getfn,setfn){ |
|
if (typeof(o)=='object'){ |
|
if(!getfn && !setfn && this.IsFormElm(o)){ // check if form element |
|
var tp=(o.type+'').toLowerCase(); |
|
if(tp=='image') { |
|
getfn=this._getFORMImage; |
|
setfn=this._setFORMImage; |
|
}else if(tp.indexOf('select')==0) { |
|
getfn=this._getFORMSelect; |
|
setfn=this._setFORMSelect; |
|
}else if(tp=='checkbox') { |
|
getfn=this._getFORMCheckBox; |
|
setfn=this._setFORMCheckBox; |
|
}else if(tp=='radio') { |
|
getfn=this._getFORMRadio; |
|
setfn=this._setFORMRadio; |
|
}else if (tp=='text'||tp=='textarea'||tp=='hidden'||tp=='button'||tp=='submit'){ |
|
getfn=this._getFORMInput; |
|
setfn=this._setFORMInput; |
|
} |
|
}else if(o.src && !getfn && !setfn) { // check if image object |
|
getfn=this._getFORMImage; |
|
setfn=this._setFORMImage; |
|
} |
|
if(getfn && setfn){ |
|
o._getDSValue = getfn; |
|
o._setDSValue = setfn; |
|
o.getDataSource = DataSource._GetDataSource; |
|
o.setDataSource = DataSource._SetDataSource; |
|
} |
|
} |
|
return o; |
|
}; |
|
DataSource.boundFormElements = function(frm,ds){ |
|
var i,elm,elmName,elmType,il={}; |
|
for (i=0;i<frm.elements.length;i++){ |
|
elm=frm.elements[i]; |
|
elmName=elm.name; |
|
elmType=elm.type; |
|
if(!il[elmName]){ |
|
fld=(elm.fieldname)? elm.fieldname:elmName; |
|
if(frm[elmName].length && (elmType=='radio'||elmType=='checkbox')) { |
|
il[elmName]=true; |
|
elm=frm[elmName]; |
|
if(!elm.type) elm.type=elmType; |
|
} |
|
elm=DataSource.createBoundObject(elm); |
|
elm.setDataSource(ds,fld); |
|
} |
|
} |
|
}; |
|
|
|
// CallBack Functions |
|
DataSource.fnProcessResponse = function(cargo,data){ |
|
var ds=DataSource.all[cargo.id]; |
|
if(!ds) return; |
|
ds._ticket=null; |
|
if(cargo.action=='submitrow'){ |
|
// data should be set to true if all went well |
|
if(data) ds.recordSet[ds.rowIndex]=cargo.data; |
|
ds.invokeEvent('submit',null,data); |
|
ds.invokeEvent('response'); |
|
}else if(cargo.action=='fetchpage'){ |
|
var rowStart=data.dataRowIndex; |
|
var fieldnames=data.fieldnames; |
|
var fieldvalues=data.fieldvalues; |
|
if(!fieldnames||!fieldvalues) return; |
|
ds.pageCount=0; |
|
ds.pageRIS=rowStart; |
|
ds.pageRIE=rowStart+(ds.pageSize-1); |
|
ds.pageNumber=parseInt(ds.pageRIS/ds.pageSize)+1; |
|
ds.rowCount=data.dataRowCount; |
|
if(ds.pageRIE>=ds.rowCount) ds.pageRIE=ds.rowCount-1; |
|
if(ds.rowCount==null) ds.rowCount=0; |
|
if(ds.rowCount>0) ds.pageCount=parseInt((ds.rowCount-1)/ds.pageSize)+1; |
|
if(ds.rowIndex==-2) ds.rowIndex=ds.pageRIE; // set rowIndex to RIS if -2 or to RIE if <0 or >=rowCount |
|
else if(ds.rowIndex<0||ds.rowIndex>=data.dataRowCount) ds.rowIndex=ds.pageRIS; |
|
var r,c,record; |
|
for(r=0;r<fieldvalues.length;r++){ |
|
if(fieldvalues[r]){ |
|
record={} |
|
for(c=0;c<fieldnames.length;c++){ |
|
record[fieldnames[c]]=fieldvalues[r][c]; |
|
} |
|
ds.recordSet[r+rowStart]=record; |
|
} |
|
} |
|
ds.setRecord(ds.recordSet[ds.rowIndex]); |
|
ds.invokeEvent('response'); |
|
}else { |
|
// after a deleterow reload the current page |
|
if(cargo.action=='deleterow' && ds.pageSize>1) ds._send('fetchpage'); |
|
else{ |
|
ds.rowCount = ds.pageCount = data.dataRowCount; |
|
ds.rowIndex = ds.pageRIS = ds.pageRIE = data.dataRowIndex; |
|
if(ds.rowCount==null) ds.rowCount=-1; |
|
ds.setRecord(data); |
|
ds.invokeEvent('response'); |
|
} |
|
} |
|
}; |
|
DataSource.fnGETPOSTResponse = function(e,s){ |
|
var ds,data,cargo; |
|
var o=e.getSource(); |
|
if(!s){ |
|
cargo=o.getCargo(true); |
|
ds=DataSource.all[cargo.id]; |
|
ds.invokeEvent('alert',null,'DataSource: Server Timeout'); |
|
return; |
|
} |
|
cargo=o.getCargo(); |
|
data = o.getVariable('record'); |
|
if(!data) return; |
|
DataSource.fnProcessResponse(cargo,data); |
|
}; |
|
DataSource.fnSODAResponse = function(e){ |
|
var ds,data,cargo; |
|
var o=e.getSource(); |
|
var r=o.getResponse(); |
|
if (r.error) { |
|
cargo=o.getCargo(true); |
|
ds=DataSource.all[cargo.id]; |
|
ds.invokeEvent('alert',null,'DataSource: Server Timeout - '+r.error.text); |
|
return; |
|
} |
|
cargo=o.getCargo(); |
|
data=r.value; |
|
if(!data) return; |
|
DataSource.fnProcessResponse(cargo,data); |
|
}; |
|
|
|
// Data source functions for DynElement |
|
DynElement.prototype._getDSValue = function(){ |
|
return (this.getHTML)? this.getHTML():null; |
|
}; |
|
DynElement.prototype._setDSValue = function(d){ |
|
if(this.setHTML) this.setHTML(d); |
|
}; |
|
DynElement.prototype.getDataSource = DataSource._GetDataSource; |
|
DynElement.prototype.setDataSource = function(ds,field){ |
|
if(ds && ds._boundObject) { |
|
this._clsid=this.id; |
|
ds._boundObject(this,field); |
|
} |
|
};
|
|
|