// supported column types (magic values grabbed from datalist/datalist.h) var CT_UNDEFINED=0x7FFFFFFF;// undefined var CT_DECIMAL=3; // Decimal var CT_INTEGER=4; // int var CT_DOUBLE=8; // double var CT_DATETIME=9; // Time var CT_STRING=12; // string var CT_INT64=-5; // int64_t // Column Sizes for different types var CS_INT64=9; var CS_INTEGER=5; var CS_STRING=5; ///////////////////////////////////////////////////////////////////////////////////// // DataSetFeederIF class ///////////////////////////////////////////////////////////////////////////////////// var DataSetFeederIF = Class.create({ initialize: function() { this.sContName_ = ""; this.sObjName_ = ""; }, Serialize: function(oS) { oS.BeginType("DataSetFeederIF"); oS.Serialize(this.sContName_); oS.Serialize(this.sObjName_); oS.EndType("DataSetFeederIF"); // throw new Error("Cannot serialize DataSetFeederIF. "); }, Restore: function(oR) { oR.BeginType("DataSetFeederIF"); this.sContName_ = oR.Restore(); this.sObjName_ = oR.Restore(); oR.EndType("DataSetFeederIF"); }, ContName: function() { return this.sContName_; }, ObjName: function() { return this.sObjName_; }, SetContName: function(sContName) { this.sContName_ = sContName; }, SetObjName: function(sObjName) { this.sObjName_ = sObjName; }, toString: function() { return "C:"+this.sContName_+",O:"+this.sObjName_; } }); ///////////////////////////////////////////////////////////////////////////////////// // ADataSource class ///////////////////////////////////////////////////////////////////////////////////// var ADataSource = Class.create({ initialize: function() { this.sModule_ = ""; this.sComponent_ = ""; this.sActionSegment_ = ""; this.oParams_ = new Object(); this.oFeeder_ = new Object(); this.aHeader_ = []; this.nRowCount_ = 0; }, Serialize: function(oS) { oS.BeginType("ADataSource"); oS.Serialize(this.sModule_); oS.Serialize(this.sComponent_); oS.Serialize(this.sActionSegment_); oS.Serialize(this.oParams_); oS.Serialize(this.oFeeder_); oS.Serialize(this.aHeader_); oS.Serialize(this.nRowCount_); oS.EndType("ADataSource"); }, Restore: function(oR) { oR.BeginType("ADataSource"); this.sModule_ = oR.Restore(); this.sComponent_ = oR.Restore(); this.sActionSegment_ = oR.Restore(); this.oParams_ = oR.Restore(); this.oFeeder_ = oR.Restore(); this.aHeader_ = oR.Restore(); this.nRowCount_ = oR.Restore().Value(); oR.EndType("ADataSource"); }, // getters Module: function() { return this.sModule_; }, Component: function() { return this.sComponent_; }, ActionSegment: function() { return this.sActionSegment_; }, Params: function() { return this.oParams_; }, Feeder: function() { return this.oFeeder_; }, Header: function() { return this.aHeader_; }, RowCount: function() { return this.nRowCount_; }, CallURL: function() { return "/srv/"+this.sModule_+"/"+this.sComponent_+"/"+this.sActionSegment_; }, // setters SetFeeder: function(oFeeder) { this.oFeeder_ = oFeeder; } }); function CompareDataSources(oDSF, oDSS) { var oSFParams = URLSerialize(oDSF.Params()); var oSSParams = URLSerialize(oDSS.Params()); return (oDSF.Module() == oDSS.Module() && oDSF.Component() == oDSS.Component() && oDSF.ActionSegment() == oDSS.ActionSegment() && oSFParams == oSSParams); } var IntRange = Class.create({ initialize: function(oValue) { if (typeof(oValue) == 'string') this.convertFromString(oValue); else this.convertFromMinMax(oValue); }, convertFromMinMax: function(oMM) { this.nMin = null; this.nMax = null; this.nVal = null; if (oMM === null || (typeof(oMM["Min"]) == 'undefined' && typeof(oMM["Max"]) == 'undefined') ) { this.nVal = oMM; return; } // this is MinMax if (typeof(oMM["Max"]) != 'undefined') this.nMax = oMM["Max"]; if (typeof(oMM["Min"]) != 'undefined') this.nMin = oMM["Min"]; }, convertFromString: function(sR) { // TODO: replace all bad chars??? if (!sR) { this.nVal = null; this.nMin = null; this.nMax = null; return; } var aR=sR.split(/\.{2,}/); // two or more dots this.nMin = null; this.nMax = null; if (aR.length == 1) { var v = (aR[0]) ? parseInt(aR[0]) : null; this.nVal = this.convert(v); this.nMin = null; this.nMax = null; return; } else if (aR.length != 2) { alert('IntRange: Bad range spec'); return; } // this is a true range var v = (aR[0]) ? parseInt(aR[0]) : null; this.nMin = this.convert(v); v = (aR[1]) ? parseInt(aR[1]) : null; this.nMax = this.convert(v); this.nVal = null; }, Val: function() { return this.nVal; }, MinVal: function() { return this.nMin; }, MaxVal: function() { return this.nMax; }, toString: function() { if (this.nVal !== null) { return this.nVal.toString(); } if (this.nMin == null && this.nMax == null) return ''; var sR = ''; if (this.nMin !== null) sR += this.nMin; sR += '...'; if (this.nMax !== null) sR += this.nMax; return sR; }, ToMinMax: function() { var oValue = new Object(); if (this.nVal !== null) { oValue = this.nVal; } else { if (this.nMin !== null) oValue["Min"] = this.nMin; if (this.nMax !== null) oValue["Max"] = this.nMax; if (this.nMin === null && this.nMax === null) oValue = null; } return oValue; }, convert: function(v) { return (v===null||isNaN(v)) ? null : int(v); } }); var Int64Range = Class.create(IntRange, { convert: function(v) { return (v===null||isNaN(v)) ? null : int64(v); } }); //{FirstRow='10', Size='10' ///////////////////////////////////////////////////////////////////////////////////// // RowBatch class ///////////////////////////////////////////////////////////////////////////////////// var RowBatch = Class.create({ initialize: function() { this.rowIndex_ = 0; this.colTypes_ = []; this.indices_ = []; this.rows_ = 0; this.data_ = null; }, Serialize: function(oS) { LogE("RowBatch serializer is not implemented. "); }, Restore: function(oR) { oR.BeginType("RowBatch"); /*this.length=*/oR.Restore().Value(); // unsigned int was there (not used) this.data_=oR.Restore(); oR.BeginType("RowIndex"); this.rows_=oR.Restore().Value(); // unsigned int was there this.indices_=[]; for(var i=0; i= this.rows_) return false; this.colIndex_ = 0; // reset column index this.index_ = this.indices_[this.rowIndex_]; this.rowIndex_++; return true; }, Read: function() { var nType = this.colTypes_[this.colIndex_]; this.colIndex_++; var oVal = null; switch (nType) { case CT_INTEGER: return this.getInt(); case CT_INT64: return this.getInt64(); case CT_STRING: return this.getString(); case CT_DATETIME: return this.getDateTime(); case CT_DOUBLE: return this.getDouble(); case CT_DECIMAL: return this.getDecimal(); default: // nothing to do alert("RowBatch: Unknown column type: "+nType); this.rowIndex_ = this.rows_; // to stop fetching } return oVal; }, getInt: function() { if(this.data_.charCodeAt(this.index_)!=0) { this.index_ += CS_INTEGER; return null; // NULL } var res=0; if(this.data_.charCodeAt(this.index_+4)<128) { // positive var pow=1; for(var i=1; i<=4; ++i) { var val=this.data_.charCodeAt(this.index_+i); res+=val*pow; pow*=256; } } else { // negative var pow=1; for(var i=1; i<=4; ++i) { var val=this.data_.charCodeAt(this.index_+i); val=(~val)&255; res+=val*pow; pow*=256; } res+=1; res=-res; } this.index_ += CS_INTEGER; // TODO: optimization for Int return res; }, getInt64: function() { // TODO: will give wrong results on real Int64 values (of order 2^60) if(this.data_.charCodeAt(this.index_)!=0) { this.index_ += CS_INT64; return null; // NULL } var res=0; if(this.data_.charCodeAt(this.index_+8)<128) { // positive var pow=1; for(var i=1; i<9; ++i) { var val=this.data_.charCodeAt(this.index_+i); res+=val*pow; pow*=256; } } else { // negative var pow=1; for(var i=1; i<9; ++i) { var val=this.data_.charCodeAt(this.index_+i); val=(~val)&255; res+=val*pow; pow*=256; } res+=1; res=-res; } this.index_ += CS_INT64; return new Int64(res); }, getString: function() { if(this.data_.charCodeAt(this.index_)!=0) { this.index_ += CS_STRING; return null; // NULL } var len=0; var pow=1; for(var i=1; i<5; ++i) { var val=this.data_.charCodeAt(this.index_+i); len+=val*pow; pow*=256; } this.index_ += CS_STRING; var val=this.data_.substr(this.index_, len-1); val=Encoder.UTF8Decode(val); this.index_+=len; return val; }, getDateTime: function() { if(this.data_.charCodeAt(this.index_)!=0) { // NULL this.index_++; return null; } this.index_++; var start=this.index_; var len=0; for(; this.data_.charCodeAt(this.index_+len)!=0; ++len); var raw=this.data_.substr(start, len); var val = new Time(raw); this.index_+=16; // aka datalist.cc::IsoTimeStringSize return val; }, getDouble: function() { if(this.data_.charCodeAt(this.index_)!=0) { // NULL this.index_+= 9; // StatusByte + sizeof(double) return null; // will not work (check NaN instead) } this.index_++; var sBytes = this.data_.substr(this.index_,8); this.index_+=8; var val = parseBytesAsDouble(sBytes); if (isNaN(val)) return null; return new Double(val); }, getDecimal: function() { if(this.data_.charCodeAt(this.index_)!=0) { // NULL this.index_+= 17; // StatusByte + sizeof(Decimal) return decimal(); } this.index_++; var sBytes=this.data_.substr(this.index_,16); this.index_+=16; var d=new CDecimal({binary: sBytes}); return new Decimal(d.toString()); } }); // Column order var CO_SORTUP = 1; var CO_SORTDOWN = 2; var CO_UNSORTED = 3; var ColSortElem = Class.create({ initialize: function(nColIndex, nSortDir) { this.nColIndex_ = nColIndex; this.nSortDir_ = nSortDir ? nSortDir : CO_SORTUP; ////LogL("ColSortElem created: "+nColIndex); }, Touch: function() { this.nSortDir_ = this.nSortDir_ % 2 + 1; // NOTE: CO_UNSORTED is disabled !!! ////LogL("ColSortElem ["+this.nColIndex_+"] touched! "+this.nSortDir_); }, Index: function() { return this.nColIndex_; }, Dir: function() { return this.nSortDir_; }, SetDir: function(nSortDir) { this.nSortDir_ = nSortDir; }, SetIndex: function(nColIndex) { this.nColIndex = nColIndex; }, Get: function() { switch (this.nSortDir_) { case CO_SORTUP: return (this.nColIndex_+1); case CO_SORTDOWN: return -(this.nColIndex_+1); case CO_UNSORTED: return null; } LogE('ColSortElem::Get: Invalid sort direction! '); return null; } }); var ColSort = Class.create({ initialize: function() { this.aOrder_ = new Array(); }, Touch: function(nIndex, bMultiSort) { if (typeof(bMultiSort)!='boolean') bMultiSort = false; if (!bMultiSort) { if (this.aOrder_.length) { // use first element as previous state (if indexes match) var oPrevElem = this.aOrder_[0]; if (oPrevElem.Index() == nIndex) { oPrevElem.Touch(); this.aOrder_ = [oPrevElem]; } else { this.aOrder_ = [new ColSortElem(nIndex)]; } } else { this.aOrder_ = [new ColSortElem(nIndex)]; } } else { var bFound = false; for (var i = 0; i < this.aOrder_.length; ++i) { var oElem = this.aOrder_[i]; if (oElem.Index() == nIndex) { oElem.Touch(); bFound = true; } } if (!bFound) { this.aOrder_.push(new ColSortElem(nIndex)); } } }, Find: function(nIndex) { for (var i = 0; i < this.aOrder_.length; ++i) { var oElem = this.aOrder_[i]; if (oElem.Index() == nIndex) return {idx: i, elem: oElem}; } return null; }, Get: function() { var aRes = new Array(); for (var i = 0; i < this.aOrder_.length; ++i) { var nI = this.aOrder_[i].Get(); if (nI) aRes.push(nI); } return aRes; }, Set: function(aSort) { this.Flush(); // length = column count var nL = aSort.length; // first, collect elements var aOrder = []; for (var i = 0; i < nL; ++i) { var nSO = aSort[i]; if (!nSO) continue; // skip non-sorted columns var nSI = Math.abs(nSO); var nDir = ((nSO > 0) ? CO_SORTUP : CO_SORTDOWN); aOrder[nSI] = new ColSortElem(i, nDir); } // second, eliminate gaps in array for (var i = 0; i < aOrder.length; ++i) { if (typeof(aOrder[i]) != 'undefined') { this.aOrder_.push(aOrder[i]); } } }, Flush: function() { this.aOrder_.clear(); } });