Automatically remove column select filter if unapplyable
[infodrom/rico3] / minsrc / ricoLiveGrid.js
index 6c89dc1..1afb5d6 100644 (file)
@@ -1,6 +1,6 @@
 /*
- *  (c) 2005-2009 Richard Cowin (http://openrico.org)
- *  (c) 2005-2009 Matt Brown (http://dowdybrown.com)
+ *  (c) 2005-2011 Richard Cowin (http://openrico.org)
+ *  (c) 2005-2011 Matt Brown (http://dowdybrown.com)
  *
  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
  *  file except in compliance with the License. You may obtain a copy of the License at
@@ -13,9 +13,6 @@
  *  and limitations under the License.
  */
 
-if(typeof Rico=='undefined') throw("LiveGrid requires the Rico JavaScript framework");
-
-
 /** @namespace */
 if (!Rico.Buffer) Rico.Buffer = {};
 
@@ -34,8 +31,8 @@ Rico.Buffer.Base.prototype = {
     this.clear();
     this.updateInProgress = false;
     this.lastOffset = 0;
-    this.rcvdRowCount = false;  // true if an eof element was included in the last xml response
-    this.foundRowCount = false; // true if an xml response is ever received with eof true
+    this.rcvdRowCount = false;  // true if an eof element was included in the last response
+    this.foundRowCount = false; // true if a response is ever received with eof true
     this.totalRows = 0;
     this.rowcntContent = "";
     this.rcvdOffset = -1;
@@ -43,14 +40,13 @@ Rico.Buffer.Base.prototype = {
       fixedHdrRows     : 0,
       canFilter        : true,  // does buffer object support filtering?
       isEncoded        : true,  // is the data received via ajax html encoded?
-      acceptStyle      : false  // copy style from original/ajax data?
+      acceptStyle      : false, // copy style from original/ajax data?
+      canRefresh       : false  // should "refresh" be shown on filter menu?
     };
     Rico.extend(this.options, options || {});
     if (dataTable) {
       this.loadRowsFromTable(dataTable,this.options.fixedHdrRows);
       dataTable.parentNode.removeChild(dataTable);  // delete the data once it has been loaded
-    } else {
-      this.clear();
     }
   },
 
@@ -211,6 +207,8 @@ Rico.Buffer.Base.prototype = {
   clear: function() {
     this.baseRows = [];
     this.rows = [];
+    this.modified = [];
+    this.attr = null;
     this.startPos = -1;
     this.size = 0;
     this.windowPos = 0;
@@ -274,7 +272,7 @@ Rico.Buffer.Base.prototype = {
 
   getWindowStyle: function(windowRow,col) {
     var bufrow=this.bufferRow(windowRow);
-    return this.attr && this.isVisible(bufrow) && col < this.attr[bufrow].length ? this.attr[bufrow][col] : '';
+    return this.attr && this.isVisible(bufrow) && this.attr[bufrow] && col < this.attr[bufrow].length ? this.attr[bufrow][col] : '';
   },
 
   getWindowValue: function(windowRow,col) {
@@ -299,8 +297,13 @@ Rico.Buffer.Base.prototype = {
     if (bufRow>=this.size) return false;
     if (!this.rows[bufRow][col]) this.rows[bufRow][col]={};
     this.rows[bufRow][col]=newval;
-    if (typeof newstyle=='string') this.rows[bufRow][col]._style=newstyle;
-    this.rows[bufRow][col].modified=true;
+    if (this.options.acceptStyle && typeof newstyle=='string') {
+      if (!this.attr) this.attr=[];
+      if (!this.attr[bufRow]) this.attr[bufRow]=[];
+      this.attr[bufRow][col]=newstyle;
+    }
+    if (!this.modified[bufRow]) this.modified[bufRow]=[];
+    this.modified[bufRow][col]=true;
     return true;
   },
 
@@ -535,8 +538,8 @@ Rico.LiveGrid.prototype = {
 
     this.bookmark=document.getElementById(this.tableId+"_bookmark");
     this.sizeDivs();
-    var filterUIrow=this.buffer.options.canFilter ? this.options.FilterLocation : false;
-    if (typeof(filterUIrow)=='number' && filterUIrow<0)
+    var filterUIrow=-1;
+    if (this.buffer.options.canFilter && this.options.AutoFilter)
       filterUIrow=this.addHeadingRow('ricoLG_FilterRow');
     this.createDataCells(this.options.visibleRows);
     if (this.pageSize == 0) return;
@@ -561,7 +564,7 @@ Rico.LiveGrid.prototype = {
       this.scrollToRow(this.options.offset);
       this.buffer.fetch(this.options.offset);
     }
-    if (typeof(filterUIrow)=='number')
+    if (filterUIrow >= 0)
       this.createFilters(filterUIrow);
     this.scrollEventFunc=Rico.eventHandle(this,'handleScroll');
     this.wheelEventFunc=Rico.eventHandle(this,'handleWheel');
@@ -574,6 +577,13 @@ Rico.LiveGrid.prototype = {
     if (this.options.windowResize)
       Rico.runLater(100,this,'pluginWindowResize');
     Rico.log("initialize complete for "+this.tableId);
+    //alert('clientLeft='+this.scrollDiv.clientLeft);
+    if (this.direction=='rtl' && (!Rico.isWebKit || this.scrollDiv.clientLeft > 0)) {
+      this.scrollTab.style.right='0px';
+    } else {
+      this.scrollTab.style.left='0px';
+      Rico.setStyle(this.tabs[1], {'float': 'left'});
+    }
   }
 };
 
@@ -643,7 +653,7 @@ Rico.LiveGridMethods = {
       var theads=table.getElementsByTagName("thead");
       if (theads.length == 1) {
         Rico.log("createTables: using thead section, id="+this.tableId);
-        if (this.options.PanelNamesOnTabHdr && this.options.panels) {
+        if (this.options.ColGroupsOnTabHdr && this.options.ColGroups) {
           var r=theads[0].insertRow(0);
           this.insertPanelNames(r, 0, this.options.frozenColumns, 'ricoFrozen');
           this.insertPanelNames(r, this.options.frozenColumns, this.options.columnSpecs.length);
@@ -712,7 +722,6 @@ Rico.LiveGridMethods = {
     // set headings
     for (i=0; i<2; i++) {
       this.thead[i]=this.tabs[i].createTHead();
-      //Rico.addClass(this.tabs[i],'ricoLG_top');
       this.thead[i].className='ricoLG_top';
       if (Rico.theme.gridheader) Rico.addClass(this.thead[i],Rico.theme.gridheader);
     }
@@ -733,7 +742,7 @@ Rico.LiveGridMethods = {
     } else {
       this.createHdr(0,0,this.options.frozenColumns);
       this.createHdr(1,this.options.frozenColumns,this.options.columnSpecs.length);
-      if (this.options.PanelNamesOnTabHdr && this.options.panels) {
+      if (this.options.ColGroupsOnTabHdr && this.options.ColGroups) {
         this.insertPanelNames(this.thead[0].insertRow(0), 0, this.options.frozenColumns);
         this.insertPanelNames(this.thead[1].insertRow(0), this.options.frozenColumns, this.options.columnSpecs.length);
       }
@@ -789,7 +798,7 @@ Rico.LiveGridMethods = {
       switch (fmt.filterUI.charAt(0)) {
         case 't':
           // text field
-          field=Rico.createFormField(divs[1],'input',Rico.inputtypes.search ? 'search' : 'text',name,name);
+          field=Rico.createFormField(divs[1],'input',Rico.inputtypes.search ? 'search' : 'text',name,'RicoFilter');
           var size=fmt.filterUI.match(/\d+/);
           field.maxLength=fmt.Length || 50;\r
           field.size=size ? parseInt(size,10) : 10;
@@ -808,17 +817,27 @@ Rico.LiveGridMethods = {
           // multi-select
         case 's':
           // drop-down select
-          field=Rico.createFormField(divs[1],'select',null,name);\r
+          field=Rico.createFormField(divs[1],'select',null,name,'RicoFilter');\r
           Rico.addSelectOption(field,this.options.FilterAllToken,Rico.getPhraseById("filterAll"));\r
           col.filterField=field;
           var options={};\r
           Rico.extend(options, this.buffer.ajaxOptions);
           var colnum=typeof(fmt.filterCol)=='number' ? fmt.filterCol : c;
-          options.parameters = {id: this.tableId, distinct:colnum};
-          options.parameters[this.actionId]="query";
+          options.parameters = this.buffer.formQueryHashXML(0,-1);
+          options.parameters.distinct = colnum;
           options.onComplete = this.filterValuesUpdateFunc(c);
           new Rico.ajaxRequest(this.buffer.dataSource, options);
           break;\r
+        case 'n':
+          field=Rico.createFormField(divs[1],'select',null,name,'RicoFilter');
+          Rico.addSelectOption(field,this.options.FilterAllToken,Rico.getPhraseById("filterAll"));
+          col.filterField=field;
+          var choices=fmt.filterUI.length == 1 ? "-0+" : fmt.filterUI.substr(1);
+          if (choices.indexOf("-") >= 0) Rico.addSelectOption(field,"LT0","< 0");
+          if (choices.indexOf("0") >= 0) Rico.addSelectOption(field,"EQ0","= 0");
+          if (choices.indexOf("+") >= 0) Rico.addSelectOption(field,"GT0","> 0");
+          Rico.eventBind(col.filterField,'change',Rico.eventHandle(col,'nFilterChange'));
+          break;
         case 'c':
           // custom
           if (typeof col._createFilters == 'function')
@@ -853,6 +872,18 @@ Rico.LiveGridMethods = {
     var rowsElement = response.getElementsByTagName('rows')[0];\r
     var col=this.columns[parseInt(colnum,10)];
     var rows = this.buffer.dom2jstable(rowsElement);\r
+    var found = !col.filterValues || !col.filterValues.length;
+    if (!found) for (var i=0; i<rows.length; i++) {
+       if (rows[i][0] == col.filterValues[0]) {
+           found = true;
+           break;
+       }
+    }
+    if (!found) {
+       col.setUnfiltered(true);
+       if (this.options.filterHandler)
+           this.options.filterHandler();
+    }
     var c,opt,v;
     if (col.filterType==Rico.ColumnConst.USERFILTER && col.filterOp=='EQ') v=col.filterValues[0];
     Rico.log('filterValuesUpdate: col='+colnum+' rows='+rows.length);
@@ -867,7 +898,7 @@ Rico.LiveGridMethods = {
         var buttonDiv = col.mFilter.appendChild(document.createElement("div"));
         buttonDiv.className = 'ricoLG_mFilter_button'
         col.mFilterButton=buttonDiv.appendChild(document.createElement("button"));
-        col.mFilterButton.innerHTML=Rico.getPhraseById("ok");
+        col.mFilterButton.innerHTML=Rico.getPhraseById("apply");
         var eventName=Rico.isWebKit ? 'mousedown' : 'click';
         Rico.eventBind(col.filterField,eventName,Rico.eventHandle(col,'mFilterSelectClick'));
         Rico.eventBind(col.mFilterButton,'click',Rico.eventHandle(col,'mFilterFinish'));
@@ -935,15 +966,15 @@ Rico.LiveGridMethods = {
     r.className='ricoLG_hdg';
     var lastIdx=-1, span, newCell=null, spanIdx=0;
     for( var c=start; c < limit; c++ ) {
-      if (lastIdx == this.options.columnSpecs[c].panelIdx) {
+      if (lastIdx == this.options.columnSpecs[c].ColGroupIdx) {
         span++;
       } else {
         if (newCell) newCell.colSpan=span;
         newCell = r.insertCell(-1);
         if (cellClass) newCell.className=cellClass;
         span=1;
-        lastIdx=this.options.columnSpecs[c].panelIdx;
-        newCell.innerHTML=this.options.panels[lastIdx];
+        lastIdx=this.options.columnSpecs[c].ColGroupIdx;
+        newCell.innerHTML=this.options.ColGroups[lastIdx];
       }
     }
     if (newCell) newCell.colSpan=span;
@@ -1083,15 +1114,18 @@ Rico.LiveGridMethods = {
   },
 
   adjustPageSize: function() {
+    Rico.log('adjustPageSize start');
     var remHt=this.remainingHt();
     Rico.log('adjustPageSize remHt='+remHt+' lastRow='+this.lastRowPos);
     if (remHt > this.rowHeight)
       this.autoAppendRows(remHt);
     else if (remHt < 0 || this.sizeTo=='data')
       this.autoRemoveRows(-remHt);
+    Rico.log('adjustPageSize end');
   },
   
   setPageSize: function(newRowCount) {
+    Rico.log('setPageSize '+this.tableId+' newRowCount='+newRowCount);
     newRowCount=Math.min(newRowCount,this.options.maxPageRows);
     newRowCount=Math.max(newRowCount,this.options.minPageRows);
     this.sizeTo='fixed';
@@ -1118,7 +1152,7 @@ Rico.LiveGridMethods = {
   },
 
   resizeWindow: function() {
-    Rico.log('resizeWindow '+this.tableId+' lastRow='+this.lastRowPos);
+    Rico.log('resizeWindow '+this.tableId+' lastRow='+this.lastRowPos+' resizeState='+this.resizeState);
     if (this.resizeState=='finish') {
       Rico.log('resizeWindow postponed');
       this.resizeState='resize';
@@ -1129,12 +1163,14 @@ Rico.LiveGridMethods = {
       return;
     }
     if (this.sizeTo=='parent' && Rico.getStyle(this.outerDiv.parentNode,'display') == 'none') return;
+    Rico.log('resizeWindow: about to adjustPageSize')
     var oldSize=this.pageSize;
     this.adjustPageSize();
     this.finishResize(oldSize);
   },
 
   finishResize: function(oldSize) {
+    Rico.log('finishResize '+this.tableId);
     if (this.pageSize > oldSize && this.buffer.totalRows>0) {
       this.isPartialBlank=true;
       var adjStart=this.adjustRow(this.lastRowPos);
@@ -1148,6 +1184,7 @@ Rico.LiveGridMethods = {
   },
 
   finishResize2: function() {
+    Rico.log('finishResize2 '+this.tableId+': resizeState='+this.resizeState);
     this.sizeDivs();
     this.updateHeightDiv();
     if (this.resizeState=='resize') {
@@ -1209,11 +1246,13 @@ Rico.LiveGridMethods = {
       newdiv.className = 'ricoLG_cell '+cls;
       newdiv.id=this.tableId+'_'+this.pageSize+'_'+c;
       this.columns[c].dataColDiv.appendChild(newdiv);
-      if (this.columns[c].format.canDrag && Rico.registerDraggable)
-        Rico.registerDraggable( new Rico.LiveGridDraggable(this, this.pageSize, c), this.options.dndMgrIdx );
-      newdiv.innerHTML='&nbsp;';   // this seems to be required by IE
       if (this.columns[c]._create) {
         this.columns[c]._create(newdiv,this.pageSize);
+      } else {
+        newdiv.innerHTML='&nbsp;';   // this seems to be required by IE
+      }
+      if (this.columns[c].format.canDrag && Rico.registerDraggable) {
+        Rico.registerDraggable( new Rico.LiveGridDraggable(this, this.pageSize, c), this.options.dndMgrIdx );
       }
     }
     this.pageSize++;
@@ -1660,19 +1699,12 @@ Rico.LiveGridMethods = {
     return -1;
   },
 
-  findColumnName: function(name) {
-    for (var n=0; n<this.columns.length; n++) {
-      if (this.columns[n].fieldName == name) return n;
-    }
-    return -1;
-  },
-  
 /**
  * Searches options.columnSpecs colAttr for matching colValue
  * @return array of matching column indexes
  */
   findColumnsBySpec: function(colAttr, colValue) {
-    var result=[]
+    var result=[];
     for (var n=0; n<this.options.columnSpecs.length; n++) {
       if (this.options.columnSpecs[n][colAttr] == colValue) result.push(n);
     }
@@ -1682,8 +1714,8 @@ Rico.LiveGridMethods = {
 /**
  * Set initial sort
  */
-  setSortUI: function( columnNameOrNum, sortDirection ) {
-    Rico.log("setSortUI: "+columnNameOrNum+' '+sortDirection);
+  setSortUI: function( columnIdOrNum, sortDirection ) {
+    Rico.log("setSortUI: "+columnIdOrNum+' '+sortDirection);
     var colnum=this.findSortedColumn();
     if (colnum >= 0) {
       sortDirection=this.columns[colnum].getSortDirection();
@@ -1694,12 +1726,12 @@ Rico.LiveGridMethods = {
         sortDirection=sortDirection.toUpperCase();
         if (sortDirection != Rico.ColumnConst.SORT_DESC) sortDirection=Rico.ColumnConst.SORT_ASC;
       }
-      switch (typeof columnNameOrNum) {
+      switch (typeof columnIdOrNum) {
         case 'string':
-          colnum=this.findColumnName(columnNameOrNum);
+          colnum=this.findColumnsBySpec('id',columnIdOrNum);
           break;
         case 'number':
-          colnum=columnNameOrNum;
+          colnum=columnIdOrNum;
           break;
       }
     }
@@ -2090,6 +2122,8 @@ getFilterText: function() {
   switch (this.filterOp) {
     case 'EQ':   return '= '+vals.join(', ');
     case 'NE':   return Rico.getPhraseById('filterNot',vals.join(', '));
+    case 'LT':   return '< '+vals[0];
+    case 'GT':   return '> '+vals[0];
     case 'LE':   return '<= '+vals[0];
     case 'GE':   return '>= '+vals[0];
     case 'LIKE': return Rico.getPhraseById('filterLike',vals[0]);
@@ -2171,12 +2205,23 @@ isFiltered: function() {
   return this.filterType == Rico.ColumnConst.USERFILTER;
 },
 
-filterChange: function(e) {\r
+filterChange: function(e) {
   var selbox=Rico.eventElement(e);
-  if (selbox.value==this.liveGrid.options.FilterAllToken)\r
-    this.setUnfiltered();\r
+  if (selbox.value==this.liveGrid.options.FilterAllToken)
+    this.setUnfiltered();
   else
-    this.setFilter('EQ',selbox.value,Rico.ColumnConst.USERFILTER,function() {selbox.selectedIndex=0;});\r
+    this.setFilter('EQ',selbox.value,Rico.ColumnConst.USERFILTER,function() {selbox.selectedIndex=0;});
+},
+
+nFilterChange: function(e) {
+  var selbox=Rico.eventElement(e);
+  if (selbox.value==this.liveGrid.options.FilterAllToken) {
+    this.setUnfiltered();
+  } else {
+    var op=selbox.value.substr(0,2);
+    var value=selbox.value.substr(2);
+    this.setFilter(op,value,Rico.ColumnConst.USERFILTER,function() {selbox.selectedIndex=0;});
+  }
 },
 
 filterClear: function(e) {\r