//#include "/js/scr-grid-service.js" var SG_DEBUG=0; // ScrollableGrid current action var SG_CA_IDLE = 0; //var SG_CA_LOAD = 1; var SG_CA_REFRESH = 2; //var SG_CA_SORT = 3; //var SG_CA_ROWS = 4; //var SG_CA_FILTER = 5; //var SG_CA_PASS = 6; var SG_CA_FSRP = 7; /* Filter, Sort, Rows, Pass */ var SG_CA_FRP = 8; /* Filter, Rows, Pass */ var SG_CA_SP = 9; /* Sort, Pass */ var SG_FT_UP = "up"; var SG_FT_DOWN = "down"; var SG_FT_REPLACE = "replace"; var SG_FT_NEW = "new"; var SG_VISIBILITY_NO = "no"; var SG_VISIBILITY_YES = "yes"; var SG_MIN_COLUMN_WIDTH = 6; // in pixels var SG_DEFAULT_WIDTH = 10; // weight var SGFetchRequest = Class.create({ grid: null, first: 0, rowNum: null, action: "", cache: false, requestID: 0, requestCounter: 0, initialize: function(oParams) { Object.extend(this, oParams); if (this.cache) { this.grid.currentCacheRequest[this.action] = this; } else { this.grid.currentRequest = this; } // if rowNum is not specified, assume SG's prefetch size (TODO: remove this if) if (this.rowNum===null) { //alert('This should not happen: rowNum is NULL, please submit a bug report on ScrollableGrid control'); this.rowNum=this.grid.prefetchSize; } if (this.first<0) this.first=0; var rowCount=(this.action==SG_FT_NEW ? this.grid.fullRowCount : this.grid.rowCount); if (this.first+this.rowNum > rowCount) this.rowNum=rowCount-this.first; if (this.rowNum <= 0 && this.action!=SG_FT_NEW) { if (SG_DEBUG) LogE("SGFetchRequest run aborted: 0 rows to fetch. "); this.grid.ClearAbortedRequest(oParams); this.grid.StopWait(); return; } // some automated debug info if (this.invoker && SG_DEBUG) LogL(this.invoker+" -> Fetch"); this.grid.Fetch(this); } }); // By default, filter class is a StringInput var SGFilterClass={}; SGFilterClass["DropDown"]="MultiSelect"; SGFilterClass["Checkbox"]="Checkbox"; SGFilterClass["DateInput"]="DateInput"; SGFilterClass["DateTimeInput"]="DateTimeInput"; // Dy default, filter window is not range var SGFilterIsRange={}; SGFilterIsRange["DateInput"]=true; SGFilterIsRange["DateTimeInput"]=true; var SGColumn = Class.create({ id_: "", bind_: "", type_: CT_UNDEFINED, typeName_: "", attrs_: null, order_: -1, clName_: "", title_: "", itemsByID_: null, itemsByValue_: null, visibility_: SG_VISIBILITY_YES, filter_: undefined, // means no filter at all filterText_: "", sort_: null, // TODO: fine value width_: 0, customWidth_: 0, precision_: 2, value_: undefined, // TODO: remove or not? headerID_:0, dynamic_: true, initialize: function(oP) { if (typeof(oP.id) != 'undefined') this.id_ = oP.id; if (typeof(oP.bind) != 'undefined') this.bind_ = oP.bind; if (typeof(oP.type) != 'undefined') this.type_ = oP.type; if (typeof(oP.typeName) != 'undefined') this.typeName_ = oP.typeName; if (typeof(oP.attrs) != 'undefined') this.attrs_ = oP.attrs; // optional DataList' column attributes if (typeof(oP.order) != 'undefined') this.order_ = oP.order; if (typeof(oP.clName) != 'undefined') this.clName_ = oP.clName; if (typeof(oP.title) != 'undefined') this.title_ = oP.title; if (typeof(oP.visibility) != 'undefined') this.visibility_ = oP.visibility; if (typeof(oP.filter) != 'undefined') this.filter_ = oP.filter; if (typeof(oP.sort) != 'undefined') this.sort_ = oP.sort; // TODO: width/customWidth initial setting? if (typeof(oP.value) != 'undefined') this.value_ = oP.value; if (!!this.attrs_ && !!this.attrs_["TypeName"]) this.typeName_ = this.attrs_["TypeName"]; }, // Getters ID: function() { return this.id_; }, BindID: function() { return this.bind_; }, Type: function() { return this.type_; }, TypeName: function() { return this.typeName_; }, Attrs: function() { return this.attrs_; }, Order: function() { return this.order_; }, ClassName: function() { return this.clName_; }, Title: function() { return this.title_; }, Visibility: function() { return this.visibility_; }, FilterValue: function() { return this.filter_; }, FilterText: function() { return this.filterText_; }, SortValue: function() { return this.sort_; }, Width: function() { return this.width_; }, CustomWidth: function() { return this.customWidth_; }, InitialWidth: function() { return this.initialWidth_; }, Value: function() { return this.value_; }, HeaderID: function() { return this.headerID_; }, Dynamic: function() { return this.dynamic_; }, // Setters SetID: function(oValue) { this.id_ = oValue; }, SetBindID: function(oValue) { this.bind_ = oValue; }, SetType: function(oValue) { this.type_ = oValue; }, SetTypeName: function(oValue) { this.typeName_ = oValue; }, SetOrder: function(oValue) { this.order_ = oValue; }, SetTitle: function(oValue) { this.title_ = oValue; }, SetVisibility: function(oValue) { this.visibility_ = oValue; }, SetFilterValue: function(oRawValue) { this.filterFromRaw(oRawValue); this.filterToText(); }, SetSortValue: function(oValue) { this.sort_ = oValue; }, SetWidth: function(oValue) { this.width_ = oValue; }, SetCustomWidth: function(oValue) { this.customWidth_ = oValue; }, SetInitialWidth: function(oValue) { this.initialWidth_ = oValue; }, SetValue: function(oValue) { this.value_ = oValue; }, SetHeaderID: function(headerID) { this.headerID_ = headerID; }, SetDynamic: function(dynamic) { this.dynamic_ = dynamic; }, InitializeHTML: function(oGrid, i) { var sGID = oGrid.ID(); if (!this.id_) return; // unreferenced column // init sorting handlers this.headerID_ = i; var elColHeader = $(sGID+'_xH'+i); Event.observe(elColHeader, 'mousedown', oGrid.OnColumnMouseDown.bind(oGrid, i)); //Event.observe(elColHeader, 'mouseup', oGrid.OnSort.bind(oGrid, i)); // switching from click to mouseup fixes #768 under IE //Event.observe(elColHeader, 'mousedown', oGrid.OnSortMouseDown.bind(oGrid)); // init filter handlers var elFilter = $(sGID+'_xDropF'+i); oGrid.observe(elFilter, 'click', oGrid.OnDropFilter.bind(oGrid, i)); var elFilterCell = $(sGID+'_xFC'+i); oGrid.observe(elFilterCell, 'click', oGrid.OnOpenFilter.bind(oGrid, i)); var sFilterID=sGID+'_xFI'+i; var elFilterIcon = $(sFilterID); oGrid.observe(elFilterIcon, 'mouseover', oGrid.OnFilterIconMouseOver.bind(oGrid, i)); oGrid.observe(elFilterIcon, 'mouseout', oGrid.OnFilterIconMouseOut.bind(oGrid, i)); oGrid.observeStop(elFilterIcon, 'mouseup'); if (Prototype.Browser.IE) { elColHeader.observe('mouseenter', oGrid.OnColHeaderMouseOver.bind(oGrid, i)); elColHeader.observe('mouseleave', oGrid.OnColHeaderMouseOut.bind(oGrid, i)); } else { Event.observe(elColHeader, 'mouseover', oGrid.OnColHeaderMouseOver.bind(oGrid, i)); Event.observe(elColHeader, 'mouseout', oGrid.OnColHeaderMouseOut.bind(oGrid, i)); } var sResizerID=sGID+'_xR'+i; var elResizer = $(sResizerID); oGrid.observe(elResizer, 'mousedown', oGrid.OnColMouseDown.bind(oGrid, 'colResize', i)); oGrid.observeStop(elResizer, 'click'); // to prevent sorting oGrid.observeStop(elResizer, 'contextmenu'); // to prevent context menu raising // init titles var sTitleID = sGID+'_xT'+i; var elTitle = $(sTitleID); this.title_=elTitle.readAttribute('title'); if (!this.typeName_) this.typeName_ = elTitle.readAttribute('et-type'); var xTypesRoot=oGrid.typeSet.XML().documentElement; var axTypes=AXML.SelectNodes(xTypesRoot, "/st:typeset/st:types/st:type[@id='"+this.typeName_+"']", STNS); if (!axTypes || !axTypes.length) { LogE("No type information found for type '"+this.typeName_+"'. "); // FIXME: fix bug for dynamic tables: this.typeName_ is empty here for some reason return; } var xType=axTypes[0]; this.clName_=xType.getAttribute('class'); var prec=xType.getAttribute('decimal-accuracy'); prec=parseInt(prec, 10); if (isNaN(prec)) prec=2; this.precision_=prec; // next, read attribute from column prec=parseInt(elColHeader.readAttribute('decimal-accuracy'),10); if (!isNaN(prec)) this.precision_=prec; // override from column this.exponent_=(elColHeader.readAttribute('exponent')=="yes"); var tz=xType.getAttribute('respect-timezone'); if(tz) this.TZ_=true; // extract drop-downs for (var xItem=xType.firstChild; xItem; xItem=xItem.nextSibling) { if (xItem.nodeType != Node.ELEMENT_NODE) continue; var id=xItem.getAttribute('id'); var value=xItem.getAttribute('value'); var icon=xItem.getAttribute('icon'); if (icon) { if (icon.charAt(0)=='/') icon=SkinPrefix+icon; else icon='/'+icon; } else icon=null; var label=xItem.getAttribute('label'); var oItem={id: id, value: value, icon: icon, label: label}; // if no items, those two maps remain null if (!this.itemsByID_) this.itemsByID_={}; if (!this.itemsByValue_) this.itemsByValue_={}; this.itemsByID_[id]=oItem; this.itemsByValue_[value]=oItem; } // TODO: revive or remove this et-width var width=parseFloat(elColHeader.readAttribute('et-width'),10); if (isNaN(width)) width=SG_DEFAULT_WIDTH; this.width_ = width; //LogL("Column width parsed: "+width); var sFClass="StringInput"; if (SGFilterClass[this.clName_]) sFClass=SGFilterClass[this.clName_]; var bRange=false; if (SGFilterIsRange[this.clName_]) bRange=true; oGrid.colFilterPWO[i] = new PopupWindowOpener({ nodeID: sFilterID, alignID: sResizerID, /* Next two lines are not kosher: we should calculate exact control offset from popup corner. The problem is that we don't know this offset until popup will be rendered */ shiftX: -6, shiftY: -26, canResize: false, autoSize: true, modal: true, bFitToScreen: true, sParent: oGrid.oParentWindow.InstanceID(), fBeforeLoadCallback: oGrid.Filter_OnBeforeLoad.bind(oGrid, sFClass, bRange, i), fAfterLoadCallback: oGrid.Filter_OnAfterLoad.bind(oGrid, bRange) }); oGrid.oPWOItems[sFilterID]=true; }, // Converts value obtained from control to suitable for DataList::Filter arguments filterFromRaw: function(oRawValue) { if (typeof(oRawValue) == 'undefined') { this.filter_ = undefined; return; } var oValue; if (this.type_==CT_INT64) { // transform oValue to MinMax var oRange=new Int64Range(oRawValue); oValue=oRange.ToMinMax(); } else if (this.type_==CT_INTEGER) { // transform oValue to MinMax var oRange = new IntRange(oRawValue); oValue=oRange.ToMinMax(); } else if (this.type_==CT_STRING) { if (oRawValue===null) { oValue=''; // treat null as empty string (control-specific behaviour) } else if (oRawValue instanceof Array) { oValue={ "Set": [] }; for (var i=0; i < oRawValue.length; ++i) oValue["Set"].push(oRawValue[i]); } else { if (typeof(oRawValue.toString) != 'undefined') oValue = oRawValue.toString(); else oValue=oRawValue; } // finally, empty string means no filtering by this column (filter-specific behaviour) if (oValue=='') oValue=undefined; } else if (this.type_==CT_DATETIME) { // try to pass as is oValue=oRawValue; } else if (this.type_==CT_DOUBLE || this.type_==CT_DECIMAL) { if(typeof(oRawValue) == 'string') { var aR=oRawValue.split(/\.{2,}/); // two or more dots if(aR.length<=1) { // single value oValue = double(parseFloat(oRawValue)); } else { oValue={}; if(aR[0]) oValue.Min=double(parseFloat(aR[0])); if(aR[1]) oValue.Max=double(parseFloat(aR[1])); } } else oValue=oRawValue; } else { // unknown column type alert('WARNING: Unhandled column type in SGColumn::filterFromRaw'); oValue=undefined; } this.filter_=oValue; }, // Converts kosher value back to control value (@sa filterFromRaw) filterToRaw: function() { var f=this.filter_; if (typeof(f) == 'undefined') return undefined; if (this.type_==CT_INT64) { var oRange=new Int64Range(f); // f contains value/Min/Max return oRange.toString(); } else if (this.type_==CT_INTEGER) { var oRange=new IntRange(f); // f contains value/Min/Max return oRange.toString(); } else if (this.type_==CT_STRING) { if (f===null) { // treat null as empty string (control-specific behaviour) return undefined; // no filtering } else if (typeof(f["Set"])!='undefined') { var aF=f["Set"]; var oValue=[]; for (var i=0; i < aF.length; ++i) oValue.push(aF[i]); return oValue; } // else this is a generic string return f; } else if (this.type_==CT_DATETIME) { // pass value as is var oValue=f; return oValue; } else if (this.type_==CT_DOUBLE || this.type_==CT_DECIMAL) { var oValue; if(f && typeof(f)=='object') { oValue=""; if(f.Min && typeof(f.Min)=='object') oValue=f.Min.toString(); oValue+='...'; if(f.Max && typeof(f.Max)=='object') oValue+=f.Max.toString(); } else if(f) oValue=f.toString(); return oValue; } alert('WARNING: Unhandled column type in SGColumn::filterToRaw'); return undefined; }, // updates text value for filter filterToText: function() { var oF=this.filter_; if (typeof(oF)=='undefined') { this.filterText_=''; return; } // otherwise column filter is not empty if (this.type_==CT_INT64) { var oRange = new Int64Range(oF); // it's already a val/Min/Max var text = oRange.toString(); if (text == "") text = "0"; this.filterText_=text; } else if (this.type_==CT_INTEGER) { var oRange = new IntRange(oF); // it's already a val/Min/Max var text = oRange.toString(); if (text == "") text = "0"; this.filterText_=text; } else if (this.type_==CT_STRING) { if (typeof(oF)=='undefined') { this.filterText_=''; } else if (typeof(oF["Set"])!='undefined') { this.filterText_='Array['+oF["Set"].toString()+']'; } else { this.filterText_=oF; } } else if (this.type_==CT_DATETIME) { if (this.clName_=='DateInput') { var val=oF["Min"]; var tx=''; if (val) tx+=this.printDate(val.adate); tx+='...'; val=oF["Max"]; if (val) tx+=this.printDate(val.adate); if (tx=='...') tx=''; this.filterText_=tx; } else if (this.clName_=='DateTimeInput') { var val=oF["Min"]; var tx=''; if (val) tx+=this.printDateTime(val); tx+='...'; val=oF["Max"]; if (val) tx+=this.printDateTime(val); if (tx=='...') tx=''; this.filterText_=tx; } else { alert('Unhandled class name. '+this.clName_); } } else if (this.type_==CT_DOUBLE || this.type_==CT_DECIMAL) { if(oF && typeof(oF)=='object') { this.filterText_=""; if(oF.Min && typeof(oF.Min)=='object') this.filterText_=oF.Min.toString(); this.filterText_+='...'; if(oF.Max && typeof(oF.Max)=='object') this.filterText_+=oF.Max.toString(); } else if(oF) this.filterText_=oF.toString(); } else { // unknown column type alert('WARNING: Unhandled column type in SGColumn::filterToText'); this.filterText_=''; return; } }, printDate: function(val) { var tx=''; if (val.IsIncorrect()) return tx; // usage of ADate type internals // tx+=val.dayPadded+'-'+DateInput.shortMonthNames[val.month]+'-'+val.yearPadded; tx+=val.dayPadded+'.'+val.monthPadded+'.'+val.yearPadded; return tx; }, printDateTime: function(val) { var tx=''; if (val.IsIncorrect()) return tx; var d=val.adate; // usage of Time type internals //tx+=d.dayPadded+'-'+DateInput.shortMonthNames[d.month]+'-'+d.yearPadded; tx+=d.dayPadded+'.'+d.monthPadded+'.'+d.yearPadded; tx+=' '; var t=val.atime; // usage of Time type internals tx+=t.hhPadded+':'+t.mmPadded+':'+t.ssPadded; return tx; }, // converts value from raw to textual representation Print: function(val) { if (val===null) return null; // pass null values AS IS if (this.itemsByValue_) { // dropdown-like var oItem=this.itemsByValue_[val]; if (!oItem) return null; // cannot find value return oItem; // return item itself } // by default, return value itself if (this.clName_=='DateInput') { return this.printDate(val); } else if (this.clName_=='TimeInput') { return val; } else if (this.clName_=='DateTimeInput') { return this.printDateTime(val); } else if (this.clName_=='Spinner' || this.clName_=='Int64Input') { return { value: val, numeric: true }; } else if (this.clName_=='MoneyInput' || this.clName_=='DoubleInput') { var num=new Number(val); if(this.exponent_==true) { return {value: String(num.toExponential(this.precision_)), numeric: true}; } return {value: String(num.toFixed(this.precision_)), numeric: true}; } return val.toString(); } }); ///////////////////////////////////////////////////////////////////////////////////// // SCROLLABLE GRID ///////////////////////////////////////////////////////////////////////////////////// var ScrollableGrid = Class.create({ initialize: function(element, aTypeFiles) { // Test suite area // this.TestHMS(); this.firstRow=0; this.lastRow=0; this.currentRow=0; // request ordering mechanism this.requestID=1; this.requestCounter=1; this.currentCacheRequest = new Object(); this.queuedCacheRequest = new Object(); this.newData=false; this.currentActionSequence=[]; this.typeFiles = aTypeFiles; // store our typeset this.typeSet=AXML.getTypeSet(aTypeFiles); // slow only on first execution in session this.data = []; this.currentRowData={}; this.currentRowDataKey=null; this.ID_ = element.readAttribute('id'); this.root = $(element); this.root.JSControl = this; if (!this.ID_) ThrowError("ScrollableGrid: Cannot get 'id' attribute from element! "); this.LocalID_ = element.readAttribute('localid'); // HTML this.oParentWindow = AControl.GetParentWindow(element); var oValue = URLRestoreV(element.readAttribute('value')); var aHeader; this.rowCount=0; if (oValue && oValue["DataSource"]) { this.oDataSource = oValue["DataSource"]; if (SG_DEBUG > 3) LogL("SET INIT FEEDER="+this.oDataSource.Feeder()); aHeader = this.oDataSource.Header(); this.rowCount=this.oDataSource.RowCount(); this.fullRowCount=this.rowCount; // store original row count LogL("Initial $$rowCount$$ set to "+this.rowCount); } else { LogE("Warning: No DataSource passed to ScrollableGrid. "); this.oDataSource = null; // no data source (empty table) } var xWinRoot = this.oParentWindow.XML().documentElement; this.xmlNode=AXML.SelectNode(xWinRoot, "/ai:wnd/ai:ele[@id='"+this.LocalID()+"']", AINS); var xColumns=AXML.SelectNodes(xWinRoot, "/ai:wnd/ai:ele[@id='"+this.LocalID()+"']/ai:ele[@class='column']", AINS); // if no columns, assume table is dynamic this.bDynamicTable = !(!!xColumns && xColumns.length); if (SG_DEBUG) LogE("DYNAMIC TABLE="+this.bDynamicTable); this.title=this.xmlNode.getAttribute('title'); this.readShortcuts(); this.stopEventCallback = ( function(evt) { evt.stop(); return false; } ); // this.aColumns can differ from XML column description this.aColumns=[]; // clear selected rows this.aSelectedData=[]; this.oSelectedRows=new Object(); this.selectedRowCount=0; this.oCV=new Object(); // ----------------------- // colCount is always equal to datafeeder column count! this.colCount = 0; if (!aHeader) aHeader = []; var realCols = 0; for (var i = 0; i < aHeader.length; ++i) { var oHCol = aHeader[i]; if(this.bDynamicTable && !oHCol["ID"]) oHCol["ID"] = oHCol["Bind"]; //LogL("hID="+oHCol["ID"]); var oCol = new SGColumn({ id: oHCol["ID"], bind: oHCol["Bind"], type: oHCol["Type"].Value(), // column type is an integer value attrs: oHCol["Attrs"] }); var aa = oCol.ID(); if (oCol.ID() != "") { oCol.SetOrder(realCols); realCols ++; } else oCol.SetOrder(-1); oCol.SetHeaderID(i); this.aColumns.push(oCol); ++this.colCount; } // Колонки у которых нет сортировки ставим в конец for (var i = 0; i < this.aColumns.length; i++) if (this.aColumns[i].Order() < 0) this.aColumns[i].SetOrder(realCols++); // set initial visibility and DataList indexes var xCol = this.xmlNode.firstChild; while (xCol) { if (typeof(xCol.getAttribute) == 'undefined') { xCol = xCol.nextSibling; continue; } var sID = xCol.getAttribute('id'); var vis = xCol.getAttribute('visibility'); var ord = xCol.getAttribute('order'); var title = xCol.getAttribute('title'); var bFound=false; for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); if (this.LocalID()+'.'+oCol.ID() == sID) { if (vis) oCol.SetVisibility(vis); if (ord) oCol.SetOrder(ord); oCol.SetDynamic(false); // set column's index that it has in DataList xCol.setAttribute('dataListIndex', i); // set title if not set (case happens after custmization on dynamic columns) if (!xCol.getAttribute('title')) { console.log('set title', oCol.BindID()); xCol.setAttribute('title', oCol.BindID()); } bFound=true; break; } } if (!bFound) { // phantom column (not found in DataList) xCol.setAttribute('dataListIndex', -1); xCol.setAttribute('phantom', 'yes'); } xCol = xCol.nextSibling; } this.addDynamicColumns(); this.updateColOrder(); this.oPWOItems={}; this.colFilterPWO=[]; this.oColSort = new ColSort(); this.aSortOrder = new Array(); this.bFiltersActive = false; this.bSortActive = false; this.body = $(this.ID()+'_xB'); this.renderTable(); this.readColXMLWidths(); this.setColumnOrder(); this.updateColHeaderOrder(); // порядок заголовков колонок в зависимости от order this.UpdateRowCount(); this.titleSpan=$(this.ID()+'_xT'); this.contentDiv = $(this.ID()+'_xDD'); this.contentTbl = $(this.ID()+'_xDT'); this.eDropFilters = $(this.ID()+'_xDropF'); this.eDropFiltersP = $(this.ID()+'_xDropFP'); this.eFilters = $(this.ID()+'_xFilters'); this.eDropSort = $(this.ID()+'_xDropS'); this.header=$(this.ID()+'_xHeader'); this.headerDiv=$(this.ID()+'_xHeaderDiv'); this.rowHeight=16; this.canvasHeight=$(element).offsetHeight; this.minColWidth=this.getNumericAttribute('et-min-col-width',80); this.maxRows=this.getNumericAttribute('et-max-rows',0); // 0 - no limit if (this.maxRows>0) { // maxRows<0 is a nonsense var max=this.rowCount; if (max>this.maxRows) max=this.maxRows; this.canvasHeight=max*this.rowHeight; } else { if (this.canvasHeight= 0; i--) { var col = $(this.ID() + '_xH' + cols[i]); col.parentNode.insertBefore(col, colLast); colLast = col; var colFilter = $(this.ID() + '_xFC' + cols[i]); colFilter.parentNode.insertBefore(colFilter, colFilterLast); colFilterLast = colFilter; } // Ширина колонок this.writeColXMLWidths(); }, moveColumnToPosition: function () { var headerID = this.MovingIndex; var Order = this.getColumnByHeaderID(headerID).Order(); var newpos = this.MovingNewIndex; var cols = []; for (var i = 0; i < this.aColumns.length; i++) { cols[this.aColumns[i].Order()] = this.aColumns[i].HeaderID(); } // Определяем позиции с учетом видимости колонок var elem_XML = cols.indexOf(headerID); var newpos_XML = 0; if (newpos >= this.visibleColumnCount) newpos_XML = this.aColXMLOrder.indexOf (this.aColOrder[this.visibleColumnCount - 1]) + 1; else var newpos_XML = this.aColXMLOrder.indexOf (this.aColOrder[newpos]); if (newpos_XML < 0) newpos_XML = this.aColXMLOrder.length; var a = cols[elem_XML]; cols.splice (elem_XML,1); if (elem_XML < newpos_XML) newpos_XML--; cols.splice(newpos_XML, 0, a); for (var i = 0; i < cols.length; i++) { this.aColumns[cols[i]].SetOrder(i); } }, MoveArrowOnPosition:function () { var position = this.MovingNewIndex; if (position < 0 || position > this.colCount) return; var ARROW_SIZE = 16; var arrow = $(this.ID()+'_xMoveArrow'); arrow.setStyle({display: 'block'}); // Расположение стрелки по высоте var title = $(this.ID()+'_xT'); var titleH = $(this.ID()+'_xHeaderDiv'); var ht = title.offsetHeight + titleH.offsetHeight - ARROW_SIZE / 2; arrow.setStyle({top: ht + 'px'}); arrow.setStyle({left: this.ColumnWidths[position] - ARROW_SIZE / 2 + 'px'}); }, HideMoveArrow:function () { var arrow = $(this.ID()+'_xMoveArrow'); arrow.setStyle({display: 'none'}); }, HideMoveColumn:function () { var col = $(this.ID()+'_xColumnMoving'); col.setStyle({display: 'none'}); }, // fast versions of Event.observe (speeds-up all execept IE) observe: function(ele, sEventName, fHandler) { if (Prototype.Browser.IE) ele.observe(sEventName, fHandler); else ele.addEventListener(sEventName, fHandler, false); }, observeStop: function(ele, sEventName) { if (Prototype.Browser.IE) ele.observe(sEventName, this.stopEventCallback); else ele.addEventListener(sEventName, this.stopEventCallback, false); }, readShortcuts: function() { // read shortcuts this.aShortcuts=[]; this.aShortcutLetters=[]; var shortCuts=this.xmlNode.getAttribute('shortcut'); if (!shortCuts) return; var aSh=shortCuts.split(' '); for (var i=0; i'; sW+=' 2) LogL("SG::SaveCustomization: Success"); }, SaveCustomizationErrorCallback: function(sMessage, nErrorCode) { this.handleException("SaveCustomization", sMessage, nErrorCode); }, ReadCustomization: function() { if (SG_DEBUG) LogE("SG::ReadCustomization started..."); var lcr=parseInt(this.xmlNode.getAttribute('et-current-row'), 10); if (!lcr || isNaN(lcr)) lcr=0; this.lastCurrentRow=lcr; //LogE("GENERIC CUSTOMIZATION (static table)"); var aSort = []; bFiltersActive = false; for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); if (!oCol.ID()) continue; // unreferenced column var elHeader = $(this.ID()+'_xH'+i); // read filters var sFilter = elHeader.readAttribute('et-filter'); if (!sFilter) sFilter = ""; if (sFilter) bFiltersActive = true; var oRawFilter=(sFilter ? URLRestore(sFilter) : undefined); this.aColumns[i].SetFilterValue(oRawFilter); // *** this.getColumnByHeaderID(i).SetFilterValue(oRawFilter); // read sorting data var sSort = elHeader.readAttribute('et-sort'); if (!sSort) sSort = "0"; var nSI = parseInt(sSort); if (!nSI) nSI = 0; aSort.push(nSI); } this.oColSort.Set(aSort); // prepare values this.updateFilterValues(!bFiltersActive); // nothing to update if no filters this.aSortOrder = this.oColSort.Get(); // it is necessary to update aSortOrder before further processing // run sequence this.currentActionSequence=[SG_CA_FSRP]; this.ProcessActions(); }, // processes current action ProcessActions: function() { if (!this.currentActionSequence.length) { if (SG_DEBUG) LogE("ProcessActions(): Action sequence is empty, setting state to SG_CA_IDLE"); this.StopWait(); return; } var nAction=this.currentActionSequence.shift(); if (nAction == SG_CA_REFRESH) { this.Wait(); this.doRefresh(); } else if (nAction==SG_CA_FSRP || nAction==SG_CA_FRP || nAction==SG_CA_SP) { this.Wait(); this.doFSRP(nAction); } }, doFSRP: function(nSequence) { if (!this.oDataSource) return; if (this.Died()) return; this.ClearFetchCache(); var first=this.firstRow; // default value // to avoid immediate cache request, we reserve full cache-size (plus 1 row at beginning & 1 row at end) var rowNum=1+3*this.prefetchSize+1; if (!this.bFirstFetchDone && this.lastCurrentRow) { this.sS={ firstRow: this.lastCurrentRow-this.prefetchSize-1, currentRow: this.lastCurrentRow, delta: 0 } this.bFirstFetchDone=true; first=this.sS.firstRow; //LogE("doFSRP: FIRST PASS, nSequence="+nSequence); } else { if (this.sS && this.sS.delta>=0) { first=this.sS.currentRow-this.sS.delta-this.prefetchSize-1; //LogL("doFSRP: not a first pass, first is SET FROM sS: "+first); } //LogE("doFSRP: Not a first pass..., nSequence="+nSequence); } var oParams={ first: first, rowNum: rowNum, sequence: nSequence, bFiltersActive: this.bFiltersActive, action: SG_FT_NEW, invoker: "doFSRP" }; if (nSequence==SG_CA_FSRP) { oParams.Filters=this.oFilters; oParams.SortOrder=this.aSortOrder; // filters presence is already set above oParams.bSort=true; oParams.rowNum=rowNum;//null; oParams.FixOverflow=true; } else if (nSequence==SG_CA_FRP) { oParams.Filters=this.oFilters; oParams.SortOrder=this.aSortOrder; oParams.bSort=true; oParams.rowNum=rowNum; oParams.FixOverflow=true; } else if (nSequence==SG_CA_SP) { oParams.bSort=true; oParams.rowNum=rowNum; oParams.SortOrder=this.aSortOrder; } //LogE("oParams="); //showObject(oParams); //LogE("oParams.Filters="); //showObject(oParams.Filters); this.AddFetchRequest(oParams); }, OnColMouseDown: function(sMode, nIndex, evt) { var bRelMode = (evt.isRightClick() || evt.ctrlKey); if (!evt.isLeftClick() && !bRelMode) return; if (sMode == 'colResize' && !this.colResizeStarted) { this.mouseUpHandler = this.OnColMouseUp.bind(this); this.mouseMoveHandler = this.OnColMouseMove.bind(this); $(document).observe('mouseup', this.mouseUpHandler) $(document).observe('mousemove', this.mouseMoveHandler); $(document).observe('dragstart', this.stopEventCallback); $(document).observe('selectstart', this.stopEventCallback); $(document).observe('contextmenu', this.stopEventCallback); this.initializeColumnResize(evt.pointerX(), nIndex, bRelMode); this.colResizeStarted = true; } this.stopMouseDown(evt); }, OnColMouseMove: function(evt) { var newX = evt.pointerX(); if (this.colResizeStarted) { this.widthDelta = newX - this.dragX; this.updateColWidths(); } evt.stop(); }, initializeColumnResize: function(dragX, nIndex, bRelMode) { this.dragX = dragX; this.widthDelta = 0; this.colResizeIndex = nIndex; var nOrderedIndex = this.aColumns[nIndex].Order(); // *** var nOrderedIndex = this.getColumnByHeaderID(nIndex).Order(); var leftSum = 0; var rightSum = 0; for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); var w = 0; if (oCol.ID() && oCol.Visibility() != SG_VISIBILITY_NO) { var elCol = $(this.ID()+'_xH'+i); w = elCol.offsetWidth; } oCol.SetInitialWidth(w); var oi = oCol.Order(); if (oi < nOrderedIndex) leftSum += w; else rightSum += w; } if (bRelMode) { //LogL("leftSum: "+leftSum+", rightSum: "+rightSum); this.colResizeLeftSum = leftSum; this.colResizeRightSum = rightSum; } this.colResizeRelative = bRelMode; }, updateSortFilterKeys: function(i, vi) { var eFIP=$(this.ID()+'_xFIP'+i); if (vi<10) eFIP.setAttribute('title', "`Filter (Alt+"+vi+")`"); else eFIP.setAttribute('title', "`Filter`"); var eSIP=$(this.ID()+'_xSIP'+i); if (vi<10) eSIP.setAttribute('title', "`Sort ("+vi+") / Multi-sort (Ctrl+"+vi+")`"); else eSIP.setAttribute('title', "`Sort / Multi-sort`"); }, updateColWidths: function() { var aW = []; var wd=this.widthDelta; var ori = this.getColumnByHeaderID(this.colResizeIndex).Order(); // порядок сортировки колонки, которую двигаем var Iori = this.aColOrder.indexOf (this.colResizeIndex); // индекс в массиве сортировки видимых колонок var oril=-1; // negative index means column not found if (ori > 0) oril = Iori - 1; //this.aColOrder[Iori - 1]; // count visible columns var lvc = oril; var rvc = this.visibleColumnCount-oril; var ri = this.getColumnHeaderIDByOrder(ori); var ril=this.aColOrder[oril]; if (this.colResizeRelative) { var lS = this.colResizeLeftSum; var rS = this.colResizeRightSum; if (oril >= 0) { // can resize if (lS+wd < lvc*SG_MIN_COLUMN_WIDTH) { wd = lvc*SG_MIN_COLUMN_WIDTH-lS; } if (rS-wd < rvc*SG_MIN_COLUMN_WIDTH) { // correct only if absolute shift value is less than previous if ( Math.abs(rS-rvc*SG_MIN_COLUMN_WIDTH) < Math.abs(wd)) { wd = rS-rvc*SG_MIN_COLUMN_WIDTH; } } for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); var oi = oCol.Order(); if (oi < ori) aW[i]=oCol.InitialWidth()*(lS+wd)/lS; else aW[i]=oCol.InitialWidth()*(rS-wd)/rS; } } } else { for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); aW[i]=oCol.InitialWidth(); } if (oril >= 0) { // can resize if (aW[ril]+wd < SG_MIN_COLUMN_WIDTH) { wd = SG_MIN_COLUMN_WIDTH-aW[ril]; } if (aW[ri]-wd < SG_MIN_COLUMN_WIDTH) { // correct only if absolute shift value is less than previous if ( Math.abs(aW[ri]-SG_MIN_COLUMN_WIDTH) < Math.abs(wd) ) { wd = aW[ri]-SG_MIN_COLUMN_WIDTH; } } aW[ril]+=wd; aW[ri]-=wd; } } // width correction for stupid IE and Chrome var boundingWidth = $(this.ID()+'_xHB').offsetWidth-1; if (Prototype.Browser.WebKit) { // Probably, the root of all evil is border width counting boundingWidth--; } var sum = 0; for (var i = 0; i < this.colCount; ++i) sum += aW[i]; if (sum > boundingWidth) { if (sum % 2) { aW[ril]--; sum--; } // make delta even aW[ril]-=((sum-boundingWidth)/2); aW[ri]-=((sum-boundingWidth)/2); } this.totalWidth=boundingWidth; // store calculated total width for Customization saving var elCG = $(this.ID()+'_xCGH'); var elCGD = $(this.ID()+'_xCGD'); var elCGC = elCG.firstDescendant(); var elCGDC = elCGD.firstDescendant(); // visible columns //LogL("vcc="+this.visibleColumnCount); for (var oi = 0; oi < this.visibleColumnCount; ++oi) { var i = this.aColOrder[oi]; var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); var w = aW[i]; oCol.SetCustomWidth(w); if (Prototype.Browser.IE) { // indeed, only IE <= 7 needs normalization w = 100*w/boundingWidth; elCGC.writeAttribute('width', w+'%'); elCGDC.writeAttribute('width', w+'%'); } else { elCGC.writeAttribute('width', w); elCGDC.writeAttribute('width', w); } elCGC=elCGC.next(); elCGDC=elCGDC.next(); } // invisible columns for (var oi = this.visibleColumnCount; oi < this.colCount; ++oi) { var i = this.aColOrder[oi]; var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); oCol.SetCustomWidth(0); } }, OnColMouseUp: function(evt) { var bRelMode = (evt.isRightClick() || evt.ctrlKey); if (!evt.isLeftClick() && !bRelMode) return; if (this.colResizeStarted) { this.updateColWidths(); this.colResizeStarted = false; for (var oi = 0; oi < this.visibleColumnCount; ++oi) { var i = this.aColOrder[oi]; var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); var w = 100*oCol.CustomWidth()/this.totalWidth; // norm widths to 100% oCol.SetWidth(w); } this.SaveCustomization({"Width": true}); } $(document).stopObserving('mousemove', this.mouseMoveHandler); $(document).stopObserving('mouseup', this.mouseUpHandler); $(document).stopObserving('dragstart', this.stopEventCallback); $(document).stopObserving('selectstart', this.stopEventCallback); $(document).stopObserving('contextmenu', this.stopEventCallback); this.mouseMoveHandler = null; this.mouseUpHandler = null; evt.stop(); }, OnResize: function(evt) { if (SG_DEBUG) LogE("SG OnResize() CALLED"); if (this.maxRows>0) { // maxRows<=0 is a nonsense var max=this.rowCount; if (max>this.maxRows) max=this.maxRows; this.canvasHeight=max*this.rowHeight; } else { var frameDiv; var frameTable; var frameRow; var aAncestors=$(this.contentDiv).ancestors(); for (var i=0; i0) this.canvasHeight-=delta; // padding correction inside grid row if (SG_DEBUG) LogL("$$"+this.ID()+"$$:" +" limit="+limit +" fixedFrameHeight="+fixedFrameHeight +" frameHeight="+frameHeight +" fixedTableHeight="+fixedTableHeight +" contentHeight="+contentHeight +" delta="+delta +" tableHeight="+tableHeight); // please do not contract to very small height (3 rows min) if (this.canvasHeight 0 && hiddenRowsUp-this.firstRow<=0) { this.AddFetchRequest({ first: this.firstRow-this.prefetchSize, action: SG_FT_UP, invoker: "DragUp" }); bFarMove = true; } if (hiddenRowsDown > 0 && hiddenRowsDown+this.lastRow-this.rowCount<=0) { this.AddFetchRequest({ first: this.lastRow, action: SG_FT_DOWN, invoker: "DragDown" }); bFarMove = true; } } this.scrollContent(top, "Drag"); if (bFarMove) { if (SG_DEBUG) LogE("Drag: FAR MOVE, no current row adjusting"); } else { this.AdjustCurrentRow("Drag"); } if (SG_DEBUG) LogL("Drag(): END!"); }, AdjustCurrentRow: function(sOperation) { var top=this.scrollDiv.scrollTop; var minVisibleIndex=Math.ceil(top/this.rowHeight); var maxVisibleIndex=Math.floor((top+this.canvasHeight)/this.rowHeight)-1; if (SG_DEBUG) { LogL("AdjustCurrentRow [$$"+sOperation+"$$]: "+ " top="+top+ " minVisibleIndex="+minVisibleIndex+ " maxVisibleIndex="+maxVisibleIndex+ " currentRow="+this.currentRow+ " first="+this.firstRow+ " last="+this.lastRow); } if (this.currentRow < minVisibleIndex) { if (SG_DEBUG) LogL("AdjustCurrentRow(): Refocusing to top"); this.Refocus(minVisibleIndex); } else if (this.currentRow > maxVisibleIndex) { if (SG_DEBUG) LogL("AdjustCurrentRow(): Refocusing to bottom"); this.Refocus(maxVisibleIndex); } else { if (SG_DEBUG) LogE("AdjustCurrentRow(): NO refocusing: "); } }, AdjustCurrentRowSimple: function(sOperation) { var top=this.scrollDiv.scrollTop; var minVisibleIndex=Math.ceil(top/this.rowHeight); var maxVisibleIndex=Math.floor((top+this.canvasHeight)/this.rowHeight)-1; if (SG_DEBUG) { LogL("AdjustCurrentRowSimple [$$"+sOperation+"$$]: "+ " top="+top+ " minVisibleIndex="+minVisibleIndex+ " maxVisibleIndex="+maxVisibleIndex+ " currentRow="+this.currentRow+ " first="+this.firstRow+ " last="+this.lastRow); } if (this.currentRow < minVisibleIndex) { this.currentRow=minVisibleIndex; if (SG_DEBUG) LogL("AdjustCurrentRowSimple() [MIN]: setting new currentRow="+minVisibleIndex); //this.Refocus(minVisibleIndex); } else if (this.currentRow > maxVisibleIndex) { if (SG_DEBUG) LogL("AdjustCurrentRowSimple() [MAX]: setting new currentRow="+maxVisibleIndex); this.currentRow=maxVisibleIndex; //this.Refocus(maxVisibleIndex); } else { if (SG_DEBUG) LogE("AdjustCurrentRowSimple(): NO currentRow changes. "); } }, HandleCache: function() { // if new data request is in progress, cancel this operation if (this.newData) { if (SG_DEBUG) LogE("HandleCache itself CANCELLED - new data request is in progress... "); return; } // if another fetch is in progress, cancel this operation if (this.currentRequest) { if (SG_DEBUG) LogE("HandleCache itself CANCELLED - another main request is in progress..."); return; } var top=this.scrollDiv.scrollTop; var hiddenRowsUp=top/this.rowHeight; var hiddenRowsDown=(this.scrollHeight-(top+this.canvasHeight))/this.rowHeight; if (SG_DEBUG) { LogL("HandleCache: "); if (SG_DEBUG > 4) LogL("rowHeight="+this.rowHeight+", scrollHeight="+this.scrollHeight+", canvasHeight="+this.canvasHeight); LogL("top="+top+", hUP="+hiddenRowsUp+", hDOWN="+hiddenRowsDown+", firstRow="+this.firstRow+", lastRow="+this.lastRow); } while (hiddenRowsUp-this.firstRow>this.prefetchSize*2) { //if (SG_DEBUG) LogL("HandleCache -> FreeUp"); if (this.FreeUp(this.prefetchSize)) this.scrollContent(top, "HandleCache -> FreeUp"); else break; } if (hiddenRowsUp-this.firstRow<=this.prefetchSize && this.firstRow>0) { this.AddFetchRequest({ first: this.firstRow-this.prefetchSize, action: SG_FT_UP, invoker: "HandleCacheUp", cache: true }); } if (hiddenRowsDown+this.lastRow-this.rowCount<=this.prefetchSize && this.lastRowthis.prefetchSize*2) { //if (SG_DEBUG) LogL("HandleCache -> FreeDown"); if (this.FreeDown(this.prefetchSize)) this.scrollContent(top, "HandleCache -> FreeDown"); else break; } }, scrollContent: function(nPos, sRef) { var newScrollTop = nPos-this.firstRow*this.rowHeight; if (this.contentDiv.scrollTop == newScrollTop) return; if (SG_DEBUG) LogL("scrollContent(): "+ " nPos="+nPos+ " firstRow="+this.firstRow+ " scrollDiv="+this.scrollDiv.scrollTop+ " contentDiv="+this.contentDiv.scrollTop); this.contentDiv.scrollTop=newScrollTop; if (SG_DEBUG) LogE("scrollContent(): new scrollTop="+newScrollTop); }, scroll: function(nPos, sRef) { if (SG_DEBUG) LogE("scroll("+nPos+") in "+sRef); this.scrollDiv.scrollTop=nPos; }, adjustScrollHeight: function() { //LogL("adjustScrollHeight CALLED"); var newScrollHeight=this.rowHeight*this.rowCount; if (newScrollHeight != this.scrollHeight) { this.scrollHeight=newScrollHeight; if (this.scrollDiv.scrollTop > this.scrollHeight) this.scrollDiv.scrollTop=this.scrollHeight; if (this.contentDiv.scrollTop > this.scrollHeight) this.contentDiv.scrollTop=this.scrollHeight; if (this.spreaderDiv) this.spreaderDiv.setStyle({height: this.scrollHeight+'px'}); } else { if (SG_DEBUG) LogL("adjustScrollHeight: ScrollHeight adjust skipped. "); } }, adjustScrollWidth: function() { var w=this.contentDiv.offsetWidth; //LogL("this.root.offsetWidth="+this.root.offsetWidth); //LogL("w="+w); //LogL("this.vcc="+this.visibleColumnCount); var edt=$(this.ID()+'_xDT'); var ect=$(this.ID()+'_xHeader'); var edw=$(this.ID()+'_xDW'); if (this.visibleColumnCount && w/this.visibleColumnCount'; var sW=''; } var sW=''; var cvDoc=new AXML(); cvDoc.Parse(sW); var oXML=cvDoc.XML(); var oTransformResult=this.transform(oXML); var eUL=$(id+'_UL'); if (eUL) { eUL.replace(oTransformResult); } if (this.oCV.oJSControl) delete this.oCV.oJSControl; var jsControl=new MenuButton(id); this.oCV.oJSControl=jsControl; var aVis=[]; var xmlColCount=this.aColXMLOrder.length; for (var xoi=0; xoi=0; --ro) { if(ro+first>=this.firstRow) continue; var eRefRow = (this.contentTbl.rows.length) ? this.contentTbl.rows[0] : null; body.insertBefore(rows[ro], eRefRow); this.aSelectedData.unshift(this.isRowSelected(rawData[ro])); this.data.unshift(rawData[ro]); this.firstRow--; count++; } if (SG_DEBUG) LogL("Appeneded: "+count+" rows, got datalen="+this.data.length); this.scrollContent(this.scrollDiv.scrollTop, "AppendUp"); }, RenderData: function() { var oTable=this.makeXMLTable(this.firstRow); var tblDOM = oTable.tblDOM; var xData = oTable.xData; var xR = oTable.xR; var aStyle=oTable.aStyle; // -------------------------------------------- var dataLen = this.data.length; for(var r=0; r < dataLen; ++r) { var row=createElementAI(tblDOM, "r"); xData.appendChild(row); var dataRow = this.data[r]; var ordValues=[]; for(var c=0; c 5) LogL("XML="+tblDOM.xml); var oTransformResult=this.transform(tblDOM); this.RedrawData(oTransformResult); this.UpdateCurrentRow(); }, RedrawData: function(dataTable) { var rows = this.DataRows(dataTable); var body=this.ContentBody(); for(var ro=0; ro 4) LogE("SCROLL STATE [$$ StartNewRequest $$]: "+ " scrollDiv="+this.sS.scrollDiv+ " contentDiv="+this.sS.contentDiv+ //" contentDivHeight="+this.sS.contentDivHeight+ " firstRow="+this.sS.firstRow+ " lastRow="+this.sS.lastRow+ " currentRow="+this.sS.currentRow+ " hiddenRowsUp="+hiddenRowsUp+ " delta="+this.sS.delta ); this.newData = true; // newData flag must be dropped in the end of UpdateData(action:SG_FT_NEW) sequence this.requestID++; if (this.cacheTimer) { // turn off HandleCache timer clearTimeout(this.cacheTimer); this.cacheTimer=null; } if (this.requestTimer) { clearTimeout(this.requestTimer); this.requestTimer=null; } if (this.queuedRequest) this.queuedRequest=null; return true; }, Refresh: function() { if (!this.StartNewRequest("Refresh")) return false; if (SG_DEBUG) LogL("Refresh started"); // clear selected rows this.oSelectedRows=new Object(); this.selectedRowCount=0; this.aSelectedData=[]; this.currentActionSequence=[SG_CA_REFRESH, SG_CA_FSRP]; this.ProcessActions(); return true; }, doRefresh: function() { if (!this.oDataSource) return; // do nothing when datasource was not initialized var oP = this.oDataSource.Params(); new ServerCall(this.oDataSource.CallURL()+'@raw', oP, { onSuccess: this.RefreshCallback, onException: this.RefreshErrorCallback, thisObject: this }); }, RefreshCallback: function(oPacket) { // we get only feeder here // TODO: if our datasource was not initialized, obtain it now and reinitialize headers if (SG_DEBUG) LogL("RefreshCallback() called. "); var oData=oPacket.Data(); var oDS=oData["DataSource"]; if (SG_DEBUG) LogL("RefreshCallback(): Got new feeder: "+oDS.Feeder()); this.oDataSource.SetFeeder(oDS.Feeder()); this.fullRowCount=oDS.RowCount(); // obtain new row count if (SG_DEBUG > 4) LogE("SCROLL STATE [$$ RefreshCallback $$]: "+ " scrollDiv="+this.scrollDiv.scrollTop+ " contentDiv="+this.contentDiv.scrollTop+ " firstRow="+this.firstRow+ " lastRow="+this.lastRow+ " currentRow="+this.currentRow); this.ProcessActions(); }, FetchCallback: function(oFR, oPacket) { if (this.Died()) return; if (SG_DEBUG) LogL("[$$"+oFR.requestID+"/"+oFR.requestCounter+"$$] FetchCallback."); if (oFR.requestID < this.requestID) { LogE("Cancelling obsolete request! "); if (oFR.cache) { // terminate current cache request this.currentCacheRequest[oFR.action] = null; } else { // TODO: ?????? } this.FinalizeRequest(oFR); return; } var oData=oPacket.Data(); if (oFR.sequence==SG_CA_FSRP || oFR.sequence==SG_CA_FRP || oFR.sequence==SG_CA_SP) { // special case var data; if (oFR.bFiltersActive || oFR.bSort || oFR.FixOverflow) { // rowCount should be defined here, by DataFeeder logic this.rowCount=oData["RowCount"].Value(); if (typeof(oData["FirstRow"])!='undefined') { var fixedFirstRow=oData["FirstRow"].Value(); // fixOverflow in action, fix state oFR.first=fixedFirstRow; // should we fix this.firstRow here? // it seems it's not necessary for new requests //LogE("FixOverflow!!!!!!!!!!!!!!!!!!!!!!!"); } data=oData["Data"]; //LogE("rowCount updated: "+this.rowCount); } else { this.rowCount=this.fullRowCount; data=oData; //LogE("rowCount restored: "+this.rowCount); } if (oFR.rowNum>this.rowCount) { oFR.rowNum=this.rowCount; // we cannot fetch more than row count } if (this.firstRow >= this.rowCount) this.firstRow=this.rowCount-1; if (this.lastRow > this.rowCount) this.lastRow=this.rowCount; if (this.currentRow >= this.rowCount) this.currentRow=this.rowCount-1; if (this.maxRows>0) this.OnResize(); else this.adjustScrollHeight(); this.UpdateRowCount(); //LogE("oFR="); //showObject(oFR); if (SG_DEBUG) LogL("FetchCallback():"+ " rowCount="+this.rowCount+ " firstRow="+this.firstRow+ " lastRow="+this.lastRow); // this will behave strange - on filter this will reset to first row :( //if (first<0) first=0; //if (first>=this.rowCount) first=this.rowCount-this.prefetchSize; this.UpdateData(oFR, data); } else { // old-way data updating this.UpdateData(oFR, oData); } }, // Column order changes when changes DF/visibility/cust.col.order. // Column visibility should be updated before. // Updates aColOrder and aColXMLOrder arrays. updateColOrder: function() { var xCol = this.xmlNode.firstChild; var nOrder = 0; //for (var i = 0; i < this.colCount; ++i) // this.aColumns[i].SetOrder(-1); var aOrder = []; var aXMLOrder = []; // column order in XML (ignoring visibility state) var aActions=[]; while (xCol) { if (typeof(xCol.getAttribute) == 'undefined') { xCol = xCol.nextSibling; continue; } var bActive=(xCol.getAttribute('handle')=='CLICK'); var sID = xCol.getAttribute('id'); for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; if (this.LocalID()+'.'+oCol.ID() == sID) { // column found aXMLOrder.push(i); // keep XML coherent with current column state xCol.setAttribute('visibility', oCol.Visibility()); if (oCol.Visibility() != SG_VISIBILITY_NO) { //LogL("Column "+oCol.ID()+" got order: "+nOrder); aOrder.push(i); aActions.push(bActive); //oCol.SetOrder(nOrder); nOrder++; } break; } } xCol = xCol.nextSibling; } this.visibleColumnCount = nOrder; // set visible column count for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; if (oCol.Visibility() == SG_VISIBILITY_NO) { //LogL("Aux Column "+oCol.ID()+" got order: "+nOrder); //oCol.SetOrder(nOrder); aOrder.push(i); nOrder++; } } this.aColOrder = aOrder; this.aColXMLOrder = aXMLOrder; // for column visibility handling this.aColActions=aActions; }, setColumnOrder: function() { var cols = []; var realCols = [] for (var i = 0; i < this.aColumns.length; i++) { cols[this.aColumns[i].Order()] = this.aColumns[i].HeaderID(); if (this.aColumns[i].ID() != "") realCols[this.aColumns[i].Order()] = this.aColumns[i].HeaderID(); } // aColXMLOrder this.aColXMLOrder = []; this.aColXMLOrder = realCols; // aColOrder this.aColOrder = []; this.visibleColumnCount = 0; var vis = []; var invis = []; var style = []; for (var i = 0; i < cols.length; i++) { if (this.aColumns[cols[i]].ID() == "") { style.push(cols[i]); continue; } if (this.aColumns[cols[i]].Visibility() == SG_VISIBILITY_YES) { vis.push (cols[i]); this.visibleColumnCount ++; } else invis.push (cols[i]); } this.aColOrder = vis.concat(invis).concat(style); }, makeXMLTable: function(nFirstRow) { var tblDoc = new AXML('ai:tbl', AIURI); var tblDOM = tblDoc.XML(); var xR = tblDOM.documentElement; xR.appendChild(this.xmlNode.cloneNode(true)); this.appendTypes(tblDOM); var xData=createElementAI(tblDOM, "data"); xData.setAttribute("firstID", nFirstRow); var aStyle=[]; for (var oi=0; oi < this.colCount; ++oi) { var i=this.aColOrder[oi]; // order index var oCol=this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); var a = oCol.Attrs(); if (a && a["GetStyleFrom"]) { var sBindID = a["GetStyleFrom"]; var nStyle = -1; for (var j = 0; j < this.colCount; ++j) { var oColS = this.aColumns[j]; // *** var oColS = this.getColumnByHeaderID(j); if (oColS.BindID() == sBindID) { nStyle = oColS.HeaderID(); break; } } if (nStyle < 0) { alert("WARNING: GetStyleFrom attribute for column '"+oCol.BindID()+ "' references unknown column '"+sBindID+"' and will be ignored."); } else { aStyle[oCol.HeaderID()]=nStyle; } } } return {"tblDOM": tblDOM, "xR": xR, "xData": xData, "aStyle": aStyle}; }, transform: function(oXML) { if (SG_DEBUG > 5) LogL("XML="+oXML.xml); var oTransformResult=new Element('div'); try { var oTransformDoc = AXML.TransformDOM(oXML, GWindowManager.XSL(), true); ApplyTreeOrString(oTransformResult, oTransformDoc); oTransformResult=oTransformResult.firstChild; // skip outer 'div' if (SG_DEBUG > 5) { LogL("TRANSFORMED.TEXT: \n"+ (oTransformDoc.documentElement) ? oTransformResult.innerHTML : oTransformResult); } } catch (exc) { alert("SG::transform failed with message: "+exc.message); } return oTransformResult; }, UpdateData: function(oFR, oRowBatch) { // TODO: implement kosher locks as setTimeout(f,0) for SetVisibility and UpdateData this.bUpdateDataLock = true; if (SG_DEBUG) { LogL("UpdateData: "+ "first="+oFR.first+ " rowNum="+oFR.rowNum+ " action="+oFR.action+ " cache="+oFR.cache+ " invoker="+oFR.invoker+ " datalen="+this.data.length); } //LogE("UpdateData: Appending started"); var oTable = this.makeXMLTable(oFR.first); var tblDOM = oTable.tblDOM; var xData = oTable.xData; var xR = oTable.xR; var aStyle=oTable.aStyle; // ----------------------------------------- var data=[]; var colTypes = []; for (var i = 0; i < this.colCount; ++i) { colTypes.push(this.aColumns[i].Type()); // *** colTypes.push (this.getColumnByHeaderID(i).Type()); } oRowBatch.SetColumnTypes(colTypes); for(var r=0; oRowBatch.Fetch(); ++r) { var row=createElementAI(tblDOM, "r"); xData.appendChild(row); var aRow=[]; var ordValues=[]; for(var c=0; c 4 ? " scrollDiv="+this.scrollDiv.scrollTop+ " contentDiv="+this.contentDiv.scrollTop/*+ " contentDivHeight="+this.contentDiv.scrollHeight*/ : "") + " firstRow="+this.firstRow+ " lastRow="+this.lastRow+ " currentRow="+this.currentRow); if (this.delayedRefocus) { if (SG_DEBUG) LogE("UpdateData: Performing delayed refocusing...."); this.scrollContent(this.scrollDiv.scrollTop, "UpdateData"); } else { this.AdjustCurrentRowSimple("UpdateData"); /*var nDI = this.currentRow - this.firstRow; var bDefined = (nDI >= 0 && nDI < this.data.length); if (bDefined) this.AdjustCurrentRow("UpdateData");*/ } if (oFR.action == SG_FT_NEW) { // UpdateSort and filter text updation can be only in case of new request this.UpdateSort(); // draw sort state var bUpdated=this.updateFilterTexts(); // filters is a new request by definition if (!this.bRowHeightCorrected) { var body=this.ContentBody(); if (body.rows && body.rows.length>0) { // please note that taking .rows[0].offsetHeight (or .scrollHeight) // gives wrong results, at least under Chrome var rc=body.rows.length; if (body.scrollHeight > 0) this.rowHeight=Math.round(body.scrollHeight/rc); //LogL("SG.rowHeight correction results: "+this.rowHeight); this.bRowHeightCorrected=true; } } if (!this.bLoaded) { // saving current row in customization //LogE("LAST_CURRENT_ROW="+this.lastCurrentRow); this.scrollDiv.scrollTop=this.lastCurrentRow*this.rowHeight; //LogE("this.scrollDiv.scrollTopVALUE="+this.lastCurrentRow*this.rowHeight); //LogE("this.scrollDiv.scrollTop="+this.scrollDiv.scrollTop); //LogE("this.scrollDiv.scrollHeight="+this.scrollDiv.scrollHeight); this.currentRow=this.lastCurrentRow; } if (!bUpdated && !this.bLoaded) { this.bLoaded=true; this.OnResize(); } if (SG_DEBUG) LogE("SG_FT_NEW: Experimental repositioning..."); this.scrollContent(this.scrollDiv.scrollTop, "UpdateData"); } // always try to update current row state and data this.UpdateCurrentRow(); this.ProcessActions(); this.FinalizeRequest(oFR); this.bUpdateDataLock = false; if (this.bDelayedSetVisibility) { //LogE("Delayed SetVisibility..."); this.bDelayedSetVisibility = false; this.setVisibility(); } if (!this.bScrollInitialized) { this.scrollDiv.observe('scroll', this.Drag.bind(this)); this.bScrollInitialized=true; } this.StopWait(); this.root.setAttribute("et-sg-initialized", "yes"); // for autotesting reasons }, FinalizeRequest: function(oFR) { if (oFR.cache) { this.currentCacheRequest[oFR.action] = null; if (SG_DEBUG) LogL("FinalizeRequest: CURRENT CACHE REQUEST IS CLEARED. Deferring ProcessFetchCacheQueue..."); this.ProcessFetchCacheQueue.bind(this, oFR.action).delay(.01); // try to process queue } else { if (this.newData && oFR.action == SG_FT_NEW) { this.newData = false; if (SG_DEBUG) LogE("NEW DATA REQUEST HAS BEEN FINISHED"); } // the end of request processing this.currentRequest = null; if (SG_DEBUG) LogL("FinalizeRequest: CURRENT REQUEST IS CLEARED. Deferring ProcessFetchQueue..."); if (oFR.action == SG_FT_NEW) { this.HandleCache(); } else { this.ProcessFetchQueue.bind(this).delay(.01); // try to process queue } } }, Fetch: function(oFR) { if (SG_DEBUG) { LogL("[$$"+oFR.requestID+"/"+oFR.requestCounter+"$$] Fetch (corrected):"+ " first="+oFR.first+ " count="+oFR.rowNum+ " action="+oFR.action+ " cache="+oFR.cache); } if (this.lastFetchFirst === oFR.first && this.lastFetchRowNum === oFR.rowNum) { if (SG_DEBUG) LogE("Fetch: Aborted (same data request). "); // as no real server call was done, we can flush timer this.ClearAbortedRequest(oFR); return; } this.lastFetchFirst = oFR.first; this.lastFetchRowNum = oFR.rowNum; // TODO: set currentRequest to null in FetchErrorCallback (if request failed) var oParams={}; oParams.FirstRow=unsigned(oFR.first); oParams.Size=unsigned(oFR.rowNum); // auxillary parameters if (typeof(oFR.Filters)!='undefined') oParams.Filters=oFR.Filters; if (typeof(oFR.SortOrder)!='undefined') oParams.SortOrder=oFR.SortOrder; if (typeof(oFR.FixOverflow)!='undefined') oParams.FixOverflow=oFR.FixOverflow; new ServerCall(this.CallURL("Pass"), oParams, { onSuccess: this.FetchCallback.bind(this, oFR), onException: this.FetchErrorCallback.bind(this, oFR), thisObject: this }); }, FreeUp: function(numRows) { var count=0; if (!this.contentTbl.rows.length) return count; if (SG_DEBUG) LogL("FreeUp:" +numRows+", tablelen="+this.contentTbl.rows.length); for (var i=0; i5) LogL("SG: OnContentMouseDown() index="+nRowIndex); if (isNaN(nRowIndex)) return; //LogE("this.bMouseSelectMode="+this.bMouseSelectMode); if (!evt.shiftKey && !evt.ctrlKey) { // pure mouse selection from one row to another // clears other selection // clear selected rows this.aSelectedData=[]; this.oSelectedRows=new Object(); this.selectedRowCount=0; this.UpdateRowCount(); //LogL("Selection cleared"); var rc = this.contentTbl.rows.length; for (var i = 0; i < rc; ++i) { var ele = $(this.contentTbl.rows[i]); ele.removeClassName('SG_ActiveRow_Single'); ele.removeClassName('SG_ActiveRow_Multiple'); ele.removeClassName('SG_SelectedRow'); ele.removeClassName('SG_SelectedRow_Even'); } var nDataIndex = nRowIndex - this.firstRow; // on selection start, we only mark clicked row as active. It should be added to selection // set only if more than one row will be selected at mouseUp. // add current row to selection //this.aSelectedData[nDataIndex]=true; //this.updateSelectedRows(nDataIndex, true); // mark current row as selected var ele = $(this.contentTbl.rows[nDataIndex]); ele.addClassName('SG_ActiveRow_Single'); // do not mark as selected rows //if (ele.hasClassName('SG_EvenRow')) ele.addClassName('SG_SelectedRow_Even'); //else ele.addClassName('SG_SelectedRow'); // store selection mode this.selectedRowStartIndex=nRowIndex; this.selectedRowCurrentIndex=nRowIndex; // current=start this.bMouseSelectMode = true; this.setFocus(); } else { this.OnSelectRow(evt, ele, nRowIndex, false); } this.Refocus(nRowIndex); return false; }, TestHMS: function() { LogE("TestHMS"); this.selectedRowStartIndex=10; this.selectedRowCurrentIndex=5; this.HandleMouseSelection(null, null, 0); LogE("================================"); this.selectedRowStartIndex=0; this.selectedRowCurrentIndex=5; this.HandleMouseSelection(null, null, 10); LogE("================================"); this.selectedRowStartIndex=5; this.selectedRowCurrentIndex=3; this.HandleMouseSelection(null, null, 10); LogE("================================"); this.selectedRowStartIndex=7; this.selectedRowCurrentIndex=10; this.HandleMouseSelection(null, null, 5); LogE("================================"); this.selectedRowStartIndex=7; this.selectedRowCurrentIndex=10; this.HandleMouseSelection(null, null, 7); LogE("================================"); this.selectedRowStartIndex=7; this.selectedRowCurrentIndex=10; this.HandleMouseSelection(null, null, 10); LogE("================================"); this.selectedRowStartIndex=5; this.selectedRowCurrentIndex=0; this.HandleMouseSelection(null, null, 3); LogE("================================"); this.selectedRowStartIndex=5; this.selectedRowCurrentIndex=10; this.HandleMouseSelection(null, null, 7); LogE("================================"); }, HandleMouseSelection: function(evt, ele, nRowIndex) { var newDir = (this.selectedRowStartIndex >= nRowIndex ? -1 : 1); var oldDir = (this.selectedRowStartIndex >= this.selectedRowCurrentIndex ? -1 : 1); //LogL("newDir="+newDir+", oldDir="+oldDir); if (newDir*oldDir < 0) { // different sides if (this.selectedRowStartIndex == nRowIndex) newDir=0; // nowhere to run for (var i = this.selectedRowStartIndex+newDir; i != nRowIndex+newDir; i += newDir) { var nCurrentDataIndex=i-this.firstRow; this.aSelectedData[nCurrentDataIndex]=true; this.updateSelectedRows(nCurrentDataIndex,true); var eleC=$(this.contentTbl.rows[nCurrentDataIndex]); eleC.removeClassName('SG_ActiveRow_Single'); eleC.removeClassName('SG_ActiveRow_Multiple'); if (eleC.hasClassName('SG_EvenRow')) eleC.addClassName('SG_SelectedRow_Even'); else eleC.addClassName('SG_SelectedRow'); //LogL("HandleMouseSelection: set "+i); } if (this.selectedRowStartIndex == this.selectedRowCurrentIndex) oldDir=0; // nowhere to run for (var i = this.selectedRowStartIndex+oldDir; i != this.selectedRowCurrentIndex+oldDir; i += oldDir) { //LogL("HandleMouseSelection: clear "+i); var nCurrentDataIndex=i-this.firstRow; this.aSelectedData[nCurrentDataIndex]=true; this.updateSelectedRows(nCurrentDataIndex,true); var eleC=$(this.contentTbl.rows[nCurrentDataIndex]); eleC.removeClassName('SG_ActiveRow_Single'); eleC.removeClassName('SG_ActiveRow_Multiple'); if (eleC.hasClassName('SG_EvenRow')) eleC.removeClassName('SG_SelectedRow_Even'); else eleC.removeClassName('SG_SelectedRow'); } } else { // same directions var moveDir = (this.selectedRowCurrentIndex >= nRowIndex ? -1 : 1); if (this.selectedRowCurrentIndex == nRowIndex) moveDir=0; //LogL("moveDir="+moveDir); var bSelected=(moveDir*newDir > 0); var sh = (bSelected ? moveDir : 0); for (var i = this.selectedRowCurrentIndex+sh; i != nRowIndex+sh; i += moveDir) { var nCurrentDataIndex=i-this.firstRow; this.aSelectedData[nCurrentDataIndex]=bSelected; this.updateSelectedRows(nCurrentDataIndex,bSelected); var eleC=$(this.contentTbl.rows[nCurrentDataIndex]); if (bSelected) { //LogL("HandleMouseSelection: mark row "+eleC.id); if (eleC.hasClassName('SG_EvenRow')) eleC.addClassName('SG_SelectedRow_Even'); else eleC.addClassName('SG_SelectedRow'); } else { if (eleC.hasClassName('SG_EvenRow')) eleC.removeClassName('SG_SelectedRow_Even'); else eleC.removeClassName('SG_SelectedRow'); } //if (bSelected) LogL("HandleMouseSelection: mark= " +i); //else LogL("HandleMouseSelection: unmark="+i); } } // update current index this.selectedRowCurrentIndex=nRowIndex; // handling of initialy clicked row var nDataIndex = this.selectedRowStartIndex - this.firstRow; if (this.selectedRowCurrentIndex==this.selectedRowStartIndex) { // only one row is selected this.aSelectedData=[]; this.oSelectedRows=new Object(); this.selectedRowCount=0; this.UpdateRowCount(); //var eleC = $(this.contentTbl.rows[nDataIndex]); //eleC.addClassName('SG_ActiveRow_Single'); } else { this.aSelectedData[nDataIndex]=true; this.updateSelectedRows(nDataIndex, true); var eleC = $(this.contentTbl.rows[nDataIndex]); //eleC.removeClassName('SG_ActiveRow_Single'); //eleC.addClassName('SG_ActiveRow_Multiple'); if (eleC.hasClassName('SG_EvenRow')) eleC.addClassName('SG_SelectedRow_Even'); else eleC.addClassName('SG_SelectedRow'); } }, OnContentMouseMove: function(event) { var evt=Event.extend(event || window.event); var ele=evt.target; while (ele && ele.nodeName!='TR') ele=ele.parentNode; if (!ele) return; ele=$(ele); var nRowIndex = parseInt(ele.id, 10); if (isNaN(nRowIndex)) return; if (SG_DEBUG>5) LogL("SG: OnContentMouseMove() index="+nRowIndex); if (!this.bMouseSelectMode) return; // not a selection mode evt.stop(); this.HandleMouseSelection(evt, ele, nRowIndex); this.Refocus(nRowIndex); return false; }, OnContentMouseUp: function(event) { if (!this.bMouseSelectMode) return; // not a selection mode var evt=Event.extend(event || window.event); var ele=evt.target; while (ele && ele.nodeName!='TR') ele=ele.parentNode; if (!ele) return; evt.stop(); ele=$(ele); if (SG_DEBUG) LogL("SG: OnContentMouseUp() index="+nRowIndex); var nRowIndex = parseInt(ele.id, 10); if (isNaN(nRowIndex)) return; this.HandleMouseSelection(evt, ele, nRowIndex); this.bMouseSelectMode=false; this.Refocus(nRowIndex); return false; }, makeDataKey: function(aRow) { var key = ""; for (var c = 0; c < this.colCount; ++c) { var val = aRow[c]; // TODO: replace | with #8 character key += (val === null ? '' : val.toString()) + '|';//String.fromCharCode(8); } return key; }, updateSelectedRows: function(nDataIndex, bAdd) { var row = this.data[nDataIndex]; var key = this.makeDataKey(row); if (bAdd) { //LogL("oSelectedRows['"+key+"] ADDED"); if (!this.oSelectedRows[key]) { this.selectedRowCount++; this.UpdateRowCount(); } this.oSelectedRows[key] = row; } else { //LogE("oSelectedRows['"+key+"] DELETED"); if (this.oSelectedRows[key]) { this.selectedRowCount--; this.UpdateRowCount(); } delete this.oSelectedRows[key]; } }, isRowSelected: function(aRow) { var key = this.makeDataKey(aRow); return !!this.oSelectedRows[key]; }, OnSelectRow: function(evt, ele, nRowIndex, bMouseSelect) { var nDataIndex = nRowIndex - this.firstRow; if (evt.ctrlKey && !evt.shiftKey && !bMouseSelect) { evt.stop(); var nCurrentDataIndex = this.currentRow-this.firstRow; if (!this.selectedRowCount) { // switching to multiple selection mode: select current row var eleC = this.contentTbl.select('tr#'+this.currentRow)[0]; if (eleC) { this.aSelectedData[nCurrentDataIndex] = true; this.updateSelectedRows(nCurrentDataIndex, true); eleC.removeClassName('SG_ActiveRow_Single'); eleC.addClassName('SG_ActiveRow_Multiple'); //LogL("mark row osr " + eleC.id); if (eleC.hasClassName('SG_EvenRow')) eleC.addClassName('SG_SelectedRow_Even'); else eleC.addClassName('SG_SelectedRow'); } else { LogE("OnSelectRow: Current row is not defined. "); } if (nDataIndex == nCurrentDataIndex) return; // when reselecting only current row, do nothing } var bSelected = !this.aSelectedData[nDataIndex]; // get inverted selection state this.aSelectedData[nDataIndex] = bSelected; // invert this.updateSelectedRows(nDataIndex, bSelected); if (!this.selectedRowCount) { // updated count var eleC = this.contentTbl.select('tr#'+this.currentRow)[0]; if (eleC) { eleC.removeClassName('SG_ActiveRow_Multiple'); if (eleC.hasClassName('SG_EvenRow')) eleC.removeClassName('SG_SelectedRow_Even'); else eleC.removeClassName('SG_SelectedRow'); } ele.removeClassName('SG_ActiveRow_Multiple'); ele.removeClassName('SG_SelectedRow'); ele.removeClassName('SG_SelectedRow_Even'); ele.addClassName('SG_ActiveRow_Single'); } else { if (bSelected) { if (ele.hasClassName('SG_EvenRow')) ele.addClassName('SG_SelectedRow_Even'); else ele.addClassName('SG_SelectedRow'); } else { if (ele.hasClassName('SG_EvenRow')) ele.removeClassName('SG_SelectedRow_Even'); else ele.removeClassName('SG_SelectedRow'); } } return; } // selection with ctrl else if (evt.shiftKey || bMouseSelect) { evt.stop(); var curRow = (bMouseSelect ? this.selectedRowStartIndex : this.currentRow); var bUp = (nRowIndex <= curRow); if (bMouseSelect) { var ele = this.contentTbl.select('tr#'+this.currentRow)[0]; ele.removeClassName('SG_ActiveRow_Multiple'); ele.removeClassName('SG_ActiveRow_Single'); } var eleC = this.contentTbl.select('tr#'+curRow)[0]; // TODO: check current row existance var bSelected = !evt.ctrlKey; var nCurrentDataIndex = curRow-this.firstRow; if (!this.selectedRowCount) { // switching to multiple selection mode: select current row if (eleC) { this.aSelectedData[nCurrentDataIndex] = true; this.updateSelectedRows(nCurrentDataIndex, true); eleC.removeClassName('SG_ActiveRow_Single'); eleC.addClassName('SG_ActiveRow_Multiple'); if (eleC.hasClassName('SG_EvenRow')) eleC.addClassName('SG_SelectedRow_Even'); else eleC.addClassName('SG_SelectedRow'); } else { LogE("OnSelectRow: Current row is not defined. "); } if (nDataIndex == nCurrentDataIndex) return; // when reselecting only current row, do nothing } //LogL(nDataIndex+", "+nCurrentDataIndex); while (eleC) { var nCID = parseInt(eleC.id, 10); if (isNaN(nCID)) break; var nCurrentDataIndex = nCID - this.firstRow; this.aSelectedData[nCurrentDataIndex] = bSelected; // set selection this.updateSelectedRows(nCurrentDataIndex, bSelected); if (bSelected) { if (eleC.hasClassName('SG_EvenRow')) eleC.addClassName('SG_SelectedRow_Even'); else eleC.addClassName('SG_SelectedRow'); } else { if (eleC.hasClassName('SG_EvenRow')) eleC.removeClassName('SG_SelectedRow_Even'); else eleC.removeClassName('SG_SelectedRow'); } if (nCID == nRowIndex) break; eleC = ( bUp ? eleC.previous() : eleC.next() ); } if (!this.selectedRowCount) { // updated count var eleC = this.contentTbl.select('tr#'+curRow)[0]; if (eleC) { eleC.removeClassName('SG_ActiveRow_Single'); eleC.removeClassName('SG_ActiveRow_Multiple'); if (eleC.hasClassName('SG_EvenRow')) eleC.removeClassName('SG_SelectedRow_Even'); else eleC.removeClassName('SG_SelectedRow'); } ele.removeClassName('SG_ActiveRow_Multiple'); ele.removeClassName('SG_SelectedRow'); ele.removeClassName('SG_SelectedRow_Even'); ele.addClassName('SG_ActiveRow_Single'); } return; } // selection with shift else { // clear all selection var eleC = this.contentTbl.rows[0]; this.oSelectedRows = new Object(); // empty selected rows while (eleC) { var nCID = parseInt(eleC.id, 10); if (isNaN(nCID)) break; var nCurrentDataIndex = nCID - this.firstRow; this.aSelectedData[nCurrentDataIndex] = false; eleC.removeClassName('SG_ActiveRow_Multiple'); eleC.removeClassName('SG_ActiveRow_Single'); if (eleC.hasClassName('SG_EvenRow')) eleC.removeClassName('SG_SelectedRow_Even'); else eleC.removeClassName('SG_SelectedRow'); eleC = eleC.next(); } this.selectedRowCount=0; this.UpdateRowCount(); } }, // client refresh (evt is a browser event) OnRefresh: function(evt) { //LogL("SG::OnRefresh!"); this.Refresh(); }, OnWMRefresh: function(oEvent) { var data=oEvent.Data(); if (!data['id']) return; // this is a refresh event for window var sLocalID=data['id']; if (SG_DEBUG > 3) LogL("OnWMRefresh: sLocalID="+sLocalID+", LocalID="+this.LocalID()); if (sLocalID != this.LocalID()) return; // this is a refresh event for another control if (this.canRefresh) { this.Refresh(); } else { alert("`Table refresh disabled, it should be re-filled with new data. `"); } }, // stops event and hides (if necessary) column visibility menu stopMouseDown: function(evt) { evt.stop(); if (this.oCV.oJSControl) { var cvMenu=this.oCV.oJSControl; if (cvMenu.menuObj) cvMenu.menuObj.Hide(); } }, readColXMLWidths: function () { var elCG = $(this.ID()+'_xCGH'); var elCGD = $(this.ID()+'_xCGD'); this.ColXMLWidth = []; var elCGC = elCG.firstDescendant(); var elCGDC = elCGD.firstDescendant(); for (var oi = 0; oi < this.visibleColumnCount; ++oi) { this.ColXMLWidth[this.aColOrder[oi]] = elCGC.readAttribute('width'); elCGC=elCGC.next(); elCGDC=elCGDC.next(); } }, OnColumnMouseDown: function (nCol, event) { // Проверяем, что нажали не на фильтре var target = (Prototype.Browser.IE ? event.srcElement : event.target); if (target.className.match("FilterIcon") != null) return; // Подписываемся на события var oCol = $(this.ID()+'_xH'+nCol); var HandlerMove = this.OnColumnMoveMouseMove.bind(this, nCol); var HandlerSort = this.OnColumnSortMouseUp.bind(this, nCol); oCol.stopObserving("mouseup"); $(document).stopObserving('mousemove', HandlerMove); Event.observe(oCol, 'mouseup', HandlerSort); $(document).observe('mousemove', HandlerMove); // Действия для сортировки var evt=Event.extend(event || window.event); var ele=evt.target; if (evt.ctrlKey || evt.shiftKey) { // evade blue frames and selection under Fx this.stopMouseDown(evt); return false; } // Действия для движения this.MovingIndex = nCol; // Запоминаем положение мыши this.mousePointerX = Event.pointerX(event) this.mousePointerY = Event.pointerY(event) // Ширины колонок this.ColumnWidths = []; var right = 0; for (var i = 0; i < this.colCount; i ++) { var column = $(this.ID()+'_xH'+i); if (column == null || column.offsetWidth == 0) continue; this.ColumnWidths.push(column.offsetLeft); if (column.offsetLeft + column.offsetWidth > right) right = column.offsetLeft + column.offsetWidth; } this.ColumnWidths.push(right); this.ColumnWidths.sort(function(a,b){return a-b}); // Ширины в XML this.readColXMLWidths(); // Запрещаем выделение на странице var body = $(this.ID()+'_xMain'); body.addClassName("unselectable"); }, OnColumnMoveMouseMove: function (nCol, event) { //console.log("Moving arrow"); // Началось ли движение? var pointerX = Event.pointerX(event); var pointerY = Event.pointerY(event); if (!this.IsMoving && Math.abs(this.mousePointerX - pointerX) < 10 && Math.abs(this.mousePointerY - pointerY) < 10) return; this.IsMoving = true; // Красим var colHeader=$(this.ID()+'_xT' + nCol); colHeader.addClassName("SG_ColHeader_Choose"); // Подписываемся на событие var column = $(this.ID()+'_xH'+nCol); column.stopObserving("mouseup"); var HandlerMoveUp = this.OnColumnMoveMouseUp.bind(this, nCol); $(document).stopObserving('mouseup'); $(document).observe('mouseup', HandlerMoveUp); //Движение if (this.MovingIndex == null) { return; } // Координаты parent var main = $(this.ID()+'_xMain'); var br = main.getBoundingClientRect(); // Координаты мыши var pointerX = Event.pointerX(event) - br.left; var pointerY = Event.pointerY(event) - br.top; // Ширины колонок for (var i = 0; i < this.ColumnWidths.length - 1; i++) { if (pointerX > this.ColumnWidths[i] && pointerX < this.ColumnWidths[i + 1]) { var mid = (this.ColumnWidths[i] + this.ColumnWidths[i + 1]) / 2; this.MovingNewIndex = (pointerX < mid ? i : i + 1); this.MoveArrowOnPosition(); } } // Двигаем за мышкой название колонки var colMoving = $(this.ID()+'_xColumnMoving'); colMoving.setStyle({display: 'block'}); colMoving.innerHTML = this.getColumnByHeaderID(nCol).Title(); colMoving.setStyle({top: (pointerY - 20) + 'px'}); colMoving.setStyle({left: (pointerX - 3) + 'px'}); }, OnColumnSortMouseUp: function (nCol, event) { //console.log("Sort"); // Отписываемся от событий var column = $(this.ID()+'_xH'+nCol); column.stopObserving("mouseup"); $(document).stopObserving('mousemove'); // Сортировка this.OnSort(nCol, event); // Убираем все от движения this.MovingIndex = null; this.MovingNewIndex = null; this.IsMoving = null; this.ColumnWidths = []; var body = $(this.ID()+'_xMain'); body.removeClassName("unselectable"); this.HideMoveArrow(); this.HideMoveColumn(); }, OnColumnMoveMouseUp: function (nCol, event) { //console.log("Move"); // Отписываемся от событий $(document).stopObserving('mousemove'); $(document).stopObserving('mouseup'); // Движение if (this.MovingIndex == null) { return; } // var colHeader=$(this.ID()+'_xT' + nCol); colHeader.removeClassName("SG_ColHeader_Choose"); // перенести столбец this.moveColumnToPosition(); this.setColumnOrder(); this.updateColHeaderOrder(); this.SaveCustomization({"Order": true}); // Убираем все от движения this.MovingIndex = null; this.MovingNewIndex = null; this.IsMoving = null; this.ColumnWidths = []; var body = $(this.ID()+'_xMain'); body.removeClassName("unselectable"); this.HideMoveArrow(); this.HideMoveColumn(); // Перерисовываем this.currentActionSequence=[SG_CA_FSRP]; this.ProcessActions(); }, /* OnSortMouseDown: function(event) { var evt=Event.extend(event || window.event); var ele=evt.target; if (evt.ctrlKey || evt.shiftKey) { // evade blue frames and selection under Fx this.stopMouseDown(evt); return false; } return true; }, */ OnSort: function(nCol, event) { if (this.colResizeStarted) return; if (SG_DEBUG) LogL("OnSort() CALLED"); if (!this.StartNewRequest("Sort")) return; // abort if there exists another request var evt = Event.extend(event || window.event); this.oColSort.Touch(nCol, (evt.shiftKey == 1)); this.Sort(); }, OnDropSort: function(event) { if (SG_DEBUG) LogL("OnDropSort() CALLED"); if (!this.StartNewRequest("Sort")) return; // abort if there exists another request this.oColSort.Flush(); this.Sort(); }, Sort: function() { if (SG_DEBUG) LogL("Sort() CALLED"); this.aSortOrder = this.oColSort.Get(); // it is necessary to update aSortOrder before further processing this.SaveCustomization({"Sort": true}); this.currentActionSequence=[SG_CA_SP]; this.ProcessActions(); }, UpdateRowCount: function() { var eRC = $(this.ID()+'_xRC'); if(!eRC) return; var sText = ''; //if (this.selectedRowCount) sText += this.selectedRowCount + ' of '; // debug-only sText += this.rowCount; eRC.innerHTML=sText; }, UpdateSort: function() { var sSIVis = 'SG_SortIcon_Vis'; if (this.skinName) sSIVis = this.skinName + '_' + sSIVis; var sSIInvis = 'SG_SortIcon_Invis'; if (this.skinName) sSIInvis = this.skinName + '_' + sSIInvis; var sSIP = 'SG_SortIcon_'; if (this.skinName) sSIP = this.skinName + '_' + sSIP; var sh='SG_ColHeaderSorted'; var nSortedCount = this.aSortOrder.length; for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); if (!oCol.ID()) continue; // unreferenced column var oS = this.oColSort.Find(i); if (this.Died()) return; var eSI = $(this.ID()+'_xSI'+i); var eSIP = $(this.ID()+'_xSIP'+i); var eSN = $(this.ID()+'_xSN'+i); var eH = $(this.ID()+'_xH'+i); if (!oS) { eSI.removeClassName(sSIVis).addClassName(sSIInvis); eSIP.className = sSIP+'0'; eSN.innerHTML=' '; eH.removeClassName(sh); } else { var idx = oS.idx+1; var nDir = oS.elem.Dir(); if (nSortedCount > 1) { // this is multisorting eSI.removeClassName(sSIInvis).addClassName(sSIVis); eSIP.className = sSIP+nDir; eSN.innerHTML=''+idx+''; } else { // single column sorting if (nDir == CO_SORTUP || nDir == CO_SORTDOWN) { eSI.removeClassName(sSIInvis).addClassName(sSIVis); eSIP.className = sSIP+nDir; eSN.innerHTML=' '; } else { eSI.removeClassName(sSIVis).addClassName(sSIInvis); eSIP.className = sSIP+'0'; eSN.innerHTML=' '; } } eH.addClassName(sh); } } this.bSortActive = !!nSortedCount; // from former UpdateSortPanel if (this.bSortActive) this.eDropSort.setStyle({visibility: 'visible'}); else this.eDropSort.setStyle({visibility: 'hidden'}); }, // update this.oFilters object from columns and set filter activity flag // must be called each time when some filters change their values updateFilterValues: function(bUpdateNotRequired) { if (SG_DEBUG) LogL("updateFilterValues() CALLED"); this.oFilters = new Object(); this.bFiltersActive = false; for (var i = 0; i < this.colCount; ++i) { var oValue = this.aColumns[i].FilterValue(); // *** var oValue = this.getColumnByHeaderID(i).FilterValue(); if (typeof(oValue) !== 'undefined') { this.oFilters[this.aColumns[i].BindID()] = oValue; // *** this.oFilters[this.getColumnByHeaderID(i).Bind()] = oValue; this.bFiltersActive = true; } } if (!bUpdateNotRequired) this.bNeedUpdateFilters = true; }, // and when they are applied... updateFilterTexts: function() { if (!this.bNeedUpdateFilters) return; this.bNeedUpdateFilters = false; // reset flag if (SG_DEBUG) LogL("updateFilterTexts() is required"); var ma = function(n,v) { return ' '+n+'="'+AXML.EscapeEntities(v)+'"'; } var sTF = ''; for (var i = 0; i < this.typeFiles.length; ++i) sTF += ''; var sF = ''+sTF; for (var i=0; i'; } } else { // generic string sText=''+AXML.EscapeEntities(oRawFilter)+''; } } else { sText=AXML.EscapeEntities(oCol.FilterText()); } var sCell = ''+sText+''; sF += sCell; } sF += ''; var fltDOM = new AXML(); fltDOM.Parse(sF); var fltDoc = fltDOM.XML(); var oTransformResult=new Element('div'); if (SG_DEBUG) LogL("updateFilterTexts():TransformDOMTree..."); try { var oTransformDoc = AXML.TransformDOM(fltDoc, GWindowManager.XSL(), true); ApplyTreeOrString(oTransformResult, oTransformDoc); oTransformResult=oTransformResult.firstChild; // skip outer 'div' if (SG_DEBUG > 5) LogL("TRANSFORMED.TEXT="+(oTransformDoc.documentElement) ? oTransformResult.innerHTML : oTransformResult); } catch (exc) { alert("SG:updateFilterTexts(): XSLT transform failed with message: "+exc.message); return; } if (SG_DEBUG) LogL("updateFilterTexts(): Updating..."); var row = $(oTransformResult).down('tr'); var ci=0; for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); if (!oCol.ID()) continue; var elFilter = $(this.ID()+'_xF'+i); var cell=row.cells[ci]; elFilter.innerHTML=cell.innerHTML; elFilter.setAttribute('title', cell.getAttribute('title')); var elFiltered = $(this.ID()+'_xFC'+i); if (elFilter.innerHTML !== '') { elFiltered.addClassName('Sorted'); } else elFiltered.removeClassName('Sorted'); ++ci; } this.UpdateFilterPanel(); if (SG_DEBUG) LogL("updateFilterTexts(): Updating complete."); // this updates size after possible resizing of filter panel, etc this.OnResize(); return true; }, UpdateFilterPanel: function() { if (SG_DEBUG) LogL("UpdateFilterPanel() CALLED"); var sDropSF_FInact = 'SG_DropSF_FInact'; if (this.skinName) sDropSF_FInact = this.skinName + '_' + sDropSF_FInact; var sDropSF_FAct = 'SG_DropSF_FAct'; if (this.skinName) sDropSF_FAct = this.skinName + '_' + sDropSF_FAct; var sDropSF_Act = 'SG_DropSF_Act'; if (this.skinName) sDropSF_Act = this.skinName + '_' + sDropSF_Act; var sDropSF_Inact = 'SG_DropSF_Inact'; if (this.skinName) sDropSF_Inact = this.skinName + '_' + sDropSF_Inact; var eDropSFC = $(this.ID()+'_xDropSF'); var eDropSFT = $(this.ID()+'_xDropSFT'); if (this.Died()) return; if (this.bFiltersActive) { // show 'Clear Filters' button this.eDropFilters.setStyle({display: ''}); this.eFilters.setStyle({display: ''}); eDropSFC.removeClassName(sDropSF_FInact).addClassName(sDropSF_FAct); eDropSFT.removeClassName(sDropSF_Inact).addClassName(sDropSF_Act); for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); if (!oCol.ID()) continue; // unreferenced column var eF = $(this.ID()+'_xDropF'+i); var eFI = $(this.ID()+'_xFI'+i); var eFIP = $(this.ID()+'_xFIP'+i); if (typeof(this.aColumns[i].FilterValue()) != 'undefined') { // *** if (typeof (this.getColumnByHeaderID(i).FilterValue()) != 'undefined') { eF.setStyle({display: ''}); eFI.removeClassName('SG_FilterIcon_Invis').addClassName('SG_FilterIcon_Vis'); eFIP.className = 'SG_FilterIcon_Act'; } else { eF.setStyle({display: 'none'}); eFI.removeClassName('SG_FilterIcon_Vis').addClassName('SG_FilterIcon_Invis'); eFIP.className = 'SG_FilterIcon_Norm'; } } } else { // hide 'Clear Filters' button this.eDropFilters.setStyle({display: 'none'}); this.eFilters.setStyle({display: 'none'}); eDropSFC.removeClassName(sDropSF_FAct).addClassName(sDropSF_FInact); eDropSFT.removeClassName(sDropSF_Act).addClassName(sDropSF_Inact); // clear icons state for (var i = 0; i < this.colCount; ++i) { var oCol = this.aColumns[i]; // *** var oCol = this.getColumnByHeaderID(i); if (!oCol.ID()) continue; // unreferenced column var eFI = $(this.ID()+'_xFI'+i); var eFIP = $(this.ID()+'_xFIP'+i); eFI.removeClassName('SG_FilterIcon_Vis').addClassName('SG_FilterIcon_Invis'); eFIP.className = 'SG_FilterIcon_Norm'; } } }, OnColHeaderMouseOver: function(nIndex) { var elFI = $(this.ID()+'_xFI'+nIndex); elFI.removeClassName('SG_FilterIcon_Invis').addClassName('SG_FilterIcon_Vis'); }, OnColHeaderMouseOut: function(nIndex) { var oCol = this.aColumns[nIndex]; // *** var oCol = this.getColumnByHeaderID(nIndex); if (typeof(oCol.FilterValue()) != 'undefined') return; var elFI = $(this.ID()+'_xFI'+nIndex); elFI.removeClassName('SG_FilterIcon_Vis').addClassName('SG_FilterIcon_Invis'); }, OnFilterIconMouseOver: function(nIndex) { var elFI = $(this.ID()+'_xFI'+nIndex); var elFIP = $(this.ID()+'_xFIP'+nIndex); elFI.removeClassName('SG_FilterIcon_Invis').addClassName('SG_FilterIcon_Vis'); elFIP.className = 'SG_FilterIcon_Over'; }, OnFilterIconMouseOut: function(nIndex) { var elFIP = $(this.ID()+'_xFIP'+nIndex); var oCol = this.aColumns[nIndex]; // *** var oCol = this.getColumnByHeaderID(nIndex); if (typeof(oCol.FilterValue()) != 'undefined') { elFIP.className = 'SG_FilterIcon_Act'; } else { elFIP.className = 'SG_FilterIcon_Norm'; } }, /* OnMovingIconMouseOver: function(nIndex) { var elMI = $(this.ID()+'_xMI'+nIndex); var elMIP = $(this.ID()+'_xMIP'+nIndex); elMI.removeClassName('SG_MovingIcon_Invis').addClassName('SG_MovingIcon_Vis'); elMIP.className = 'SG_MovingIcon_Over'; }, OnMovingIconMouseOut: function(nIndex) { var elMIP = $(this.ID()+'_xMIP'+nIndex); var oCol = this.aColumns[nIndex]; // *** var oCol = this.getColumnByHeaderID(nIndex); elMIP.className = 'SG_MovingIcon_Norm'; //console.log("value of x is %s and value of y is %d", 1, 2); }, OnMovingIconMouseDown: function(nIndex, event) { var elMIP = $(this.ID()+'_xMIP'+nIndex); var oCol = this.aColumns[nIndex]; // *** var oCol = this.getColumnByHeaderID(nIndex); elMIP.className = 'SG_MovingIcon_Act'; // observe var elMI = $(this.ID()+'_xMI'+nIndex); elMI.stopObserving('mouseout'); // Данные для движения this.MovingIndex = oCol.HeaderID(); // Расположение стрелки по ширине this.ColumnWidths = []; var right = 0; for (var i = 0; i < this.colCount; i ++) { var column = $(this.ID()+'_xH'+i); if (column == null || column.offsetWidth == 0) continue; this.ColumnWidths.push(column.offsetLeft); if (column.offsetLeft + column.offsetWidth > right) right = column.offsetLeft + column.offsetWidth; } this.ColumnWidths.push(right); this.ColumnWidths.sort(function(a,b){return a-b}); var Handler = this.OnMovingIconMouseUp.bind(this); var HandlerMove = this.OnMovingIconMouseMove.bind(this); $(document).observe('mouseup', Handler); $(document).observe('mousemove', HandlerMove); for (var i = 0; i < this.colCount; i++) { var elColHeader = $(this.ID()+'_xH'+i); if (elColHeader == null) continue; elColHeader.stopObserving('mouseover'); elColHeader.stopObserving('mouseout'); elColHeader.stopObserving('mouseup'); elColHeader.addClassName("cursor_move"); } var body = $(this.ID()+'_xMain'); body.addClassName("unselectable"); }, OnMovingIconMouseMove: function(event) { if (this.MovingIndex == null) { return; } // Координаты parent var main = $(this.ID()+'_xMain'); var br = main.getBoundingClientRect(); // Координаты мыши var pointerX = Event.pointerX(event) - br.left; var pointerY = Event.pointerY(event) - br.top; // Ширины колонок for (var i = 0; i < this.ColumnWidths.length - 1; i++) { if (pointerX > this.ColumnWidths[i] && pointerX < this.ColumnWidths[i + 1]) { var mid = (this.ColumnWidths[i] + this.ColumnWidths[i + 1]) / 2; this.MovingNewIndex = (pointerX < mid ? i : i + 1); this.MoveArrowOnPosition(); } } }, OnMovingIconMouseUp: function(event) { if (this.MovingIndex == null) { return; } // перенести столбец this.moveColumnToPosition(); this.setColumnOrder(); this.updateColHeaderOrder(); var elMIP = $(this.ID()+'_xMIP'+this.MovingIndex); var oCol = this.getColumnByHeaderID[this.MovingIndex]; // *** var oCol = this.getColumnByHeaderID(this.MovingIndex); elMIP.className = 'SG_MovingIcon_Norm'; var elMI = $(this.ID()+'_xMI'+this.MovingIndex); Event.observe(elMI, "mouseout", this.OnMovingIconMouseOut.bind(this, this.MovingIndex)); var Handler = this.OnMovingIconMouseUp.bind(this); var HandlerMove = this.OnMovingIconMouseMove.bind(this); $(document).stopObserving('mouseup', Handler); $(document).stopObserving('mousemove', HandlerMove); this.MovingIndex = null; this.MovingNewIndex = null; for (var i = 0; i < this.colCount; i++) { var elColHeader = $(this.ID()+'_xH'+i); if (elColHeader == null) continue; if (Prototype.Browser.IE) { elColHeader.observe('mouseenter', this.OnColHeaderMouseOver.bind(this, i)); elColHeader.observe('mouseleave', this.OnColHeaderMouseOut.bind(this, i)); elColHeader.observe('mouseup', this.OnSort.this(oGrid, i)); } else { Event.observe(elColHeader, 'mouseover', this.OnColHeaderMouseOver.bind(this, i)); Event.observe(elColHeader, 'mouseout', this.OnColHeaderMouseOut.bind(this, i)); Event.observe(elColHeader, 'mouseup', this.OnSort.bind(this, i)); } elColHeader.removeClassName("cursor_move"); } var body = $(this.ID()+'_xMain'); body.removeClassName("unselectable"); this.HideMoveArrow(); this.SaveCustomization({"Order": true}); // Перерисовываем this.currentActionSequence=[SG_CA_FSRP]; this.ProcessActions(); //this.updateColWidths(); }, */ SetFilter: function(nCol, oValue) { // TODO: fix StartNewRequest call (it must be moved away from here) if (!this.StartNewRequest("Filter")) return; if (SG_DEBUG) LogL("SetFilter CALLED"); this.aColumns[nCol].SetFilterValue(oValue); // *** this.getColumnByHeaderID(nCol).SetFilterValue(oValue); // clear selected rows this.oSelectedRows=new Object(); this.selectedRowCount=0; this.aSelectedData=[]; // ---------------------- this.updateFilterValues(); this.Filter(); }, Filter: function() { if (SG_DEBUG) LogL("Filter() CALLED"); this.SaveCustomization({"Filter": true}); this.currentActionSequence=[SG_CA_FRP]; this.ProcessActions(); }, OnMouseWheel: function(evt) { if(!evt) evt=window.event; var wheelDelta=0; if (evt.wheelDelta) { // IE and Opera: one elementary scroll of wheel gives 120 in evt.wheelDelta (experimental value) wheelDelta = -evt.wheelDelta/40; } else if(evt.detail) { // Mozilla: evt.detail allows to track mouse wheel. One elementary scroll gives 3 in evt.detail // and has inverted sign (in comparing with evt.wheelDelta) wheelDelta = evt.detail; } if( (wheelDelta<0 && this.scrollDiv.scrollTop>0) || (wheelDelta>0 && this.scrollDiv.scrollTop= 48 && key <= 57) { // sorting if (key==48) { // drop sorting this.OnDropSort(evt); return true; } key-=49; // convert key to column index var vIndex=0; var colIndex=-1; // invalid index for (var oi=0; oi < this.visibleColumnCount; ++oi, vIndex++) { var i=this.aColOrder[oi]; if (vIndex==key) { // column found colIndex=i; break; } } if (colIndex>=0) this.OnSort(colIndex, evt); return true; } else if (evt.altKey && !evt.ctrlKey && key >= 48 && key <= 57) { // filtering if (key==48) { this.OnDropFilters(evt); return true; } key-=49; // convert key to column index var vIndex=0; var colIndex=-1; // invalid index for (var oi=0; oi < this.visibleColumnCount; ++oi, vIndex++) { var i=this.aColOrder[oi]; if (vIndex==key) { // column found colIndex=i; break; } } if (colIndex>=0) this.OnOpenFilter(colIndex, evt); return true; } else if (key == 38 || key == 40) { // UP/DOWN this.IncDecCurrentRow(evt, key); return true; // event should stop } else if (key == 33 || key == 34) { // PageUP/PageDOWN this.PageUpDownCurrentRow(key); return true; // event should stop } if (this.aShortcuts[key]) { var r=this.processShortcut(evt, this.aShortcuts[key]); if (r===true || r===false) return r; // null means continue processing } return false; }, OnKeyUp: function(evt) { if (typeof(evt.keyCode) == 'undefined') return false; var key = evt.keyCode; return false; }, OnKeyPress: function(evt) { var eKD=GetKeyCode(evt); var key=eKD.charCode; return false; }, OnKeyPressDown: function(evt) { var key=evt.which || evt.keyCode; if (!key) return false; if (this.aShortcutLetters[key]) { var r=this.processShortcut(evt, this.aShortcutLetters[key]); if (r===true || r===false) return r; // null means continue processing } return false; }, HandleClick: function(column) { if (!this.currentRowDataDefined) { LogE("Cannot fire CLICK event when SG is processing requests. "); return; } var obj=this; if (column) { // column click obj=this.ID()+'.'+column; } else { if (!this.bClickable) return; } new AEvent('CLICK', { args: this.currentRowData }, obj); }, UpdateCurrentRow: function(newCR) { this.updateCurrentRowElement(newCR); this.updateCurrentRowData(); }, /** * Updates current table row element. * @param newCR new current row (optional). There exist three cases: * When provided with non-null argument, it selects the specified row. * When argument is null, it unselects current row. * When argument is undefined, it makes element with 'id'=this.currentRow active. **/ updateCurrentRowElement: function(newCR) { if (SG_DEBUG) LogE("updateCurrentRowElement: "+typeof(newCR)+", isNull="+(newCR===null)); var sNewClassName = (this.selectedRowCount == 0 ? 'SG_ActiveRow_Single' : 'SG_ActiveRow_Multiple'); //LogL("sNewClassName="+sNewClassName); // if nothing to do, element already has necessary if (newCR && $(newCR).hasClassName(sNewClassName)) { //LogL("nothing to do."); return; } var aCR = this.contentTbl.select('tr.SG_ActiveRow_Single'); // if nothing found, try multiselect mode if (!aCR.length) aCR = this.contentTbl.select('tr.SG_ActiveRow_Multiple'); for (var i = 0; i < aCR.length; ++i) { var cr=aCR[i]; //if (cr.id == String(this.currentRow)) return; // nothing to do, already selected cr.removeClassName('SG_ActiveRow_Single'); cr.removeClassName('SG_ActiveRow_Multiple'); //LogL("removing from "+cr.id); } if (newCR === null) return; // unset current row // TODO: remove this bullshit (.select() used) cr = (newCR) ? newCR : this.contentTbl.select('tr#'+this.currentRow)[0]; if (cr) { //LogL("adding to "+cr.id); cr.addClassName(sNewClassName); } }, /** * Updates current table row data. * @param nRowIndex current row index (optional). If provided, selects row with that index, * otherwise uses data from row #this.currentRow. * Also emits CHANGE event. **/ updateCurrentRowData: function() { if (SG_DEBUG) LogL("updateCurrentRowData(): currentRow="+this.currentRow+" rowCount="+this.rowCount); var nDI = this.currentRow - this.firstRow; var bDefined = (nDI >= 0 && nDI < this.data.length); // use deep copy, as this.data array is mutable if (bDefined) { var r=this.data[nDI]; var newKey=this.makeDataKey(r); for (var i=0; i < this.colCount; ++i) { var oValue=r[i]; var id=this.aColumns[i].ID(); // *** var id = this.getColumnByHeaderID(i).ID(); if (!id) continue; // unreferenced column this.currentRowData[id]=oValue; if (SG_DEBUG > 4) LogL("Col["+id+"]: "+oValue); } this.currentRowDataDefined=true; if (SG_DEBUG) LogL("SET currentRowDataDefined TRUE"); } else { if (SG_DEBUG) LogE("SET currentRowDataDefined FALSE"); this.currentRowDataDefined = false; } if (this.currentRowDataKey===newKey) return; this.currentRowDataKey=newKey; // update key // The only place where CHANGE is emitted new AEvent("CHANGE", { args: this.currentRowData, bMutable: true }, this); if (SG_DEBUG > 3) LogL("SG CHANGED! "); }, Refocus: function(newPos) { this.delayedRefocus=false; if (SG_DEBUG) LogL("Refocus(): newPos="+newPos+", currentRow="+this.currentRow); if (newPos == this.currentRow) { if (SG_DEBUG) LogL("Refocus(): Nothing more than update currentRowData!"); this.UpdateCurrentRow(); // ensure that something is selected return; // and nothing more } var oldCurrentRow=this.currentRow; this.currentRow=newPos; var nDataIndex=this.currentRow-this.firstRow; var cr = null; if (nDataIndex>=0 && nDataIndex < this.contentTbl.rows.length) cr = this.contentTbl.rows[nDataIndex]; //var cr=this.contentTbl.select('tr#'+this.currentRow)[0]; if (cr) { // current row is found in cache var top=this.scrollDiv.scrollTop; var hiddenRowsUp=top/this.rowHeight; var hiddenRowsDown=Math.ceil((this.scrollHeight-(top+this.canvasHeight))/this.rowHeight); if (SG_DEBUG) { LogL("Refocus():"+ " top="+top+ " hiddenRowsUp="+hiddenRowsUp+ " hiddenRowsDown="+hiddenRowsDown); } if(this.currentRow