2 * (c) 2005-2009 Richard Cowin (http://openrico.org)
3 * (c) 2005-2009 Matt Brown (http://dowdybrown.com)
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
6 * file except in compliance with the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software distributed under the
11 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
12 * either express or implied. See the License for the specific language governing permissions
13 * and limitations under the License.
16 if(typeof Rico=='undefined') throw("GridCommon requires the Rico JavaScript framework");
19 * Define methods that are common to both SimpleGrid and LiveGrid
23 baseInit: function() {
25 resizeBackground : 'resize.gif',
26 saveColumnInfo : {width:true, filter:false, sort:false}, // save info in cookies?
27 cookiePrefix : 'RicoGrid.',
28 allowColResize : true, // allow user to resize columns
29 windowResize : true, // Resize grid on window.resize event? Set to false when embedded in an accordian.
33 menuEvent : 'dblclick', // event that triggers menus - click, dblclick, contextmenu, or none (no menus)
34 defaultWidth : -1, // if -1, then use unformatted column width
35 scrollBarWidth : 19, // this is the value used in positioning calculations, it does not actually change the width of the scrollbar
36 minScrollWidth : 100, // min scroll area width when width of frozen columns exceeds window width
37 exportWindow : "height=400,width=500,scrollbars=1,menubar=1,resizable=1",
38 exportStyleList : ['background-color','color','text-align','font-weight','font-size','font-family'],
39 exportImgTags : false, // applies to grid header and to SimpleGrid cells (not LiveGrid cells)
40 exportFormFields : true,
41 FilterLocation : null, // heading row number to place filters. -1=add a new heading row.
42 FilterAllToken : '___ALL___', // select box value to use to indicate ALL
48 this.headerRowIdx=0; // row in header which gets resizers (no colspan's in this row)
49 this.tabs=new Array(2);
50 this.thead=new Array(2);
51 this.tbody=new Array(2);
54 attachMenuEvents: function() {
56 if (!this.options.menuEvent || this.options.menuEvent=='none') return;
57 this.hideScroll=navigator.userAgent.match(/Macintosh\b.*\b(Firefox|Camino)\b/i) || (Rico.isOpera && parseFloat(window.opera.version())<9.5);
58 this.options[this.options.menuEvent]=Rico.eventHandle(this,'handleMenuClick');
59 if (this.highlightDiv) {
60 switch (this.options.highlightElem) {
62 this.attachMenu(this.highlightDiv[0]);
66 this.attachMenu(this.highlightDiv[i]);
72 this.attachMenu(this.tbody[i]);
76 attachMenu: function(elem) {
77 if (this.options.click)
78 Rico.eventBind(elem, 'click', this.options.click, false);
79 if (this.options.dblclick) {
80 if (Rico.isWebKit || Rico.isOpera)
81 Rico.eventBind(elem, 'click', Rico.eventHandle(this,'handleDblClick'), false);
83 Rico.eventBind(elem, 'dblclick', this.options.dblclick, false);
85 if (this.options.contextmenu) {
86 if (Rico.isOpera || Rico.isKonqueror)
87 Rico.eventBind(elem, 'click', Rico.eventHandle(this,'handleContextMenu'), false);
89 Rico.eventBind(elem, 'contextmenu', this.options.contextmenu, false);
94 * implement double-click for browsers that don't support a double-click event (e.g. Safari)
96 handleDblClick: function(e) {
97 var elem=Rico.eventElement(e);
98 if (this.dblClickElem == elem) {
99 this.options.dblclick(e);
101 this.dblClickElem = elem;
102 this.safariTimer=Rico.runLater(300,this,'clearDblClick');
106 clearDblClick: function() {
107 this.dblClickElem=null;
111 * implement right-click for browsers that don't support contextmenu event (e.g. Opera, Konqueror)
112 * use control-click instead
114 handleContextMenu: function(e) {
116 if( typeof( e.which ) == 'number' )
117 b = e.which; //Netscape compatible
118 else if( typeof( e.button ) == 'number' )
122 if (b==1 && e.ctrlKey) {
123 this.options.contextmenu(e);
127 cancelMenu: function() {
128 if (this.menu) this.menu.cancelmenu();
132 * gather info from original headings
134 getColumnInfo: function(hdrSrc) {
135 Rico.log('getColumnInfo: len='+hdrSrc.length);
136 if (hdrSrc.length == 0) return 0;
137 this.headerRowCnt=hdrSrc.length;
139 for (r=0; r<this.headerRowCnt; r++) {
140 var headerRow = hdrSrc[r];
141 var headerCells=headerRow.cells;
142 if (r >= this.hdrCells.length) this.hdrCells[r]=[];
143 for (c=0; c<headerCells.length; c++) {
145 obj.cell=headerCells[c];
146 obj.colSpan=headerCells[c].colSpan || 1; // Safari & Konqueror return default colspan of 0
147 if (this.options.defaultWidth < 0) obj.initWidth=headerCells[c].offsetWidth;
148 this.hdrCells[r].push(obj);
150 if (headerRow.id.slice(-5)=='_main') {
151 colcnt=this.hdrCells[r].length;
156 this.headerRowIdx=this.headerRowCnt-1;
157 colcnt=this.hdrCells[this.headerRowIdx].length;
159 Rico.log("getColumnInfo: colcnt="+colcnt);
163 addHeadingRow: function(className) {
164 var r=this.headerRowCnt++;
166 for( var h=0; h < 2; h++ ) {
167 var row = this.thead[h].insertRow(-1);
168 var newClass='ricoLG_hdg '+this.tableId+'_hdg'+r;
169 if (className) newClass+=' '+className;
170 row.className=newClass;
171 var limit= h==0 ? this.options.frozenColumns : this.headerColCnt-this.options.frozenColumns;
172 for( var c=0; c < limit; c++ ) {
173 var hdrCell=row.insertCell(-1);
174 var colDiv=Rico.wrapChildren(hdrCell,'ricoLG_col');
175 Rico.wrapChildren(colDiv,'ricoLG_cell');
176 this.hdrCells[r].push({cell:hdrCell,colSpan:1});
183 * create column array
185 createColumnArray: function(columnType) {
186 this.direction=Rico.getStyle(this.outerDiv,'direction').toLowerCase(); // ltr or rtl
187 this.align=this.direction=='rtl' ? ['right','left'] : ['left','right'];
188 Rico.log('createColumnArray: dir='+this.direction);
190 for (var c=0 ; c < this.headerColCnt; c++) {
191 Rico.log("createColumnArray: c="+c);
192 var tabidx=c<this.options.frozenColumns ? 0 : 1;
193 var col=new Rico[columnType](this, c, this.hdrCells[this.headerRowIdx][c], tabidx);
194 this.columns.push(col);
195 if (c > 0) this.columns[c-1].next=col;
201 * Create div structure
203 createDivs: function() {
204 Rico.log("createDivs start");
205 this.outerDiv = this.createDiv("outer");
206 if (Rico.theme.widget) Rico.addClass(this.outerDiv,Rico.theme.widget);
207 //if (Rico.isOpera) this.outerDiv.style.overflow="hidden";
208 this.scrollDiv = this.createDiv("scroll",this.outerDiv);
209 this.frozenTabs = this.createDiv("frozenTabs",this.outerDiv);
210 this.innerDiv = this.createDiv("inner",this.outerDiv);
211 this.resizeDiv = this.createDiv("resize",this.outerDiv,true);
212 this.exportDiv = this.createDiv("export",this.outerDiv,true);
214 this.messagePopup=new Rico.Popup();
215 this.messagePopup.createContainer({hideOnEscape:false, hideOnClick:false, parent:this.outerDiv});
216 this.messagePopup.content.className='ricoLG_messageDiv';
217 if (Rico.theme.gridMessage) Rico.addClass(this.messagePopup.content,Rico.theme.gridMessage);
219 this.keywordPopup=new Rico.Window('', {zIndex:-1, parent:this.outerDiv});
220 this.keywordPopup.container.className='ricoLG_keywordDiv';
221 var instructions=this.keywordPopup.contentDiv.appendChild(document.createElement("p"));
222 instructions.innerHTML=Rico.getPhraseById("keywordPrompt");
223 this.keywordBox=this.keywordPopup.contentDiv.appendChild(document.createElement("input"));
224 this.keywordBox.size=20;
225 Rico.eventBind(this.keywordBox,"keypress", Rico.eventHandle(this,'keywordKey'), false);
226 this.keywordPopup.contentDiv.appendChild(Rico.floatButton('Checkmark', Rico.eventHandle(this,'processKeyword')));
227 var s=this.keywordPopup.contentDiv.appendChild(document.createElement("p"));
228 Rico.setStyle(s,{clear:'both'});
230 //this.frozenTabs.style[this.align[0]]='0px';
231 //this.innerDiv.style[this.align[0]]='0px';
232 Rico.log("createDivs end");
235 keywordKey: function(e) {
236 switch (Rico.eventKey(e)) {
237 case 27: this.closeKeyword(); Rico.eventStop(e); return false;
238 case 13: this.processKeyword(); Rico.eventStop(e); return false;
243 openKeyword: function(colnum) {
244 this.keywordCol=colnum;
245 this.keywordBox.value='';
246 this.keywordPopup.setTitle(this.columns[colnum].displayName);
247 this.keywordPopup.centerPopup();
248 this.keywordBox.focus();
251 closeKeyword: function() {
252 this.keywordPopup.closePopup();
256 processKeyword: function() {
257 var keyword=this.keywordBox.value;
259 this.columns[this.keywordCol].setFilterKW(keyword);
263 * Create a div and give it a standardized id and class name.
264 * If the div already exists, then just assign the class name.
266 createDiv: function(elemName,elemParent,hidden) {
267 var id=this.tableId+"_"+elemName+"Div";
268 var newdiv=document.getElementById(id);
270 newdiv = document.createElement("div");
272 if (elemParent) elemParent.appendChild(newdiv);
274 newdiv.className = "ricoLG_"+elemName+"Div";
275 if (hidden) Rico.hide(newdiv);
280 * Common code used to size & position divs in both SimpleGrid & LiveGrid
282 baseSizeDivs: function() {
283 this.setOtherHdrCellWidths();
285 if (this.options.frozenColumns) {
286 Rico.show(this.tabs[0]);
287 Rico.show(this.frozenTabs);
288 // order of next 3 lines is critical in IE6
289 this.hdrHt=Math.max(Rico.nan2zero(this.thead[0].offsetHeight),this.thead[1].offsetHeight);
290 this.dataHt=Math.max(Rico.nan2zero(this.tbody[0].offsetHeight),this.tbody[1].offsetHeight);
291 this.frzWi=this.borderWidth(this.tabs[0]);
293 Rico.hide(this.tabs[0]);
294 Rico.hide(this.frozenTabs);
296 this.hdrHt=this.thead[1].offsetHeight;
297 this.dataHt=this.tbody[1].offsetHeight;
301 var borderWi=this.borderWidth(this.columns[0].dataCell);
302 Rico.log('baseSizeDivs '+this.tableId+': hdrHt='+this.hdrHt+' dataHt='+this.dataHt);
303 Rico.log(this.tableId+' frzWi='+this.frzWi+' borderWi='+borderWi);
304 for (i=0; i<this.options.frozenColumns; i++) {
305 if (this.columns[i].visible) this.frzWi+=parseInt(this.columns[i].colWidth,10)+borderWi;
307 this.scrTabWi=this.borderWidth(this.tabs[1]);
308 Rico.log('scrTabWi: '+this.scrTabWi);
309 for (i=this.options.frozenColumns; i<this.columns.length; i++) {
310 if (this.columns[i].visible) this.scrTabWi+=parseInt(this.columns[i].colWidth,10)+borderWi;
312 this.scrWi=this.scrTabWi+this.options.scrollBarWidth;
313 if (this.sizeTo=='parent') {
314 if (Rico.isIE) Rico.hide(this.outerDiv);
315 wiLimit=this.outerDiv.parentNode.offsetWidth;
316 if (Rico.isIE) Rico.show(this.outerDiv);
318 wiLimit=Rico.windowWidth()-this.options.scrollBarWidth-8;
320 if (this.outerDiv.parentNode.clientWidth > 0)
321 wiLimit=Math.min(this.outerDiv.parentNode.clientWidth, wiLimit);
322 var overage=this.frzWi+this.scrWi-wiLimit;
323 Rico.log('baseSizeDivs '+this.tableId+': scrWi='+this.scrWi+' wiLimit='+wiLimit+' overage='+overage+' clientWidth='+this.outerDiv.parentNode.clientWidth);
324 if (overage > 0 && this.options.frozenColumns < this.columns.length)
325 this.scrWi=Math.max(this.scrWi-overage, this.options.minScrollWidth);
326 this.scrollDiv.style.width=this.scrWi+'px';
327 this.scrollDiv.style.top=this.hdrHt+'px';
328 this.frozenTabs.style.width=this.scrollDiv.style[this.align[0]]=this.innerDiv.style[this.align[0]]=this.frzWi+'px';
329 this.outerDiv.style.width=(this.frzWi+this.scrWi)+'px';
333 * Returns the sum of the left & right border widths of an element
335 borderWidth: function(elem) {
336 var l=Rico.nan2zero(Rico.getStyle(elem,'borderLeftWidth'));
337 var r=Rico.nan2zero(Rico.getStyle(elem,'borderRightWidth'));
338 Rico.log((elem.id || elem.tagName)+' borderWidth: L='+l+', R='+r);
340 // return Rico.nan2zero(Rico.getStyle(elem,'borderLeftWidth')) + Rico.nan2zero(Rico.getStyle(elem,'borderRightWidth'));
343 setOtherHdrCellWidths: function() {
344 var c,i,j,r,w,hdrcell,cell,origSpan,newSpan,divs;
345 for (r=0; r<this.hdrCells.length; r++) {
346 if (r==this.headerRowIdx) continue;
347 Rico.log('setOtherHdrCellWidths: r='+r);
349 while (i<this.headerColCnt && c<this.hdrCells[r].length) {
350 hdrcell=this.hdrCells[r][c];
352 origSpan=newSpan=hdrcell.colSpan;
353 for (w=j=0; j<origSpan; j++, i++) {
354 if (this.columns[i].hdrCell.style.display=='none')
356 else if (this.columns[i].hdrColDiv.style.display!='none')
357 w+=parseInt(this.columns[i].colWidth,10);
359 if (!hdrcell.hdrColDiv || !hdrcell.hdrCellDiv) {
360 divs=cell.getElementsByTagName('div');
361 hdrcell.hdrColDiv=(divs.length<1) ? Rico.wrapChildren(cell,'ricoLG_col') : divs[0];
362 hdrcell.hdrCellDiv=(divs.length<2) ? Rico.wrapChildren(hdrcell.hdrColDiv,'ricoLG_cell') : divs[1];
365 cell.style.display='none';
367 hdrcell.hdrColDiv.style.display='none';
368 cell.colSpan=newSpan;
370 cell.style.display='';
371 hdrcell.hdrColDiv.style.display='';
372 cell.colSpan=newSpan;
373 hdrcell.hdrColDiv.style.width=w+'px';
380 initFilterImage: function(filterRowNum){
381 this.filterAnchor=document.getElementById(this.tableId+'_filterLink');
382 if (!this.filterAnchor) return;
383 this.filterRows=Rico.select('tr.'+this.tableId+'_hdg'+filterRowNum);
384 if (this.filterRows.length!=2) return;
385 for (var i=0, r=[]; i<2; i++) r[i]=Rico.select('.ricoLG_cell',this.filterRows[i]);
386 this.filterElements=r[0].concat(r[1]);
387 this.saveHeight = this.filterElements[0].offsetHeight;
388 var pt=Rico.getStyle(this.filterElements[0],'paddingTop');
389 var pb=Rico.getStyle(this.filterElements[0],'paddingBottom');
390 if (pt) this.saveHeight-=parseInt(pt,10);
391 if (pb) this.saveHeight-=parseInt(pb,10);
392 this.rowNum = filterRowNum;
393 this.setFilterImage(false);
394 //Rico.eventBind(this.filterAnchor, 'click', Rico.eventHandle(this,'toggleFilterRow'), false);
397 toggleFilterRow: function() {
398 if ( Rico.visible(this.filterRows[0]) )
399 this.slideFilterUp();
401 this.slideFilterDown();
404 setFilterImage: function(expandFlag) {
405 var altText=Rico.getPhraseById((expandFlag ? 'show' : 'hide')+'FilterRow');
406 this.filterAnchor.innerHTML = '<img src="'+Rico.imgDir+'tableFilter'+(expandFlag ? 'Expand' : 'Collapse')+'.gif" alt="'+altText+'" border="0">';
410 * Returns a div for the cell at the specified row and column index.
411 * In SimpleGrid, r can refer to any row in the grid.
412 * In LiveGrid, r refers to a visible row (row 0 is the first visible row).
414 cell: function(r,c) {
415 return (0<=c && c<this.columns.length && r>=0) ? this.columns[c].cell(r) : null;
419 * Returns the screen height available for a grid
421 availHt: function() {
422 var divPos=Rico.cumulativeOffset(this.outerDiv);
423 return Rico.windowHeight()-divPos.top-2*this.options.scrollBarWidth-15; // allow for scrollbar and some margin
426 setHorizontalScroll: function() {
427 var newLeft=(-this.scrollDiv.scrollLeft)+'px';
428 this.hdrTabs[1].style.left=newLeft;
431 pluginScroll: function() {
432 if (this.scrollPluggedIn) return;
433 Rico.eventBind(this.scrollDiv,"scroll",this.scrollEventFunc, false);
434 this.scrollPluggedIn=true;
437 unplugScroll: function() {
438 Rico.eventUnbind(this.scrollDiv,"scroll", this.scrollEventFunc , false);
439 this.scrollPluggedIn=false;
442 hideMsg: function() {
443 this.messagePopup.closePopup();
446 showMsg: function(msg) {
447 this.messagePopup.setContent(msg);
448 this.messagePopup.centerPopup();
449 Rico.log("showMsg: "+msg);
453 * @return array of column objects which have invisible status
455 listInvisible: function(attr) {
456 var hiddenColumns=[];
457 for (var x=0;x<this.columns.length;x++) {
458 if (!this.columns[x].visible)
459 hiddenColumns.push(attr ? this.columns[x][attr] : this.columns[x]);
461 return hiddenColumns;
465 * @return index of left-most visibile column, or -1 if there are no visible columns
467 firstVisible: function() {
468 for (var x=0;x<this.columns.length;x++) {
469 if (this.columns[x].visible) return x;
477 showAll: function() {
478 var invisible=this.listInvisible();
479 for (var x=0;x<invisible.length;x++)
480 invisible[x].showColumn();
483 chooseColumns: function() {
484 this.menu.cancelmenu();
485 var x,z,col,itemDiv,span,contentDiv;
\r
486 if (!this.columnChooser) {
487 Rico.log('creating columnChooser');
488 z=Rico.getStyle(this.outerDiv.offsetParent,'zIndex');
489 if (typeof z!='number') z=0;
490 this.columnChooser=new Rico.Window(Rico.getPhraseById('gridChooseCols'), {zIndex:z+2, parent:this.outerDiv});
491 this.columnChooser.container.className='ricoLG_chooserDiv';
492 contentDiv=this.columnChooser.contentDiv;
493 for (x=0;x<this.columns.length;x++) {
495 itemDiv=contentDiv.appendChild(document.createElement('div'));
496 col.ChooserBox=Rico.createFormField(itemDiv,'input','checkbox');
497 span=itemDiv.appendChild(document.createElement('span'));
498 span.innerHTML=col.displayName;
499 Rico.eventBind(col.ChooserBox, 'click', Rico.eventHandle(col,'chooseColumn'), false);
502 Rico.log('opening columnChooser');
503 this.columnChooser.openPopup(1,this.hdrHt);
504 for (x=0;x<this.columns.length;x++) {
505 this.columns[x].ChooserBox.checked=this.columns[x].visible;
506 this.columns[x].ChooserBox.disabled = !this.columns[x].canHideShow();
510 blankRow: function(r) {
511 for (var c=0; c < this.columns.length; c++) {
512 this.columns[c].clearCell(r);
516 getExportStyles: function(chkelem) {
517 var exportStyles=this.options.exportStyleList;
518 var bgImg=Rico.getStyle(chkelem,'backgroundImage');
519 if (!bgImg || bgImg=='none') return exportStyles;
520 for (var styles=[],i=0; i<exportStyles.length; i++)
521 if (exportStyles[i]!='background-color' && exportStyles[i]!='color') styles.push(exportStyles[i]);
526 * Support function for printVisible()
528 exportStart: function() {
529 var r,c,i,j,hdrcell,newSpan,divs,cell;
530 var exportStyles=this.getExportStyles(this.thead[0]);
531 //alert(exportStyles.join('\n'));
533 this.exportText="<table border='1' cellspacing='0'>";
\r
534 for (c=0; c<this.columns.length; c++) {
\r
535 if (this.columns[c].visible) this.exportText+="<col width='"+parseInt(this.columns[c].colWidth,10)+"'>";
537 this.exportText+="<thead style='display: table-header-group;'>";
538 if (this.exportHeader) this.exportText+=this.exportHeader;
539 for (r=0; r<this.hdrCells.length; r++) {
540 if (this.hdrCells[r].length==0 || !Rico.visible(this.hdrCells[r][0].cell.parentNode)) continue;
541 this.exportText+="<tr>";
542 for (c=0,i=0; c<this.hdrCells[r].length; c++) {
543 hdrcell=this.hdrCells[r][c];
544 newSpan=hdrcell.colSpan;
545 for (j=0; j<hdrcell.colSpan; j++, i++) {
546 if (!this.columns[i].visible) newSpan--;
549 divs=Rico.select('.ricoLG_cell',hdrcell.cell);
550 cell=divs && divs.length>0 ? divs[0] : hdrcell.cell;
551 this.exportText+="<td style='"+this.exportStyle(cell,exportStyles)+"'";
552 if (hdrcell.colSpan > 1) this.exportText+=" colspan='"+newSpan+"'";
553 this.exportText+=">"+Rico.getInnerText(cell,!this.options.exportImgTags, !this.options.exportFormFields, 'NoExport')+"</td>";
556 this.exportText+="</tr>";
558 this.exportText+="</thead><tbody>";
562 * Support function for printVisible().
563 * exportType is optional and defaults 'plain'; 'owc' can be used for IE users with Office Web Components.
565 exportFinish: function(exportType) {
566 if (this.hideMsg) this.hideMsg();
567 window.status=Rico.getPhraseById('exportComplete');
568 if (this.exportRows.length > 0) this.exportText+='<tr>'+this.exportRows.join('</tr><tr>')+'</tr>';
569 if (this.exportFooter) this.exportText+=this.exportFooter;
570 this.exportText+="</tbody></table>";
571 this.exportDiv.innerHTML=this.exportText;
572 this.exportText=undefined;
573 this.exportRows=undefined;
574 if (this.cancelMenu) this.cancelMenu();
575 var w=window.open(Rico.htmDir+'export-'+(exportType || 'plain')+'.html?'+this.exportDiv.id,'',this.options.exportWindow);
576 if (w == null) alert(Rico.getPhraseById('disableBlocker'));
580 * Support function for printVisible()
582 exportStyle: function(elem,styleList) {
583 for (var i=0,s=''; i < styleList.length; i++) {
585 var curstyle=Rico.getStyle(elem,styleList[i]);
586 if (curstyle) s+=styleList[i]+':'+curstyle+';';
593 * Gets the value of the grid cookie and interprets the contents.
594 * All information for a particular grid is stored in a single cookie.
595 * This may include column widths, column hide/show status, current sort, and any column filters.
597 getCookie: function() {
598 var c=Rico.getCookie(this.options.cookiePrefix+this.tableId);
600 var cookieVals=c.split(',');
601 for (var i=0; i<cookieVals.length; i++) {
602 var v=cookieVals[i].split(':');
603 if (v.length!=2) continue;
604 var colnum=parseInt(v[0].slice(1),10);
605 if (colnum < 0 || colnum >= this.columns.length) continue;
606 var col=this.columns[colnum];
607 switch (v[0].charAt(0)) {
609 col.setColWidth(v[1]);
610 col.customWidth=true;
613 if (v[1].toLowerCase()=='true')
614 col.hideshow(true,true);
616 col.hideshow(false,true);
619 if (!this.options.saveColumnInfo.sort || !col.sortable) break;
623 if (!this.options.saveColumnInfo.filter || !col.filterable) break;
624 var filterTemp=v[1].split('~');
625 col.filterOp=filterTemp.shift();
626 col.filterValues = [];
627 col.filterType = Rico.ColumnConst.USERFILTER;
628 for (var j=0; j<filterTemp.length; j++)
629 col.filterValues.push(unescape(filterTemp[j]));
636 * Sets the grid cookie.
637 * All information for a particular grid is stored in a single cookie.
638 * This may include column widths, column hide/show status, current sort, and any column filters.
640 setCookie: function() {
642 for (var i=0; i<this.columns.length; i++) {
643 var col=this.columns[i];
644 if (this.options.saveColumnInfo.width) {
645 if (col.customWidth) cookieVals.push('w'+i+':'+col.colWidth);
646 if (col.customVisible) cookieVals.push('h'+i+':'+col.visible);
648 if (this.options.saveColumnInfo.sort) {
649 if (col.currentSort != Rico.ColumnConst.UNSORTED)
650 cookieVals.push('s'+i+':'+col.currentSort);
652 if (this.options.saveColumnInfo.filter && col.filterType == Rico.ColumnConst.USERFILTER) {
653 var filterTemp=[col.filterOp];
654 for (var j=0; j<col.filterValues.length; j++)
655 filterTemp.push(escape(col.filterValues[j]));
656 cookieVals.push('f'+i+':'+filterTemp.join('~'));
659 Rico.setCookie(this.options.cookiePrefix+this.tableId, cookieVals.join(','), this.options.cookieDays, this.options.cookiePath, this.options.cookieDomain);
675 DOLLAR: {type:'number', prefix:'$', decPlaces:2, ClassName:'alignright'},
676 EURO: {type:'number', prefix:'€', decPlaces:2, ClassName:'alignright'},
677 PERCENT: {type:'number', suffix:'%', decPlaces:2, multiplier:100, ClassName:'alignright'},
678 QTY: {type:'number', decPlaces:0, ClassName:'alignright'},
679 DEFAULT: {type:"showTags"}
684 * @class Define methods that are common to columns in both SimpleGrid and LiveGrid
686 Rico.TableColumnBase = function() {};
688 Rico.TableColumnBase.prototype = {
691 * Common code used to initialize the column in both SimpleGrid & LiveGrid
693 baseInit: function(liveGrid,colIdx,hdrInfo,tabIdx) {
694 Rico.log("TableColumnBase.init index="+colIdx+" tabIdx="+tabIdx);
695 this.liveGrid = liveGrid;
697 this.hideWidth = Rico.isKonqueror || Rico.isWebKit || liveGrid.headerRowCnt>1 ? 5 : 2; // column width used for "hidden" columns. Anything less than 5 causes problems with Konqueror. Best to keep this greater than padding used inside cell.
698 this.options = liveGrid.options;
699 this.tabIdx = tabIdx;
700 this.hdrCell = hdrInfo.cell;
701 this.body = document.getElementsByTagName("body")[0]; // work around FireFox bug (document.body doesn't exist after XSLT)
702 this.displayName = this.getDisplayName(this.hdrCell);
703 var divs=this.hdrCell.getElementsByTagName('div');
704 this.hdrColDiv=(divs.length<1) ? Rico.wrapChildren(this.hdrCell,'ricoLG_col') : divs[0];
705 this.hdrCellDiv=(divs.length<2) ? Rico.wrapChildren(this.hdrColDiv,'ricoLG_cell') : divs[1];
706 var sectionIndex= tabIdx==0 ? colIdx : colIdx-liveGrid.options.frozenColumns;
707 this.dataCell = liveGrid.tbody[tabIdx].rows[0].cells[sectionIndex];
708 divs=this.dataCell.getElementsByTagName('div');
709 this.dataColDiv=(divs.length<1) ? Rico.wrapChildren(this.dataCell,'ricoLG_col') : divs[0];
711 this.mouseDownHandler= Rico.eventHandle(this,'handleMouseDown');
712 this.mouseMoveHandler= Rico.eventHandle(this,'handleMouseMove');
713 this.mouseUpHandler = Rico.eventHandle(this,'handleMouseUp');
714 this.mouseOutHandler = Rico.eventHandle(this,'handleMouseOut');
716 this.fieldName = 'col'+this.index;
717 var spec = liveGrid.options.columnSpecs[colIdx];
718 this.format=Rico.extend( {}, Rico.ColumnConst.DEFAULT);
719 switch (typeof spec) {
721 if (typeof spec.format=='string') Rico.extend(this.format, Rico.ColumnConst[spec.format.toUpperCase()]);
722 Rico.extend(this.format, spec);
725 if (spec.slice(0,4)=='spec') spec=spec.slice(4).toUpperCase(); // for backwards compatibility
726 if (typeof Rico.ColumnConst[spec]=='object') Rico.extend(this.format, Rico.ColumnConst[spec]);
729 Rico.addClass(this.dataColDiv, this.colClassName());
731 if (typeof this.format.visible=='boolean') this.visible=this.format.visible;
732 Rico.log("TableColumn.init index="+colIdx+" fieldName="+this.fieldName);
733 this.sortable = typeof this.format.canSort=='boolean' ? this.format.canSort : liveGrid.options.canSortDefault;
734 this.currentSort = Rico.ColumnConst.UNSORTED;
735 this.filterable = typeof this.format.canFilter=='boolean' ? this.format.canFilter : liveGrid.options.canFilterDefault;
736 this.filterType = Rico.ColumnConst.UNFILTERED;
737 this.hideable = typeof this.format.canHide=='boolean' ? this.format.canHide : liveGrid.options.canHideDefault;
739 var wi=(typeof(this.format.width)=='number') ? this.format.width : hdrInfo.initWidth;
740 wi=(typeof(wi)=='number') ? Math.max(wi,Rico.ColumnConst.MINWIDTH) : liveGrid.options.defaultWidth;
741 this.setColWidth(wi);
742 if (!this.visible) this.setDisplay('none');
743 if (this.options.allowColResize && !this.format.noResize) this.insertResizer();
746 colClassName: function() {
747 return this.format.ClassName ? this.format.ClassName : this.liveGrid.tableId+'_col'+this.index;
750 insertResizer: function() {
751 this.hdrCell.style.width='';
752 var resizer=this.hdrCellDiv.appendChild(document.createElement('div'));
753 resizer.className='ricoLG_Resize';
754 resizer.style[this.liveGrid.align[1]]='0px';
755 if (this.options.resizeBackground) {
756 var resizePath=Rico.imgDir+this.options.resizeBackground;
757 if (Rico.isIE && Rico.ieVersion < 8)
758 resizePath=location.protocol+resizePath; // IE6+7 only
759 resizer.style.backgroundImage='url('+resizePath+')';
761 Rico.eventBind(resizer,"mousedown", this.mouseDownHandler, false);
765 * get the display name of a column
767 getDisplayName: function(el) {
768 var anchors=el.getElementsByTagName("A");
769 //Check the existance of A tags
770 if (anchors.length > 0)
771 return anchors[0].innerHTML;
773 return Rico.stripTags(el.innerHTML);
776 _clear: function(gridCell) {
777 gridCell.innerHTML=' ';
780 clearCell: function(rowIndex) {
781 var gridCell=this.cell(rowIndex);
782 this._clear(gridCell,rowIndex);
783 if (!this.liveGrid.buffer) return;
784 var acceptAttr=this.liveGrid.buffer.options.acceptAttr;
785 for (var k=0; k<acceptAttr.length; k++) {
786 switch (acceptAttr[k]) {
787 case 'style': gridCell.style.cssText=''; break;
788 case 'class': gridCell.className=''; break;
789 default: gridCell['_'+acceptAttr[k]]=''; break;
794 dataTable: function() {
795 return this.liveGrid.tabs[this.tabIdx];
798 numRows: function() {
799 return this.dataColDiv.childNodes.length;
802 clearColumn: function() {
803 var childCnt=this.numRows();
804 for (var r=0; r<childCnt; r++)
809 return this.dataColDiv.childNodes[r];
812 getFormattedValue: function(r,xImg,xForm,xClass) {
813 return Rico.getInnerText(this.cell(r),xImg,xForm,xClass);
816 setColWidth: function(wi) {
817 if (typeof wi=='number') {
819 if (wi < Rico.ColumnConst.MINWIDTH) return;
822 Rico.log('setColWidth '+this.index+': '+wi);
824 this.hdrColDiv.style.width=wi;
825 this.dataColDiv.style.width=wi;
828 pluginMouseEvents: function() {
829 if (this.mousePluggedIn==true) return;
830 Rico.eventBind(this.body,"mousemove", this.mouseMoveHandler, false);
831 Rico.eventBind(this.body,"mouseup", this.mouseUpHandler , false);
832 Rico.eventBind(this.body,"mouseout", this.mouseOutHandler , false);
833 this.mousePluggedIn=true;
836 unplugMouseEvents: function() {
837 Rico.eventUnbind(this.body,"mousemove", this.mouseMoveHandler, false);
838 Rico.eventUnbind(this.body,"mouseup", this.mouseUpHandler , false);
839 Rico.eventUnbind(this.body,"mouseout", this.mouseOutHandler , false);
840 this.mousePluggedIn=false;
843 handleMouseDown: function(e) {
844 this.resizeStart=Rico.eventClient(e).x;
845 this.origWidth=parseInt(this.colWidth,10);
846 var p=Rico.positionedOffset(this.hdrCell);
847 if (this.liveGrid.direction=='rtl') {
848 this.edge=p.left+this.liveGrid.options.scrollBarWidth;
849 switch (this.tabIdx) {
850 case 0: this.edge+=this.liveGrid.innerDiv.offsetWidth; break;
851 case 1: this.edge-=this.liveGrid.scrollDiv.scrollLeft; break;
854 this.edge=p.left+this.hdrCell.offsetWidth;
855 if (this.tabIdx>0) this.edge+=Rico.nan2zero(this.liveGrid.tabs[0].offsetWidth)-this.liveGrid.scrollDiv.scrollLeft;
857 this.liveGrid.resizeDiv.style.left=this.edge+"px";
858 this.liveGrid.resizeDiv.style.display="";
859 this.liveGrid.outerDiv.style.cursor='e-resize';
860 this.tmpHighlight=this.liveGrid.highlightEnabled;
861 this.liveGrid.highlightEnabled=false;
862 this.pluginMouseEvents();
866 handleMouseMove: function(e) {
867 var delta=Rico.eventClient(e).x-this.resizeStart;
868 var newWidth=(this.liveGrid.direction=='rtl') ? this.origWidth-delta : this.origWidth+delta;
869 if (newWidth < Rico.ColumnConst.MINWIDTH) return;
870 this.liveGrid.resizeDiv.style.left=(this.edge+delta)+"px";
871 this.colWidth=newWidth;
875 handleMouseUp: function(e) {
876 this.unplugMouseEvents();
877 Rico.log('handleMouseUp '+this.liveGrid.tableId);
878 this.liveGrid.outerDiv.style.cursor='';
879 this.liveGrid.resizeDiv.style.display="none";
880 this.setColWidth(this.colWidth);
881 this.customWidth=true;
882 this.liveGrid.setCookie();
883 this.liveGrid.highlightEnabled=this.tmpHighlight;
884 this.liveGrid.sizeDivs();
888 handleMouseOut: function(e) {
889 var reltg = Rico.eventRelatedTarget(e) || e.toElement;
890 while (reltg != null && reltg.nodeName.toLowerCase() != 'body')
891 reltg=reltg.parentNode;
892 if (reltg!=null && reltg.nodeName.toLowerCase() == 'body') return true;
893 this.handleMouseUp(e);
897 setDisplay: function(d) {
898 this.hdrCell.style.display=d;
899 this.hdrColDiv.style.display=d;
900 this.dataCell.style.display=d;
901 this.dataColDiv.style.display=d;
904 hideshow: function(visible,noresize) {
905 this.setDisplay(visible ? '' : 'none');
906 this.liveGrid.cancelMenu();
907 this.visible=visible;
908 this.customVisible=true;
909 if (noresize) return;
910 this.liveGrid.setCookie();
911 this.liveGrid.sizeDivs();
914 hideColumn: function() {
915 Rico.log('hideColumn '+this.liveGrid.tableId);
916 this.hideshow(false,false);
919 showColumn: function() {
920 Rico.log('showColumn '+this.liveGrid.tableId);
921 this.hideshow(true,false);
924 chooseColumn: function(e) {
925 var elem=Rico.eventElement(e);
926 this.hideshow(elem.checked,false);
929 setImage: function() {
930 if ( this.currentSort == Rico.ColumnConst.SORT_ASC ) {
931 this.imgSort.style.display='inline-block';
932 this.imgSort.className=Rico.theme.sortAsc || 'ricoLG_sortAsc';
933 } else if ( this.currentSort == Rico.ColumnConst.SORT_DESC ) {
934 this.imgSort.style.display='inline-block';
935 this.imgSort.className=Rico.theme.sortDesc || 'ricoLG_sortDesc';
937 this.imgSort.style.display='none';
939 if (this.filterType == Rico.ColumnConst.USERFILTER) {
940 this.imgFilter.style.display='';
941 this.imgFilter.title=this.getFilterText();
943 this.imgFilter.style.display='none';
947 canHideShow: function() {
948 return this.hideable;
953 Rico.includeLoaded('ricoGridCommon.js');