configurationengine/source/scripts/tablefilter.js
changeset 3 e7e0ae78773e
equal deleted inserted replaced
2:87cfa131b535 3:e7e0ae78773e
       
     1 /*------------------------------------------------------------------------
       
     2 	- HTML Table Filter Generator v1.9.6
       
     3 	- By Max Guglielmi (tablefilter.free.fr)
       
     4 	- Licensed under the MIT License
       
     5 --------------------------------------------------------------------------
       
     6 Copyright (c) 2009 Max Guglielmi
       
     7 
       
     8 Permission is hereby granted, free of charge, to any person obtaining
       
     9 a copy of this software and associated documentation files (the
       
    10 "Software"), to deal in the Software without restriction, including
       
    11 without limitation the rights to use, copy, modify, merge, publish,
       
    12 distribute, sublicense, and/or sell copies of the Software, and to
       
    13 permit persons to whom the Software is furnished to do so, subject to
       
    14 the following conditions:
       
    15 
       
    16 The above copyright notice and this permission notice shall be included
       
    17 in all copies or substantial portions of the Software.
       
    18 
       
    19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
       
    20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
       
    21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
       
    22 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
       
    23 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
       
    24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       
    25 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
    26 --------------------------------------------------------------------------
       
    27 	- Special credit to: 
       
    28 	Cedric Wartel, cnx.claude@free.fr, Florent Hirchy, Váry Péter, 
       
    29 	Anthony Maes, Nuovella Williams, Fuggerbit, Venkata Seshagiri Rao 
       
    30 	Raya for active contribution and inspiration
       
    31 ------------------------------------------------------------------------*/
       
    32 
       
    33 function setFilterGrid(id)
       
    34 /*====================================================
       
    35 	- Sets filters grid bar
       
    36 	- Calls TF Constructor and generates grid bar
       
    37 	- Params:
       
    38 			- id: table id (string)
       
    39 			- refRow (optional): row index (number)
       
    40 			- config (optional): configuration 
       
    41 			object (literal object)
       
    42 =====================================================*/
       
    43 {
       
    44 	if( arguments.length==0 ) return;
       
    45 	eval( 'tf_'+id+' = new TF(arguments[0],arguments[1],arguments[2])' );
       
    46 	eval( 'tf_'+id+'.AddGrid();' );
       
    47 }
       
    48 
       
    49 /*===BEGIN removable section===========================
       
    50 	- Unobtrusive grid bar generation using 
       
    51 	'filterable' class
       
    52 	- If you don't use it you can remove safely this 
       
    53 	section
       
    54 /*=====================================================*/
       
    55 tf_addEvent(window, 'load', initFilterGrid);
       
    56 
       
    57 function initFilterGrid()
       
    58 {
       
    59 	if (!document.getElementsByTagName) return;
       
    60 	var tbls = tf_Tag(document,'table'), config;
       
    61 	for (var i=0; i<tbls.length; i++)
       
    62 	{
       
    63 		var cTbl = tbls[i], cTblId = cTbl.getAttribute('id');
       
    64 		if( tf_hasClass(cTbl,'filterable') && cTblId )
       
    65 		{
       
    66 			if( tf_isObj(cTblId+'_config') )
       
    67 				config = eval(cTblId+'_config');
       
    68 			else
       
    69 				config = undefined;
       
    70 			setFilterGrid( cTblId,config );
       
    71 		}
       
    72 	}// for i
       
    73 }
       
    74 /*===END removable section===========================*/
       
    75 
       
    76 var TF = function( id )
       
    77 /*====================================================
       
    78 	- TF object constructor
       
    79 	- Params:
       
    80 			- id: table id (string)
       
    81 			- refRow (optional): row index (number)
       
    82 			- config (optional): configuration 
       
    83 			object (literal object)
       
    84 =====================================================*/
       
    85 {
       
    86 	if( arguments.length==0 ) return;
       
    87 		
       
    88 	this.id = id;
       
    89 	this.tbl = tf_Id(id);
       
    90 	this.startRow = undefined;
       
    91 	this.refRow = null;
       
    92 	this.headersRow = null;
       
    93 	this.fObj = null;
       
    94 	this.nbFilterableRows = null;
       
    95 	this.nbRows = null;
       
    96 	this.nbCells = null;
       
    97 	this.hasGrid = false;
       
    98 	
       
    99 	if(this.tbl != null && this.tbl.nodeName.tf_LCase() == 'table' && this.GetRowsNb())
       
   100     {
       
   101 		if(arguments.length>1)
       
   102         {
       
   103             for(var i=0; i<arguments.length; i++)
       
   104             {
       
   105                 var argtype = typeof arguments[i];
       
   106                
       
   107                 switch(argtype.tf_LCase())
       
   108                 {
       
   109                     case 'number':
       
   110                         this.startRow = arguments[i];
       
   111                     break;
       
   112                     case 'object':
       
   113                         this.fObj = arguments[i];
       
   114                     break;
       
   115                 }//switch                           
       
   116             }//for
       
   117         }//if
       
   118 		
       
   119 		var f = this.fObj;
       
   120 		
       
   121 		/*** filter types ***/
       
   122 		this.fltTypeInp =			'input';
       
   123 		this.fltTypeSlc =			'select';
       
   124 		this.fltTypeMulti =			'multiple';
       
   125 		this.fltTypeCheckList =		'checklist';
       
   126 		this.fltTypeNone =			'none';
       
   127 		
       
   128 		/*** filters' grid properties ***/
       
   129 		this.fltGrid = 				f!=undefined && f.grid==false ? false : true; //enables/disables filter grid
       
   130 		
       
   131 		/*** Grid layout ***/
       
   132 		this.gridLayout = 			f!=undefined && f.grid_layout ? true : false; //enables/disables grid layout (fixed headers)
       
   133 		this.gridWidth =			f!=undefined && f.grid_width!=undefined ? f.grid_width : null; //defines grid width
       
   134 		this.gridHeight =			f!=undefined && f.grid_height!=undefined ? f.grid_height : null; //defines grid height
       
   135 		this.gridMainContCssClass = f!=undefined && f.grid_cont_css_class!=undefined //defines css class for main container
       
   136 										? f.grid_cont_css_class : 'grd_Cont';
       
   137 		this.gridContCssClass =		f!=undefined && f.grid_tbl_cont_css_class!=undefined //defines css class for div containing table
       
   138 										? f.grid_tbl_cont_css_class : 'grd_tblCont';
       
   139 		this.gridHeadContCssClass = f!=undefined && f.grid_tblHead_cont_css_class!=undefined //defines css class for div containing headers' table
       
   140 										? f.grid_tblHead_cont_css_class : 'grd_headTblCont';
       
   141 		this.gridInfDivCssClass =	f!=undefined && f.grid_inf_grid_css_class!=undefined //defines css class for div containing rows counter, paging etc.
       
   142 										? f.grid_inf_grid_css_class : 'grd_inf';
       
   143 		this.gridHeadRowIndex =		f!=undefined && f.grid_headers_row_index!=undefined //defines which row contains column headers
       
   144 										? f.grid_headers_row_index : 0; 
       
   145 		this.gridHeadRows =			f!=undefined && f.grid_headers_rows!=undefined //array of headers row indexes to be placed in header table
       
   146 										? f.grid_headers_rows : [0];
       
   147 		this.gridEnableFilters =	f!=undefined && f.grid_enable_default_filters!=undefined 
       
   148 										? f.grid_enable_default_filters : true; //generate filters in table headers
       
   149 		this.gridDefaultColWidth =	f!=undefined && f.grid_default_col_width!=undefined 
       
   150 										? f.grid_default_col_width : '100px'; //default col width						
       
   151 		this.gridEnableColResizer =	f!=undefined && f.grid_enable_cols_resizer!=undefined 
       
   152 										? f.grid_enable_cols_resizer : true; //enables/disables columns resizer
       
   153 		this.hasGridWidthsRow =		false; //flag indicating if the grid has an additional row for column widths (IE<=7)
       
   154 		this.gridColElms =			[];
       
   155 		this.sourceTblHtml = 		this.tbl.outerHTML; //original table html												
       
   156 		/*** ***/
       
   157 								
       
   158 		this.filtersRowIndex =		f!=undefined && f.filters_row_index!=undefined //defines in which row filters grid bar is generated
       
   159 										? f.filters_row_index>1 ? 1 : f.filters_row_index : 0;
       
   160 		this.fltCellTag =			f!=undefined && f.filters_cell_tag!=undefined //defines tag of the cells containing filters (td/th)
       
   161 										? (f.filters_cell_tag!='th' ? 'td' : 'th') : 'td';		
       
   162 		this.fltIds = 				[]; //stores filters ids
       
   163 		this.searchArgs =			null; //stores filters values
       
   164 		this.tblData =				[]; //stores table data
       
   165 		this.validRowsIndex =		null; //stores valid rows indexes (rows visible upon filtering)
       
   166 		this.fltGridEl =			null; //stores filters row element
       
   167 		this.isFirstLoad =			true; //is first load boolean 
       
   168 		this.infDiv =				null; //container div for paging elements, reset btn etc.
       
   169 		this.lDiv =					null; //div for rows counter
       
   170 		this.rDiv =					null; //div for reset button and results per page select
       
   171 		this.mDiv =					null; //div for paging elements
       
   172 		this.contDiv =				null; //table container div for fixed headers (IE only)
       
   173 		this.infDivCssClass =		f!=undefined && f.inf_div_css_class!=undefined	//defines css class for div containing
       
   174 										? f.inf_div_css_class : 'inf';				//paging elements, rows counter etc.
       
   175 		this.lDivCssClass =			f!=undefined && f.left_div_css_class!=undefined	//defines css class for left div 
       
   176 										? f.left_div_css_class : 'ldiv';
       
   177 		this.rDivCssClass =			f!=undefined && f.right_div_css_class!=undefined //defines css class for right div 
       
   178 										? f.right_div_css_class : 'rdiv';
       
   179 		this.mDivCssClass =			f!=undefined && f.middle_div_css_class!=undefined //defines css class for mid div 
       
   180 										? f.middle_div_css_class : 'mdiv';
       
   181 		this.contDivCssClass =		f!=undefined && f.content_div_css_class!=undefined 
       
   182 										? f.content_div_css_class : 'cont';	//table container div css class
       
   183 		
       
   184 		/*** filters' grid appearance ***/
       
   185 		this.fltsRowCssClass =		f!=undefined && f.flts_row_css_class!=undefined //defines css class for filters row
       
   186 										? f.flts_row_css_class : 'fltrow';		
       
   187 		this.alternateBgs =			f!=undefined && f.alternate_rows ? true : false; //enables/disbles rows alternating bg colors
       
   188 		this.hasColWidth =			f!=undefined && f.col_width ? true : false; //defines widths of columns
       
   189 		this.colWidth =				f!=undefined && this.hasColWidth ? f.col_width : null;
       
   190 		this.fixedHeaders =			f!=undefined && f.fixed_headers ? true : false; //enables/disables fixed headers
       
   191 		this.tBodyH = 				f!=undefined && f.tbody_height ? f.tbody_height : 200; //tbody height if fixed headers enabled
       
   192 		this.fltCssClass =			f!=undefined && f.flt_css_class!=undefined //defines css class for filters
       
   193 										? f.flt_css_class : 'flt';
       
   194 		this.fltMultiCssClass =		f!=undefined && f.flt_multi_css_class!=undefined //defines css class for multiple selects filters
       
   195 										? f.flt_multi_css_class : 'flt_multi';
       
   196 		this.fltSmallCssClass =		f!=undefined && f.flt_small_css_class!=undefined //defines css class for filters
       
   197 										? f.flt_small_css_class : 'flt_s';
       
   198 		this.singleFltCssClass =	f!=undefined && f.single_flt_css_class!=undefined //defines css class for single-filter
       
   199 										? f.single_flt_css_class : 'single_flt';	
       
   200 		this.isStartBgAlternate =	true;
       
   201 		this.rowBgEvenCssClass =	f!=undefined && f.even_row_css_class!=undefined //defines css class for even rows
       
   202 										? f.even_row_css_class :'even';
       
   203 		this.rowBgOddCssClass =		f!=undefined && f.odd_row_css_class!=undefined //defines css class for odd rows
       
   204 										? f.odd_row_css_class :'odd';
       
   205 		
       
   206 		/*** filters' grid behaviours ***/
       
   207 		this.enterKey =				f!=undefined && f.enter_key==false ? false : true; //enables/disables enter key
       
   208 		this.isModFilterFn = 		f!=undefined && f.mod_filter_fn ? true : false; //enables/disables alternative fn call		
       
   209 		this.modFilterFn =			this.isModFilterFn ? f.mod_filter_fn : null;// used by tf_DetectKey fn
       
   210 		this.onBeforeFilter =		f!=undefined && tf_isFn(f.on_before_filter) //calls function before filtering starts
       
   211 										? f.on_before_filter : null;
       
   212 		this.onAfterFilter =		f!=undefined && tf_isFn(f.on_after_filter) //calls function after filtering
       
   213 										? f.on_after_filter : null;								
       
   214 		this.matchCase =			f!=undefined && f.match_case ? true : false; //enables/disables case sensitivity
       
   215 		this.exactMatch =			f!=undefined && f.exact_match ? true : false; //enables/disbles exact match for search
       
   216 		this.refreshFilters =		f!=undefined && f.refresh_filters ? true : false; //refreshes drop-down lists upon validation
       
   217 		this.activeFlt =			null; //stores active filter element
       
   218 		this.activeFilterId =		null; //id of active filter
       
   219 		this.hasColOperation =		f!=undefined && f.col_operation ? true : false; //enables/disbles column operation(sum,mean)
       
   220 		this.colOperation =			null;
       
   221 		this.hasVisibleRows = 		f!=undefined && f.rows_always_visible ? true : false; //enables always visible rows
       
   222 		this.visibleRows =			this.hasVisibleRows ? f.rows_always_visible : [];//array containing always visible rows
       
   223 		this.searchType =			f!=undefined && f.search_type!=undefined //defines search type: include or exclude
       
   224 										? f.search_type : 'include';
       
   225 		this.isExternalFlt =		f!=undefined && f.external_flt_grid ? true : false; //enables/disables external filters generation
       
   226 		this.externalFltTgtIds =	f!=undefined && f.external_flt_grid_ids!=undefined //array containing ids of external elements containing filters
       
   227 										? f.external_flt_grid_ids : null;
       
   228 		this.externalFltEls =		[]; //stores filters elements if isExternalFlt is true		
       
   229 		this.execDelay =			f!=undefined && f.exec_delay ? parseInt(f.exec_delay) : 100; //delays filtering process if loader true
       
   230 		this.status =				f!=undefined && f.status ? true : false; //enables/disables status messages
       
   231 		this.onFiltersLoaded =		f!=undefined && tf_isFn(f.on_filters_loaded) //calls function when filters grid loaded
       
   232 										? f.on_filters_loaded : null;
       
   233 		this.singleSearchFlt =		f!=undefined && f.single_search_filter ? true : false; //enables/disables single filter search
       
   234 		this.onRowValidated =		f!=undefined && tf_isFn(f.on_row_validated) //calls function after row is validated
       
   235 									 	? f.on_row_validated : null;
       
   236 		this.customCellDataCols =	f!=undefined && f.custom_cell_data_cols ? f.custom_cell_data_cols : []; //array defining columns for customCellData event 	
       
   237 		this.customCellData =		f!=undefined && tf_isFn(f.custom_cell_data) //calls custom function for retrieving cell data
       
   238 									 	? f.custom_cell_data : null;																
       
   239 		
       
   240 		/*** selects customisation and behaviours ***/
       
   241 		this.displayAllText =		f!=undefined && f.display_all_text!=undefined ? f.display_all_text : ''; //defines 1st option text
       
   242 		this.onSlcChange = 			f!=undefined && f.on_change==false ? false : true; //enables/disables onChange event on combo-box 
       
   243 		this.sortSlc =				f!=undefined && f.sort_select==false ? false : true; //enables/disables select options sorting
       
   244 		this.isSortNumAsc =			f!=undefined && f.sort_num_asc ? true : false; //enables/disables ascending numeric options sorting
       
   245 		this.sortNumAsc =			this.isSortNumAsc ? f.sort_num_asc : null;
       
   246 		this.isSortNumDesc =		f!=undefined && f.sort_num_desc ? true : false; //enables/disables descending numeric options sorting
       
   247 		this.sortNumDesc =			this.isSortNumDesc ? f.sort_num_desc : null;
       
   248 		this.slcFillingMethod =		f!=undefined && f.slc_filling_method!=undefined //sets select filling method: 'innerHTML' or 
       
   249 										? f.slc_filling_method : 'createElement';	//'createElement'
       
   250 		this.fillSlcOnDemand =		f!=undefined && f.fill_slc_on_demand ? true : false; //enabled selects are populated on demand
       
   251 		this.activateSlcTooltip =	f!=undefined && f.activate_slc_tooltip!=undefined //IE only, tooltip text appearing on select 
       
   252 										? f.activate_slc_tooltip : 'Click to activate'; // before it is populated
       
   253 		this.multipleSlcTooltip =	f!=undefined && f.multiple_slc_tooltip!=undefined //tooltip text appearing on multiple select 
       
   254 										? f.multiple_slc_tooltip : 'Use Ctrl key for multiple selections';
       
   255 		this.hasCustomSlcOptions =	f!=undefined && f.custom_slc_options &&
       
   256 										(typeof f.custom_slc_options).tf_LCase() == 'object' 
       
   257 										? true : false;	
       
   258 		this.customSlcOptions =		f!=undefined && f.custom_slc_options!=undefined
       
   259 										? f.custom_slc_options : null;
       
   260 		this.onBeforeOperation =	f!=undefined && tf_isFn(f.on_before_operation) //calls function before col operation
       
   261 										? f.on_before_operation : null;
       
   262 		this.onAfterOperation =		f!=undefined && tf_isFn(f.on_after_operation) //calls function after col operation
       
   263 										? f.on_after_operation : null;
       
   264 		
       
   265 		/*** checklist customisation and behaviours ***/
       
   266 		this.checkListDiv = 		[]; //checklist container div
       
   267 		this.checkListDivCssClass = f!=undefined && f.div_checklist_css_class!=undefined 
       
   268 										? f.div_checklist_css_class : 'div_checklist'; //defines css class for div containing checklist filter
       
   269 		this.checkListCssClass =	f!=undefined && f.checklist_css_class!=undefined //defines css class for checklist filters
       
   270 										? f.checklist_css_class : 'flt_checklist';
       
   271 		this.checkListItemCssClass = f!=undefined && f.checklist_item_css_class!=undefined //defines css class for checklist item (li)
       
   272 										? f.checklist_item_css_class : 'flt_checklist_item';
       
   273 		this.checkListSlcItemCssClass = f!=undefined && f.checklist_selected_item_css_class!=undefined //defines css class for selected checklist item (li)
       
   274 										? f.checklist_selected_item_css_class : 'flt_checklist_slc_item';								
       
   275 		this.activateCheckListTxt =	f!=undefined && f.activate_checklist_text!=undefined //Load on demand text 
       
   276 										? f.activate_checklist_text : 'Click to load data';
       
   277 		
       
   278 		/*** Filter operators ***/
       
   279 		this.orOperator =			f!=undefined && f.or_operator!=undefined ? f.or_operator : '||';
       
   280 		this.anOperator =			f!=undefined && f.and_operator!=undefined ? f.and_operator : '&&';
       
   281 		this.grOperator = 			f!=undefined && f.greater_operator!=undefined ? f.greater_operator : '>';
       
   282 		this.lwOperator =			f!=undefined && f.lower_operator!=undefined ? f.lower_operator : '<';
       
   283 		this.leOperator =			f!=undefined && f.lower_equal_operator!=undefined ? f.lower_equal_operator : '<=';
       
   284 		this.geOperator =			f!=undefined && f.greater_equal_operator!=undefined ? f.greater_equal_operator : '>=';
       
   285 		this.dfOperator =			f!=undefined && f.different_operator!=undefined ? f.different_operator : '!';
       
   286 		this.lkOperator =			f!=undefined && f.like_operator!=undefined ? f.like_operator : '*';
       
   287 		this.eqOperator =			f!=undefined && f.equal_operator!=undefined ? f.equal_operator : '=';
       
   288 		this.stOperator =			f!=undefined && f.start_with_operator!=undefined ? f.start_with_operator : '{';
       
   289 		this.enOperator =			f!=undefined && f.end_with_operator!=undefined ? f.end_with_operator : '}';
       
   290 		this.curExp =				f!=undefined && f.cur_exp!=undefined ? f.cur_exp : '^[¥£€$]';
       
   291 		this.separator = 			f!=undefined && f.separator!=undefined ? f.separator : ',';
       
   292 		
       
   293 		/*** rows counter ***/
       
   294 		this.rowsCounter = 			f!=undefined && f.rows_counter ? true : false; //show/hides rows counter
       
   295 		this.rowsCounterTgtId =		f!=undefined && f.rows_counter_target_id!=undefined //id of custom container element
       
   296 										? f.rows_counter_target_id : null;
       
   297 		this.rowsCounterDiv =		null; //element containing tot nb rows
       
   298 		this.rowsCounterSpan =		null; //element containing tot nb rows label
       
   299 		this.rowsCounterText =		f!=undefined && f.rows_counter_text!=undefined
       
   300 										? f.rows_counter_text : 'Rows: '; //defines rows counter text
       
   301 		this.totRowsCssClass =		f!=undefined && f.tot_rows_css_class!=undefined //defines css class rows counter
       
   302 										? f.tot_rows_css_class : 'tot';		
       
   303 		
       
   304 		/*** status bar ***/
       
   305 		this.statusBar =			f!=undefined && f.status_bar ? true : false; //show/hides status bar
       
   306 		this.statusBarTgtId =		f!=undefined && f.status_bar_target_id!=undefined //id of custom container element
       
   307 										? f.status_bar_target_id : null;
       
   308 		this.statusBarDiv =			null; //element containing status bar label
       
   309 		this.statusBarSpan =		null; //status bar
       
   310 		this.statusBarSpanText =	null; //status bar label
       
   311 		this.statusBarText =		f!=undefined && f.status_bar_text!=undefined
       
   312 										? f.status_bar_text : ''; //defines status bar text
       
   313 		this.statusBarCssClass =	f!=undefined && f.status_bar_css_class!=undefined //defines css class status bar
       
   314 										? f.status_bar_css_class : 'status';
       
   315 		this.statusBarCloseDelay =	250; //delay for status bar clearing			
       
   316 		
       
   317 		/*** loader ***/
       
   318 		this.loader =				f!=undefined && f.loader ? true : false; //enables/disables loader
       
   319 		this.loaderTgtId =			f!=undefined && f.loader_target_id!=undefined //id of container element
       
   320 										? f.loader_target_id : null;
       
   321 		this.loaderDiv =			null; //div containing loader
       
   322 		this.loaderText =			f!=undefined && f.loader_text!=undefined ? f.loader_text : 'Loading...'; //defines loader text
       
   323 		this.loaderHtml =			f!=undefined && f.loader_html!=undefined ? f.loader_html : null; //defines loader innerHtml
       
   324 		this.loaderCssClass = 		f!=undefined && f.loader_css_class!=undefined //defines css class for loader div
       
   325 										? f.loader_css_class : 'loader';
       
   326 		this.loaderCloseDelay =		200; //delay for hiding loader
       
   327 		this.onShowLoader =			f!=undefined && tf_isFn(f.on_show_loader) //calls function before loader is displayed
       
   328 										? f.on_show_loader : null;
       
   329 		this.onHideLoader =			f!=undefined && tf_isFn(f.on_hide_loader) //calls function after loader is closed
       
   330 										? f.on_hide_loader : null;					
       
   331 		
       
   332 		/*** validation - reset buttons/links ***/
       
   333 		this.displayBtn =			f!=undefined && f.btn ? true : false; //show/hides filter's validation button
       
   334 		this.btnText =				f!=undefined && f.btn_text!=undefined ? f.btn_text : 'go'; //defines validation button text
       
   335 		this.btnCssClass =			f!=undefined && f.btn_css_class!=undefined //defines css class for validation button
       
   336 										? f.btn_css_class : 'btnflt';
       
   337 		this.btnReset = 			f!=undefined && f.btn_reset ? true : false; //show/hides reset link
       
   338 		this.btnResetTgtId =		f!=undefined && f.btn_reset_target_id!=undefined //id of container element
       
   339 										? f.btn_reset_target_id : null;
       
   340 		this.btnResetEl =			null; //reset button element
       
   341 		this.btnResetText =			f!=undefined && f.btn_reset_text!=undefined ? f.btn_reset_text : 'Reset'; //defines reset text
       
   342 		this.btnResetHtml = 		f!=undefined && f.btn_reset_html!=undefined ? f.btn_reset_html : null; //defines reset button innerHtml
       
   343 		this.btnResetCssClass =		f!=undefined && f.btn_reset_css_class!=undefined //defines css class for reset button
       
   344 										? f.btn_reset_css_class :'reset';
       
   345 		
       
   346 		/*** paging ***/
       
   347 		this.paging =				f!=undefined && f.paging ? true : false; //enables/disables table paging
       
   348 		this.pagingTgtId =			f!=undefined && f.paging_target_id!=undefined //id of container element
       
   349 										? f.paging_target_id : null;		
       
   350 		this.pagingLength =			f!=undefined && f.paging_length!=undefined ? f.paging_length : 10; //defines table paging length
       
   351 		this.hasResultsPerPage =	f!=undefined && f.results_per_page ? true : false; //enables/disables results per page drop-down
       
   352 		this.resultsPerPageTgtId =	f!=undefined && f.results_per_page_target_id!=undefined //id of container element
       
   353 										? f.results_per_page_target_id : null;	
       
   354 		this.resultsPerPage =		null; //stores results per page text and values			
       
   355 		this.pagingSlc =			null; //stores paging select element
       
   356 		this.isPagingRemoved =		false; //indicates if paging elements were previously removed
       
   357 		this.pgSlcCssClass =		f!=undefined && f.paging_slc_css_class!=undefined
       
   358 										? f.paging_slc_css_class :'pgSlc'; //css class for paging select element
       
   359 		this.pgInpCssClass =		f!=undefined && f.paging_inp_css_class!=undefined
       
   360 										? f.paging_inp_css_class :'pgNbInp'; //css class for paging input element
       
   361 		this.resultsPerPageSlc =	null; //results per page select element
       
   362 		this.resultsSlcCssClass =	f!=undefined && f.results_slc_css_class!=undefined
       
   363 										? f.results_slc_css_class :'rspg'; //defines css class for results per page select
       
   364 		this.resultsSpanCssClass =	f!=undefined && f.results_span_css_class!=undefined
       
   365 										? f.results_span_css_class :'rspgSpan'; //css class for label preceding results per page select
       
   366 		this.nbVisibleRows	=		0; //nb visible rows
       
   367 		this.nbHiddenRows =			0; //nb hidden rows
       
   368 		this.startPagingRow =		0; //1st row index of current page
       
   369 		this.nbPages = 				0; //total nb of pages
       
   370 		this.currentPageNb =		1; //current page nb
       
   371 		this.btnNextPageText = 		f!=undefined && f.btn_next_page_text!=undefined
       
   372 										? f.btn_next_page_text : '>'; //defines next page button text
       
   373 		this.btnPrevPageText =		f!=undefined && f.btn_prev_page_text!=undefined
       
   374 										? f.btn_prev_page_text : '<'; //defines previous page button text
       
   375 		this.btnLastPageText =		f!=undefined && f.btn_last_page_text!=undefined
       
   376 										? f.btn_last_page_text : '>|'; //defines last page button text
       
   377 		this.btnFirstPageText =		f!=undefined && f.btn_first_page_text!=undefined
       
   378 										? f.btn_first_page_text : '|<' ; //defines first page button text
       
   379 		this.btnNextPageHtml =		f!=undefined && f.btn_next_page_html!=undefined
       
   380 										? f.btn_next_page_html : null; //defines next page button html
       
   381 		this.btnPrevPageHtml =		f!=undefined && f.btn_prev_page_html!=undefined
       
   382 										? f.btn_prev_page_html : null; //defines previous page button html
       
   383 		this.btnFirstPageHtml =		f!=undefined && f.btn_first_page_html!=undefined
       
   384 										? f.btn_first_page_html : null; //defines last page button html
       
   385 		this.btnLastPageHtml =		f!=undefined && f.btn_last_page_html!=undefined
       
   386 										? f.btn_last_page_html : null; //defines previous page button html
       
   387 		this.btnPageCssClass =		f!=undefined && f.paging_btn_css_class!=undefined
       
   388 										? f.paging_btn_css_class :'pgInp'; //css class for paging buttons (previous,next,etc.)
       
   389 		this.nbPgSpanCssClass = 	f!=undefined && f.nb_pages_css_class!=undefined
       
   390 										? f.nb_pages_css_class :'nbpg'; //css class for span containing tot nb of pages
       
   391 		this.hasPagingBtns =		f!=undefined && f.paging_btns==false ? false : true; //enables/disables paging buttons
       
   392 		this.pagingBtnEvents =		null; //stores paging buttons events
       
   393 		this.pageSelectorType =		f!=undefined && f.page_selector_type!=undefined
       
   394 										? f.page_selector_type : this.fltTypeSlc; //defines previous page button html		
       
   395 		
       
   396 		/*** webfx sort adapter ***/
       
   397 		this.sort =					f!=undefined && f.sort ? true : false; //enables/disables default table sorting
       
   398 		this.isSortEnabled =		false; //indicates if sort is set (used in tfAdapter.sortabletable.js)
       
   399 		this.sorted =				false; //indicates if tables was sorted
       
   400 		this.sortConfig =			f!=undefined && f.sort_config!=undefined 
       
   401 										? f.sort_config : {};
       
   402 		this.sortConfig.name =		f!=undefined && f.sort_config!=undefined && f.sort_config.name
       
   403 										? f.sort_config.name : 'sortabletable';
       
   404 		this.sortConfig.src =		f!=undefined && f.sort_config!=undefined && f.sort_config.src
       
   405 										? f.sort_config.src : 'sortabletable.js';
       
   406 		this.sortConfig.adapterSrc =f!=undefined && f.sort_config!=undefined && f.sort_config.adapter_src
       
   407 										? f.sort_config.adapter_src : 'tfAdapter.sortabletable.js';
       
   408 		this.sortConfig.initialize =f!=undefined && f.sort_config!=undefined && f.sort_config.initialize
       
   409 										? f.sort_config.initialize
       
   410 										: function(o){ if(o.SetSortTable) o.SetSortTable(); };
       
   411 		this.sortConfig.sortTypes =	f!=undefined && f.sort_config!=undefined && f.sort_config.sort_types
       
   412 										? f.sort_config.sort_types : [];
       
   413 		this.sortConfig.sortCol =	f!=undefined && f.sort_config!=undefined && f.sort_config.sort_col!=undefined
       
   414 										? f.sort_config.sort_col : null;
       
   415 		this.sortConfig.asyncSort =	f!=undefined && f.sort_config!=undefined && f.sort_config.async_sort
       
   416 										? true : false;
       
   417 		this.sortConfig.triggerIds =f!=undefined && f.sort_config!=undefined && f.sort_config.sort_trigger_ids
       
   418 										? f.sort_config.sort_trigger_ids : [];									
       
   419 		
       
   420 		/*** onkeyup event ***/
       
   421 		this.onKeyUp =				f!=undefined && f.on_keyup ? true : false; //enables/disables onkeyup event, table is filtered when user stops typing
       
   422 		this.onKeyUpDelay =			f!=undefined && f.on_keyup_delay!=undefined ? f.on_keyup_delay : 900; //onkeyup delay timer (msecs)
       
   423 		this.isUserTyping = 		null; //typing indicator
       
   424 		this.onKeyUpTimer = 		undefined;		
       
   425 		
       
   426 		/*** keyword highlighting ***/
       
   427 		this.highlightKeywords = 	f!=undefined && f.highlight_keywords ? true : false; //enables/disables keyword highlighting
       
   428 		this.highlightCssClass =	f!=undefined && f.highlight_css_class!=undefined //defines css class for highlighting
       
   429 										? f.highlight_css_class : 'keyword';	
       
   430 		
       
   431 		/*** data types ***/
       
   432 		this.defaultDateType =		f!=undefined && f.default_date_type!=undefined //defines default date type (european DMY)
       
   433 										? f.default_date_type : 'DMY';
       
   434 		this.thousandsSeparator =	f!=undefined && f.thousands_separator!=undefined //defines default thousands separator 
       
   435 										? f.thousands_separator : ','; //US = ',' EU = '.'
       
   436 		this.decimalSeparator = 	f!=undefined && f.decimal_separator!=undefined //defines default decimal separator 
       
   437 										? f.decimal_separator : '.'; //US & javascript = '.' EU = ','
       
   438 		this.hasColNbFormat = 		f!=undefined && f.col_number_format ? true : false; //enables number format per column
       
   439 		this.colNbFormat = 			f!=undefined && this.hasColNbFormat ? f.col_number_format : null; //array containing columns nb formats
       
   440 		this.hasColDateType = 		f!=undefined && f.col_date_type ? true : false; //enables date type per column
       
   441 		this.colDateType =			f!=undefined && this.hasColDateType ? f.col_date_type : null; //array containing columns date type
       
   442 		
       
   443 		/*** status messages ***/
       
   444 		this.msgFilter =			f!=undefined && f.msg_filter!=undefined //filtering
       
   445 										? f.msg_filter : 'Filtering data...'; 
       
   446 		this.msgPopulate =			f!=undefined && f.msg_populate!=undefined //populating drop-downs
       
   447 										? f.msg_populate : 'Populating filter...'; 
       
   448 		this.msgPopulateCheckList =	f!=undefined && f.msg_populate_checklist!=undefined //populating drop-downs
       
   449 										? f.msg_populate_checklist : 'Populating list...'; 
       
   450 		this.msgChangePage =		f!=undefined && f.msg_change_page!=undefined //changing paging page
       
   451 										? f.msg_change_page : 'Collecting paging data...';
       
   452 		this.msgClear =				f!=undefined && f.msg_clear!=undefined //clearing filters
       
   453 										? f.msg_clear : 'Clearing filters...';
       
   454 		this.msgChangeResults =		f!=undefined && f.msg_change_results!=undefined //changing nb results/page
       
   455 										? f.msg_change_results : 'Changing results per page...';
       
   456 		this.msgResetValues =		f!=undefined && f.msg_reset_grid_values!=undefined //re-setting grid values
       
   457 										? f.msg_reset_grid_values : 'Re-setting filters values...';
       
   458 		this.msgResetPage =			f!=undefined && f.msg_reset_page!=undefined //re-setting page
       
   459 										? f.msg_reset_page : 'Re-setting page...';
       
   460 		this.msgResetPageLength =	f!=undefined && f.msg_reset_page_length!=undefined //re-setting page length
       
   461 										? f.msg_reset_page_length : 'Re-setting page length...';
       
   462 		this.msgSort =				f!=undefined && f.msg_sort!=undefined //table sorting
       
   463 										? f.msg_sort : 'Sorting data...';
       
   464 		this.msgLoadExtensions =	f!=undefined && f.msg_load_extensions!=undefined //table sorting
       
   465 										? f.msg_load_extensions : 'Loading extensions...';			
       
   466 
       
   467 		/*** ids prefixes ***/
       
   468 		this.prfxFlt =				'flt'; //filters (inputs - selects)
       
   469 		this.prfxValButton =		'btn'; //validation button
       
   470 		this.prfxInfDiv =			'inf_'; //container div for paging elements, rows counter etc.
       
   471 		this.prfxLDiv =				'ldiv_'; //left div
       
   472 		this.prfxRDiv =				'rdiv_'; //right div
       
   473 		this.prfxMDiv =				'mdiv_'; //middle div
       
   474 		this.prfxContentDiv =		'cont_'; //table container if fixed headers enabled
       
   475 		this.prfxCheckListDiv =		'chkdiv_'; //checklist filter container div
       
   476 		this.prfxSlcPages =			'slcPages_'; //pages select
       
   477 		this.prfxSlcResults = 		'slcResults_'; //results per page select
       
   478 		this.prfxSlcResultsTxt =	'slcResultsTxt_'; //label preciding results per page select	
       
   479 		this.prfxBtnNextSpan =		'btnNextSpan_'; //span containing next page button
       
   480 		this.prfxBtnPrevSpan =		'btnPrevSpan_'; //span containing previous page button
       
   481 		this.prfxBtnLastSpan =		'btnLastSpan_'; //span containing last page button
       
   482 		this.prfxBtnFirstSpan =		'btnFirstSpan_'; //span containing first page button
       
   483 		this.prfxBtnNext =			'btnNext_'; //next button
       
   484 		this.prfxBtnPrev =			'btnPrev_'; //previous button
       
   485 		this.prfxBtnLast =			'btnLast_'; //last button
       
   486 		this.prfxBtnFirst =			'btnFirst_'; //first button
       
   487 		this.prfxPgSpan =			'pgspan_'; //span for tot nb pages
       
   488 		this.prfxPgBeforeSpan =		'pgbeforespan_'; //span preceding pages select (contains 'Page')
       
   489 		this.prfxPgAfterSpan =		'pgafterspan_'; //span following pages select (contains ' of ')
       
   490 		this.prfxCounter =			'counter_'; //rows counter div
       
   491 		this.prfxTotRows =			'totrows_span_'; //nb displayed rows label
       
   492 		this.prfxTotRowsTxt =		'totRowsTextSpan_'; //label preceding nb rows label
       
   493 		this.prfxResetSpan =		'resetspan_'; //span containing reset button
       
   494 		this.prfxLoader =			'load_'; //loader div
       
   495 		this.prfxStatus =			'status_'; //status bar div
       
   496 		this.prfxStatusSpan =		'statusSpan_'; //status bar label
       
   497 		this.prfxStatusTxt =		'statusText_';//text preceding status bar label
       
   498 		this.prfxCookieFltsValues =	'tf_flts_'; //filter values cookie
       
   499 		this.prfxCookiePageNb =		'tf_pgnb_'; //page nb cookie
       
   500 		this.prfxCookiePageLen = 	'tf_pglen_'; //page length cookie
       
   501 		this.prfxMainTblCont =		'gridCont_'; //div containing grid elements if grid_layout true
       
   502 		this.prfxTblCont =			'tblCont_'; //div containing table if grid_layout true
       
   503 		this.prfxHeadTblCont = 		'tblHeadCont_'; //div containing headers table if grid_layout true
       
   504 		this.prfxHeadTbl =			'tblHead_';	//headers' table if grid_layout true
       
   505 		this.prfxGridFltTd =		'_td_'; //id of td containing the filter if grid_layout true
       
   506 		this.prfxGridTh =			'tblHeadTh_'; //id of th containing column header if grid_layout true				
       
   507 
       
   508 		/*** cookies ***/
       
   509 		this.hasStoredValues =		false;
       
   510 		this.rememberGridValues =	f!=undefined && f.remember_grid_values ? true : false; //remembers filters values on page load
       
   511 		this.fltsValuesCookie =		this.prfxCookieFltsValues + this.id; //cookie storing filter values
       
   512 		this.rememberPageNb =		this.paging && f!=undefined && f.remember_page_number
       
   513 										? true : false; //remembers page nb on page load	
       
   514 		this.pgNbCookie =			this.prfxCookiePageNb + this.id; //cookie storing page nb
       
   515 		this.rememberPageLen =		this.paging && f!=undefined && f.remember_page_length
       
   516 										? true : false; //remembers page length on page load
       
   517 		this.pgLenCookie =			this.prfxCookiePageLen + this.id; //cookie storing page length
       
   518 		this.cookieDuration =		f!=undefined && f.set_cookie_duration 
       
   519 										? parseInt(f.set_cookie_duration) :100000; //cookie duration
       
   520 		
       
   521 		/*** extensions ***/
       
   522 		this.hasExtensions =		f!=undefined && f.extensions ? true : false; //imports external script
       
   523 		this.extensions =			(this.hasExtensions) ? f.extensions : null;
       
   524 
       
   525 		/***(deprecated: backward compatibility) ***/
       
   526 		this.hasBindScript =		f!=undefined && f.bind_script ? true : false; //imports external script
       
   527 		this.bindScript =			(this.hasBindScript) ? f.bind_script : null;
       
   528 		
       
   529 		/*** TF events ***/
       
   530 		var o = this;
       
   531 		this.Evt = {
       
   532 			name: {
       
   533 				filter: 'Filter',
       
   534 				populateselect: 'Populate',
       
   535 				populatechecklist: 'PopulateCheckList',
       
   536 				changepage: 'ChangePage',
       
   537 				clear: 'Clear',
       
   538 				changeresultsperpage: 'ChangeResults',
       
   539 				resetvalues: 'ResetValues',
       
   540 				resetpage: 'ResetPage',
       
   541 				resetpagelength: 'ResetPageLength',
       
   542 				sort: 'Sort',
       
   543 				loadextensions: 'LoadExtensions'			
       
   544 			},
       
   545 			_DetectKey: function(e)
       
   546 			/*====================================================
       
   547 				- common fn that detects return key for a given
       
   548 				element (onkeypress for inputs)
       
   549 			=====================================================*/
       
   550 			{
       
   551 				if(!o.enterKey) return;
       
   552 				var evt=(e)?e:(window.event)?window.event:null;
       
   553 				if(evt)
       
   554 				{
       
   555 					var key=(evt.charCode)?evt.charCode:
       
   556 						((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0));
       
   557 					if(key=='13')
       
   558 					{
       
   559 						o.Filter();
       
   560 					} else { 
       
   561 						o.isUserTyping = true;
       
   562 						window.clearInterval(o.onKeyUpTimer);
       
   563 						o.onKeyUpTimer = undefined; 
       
   564 					}
       
   565 				}//if evt
       
   566 			},
       
   567 			_OnKeyUp: function(e)
       
   568 			/*====================================================
       
   569 				- onkeyup event for text filters 
       
   570 				(onKeyUp property)
       
   571 			=====================================================*/
       
   572 			{
       
   573 				if(!o.onKeyUp) return;
       
   574 				var evt=(e)?e:(window.event)?window.event:null;
       
   575 				var key=(evt.charCode)?evt.charCode:
       
   576 						((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0));
       
   577 				o.isUserTyping = false;
       
   578 				
       
   579 				if( key!=13 && key!=9 && key!=27 && key!=38 && key!=40 )
       
   580 				{
       
   581 					function filter()
       
   582 					{
       
   583 						window.clearInterval(o.onKeyUpTimer);
       
   584 						o.onKeyUpTimer = undefined;
       
   585 						if( !o.isUserTyping )
       
   586 						{
       
   587 							o.Filter();
       
   588 							o.isUserTyping = null;			
       
   589 						}
       
   590 					}
       
   591 					if(o.onKeyUpTimer==undefined)
       
   592 						o.onKeyUpTimer = window.setInterval( filter, o.onKeyUpDelay );
       
   593 				} else { 
       
   594 					window.clearInterval(o.onKeyUpTimer); 
       
   595 					o.onKeyUpTimer = undefined; 
       
   596 				}
       
   597 			},
       
   598 			_OnKeyDown: function(e)
       
   599 			/*====================================================
       
   600 				- onkeydown event for input filters 
       
   601 				(onKeyUp property)
       
   602 			=====================================================*/
       
   603 			{
       
   604 				if(!o.onKeyUp) return;
       
   605 				o.isUserTyping = true;
       
   606 			},
       
   607 			_OnInpBlur: function(e)
       
   608 			/*====================================================
       
   609 				- onblur event for input filters (onKeyUp property)
       
   610 			=====================================================*/
       
   611 			{
       
   612 				if(!o.onKeyUp) return;
       
   613 				o.isUserTyping = false; 
       
   614 				window.clearInterval(o.onKeyUpTimer);
       
   615 			},
       
   616 			_OnInpFocus: function()
       
   617 			/*====================================================
       
   618 				- onfocus event for input filters
       
   619 			=====================================================*/
       
   620 			{
       
   621 				o.activeFilterId=this.getAttribute('id');
       
   622 				o.activeFlt = tf_Id(o.activeFilterId);
       
   623 			},
       
   624 			_OnSlcFocus: function()
       
   625 			/*====================================================
       
   626 				- onfocus event for select filters
       
   627 			=====================================================*/
       
   628 			{
       
   629 				o.activeFilterId = this.getAttribute('id');
       
   630 				o.activeFlt = tf_Id(o.activeFilterId);
       
   631 				if(o.fillSlcOnDemand && this.getAttribute('filled') == '0')
       
   632 				{// select is populated when element has focus
       
   633 					var ct = this.getAttribute('ct');
       
   634 					o.PopulateSelect(ct);
       
   635 					if(!tf_isIE) this.setAttribute('filled','1');
       
   636 				}
       
   637 			},
       
   638 			_OnSlcChange: function()
       
   639 			/*====================================================
       
   640 				- onchange event for select filters
       
   641 			=====================================================*/
       
   642 			{
       
   643 				if(o.onSlcChange) o.Filter();
       
   644 			},
       
   645 			_OnSlcBlur: function()
       
   646 			/*====================================================
       
   647 				- onblur event for select filters
       
   648 			=====================================================*/
       
   649 			{
       
   650 			},
       
   651 			_OnCheckListClick: function()
       
   652 			/*====================================================
       
   653 				- onclick event for checklist filters
       
   654 			=====================================================*/
       
   655 			{
       
   656 				if(o.fillSlcOnDemand && this.getAttribute('filled') == '0')
       
   657 				{
       
   658 					var ct = this.getAttribute('ct');
       
   659 					o.PopulateCheckList(ct);
       
   660 					o.checkListDiv[ct].onclick = null;
       
   661 					o.checkListDiv[ct].title = '';
       
   662 				}
       
   663 			},
       
   664 			_OnCheckListFocus: function()
       
   665 			/*====================================================
       
   666 				- onclick event for checklist filter container
       
   667 			=====================================================*/
       
   668 			{
       
   669 				o.activeFilterId = this.firstChild.getAttribute('id');
       
   670 				o.activeFlt = tf_Id(o.activeFilterId);
       
   671 			},
       
   672 			_OnBtnClick: function()
       
   673 			/*====================================================
       
   674 				- onclick event for validation button 
       
   675 				(btn property)
       
   676 			=====================================================*/
       
   677 			{
       
   678 				o.Filter();
       
   679 			},
       
   680 			_OnSlcPagesChange: function()
       
   681 			/*====================================================
       
   682 				- onchange event for paging select
       
   683 			=====================================================*/
       
   684 			{
       
   685 				if(o.Evt._Paging._OnSlcPagesChangeEvt)
       
   686 					o.Evt._Paging._OnSlcPagesChangeEvt();
       
   687 				o.ChangePage();
       
   688 				this.blur();
       
   689 				//ie only: blur is not enough...
       
   690 				if(this.parentNode && tf_isIE)
       
   691 					this.parentNode.focus();
       
   692 			},
       
   693 			_OnSlcPagesChangeEvt: null, //used by sort adapter
       
   694 			_OnSlcResultsChange: function()
       
   695 			/*====================================================
       
   696 				- onchange event for results per page select
       
   697 			=====================================================*/
       
   698 			{
       
   699 				o.ChangeResultsPerPage();
       
   700 				this.blur();
       
   701 				//ie only: blur is not enough...
       
   702 				if(this.parentNode && tf_isIE) 
       
   703 					this.parentNode.focus();
       
   704 			},
       
   705 			_Paging: {// paging buttons events
       
   706 				slcIndex: function(){ 
       
   707 					return (o.pageSelectorType==o.fltTypeSlc) 
       
   708 						? o.pagingSlc.options.selectedIndex 
       
   709 						: parseInt(o.pagingSlc.value)-1;
       
   710 				},
       
   711 				nbOpts: function(){ 
       
   712 					return (o.pageSelectorType==o.fltTypeSlc) 
       
   713 					? parseInt(o.pagingSlc.options.length)-1 
       
   714 					: (o.nbPages-1);
       
   715 				},
       
   716 				next: function(){
       
   717 					if(o.Evt._Paging.nextEvt) o.Evt._Paging.nextEvt();
       
   718 					var nextIndex = (o.Evt._Paging.slcIndex()<o.Evt._Paging.nbOpts()) 
       
   719 						? o.Evt._Paging.slcIndex()+1 : 0;
       
   720 					o.ChangePage(nextIndex);
       
   721 				},
       
   722 				nextEvt: null, //used by sort adapter
       
   723 				prev: function(){
       
   724 					if(o.Evt._Paging.prevEvt) o.Evt._Paging.prevEvt();
       
   725 					var prevIndex = o.Evt._Paging.slcIndex()>0 
       
   726 						? o.Evt._Paging.slcIndex()-1 : o.Evt._Paging.nbOpts();
       
   727 					o.ChangePage(prevIndex);
       
   728 				},
       
   729 				prevEvt: null, //used by sort adapter
       
   730 				last: function(){
       
   731 					if(o.Evt._Paging.lastEvt) o.Evt._Paging.lastEvt();
       
   732 					o.ChangePage(o.Evt._Paging.nbOpts());
       
   733 				},
       
   734 				lastEvt: null, //used by sort adapter
       
   735 				first: function(){
       
   736 					if(o.Evt._Paging.firstEvt)  o.Evt._Paging.firstEvt();
       
   737 					o.ChangePage(0);
       
   738 				},
       
   739 				firstEvt: null, //used by sort adapter
       
   740 				_detectKey: function(e)
       
   741 				{
       
   742 					var evt=(e)?e:(window.event)?window.event:null;
       
   743 					if(evt)
       
   744 					{
       
   745 						var key=(evt.charCode)?evt.charCode:
       
   746 							((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0));
       
   747 						if(key=='13'){ 
       
   748 							if(o.sorted){ o.Filter(); o.ChangePage(o.Evt._Paging.slcIndex()); }
       
   749 							else o.ChangePage();								
       
   750 							this.blur(); 
       
   751 						}
       
   752 					}//if evt
       
   753 				}
       
   754 			},
       
   755 			_EnableSlc: function()
       
   756 			/*====================================================
       
   757 				- onclick event slc parent node (enables filters)
       
   758 				IE only
       
   759 			=====================================================*/
       
   760 			{
       
   761 				this.firstChild.disabled = false;							
       
   762 				this.firstChild.focus();							
       
   763 				this.onclick = null;
       
   764 			},
       
   765 			_Clear: function()
       
   766 			/*====================================================
       
   767 				- clears filters
       
   768 			=====================================================*/
       
   769 			{
       
   770 				o.ClearFilters();
       
   771 			},
       
   772 			_EnableSort: function()
       
   773 			/*====================================================
       
   774 				- enables table sorting
       
   775 			=====================================================*/
       
   776 			{
       
   777 				if(tf_isImported(o.sortConfig.adapterSrc))
       
   778 					o.sortConfig.initialize.call(null,o);
       
   779 				else
       
   780 					o.IncludeFile(
       
   781 						o.sortConfig.name+'_adapter',
       
   782 						o.sortConfig.adapterSrc,
       
   783 						function(){ o.sortConfig.initialize.call(null,o); }
       
   784 					);
       
   785 			}
       
   786 		};
       
   787 		
       
   788 		/*** TF extensions ***/
       
   789 		this.Ext = {
       
   790 			list: {},
       
   791 			add: function(extName, extDesc, extPath, extCallBack)
       
   792 			{
       
   793 				var file = extPath.split('/')[extPath.split('/').length-1];
       
   794 				var re = new RegExp(file);
       
   795 				var path = extPath.replace(re,'');
       
   796 				o.Ext.list[extName] = { 
       
   797 					name: extName,
       
   798 					description: extDesc,
       
   799 					file: file,
       
   800 					path: path,
       
   801 					callback: extCallBack
       
   802 				};
       
   803 			}
       
   804 		};
       
   805 		
       
   806     }//if tbl!=null		
       
   807 }
       
   808 
       
   809 TF.prototype = {
       
   810 	
       
   811 	AddGrid: function()
       
   812 	/*====================================================
       
   813 		- adds row with filtering grid bar and sets grid 
       
   814 		behaviours and layout
       
   815 	=====================================================*/
       
   816 	{
       
   817 		if(this.hasGrid) return;
       
   818 		this.refRow = this.startRow==undefined ? 2 : (this.startRow+1);
       
   819 		if(this.gridLayout) this.refRow = this.startRow==undefined ? 0 : this.startRow;
       
   820 		this.headersRow = (this.filtersRowIndex==0) ? 1 : 0;
       
   821 		try{ this.nbCells = this.GetCellsNb(this.refRow) }
       
   822 		catch(e){ this.nbCells = this.GetCellsNb(0) }
       
   823 
       
   824 		var f = this.fObj==undefined ? {} : this.fObj;
       
   825 		var n = (this.singleSearchFlt) ? 1 : this.nbCells, inpclass;
       
   826 		
       
   827 		if(this.gridLayout)
       
   828 		{
       
   829 			this.isExternalFlt = true;
       
   830 			this.SetGridLayout();
       
   831 			//Once grid generated 1st filterable row is 0 again
       
   832 			this.refRow = (tf_isIE || tf_isIE7) ? (this.refRow+1) : 0;
       
   833 		}
       
   834 		
       
   835 		if(this.loader) this.SetLoader();
       
   836 	
       
   837 		if(this.hasResultsPerPage)
       
   838 		{ 
       
   839 			this.resultsPerPage = f['results_per_page']!=undefined   
       
   840 				? f['results_per_page'] : this.resultsPerPage;
       
   841 			if(this.resultsPerPage.length<2)
       
   842 				this.hasResultsPerPage = false;
       
   843 			else
       
   844 				this.pagingLength = this.resultsPerPage[1][0];
       
   845 		}
       
   846 		
       
   847 		if(!this.fltGrid)
       
   848 		{//filters grid is not genetared
       
   849 			this.refRow = (this.refRow-1);
       
   850 			if(this.gridLayout) this.refRow = 0;
       
   851 			this.nbFilterableRows = this.GetRowsNb();
       
   852 			this.nbVisibleRows = this.nbFilterableRows;
       
   853 			this.nbRows = this.nbFilterableRows;
       
   854 		} else {
       
   855 			if(this.isFirstLoad)
       
   856 			{
       
   857 				if(!this.gridLayout){
       
   858 					var fltrow;
       
   859 					var thead = tf_Tag(this.tbl,'thead');
       
   860 					if( thead.length>0 )
       
   861 						fltrow = thead[0].insertRow(this.filtersRowIndex);
       
   862 					else
       
   863 						fltrow = this.tbl.insertRow(this.filtersRowIndex);
       
   864 					
       
   865 					if(this.fixedHeaders) this.SetFixedHeaders();
       
   866 					
       
   867 					fltrow.className = this.fltsRowCssClass;
       
   868 					//Disable for grid_layout
       
   869 					if( this.isExternalFlt && !this.gridLayout ) fltrow.style.display = 'none';
       
   870 				}
       
   871 				
       
   872 				this.nbFilterableRows = this.GetRowsNb();
       
   873 				this.nbVisibleRows = this.nbFilterableRows;
       
   874 				this.nbRows = this.tbl.rows.length;
       
   875 				
       
   876 				for(var i=0; i<n; i++)// this loop adds filters
       
   877 				{
       
   878 					var fltcell = tf_CreateElm(this.fltCellTag);
       
   879 					if(this.singleSearchFlt) fltcell.colSpan = this.nbCells;
       
   880 					if(!this.gridLayout) fltrow.appendChild( fltcell );
       
   881 					inpclass = (i==n-1 && this.displayBtn) ? this.fltSmallCssClass : this.fltCssClass;
       
   882 					
       
   883 					if( this['col'+i]==undefined )
       
   884 						this['col'+i] = (f['col_'+i]==undefined) 
       
   885 							? this.fltTypeInp : f['col_'+i].tf_LCase();
       
   886 							
       
   887 					if(this.singleSearchFlt)
       
   888 					{//only 1 input for single search
       
   889 						this['col'+i] = this.fltTypeInp;
       
   890 						inpclass = this.singleFltCssClass;
       
   891 					}
       
   892 	
       
   893 					if(this['col'+i]==this.fltTypeSlc || this['col'+i]==this.fltTypeMulti)
       
   894 					{//selects					
       
   895 						var slc = tf_CreateElm( this.fltTypeSlc,
       
   896 							['id',this.prfxFlt+i+'_'+this.id],
       
   897 							['ct',i],['filled','0'] );
       
   898 						if(this['col'+i]==this.fltTypeMulti)
       
   899 						{
       
   900 							slc.multiple = this.fltTypeMulti;
       
   901 							slc.title = this.multipleSlcTooltip;
       
   902 						}
       
   903 						slc.className = (this['col'+i].tf_LCase()==this.fltTypeSlc) 
       
   904 							? inpclass : this.fltMultiCssClass;// for ie<=6
       
   905 						
       
   906 						if( this.isExternalFlt && this.externalFltTgtIds && tf_Id(this.externalFltTgtIds[i]) )
       
   907 						{//filter is appended in desired element
       
   908 							tf_Id( this.externalFltTgtIds[i] ).appendChild(slc);
       
   909 							this.externalFltEls.push(slc);
       
   910 						} else {
       
   911 							fltcell.appendChild(slc);
       
   912 						}
       
   913 						
       
   914 						this.fltIds.push(this.prfxFlt+i+'_'+this.id);
       
   915 						
       
   916 						if(!this.fillSlcOnDemand) this.PopulateSelect(i);
       
   917 						
       
   918 						slc.onkeypress = this.Evt._DetectKey;
       
   919 						slc.onchange = this.Evt._OnSlcChange;
       
   920 						slc.onfocus = this.Evt._OnSlcFocus;
       
   921 						slc.onblur = this.Evt._OnSlcBlur;
       
   922 						
       
   923 						if(this.fillSlcOnDemand)
       
   924 						{//1st option is created here since PopulateSelect isn't invoked
       
   925 							var opt0 = tf_CreateOpt(this.displayAllText,'');
       
   926 							slc.appendChild( opt0 );						
       
   927 						}
       
   928 						
       
   929 						/* 	Code below for IE: it prevents select options to
       
   930 							slide out before select it-self is populated.
       
   931 							This is an unexpeted behavior for users since at
       
   932 							1st click options are empty. Work around: 
       
   933 							select is disabled and by clicking on element 
       
   934 							(parent td), users enable drop-down and select is
       
   935 							populated at same time.  */
       
   936 						if( this.fillSlcOnDemand && tf_isIE)
       
   937 						{
       
   938 							slc.disabled = true;
       
   939 							slc.title = this.activateSlcTooltip;
       
   940 							slc.parentNode.onclick = this.Evt._EnableSlc;
       
   941 							if( this['col'+i]==this.fltTypeMulti)
       
   942 								this.__deferMultipleSelection(slc,0);
       
   943 						}
       
   944 					}
       
   945 					
       
   946 					else if( this['col'+i]==this.fltTypeCheckList )
       
   947 					{// checklist
       
   948 						var divCont = tf_CreateElm('div',
       
   949 										['id',this.prfxCheckListDiv+i+'_'+this.id],
       
   950 										['ct',i],['filled','0'] );
       
   951 						divCont.className = this.checkListDivCssClass;
       
   952 						
       
   953 						if( this.isExternalFlt && this.externalFltTgtIds 
       
   954 							&& tf_Id(this.externalFltTgtIds[i]) )
       
   955 						{//filter is appended in desired element
       
   956 							tf_Id( this.externalFltTgtIds[i] ).appendChild(divCont);
       
   957 							this.externalFltEls.push(divCont);
       
   958 						} else {
       
   959 							fltcell.appendChild(divCont);
       
   960 						}
       
   961 						
       
   962 						this.checkListDiv[i] = divCont;
       
   963 						this.fltIds.push(this.prfxFlt+i+'_'+this.id);
       
   964 						if(!this.fillSlcOnDemand) this.PopulateCheckList(i);
       
   965 						
       
   966 						divCont.onclick = this.Evt._OnCheckListFocus;
       
   967 						
       
   968 						if(this.fillSlcOnDemand)
       
   969 						{
       
   970 							divCont.onclick = this.Evt._OnCheckListClick;
       
   971 							divCont.appendChild(tf_CreateText(this.activateCheckListTxt));
       
   972 						}
       
   973 					}
       
   974 					
       
   975 					else
       
   976 					{
       
   977 						var inptype;
       
   978 						(this['col'+i]==this.fltTypeInp) ? inptype='text' : inptype='hidden';//show/hide input	
       
   979 						var inp = tf_CreateElm( this.fltTypeInp,['id',this.prfxFlt+i+'_'+this.id],['type',inptype],['ct',i] );					
       
   980 						inp.className = inpclass;// for ie<=6
       
   981 						inp.onfocus = this.Evt._OnInpFocus;
       
   982 						
       
   983 						if( this.isExternalFlt && this.externalFltTgtIds && tf_Id(this.externalFltTgtIds[i]) )
       
   984 						{//filter is appended in desired element
       
   985 							tf_Id( this.externalFltTgtIds[i] ).appendChild(inp);
       
   986 							this.externalFltEls.push(inp);
       
   987 						} else {
       
   988 							fltcell.appendChild(inp);
       
   989 						}
       
   990 						
       
   991 						this.fltIds.push(this.prfxFlt+i+'_'+this.id);
       
   992 						
       
   993 						inp.onkeypress = this.Evt._DetectKey;
       
   994 						inp.onkeydown = this.Evt._OnKeyDown;
       
   995 						inp.onkeyup = this.Evt._OnKeyUp;
       
   996 						inp.onblur = this.Evt._OnInpBlur;
       
   997 						
       
   998 						if(this.rememberGridValues)
       
   999 						{
       
  1000 							var flts = tf_ReadCookie(this.fltsValuesCookie); //reads the cookie
       
  1001 							var reg = new RegExp(',','g');
       
  1002 							var flts_values = flts.split(reg); //creates an array with filters' values
       
  1003 							if (flts_values[i]!=' ')
       
  1004 								this.SetFilterValue(i,flts_values[i],false);					
       
  1005 						}
       
  1006 					}
       
  1007 					
       
  1008 					if(i==n-1 && this.displayBtn)// this adds validation button
       
  1009 					{
       
  1010 						var btn = tf_CreateElm( this.fltTypeInp,['id',this.prfxValButton+i+'_'+this.id],
       
  1011 												['type','button'], ['value',this.btnText] );
       
  1012 						btn.className = this.btnCssClass;
       
  1013 						
       
  1014 						if( this.isExternalFlt && this.externalFltTgtIds && tf_Id(this.externalFltTgtIds[i]) ) 
       
  1015 						//filter is appended in desired element
       
  1016 							tf_Id( this.externalFltTgtIds[i] ).appendChild(btn);
       
  1017 						else
       
  1018 							fltcell.appendChild(btn);
       
  1019 						
       
  1020 						btn.onclick = this.Evt._OnBtnClick;				
       
  1021 					}//if
       
  1022 					
       
  1023 				}// for i
       
  1024 				
       
  1025 			} else {
       
  1026 				this.__resetGrid();			
       
  1027 			}//if isFirstLoad
       
  1028 		}//if this.fltGrid
       
  1029 		
       
  1030 		/* Filter behaviours */
       
  1031 		if(this.rowsCounter) this.SetRowsCounter();
       
  1032 		if(this.statusBar) this.SetStatusBar();
       
  1033 		if(this.fixedHeaders && !this.isFirstLoad) this.SetFixedHeaders();
       
  1034 		if(this.paging)	this.SetPaging();
       
  1035 		if(this.hasResultsPerPage && this.paging) this.SetResultsPerPage();
       
  1036 		if(this.btnReset) this.SetResetBtn();
       
  1037 		
       
  1038 		if(this.hasColWidth && !this.gridLayout) this.SetColWidths();
       
  1039 		
       
  1040 		if( this.alternateBgs && this.isStartBgAlternate )
       
  1041 			this.SetAlternateRows(); //1st time only if no paging and rememberGridValues
       
  1042 		
       
  1043 		if(this.hasColOperation && this.fltGrid)
       
  1044 		{
       
  1045 			this.colOperation = f.col_operation;
       
  1046 			this.SetColOperation();
       
  1047 		}
       
  1048 		
       
  1049 		if(this.sort) this.SetSort();
       
  1050 		
       
  1051 		/* Deprecated Loads external script */
       
  1052 		if(this.hasBindScript)
       
  1053 		{
       
  1054 			if(this.bindScript['src']!=undefined)
       
  1055 			{
       
  1056 				var scriptPath = this.bindScript['src'];
       
  1057 				var scriptName = (this.bindScript['name']!=undefined)
       
  1058 									? this.bindScript['name'] : '';
       
  1059 				this.IncludeFile(scriptName,scriptPath,this.bindScript['target_fn']);
       
  1060 			}
       
  1061 		}//if bindScript
       
  1062 		/* */
       
  1063 		
       
  1064 		this.isFirstLoad = false;
       
  1065 		this.hasGrid = true;
       
  1066 		
       
  1067 		if( this.rememberGridValues ||
       
  1068 			this.rememberPageLen ||
       
  1069 			this.rememberPageNb )
       
  1070 			this.ResetValues();
       
  1071 		
       
  1072 		this.ShowLoader('none');
       
  1073 		
       
  1074 		if(this.onFiltersLoaded)
       
  1075 			this.onFiltersLoaded.call(null,this);
       
  1076 
       
  1077 		/* Loads extensions */
       
  1078 		this.LoadExtensions();
       
  1079 		/* */
       
  1080 	},// AddGrid
       
  1081 	
       
  1082 	EvtManager: function( evt,s )
       
  1083 	/*====================================================
       
  1084 		- TF events manager
       
  1085 		- Params: 
       
  1086 			- event name (string)
       
  1087 			- config object (optional literal object)
       
  1088 	=====================================================*/
       
  1089 	{
       
  1090 		var o = this;
       
  1091 		var slcIndex = (s!=undefined && s.slcIndex!=undefined) ? s.slcIndex : null;
       
  1092 		var slcExternal = (s!=undefined && s.slcExternal!=undefined) ? s.slcExternal : false;
       
  1093 		var slcId = (s!=undefined && s.slcId!=undefined) ? s.slcId : null;
       
  1094 		var pgIndex = (s!=undefined && s.pgIndex!=undefined) ? s.pgIndex : null;
       
  1095 		function efx(){
       
  1096 			if(evt!=undefined)
       
  1097 			switch( evt )
       
  1098 			{
       
  1099 				case o.Evt.name.filter:
       
  1100 					(o.isModFilterFn) 
       
  1101 						? o.modFilterFn.call(null,o)
       
  1102 						: o._Filter();
       
  1103 				break;
       
  1104 				case o.Evt.name.populateselect:
       
  1105 					(o.refreshFilters) 
       
  1106 						? o._PopulateSelect(slcIndex,true) 
       
  1107 						: o._PopulateSelect(slcIndex,false,slcExternal,slcId);
       
  1108 				break;
       
  1109 				case o.Evt.name.populatechecklist:
       
  1110 					o._PopulateCheckList(slcIndex,slcExternal,slcId);
       
  1111 				break;
       
  1112 				case o.Evt.name.changepage:
       
  1113 					o._ChangePage(pgIndex);
       
  1114 				break;
       
  1115 				case o.Evt.name.clear:
       
  1116 					o._ClearFilters(); 
       
  1117 					o._Filter();
       
  1118 				break;
       
  1119 				case o.Evt.name.changeresultsperpage:
       
  1120 					o._ChangeResultsPerPage();
       
  1121 				break;
       
  1122 				case o.Evt.name.resetvalues:
       
  1123 					o._ResetValues();					
       
  1124 					o._Filter();
       
  1125 				break;
       
  1126 				case o.Evt.name.resetpage:
       
  1127 					o._ResetPage(o.pgNbCookie);
       
  1128 				break;
       
  1129 				case o.Evt.name.resetpagelength:
       
  1130 					o._ResetPageLength(o.pgLenCookie);
       
  1131 				break;
       
  1132 				case o.Evt.name.sort:
       
  1133 					void(0);
       
  1134 				break;
       
  1135 				case o.Evt.name.loadextensions:
       
  1136 					o._LoadExtensions();
       
  1137 				break;
       
  1138 				default: //to be used by extensions events when needed
       
  1139 					o['_'+evt].call(null,o,s);
       
  1140 				break;
       
  1141 			}
       
  1142 			o.StatusMsg('');
       
  1143 			o.ShowLoader('none');
       
  1144 		}
       
  1145 		
       
  1146 		if(this.loader || this.status || this.statusBar)
       
  1147 		{
       
  1148 			this.ShowLoader('');
       
  1149 			this.StatusMsg(o['msg'+evt]);
       
  1150 			window.setTimeout(efx,this.execDelay);
       
  1151 		} else efx();
       
  1152 	},
       
  1153 	
       
  1154 	LoadExtensions: function()
       
  1155 	{
       
  1156 		this.EvtManager(this.Evt.name.loadextensions);
       
  1157 	},
       
  1158 	
       
  1159 	_LoadExtensions: function()
       
  1160 	/*====================================================
       
  1161 		- loads TF extensions
       
  1162 	=====================================================*/
       
  1163 	{
       
  1164 		if(!this.hasExtensions) return;
       
  1165 		if((typeof this.extensions.name).tf_LCase() == 'object' && 
       
  1166 				(typeof this.extensions.src).tf_LCase() == 'object')
       
  1167 		{
       
  1168 			var ext = this.extensions;
       
  1169 			for(var e=0; e<ext.name.length; e++)
       
  1170 			{
       
  1171 				var extPath = ext.src[e];
       
  1172 				var extName = ext.name[e];
       
  1173 				var extInit = (ext.initialize && ext.initialize[e]) ? ext.initialize[e] : null;
       
  1174 				var extDesc = (ext.description && ext.description[e] ) ? ext.description[e] : null;
       
  1175 				
       
  1176 				//Registers extension 
       
  1177 				this.Ext.add(extName, extDesc, extPath, extInit);
       
  1178 				
       
  1179 				if(tf_isImported(extPath) && extInit)
       
  1180 				{
       
  1181 					try{ extInit.call(null,this); }
       
  1182 					catch(e){
       
  1183 						var o = this;
       
  1184 						function fn(){extInit.call(null,o);}
       
  1185 						if(!tf_isIE) tf_addEvent(window,'load',fn); 
       
  1186 						else{
       
  1187 							function testReady(){
       
  1188 								if (document.readyState == "complete") 
       
  1189 								{
       
  1190 									fn(); clearInterval(s);
       
  1191 								}
       
  1192 							}
       
  1193 							var s = setInterval(testReady,10);
       
  1194 						}		
       
  1195 					}
       
  1196 				}
       
  1197 				else
       
  1198 					this.IncludeFile(extName,extPath,extInit);
       
  1199 			}
       
  1200 		}
       
  1201 	},
       
  1202 	
       
  1203 	RemoveGrid: function()
       
  1204 	/*====================================================
       
  1205 		- removes a filter grid
       
  1206 	=====================================================*/
       
  1207 	{
       
  1208 		if( this.fltGrid && this.hasGrid )
       
  1209 		{
       
  1210 			var row = this.tbl.rows;
       
  1211 			
       
  1212 			this.RemovePaging();
       
  1213 			this.RemoveStatusBar();
       
  1214 			this.RemoveRowsCounter();
       
  1215 			this.RemoveResetBtn();
       
  1216 			this.RemoveResultsPerPage();
       
  1217 			this.RemoveExternalFlts();
       
  1218 			this.RemoveFixedHeaders();
       
  1219 			this.RemoveTopDiv();
       
  1220 			this.UnhighlightAll();
       
  1221 			this.RemoveSort();
       
  1222 			this.RemoveLoader();
       
  1223 			
       
  1224 			for(var j=this.refRow; j<this.nbRows; j++)
       
  1225 			{//this loop shows all rows and removes validRow attribute			
       
  1226 				row[j].style.display = '';
       
  1227 				try
       
  1228 				{ 
       
  1229 					if( row[j].hasAttribute('validRow') ) 
       
  1230 						row[j].removeAttribute('validRow');
       
  1231 				} //ie<=6 doesn't support hasAttribute method
       
  1232 				catch(e){
       
  1233 					for( var x = 0; x < row[j].attributes.length; x++ ) 
       
  1234 					{
       
  1235 						if( row[j].attributes[x].nodeName.tf_LCase()=='validrow' ) 
       
  1236 							row[j].removeAttribute('validRow');
       
  1237 					}//for x
       
  1238 				}//catch(e)
       
  1239 				
       
  1240 				//removes alterning colors
       
  1241 				this.RemoveRowBg(j);
       
  1242 				
       
  1243 			}//for j
       
  1244 	
       
  1245 			if(this.fltGrid && !this.gridLayout)
       
  1246 			{
       
  1247 				this.fltGridEl = row[this.filtersRowIndex];			
       
  1248 				this.tbl.deleteRow(this.filtersRowIndex);
       
  1249 			}
       
  1250 			this.activeFlt = null;
       
  1251 			this.isStartBgAlternate = true;
       
  1252 			this.hasGrid = false;
       
  1253 			this.RemoveGridLayout();
       
  1254 	
       
  1255 		}//if this.fltGrid
       
  1256 	},
       
  1257 	
       
  1258 	SetGridLayout: function()
       
  1259 	/*====================================================
       
  1260 		- generates a grid with fixed headers
       
  1261 	=====================================================*/
       
  1262 	{
       
  1263 		if(!this.gridLayout) return;
       
  1264 		if(!this.hasColWidth){// in case column widths are not set default width 100px
       
  1265 			this.colWidth = [];
       
  1266 			for(var k=0; k<this.nbCells; k++){
       
  1267 				var colW, cell = this.tbl.rows[this.gridHeadRowIndex].cells[k];
       
  1268 				if(cell.width!='') colW = cell.width;
       
  1269 				else if(cell.style.width!='') colW = parseInt(cell.style.width);
       
  1270 				else colW = this.gridDefaultColWidth;
       
  1271 				this.colWidth[k] = colW;
       
  1272 			}
       
  1273 			this.hasColWidth = true;
       
  1274 		}
       
  1275 		this.SetColWidths(this.gridHeadRowIndex);
       
  1276 		
       
  1277 		var tblW;//initial table width
       
  1278 		if(this.tbl.width!='') tblW = this.tbl.width;
       
  1279 		else if(this.tbl.style.width!='') tblW = parseInt(this.tbl.style.width);
       
  1280 		else tblW = this.tbl.clientWidth;
       
  1281 		
       
  1282 		//Main container: it will contain all the elements
       
  1283 		this.tblMainCont = tf_CreateElm('div',['id', this.prfxMainTblCont + this.id]);
       
  1284 		this.tblMainCont.className = this.gridMainContCssClass;
       
  1285 		if(this.gridWidth) this.tblMainCont.style.width = this.gridWidth;
       
  1286 		this.tbl.parentNode.insertBefore(this.tblMainCont, this.tbl);
       
  1287 		
       
  1288 		//Table container: div wrapping content table
       
  1289 		this.tblCont = tf_CreateElm('div',['id', this.prfxTblCont + this.id]);
       
  1290 		this.tblCont.className = this.gridContCssClass;
       
  1291 		if(this.gridWidth) this.tblCont.style.width = this.gridWidth;
       
  1292 		if(this.gridHeight) this.tblCont.style.height = this.gridHeight;
       
  1293 		this.tbl.parentNode.insertBefore(this.tblCont, this.tbl);
       
  1294 		var t = this.tbl.parentNode.removeChild(this.tbl);
       
  1295 		this.tblCont.appendChild(t);
       
  1296 		
       
  1297 		//In case table width is expressed in %
       
  1298 		if(this.tbl.style.width == '')
       
  1299 			this.tbl.style.width = (this.__containsStr('%',tblW) 
       
  1300 									? this.tbl.clientWidth : tblW) + 'px';
       
  1301 
       
  1302 		var d = this.tblCont.parentNode.removeChild(this.tblCont);
       
  1303 		this.tblMainCont.appendChild(d);
       
  1304 		
       
  1305 		//Headers table container: div wrapping headers table
       
  1306 		this.headTblCont = tf_CreateElm('div',['id', this.prfxHeadTblCont + this.id]);
       
  1307 		this.headTblCont.className = this.gridHeadContCssClass;
       
  1308 		if(this.gridWidth) this.headTblCont.style.width = this.gridWidth;		
       
  1309 		
       
  1310 		//Headers table
       
  1311 		this.headTbl = tf_CreateElm('table',['id', this.prfxHeadTbl + this.id]);
       
  1312 		var tH = tf_CreateElm('tHead'); //IE<7 needs it
       
  1313 		
       
  1314 		//1st row should be headers row, ids are added if not set
       
  1315 		//Those ids are used by the sort feature
       
  1316 		var hRow = this.tbl.rows[this.gridHeadRowIndex];
       
  1317 		var sortTriggers = [];
       
  1318 		for(var n=0; n<this.nbCells; n++){
       
  1319 			var cell = hRow.cells[n];
       
  1320 			var thId = cell.getAttribute('id');
       
  1321 			if(!thId || thId==''){ 
       
  1322 				thId = this.prfxGridTh+n+'_'+this.id 
       
  1323 				cell.setAttribute('id', thId);
       
  1324 			}
       
  1325 			sortTriggers.push(thId);
       
  1326 		}
       
  1327 		
       
  1328 		//Filters row is created
       
  1329 		var filtersRow = tf_CreateElm('tr');
       
  1330 		if(this.gridEnableFilters && this.fltGrid){
       
  1331 			this.externalFltTgtIds = [];
       
  1332 			for(var j=0; j<this.nbCells; j++)
       
  1333 			{
       
  1334 				var fltTdId = this.prfxFlt+j+ this.prfxGridFltTd +this.id;
       
  1335 				var c = tf_CreateElm(this.fltCellTag, ['id', fltTdId]);
       
  1336 				filtersRow.appendChild(c);
       
  1337 				this.externalFltTgtIds[j] = fltTdId;
       
  1338 			}
       
  1339 		} 
       
  1340 		//Headers row are moved from content table to headers table
       
  1341 		for(var i=0; i<this.gridHeadRows.length; i++)
       
  1342 		{
       
  1343 			var headRow = this.tbl.rows[this.gridHeadRows[0]];			
       
  1344 			tH.appendChild(headRow);
       
  1345 		}
       
  1346 		this.headTbl.appendChild(tH);
       
  1347 		if(this.filtersRowIndex == 0) tH.insertBefore(filtersRow,hRow);
       
  1348 		if(this.filtersRowIndex == 1) tH.appendChild(filtersRow);
       
  1349 		
       
  1350 		this.headTblCont.appendChild(this.headTbl);
       
  1351 		this.tblCont.parentNode.insertBefore(this.headTblCont, this.tblCont);
       
  1352 		
       
  1353 		//THead needs to be removed in content table for sort feature
       
  1354 		var thead = tf_Tag(this.tbl,'thead');
       
  1355 		if( thead.length>0 ) this.tbl.removeChild(thead[0]);
       
  1356 
       
  1357 		//Headers table style
       
  1358 		this.headTbl.style.width = this.tbl.style.width;
       
  1359 		this.headTbl.style.tableLayout = 'fixed';
       
  1360 		this.tbl.style.tableLayout = 'fixed';
       
  1361 		this.headTbl.cellPadding = this.tbl.cellPadding;
       
  1362 		this.headTbl.cellSpacing = this.tbl.cellSpacing;
       
  1363 		
       
  1364 		//Headers container width
       
  1365 		this.headTblCont.style.width = this.tblCont.clientWidth+'px';
       
  1366 		
       
  1367 		//content table without headers needs col widths to be reset
       
  1368 		this.SetColWidths();
       
  1369 		
       
  1370 		this.tbl.style.width = '';		
       
  1371 		if(tf_isIE || tf_isIE7)	this.headTbl.style.width = '';
       
  1372 		
       
  1373 		//scroll synchronisation
       
  1374 		var o = this; //TF object
       
  1375 		this.tblCont.onscroll = function(){
       
  1376 			o.headTblCont.scrollLeft = this.scrollLeft;
       
  1377 			var _o = this; //this = scroll element
       
  1378 			//New pointerX calc taking into account scrollLeft
       
  1379 			if(!o.isPointerXOverwritten){
       
  1380 				try{					
       
  1381 					TF.Evt.pointerX = function(e)
       
  1382 					{
       
  1383 						e = e || window.event;
       
  1384 						var scrollLeft = tf_StandardBody().scrollLeft + _o.scrollLeft;
       
  1385 						return (e.pageX + _o.scrollLeft) || (e.clientX + scrollLeft);
       
  1386 					}					
       
  1387 					o.isPointerXOverwritten = true;
       
  1388 				} catch(ee) {
       
  1389 					o.isPointerXOverwritten = false;
       
  1390 				}
       
  1391 			}
       
  1392 		}
       
  1393 
       
  1394 		/*** Default behaviours activation ***/
       
  1395 		var f = this.fObj==undefined ? {} : this.fObj;
       
  1396 		
       
  1397 		//Sort is enabled if not specified in config object
       
  1398 		if(f.sort != false){
       
  1399 			this.sort = true;
       
  1400 			this.sortConfig.asyncSort = true;
       
  1401 			this.sortConfig.triggerIds = sortTriggers;
       
  1402 		}
       
  1403 		
       
  1404 		if(this.gridEnableColResizer){
       
  1405 			if(!this.hasExtensions){
       
  1406 				this.extensions = {
       
  1407 					name:['ColumnsResizer'],
       
  1408 					src:['TFExt_ColsResizer/TFExt_ColsResizer.js'], 
       
  1409 					description:['Columns Resizing'],
       
  1410 					initialize:[function(o){o.SetColsResizer('ColumnsResizer');}]
       
  1411 				}
       
  1412 				this.hasExtensions = true;
       
  1413 			} else {
       
  1414 				if(!this.__containsStr('colsresizer',this.extensions.src.toString().tf_LCase())){
       
  1415 					this.extensions.name.push('ColumnsResizer');
       
  1416 					this.extensions.src.push('TFExt_ColsResizer/TFExt_ColsResizer.js');
       
  1417 					this.extensions.description.push('Columns Resizing');
       
  1418 					this.extensions.initialize.push(function(o){o.SetColsResizer('ColumnsResizer');});
       
  1419 				}  
       
  1420 			}
       
  1421 		}
       
  1422 		
       
  1423 		//Default columns resizer properties for grid layout
       
  1424 		f.col_resizer_cols_headers_table = this.headTbl.getAttribute('id');
       
  1425 		f.col_resizer_cols_headers_index = this.gridHeadRowIndex;
       
  1426 		f.col_resizer_width_adjustment = 0;
       
  1427 		f.col_enable_text_ellipsis = false;
       
  1428 		
       
  1429 		//Cols generation for all browsers excepted IE<=7
       
  1430 		o.tblHasColTag = (tf_Tag(o.tbl,'col').length > 0) ? true : false;
       
  1431 		if(!tf_isIE && !tf_isIE7){
       
  1432 			//Col elements are enough to keep column widths after sorting and filtering
       
  1433 			function createColTags(o)
       
  1434 			{
       
  1435 				if(!o) return;
       
  1436 				for(var k=(o.nbCells-1); k>=0; k--)
       
  1437 				{
       
  1438 					var col = tf_CreateElm( 'col', ['id', o.id+'_col_'+k]);
       
  1439 					o.tbl.firstChild.parentNode.insertBefore(col,o.tbl.firstChild);
       
  1440 					col.style.width = o.colWidth[k];
       
  1441 					o.gridColElms[k] = col;
       
  1442 				}
       
  1443 				o.tblHasColTag = true;
       
  1444 			}
       
  1445 			if(!o.tblHasColTag) createColTags(o);
       
  1446 			else{
       
  1447 				var cols = tf_Tag(o.tbl,'col');
       
  1448 				for(var i=0; i<o.nbCells; i++){
       
  1449 					cols[i].setAttribute('id', o.id+'_col_'+i);
       
  1450 					cols[i].style.width = o.colWidth[i];
       
  1451 					o.gridColElms.push(cols[i]);
       
  1452 				}
       
  1453 			}
       
  1454 		}
       
  1455 		
       
  1456 		//IE <= 7 needs an additional row for widths as col element width is not enough...
       
  1457 		if(tf_isIE || tf_isIE7){
       
  1458 			var tbody = tf_Tag(o.tbl,'tbody'), r;
       
  1459 			if( tbody.length>0 ) r = tbody[0].insertRow(0);
       
  1460 			else r = o.tbl.insertRow(0);
       
  1461 			r.style.height = '0px';
       
  1462 			for(var i=0; i<o.nbCells; i++){
       
  1463 				var col = tf_CreateElm('td', ['id', o.id+'_col_'+i]);
       
  1464 				col.style.width = o.colWidth[i];
       
  1465 				o.tbl.rows[1].cells[i].style.width = '';
       
  1466 				r.appendChild(col);
       
  1467 				o.gridColElms.push(col);
       
  1468 			}
       
  1469 			this.hasGridWidthsRow = true;
       
  1470 			//Data table row with widths expressed
       
  1471 			o.leadColWidthsRow = o.tbl.rows[0];
       
  1472 			o.leadColWidthsRow.setAttribute('validRow','false');
       
  1473 			
       
  1474 			var beforeSortFn = tf_isFn(f.on_before_sort) ? f.on_before_sort : null;
       
  1475 			f.on_before_sort = function(o,colIndex){
       
  1476 				o.leadColWidthsRow.setAttribute('validRow','false');
       
  1477 				if(beforeSortFn!=null) beforeSortFn.call(null,o,colIndex);
       
  1478 			} 
       
  1479 			
       
  1480 			var afterSortFn = tf_isFn(f.on_after_sort) ? f.on_after_sort : null;
       
  1481 			f.on_after_sort = function(o,colIndex){
       
  1482 				if(o.leadColWidthsRow.rowIndex != 0){
       
  1483 					var r = o.leadColWidthsRow;
       
  1484 					if( tbody.length>0 )
       
  1485 						tbody[0].moveRow(o.leadColWidthsRow.rowIndex, 0);
       
  1486 					else o.tbl.moveRow(o.leadColWidthsRow.rowIndex, 0);
       
  1487 				}
       
  1488 				if(afterSortFn!=null) afterSortFn.call(null,o,colIndex);
       
  1489 			}	
       
  1490 		}
       
  1491 		
       
  1492 		var afterColResizedFn = tf_isFn(f.on_after_col_resized) ? f.on_after_col_resized : null;
       
  1493 		f.on_after_col_resized = function(o,colIndex){
       
  1494 			if(colIndex==undefined) return;
       
  1495 			var w = o.crWColsRow.cells[colIndex].style.width;
       
  1496 			var col = o.gridColElms[colIndex];
       
  1497 			col.style.width = w;
       
  1498 			
       
  1499 			var thCW = o.crWColsRow.cells[colIndex].clientWidth;
       
  1500 			var tdCW = o.crWRowDataTbl.cells[colIndex].clientWidth;
       
  1501 			
       
  1502 			if(tf_isIE || tf_isIE7)
       
  1503 				o.tbl.style.width = o.headTbl.clientWidth+'px';
       
  1504 			
       
  1505 			if(thCW != tdCW && !tf_isIE && !tf_isIE7)
       
  1506 				o.headTbl.style.width = o.tbl.clientWidth+'px'; 
       
  1507 			
       
  1508 			if(afterColResizedFn!=null) afterColResizedFn.call(null,o,colIndex);			
       
  1509 		}	
       
  1510 		
       
  1511 		if(this.tbl.clientWidth != this.headTbl.clientWidth)
       
  1512 			this.tbl.style.width = this.headTbl.clientWidth+'px';
       
  1513 	},
       
  1514 	
       
  1515 	RemoveGridLayout: function()
       
  1516 	{
       
  1517 		if(!this.gridLayout) return;		
       
  1518 		var t = this.tbl.parentNode.removeChild(this.tbl);
       
  1519 		this.tblMainCont.parentNode.insertBefore(t, this.tblMainCont);
       
  1520 		this.tblMainCont.parentNode.removeChild( this.tblMainCont );
       
  1521 		this.tblMainCont = null;
       
  1522 		this.headTblCont = null;
       
  1523 		this.headTbl = null;
       
  1524 		this.tblCont = null;
       
  1525 		//TO DO: alternative solution for Firefox
       
  1526 		this.tbl.outerHTML = this.sourceTblHtml;
       
  1527 		this.tbl = tf_Id(this.id);
       
  1528 		this.isFirstLoad = true;
       
  1529 		this.activeFlt = null;
       
  1530 		this.isStartBgAlternate = true;
       
  1531 		this.hasGrid = false;
       
  1532 	},
       
  1533 	
       
  1534 	SetTopDiv: function()
       
  1535 	/*====================================================
       
  1536 		- Generates div above table where paging,
       
  1537 		reset button, rows counter label etc. are placed
       
  1538 	=====================================================*/
       
  1539 	{
       
  1540 		if( this.infDiv!=null ) return;
       
  1541 	
       
  1542 		/*** container div ***/
       
  1543 		var infdiv = tf_CreateElm( 'div',['id',this.prfxInfDiv+this.id] );
       
  1544 		infdiv.className = this.infDivCssClass;// setAttribute method doesn't seem to work on ie<=6
       
  1545 		if(this.fixedHeaders && this.contDiv)
       
  1546 			this.contDiv.parentNode.insertBefore(infdiv, this.contDiv);
       
  1547 		else if(this.gridLayout){
       
  1548 			this.tblMainCont.appendChild(infdiv);
       
  1549 			infdiv.className = this.gridInfDivCssClass;
       
  1550 		}
       
  1551 		else
       
  1552 			this.tbl.parentNode.insertBefore(infdiv, this.tbl);
       
  1553 		this.infDiv = tf_Id( this.prfxInfDiv+this.id );
       
  1554 		
       
  1555 		/*** left div containing rows # displayer ***/
       
  1556 		var ldiv = tf_CreateElm( 'div',['id',this.prfxLDiv+this.id] );
       
  1557 		ldiv.className = this.lDivCssClass;/*'ldiv'*/;
       
  1558 		infdiv.appendChild(ldiv);
       
  1559 		this.lDiv = tf_Id( this.prfxLDiv+this.id );		
       
  1560 		
       
  1561 		/*** 	right div containing reset button 
       
  1562 				+ nb results per page select 	***/	
       
  1563 		var rdiv = tf_CreateElm( 'div',['id',this.prfxRDiv+this.id] );
       
  1564 		rdiv.className = this.rDivCssClass/*'rdiv'*/;
       
  1565 		infdiv.appendChild(rdiv);
       
  1566 		this.rDiv = tf_Id( this.prfxRDiv+this.id );
       
  1567 		
       
  1568 		/*** mid div containing paging elements ***/
       
  1569 		var mdiv = tf_CreateElm( 'div',['id',this.prfxMDiv+this.id] );
       
  1570 		mdiv.className = this.mDivCssClass/*'mdiv'*/;						
       
  1571 		infdiv.appendChild(mdiv);
       
  1572 		this.mDiv = tf_Id( this.prfxMDiv+this.id );
       
  1573 	},
       
  1574 	
       
  1575 	RemoveTopDiv: function()
       
  1576 	/*====================================================
       
  1577 		- Removes div above table where paging,
       
  1578 		reset button, rows counter label etc. are placed
       
  1579 	=====================================================*/
       
  1580 	{
       
  1581 		if( this.infDiv==null ) return;
       
  1582 		this.infDiv.parentNode.removeChild( this.infDiv );
       
  1583 		this.infDiv = null;
       
  1584 	},
       
  1585 	
       
  1586 	SetFixedHeaders: function()
       
  1587 	/*====================================================
       
  1588 		- CSS solution making headers fixed
       
  1589 	=====================================================*/
       
  1590 	{
       
  1591 		if((!this.hasGrid && !this.isFirstLoad) || !this.fixedHeaders) return;
       
  1592 		if(this.contDiv) return;	
       
  1593 		var thead = tf_Tag(this.tbl,'thead');
       
  1594 		if( thead.length==0 ) return;
       
  1595 		var tbody = tf_Tag(this.tbl,'tbody');	
       
  1596 		if( tbody[0].clientHeight!=0 ) 
       
  1597 		{//firefox returns tbody height
       
  1598 			//previous values
       
  1599 			this.prevTBodyH = tbody[0].clientHeight;
       
  1600 			this.prevTBodyOverflow = tbody[0].style.overflow;
       
  1601 			this.prevTBodyOverflowX = tbody[0].style.overflowX;
       
  1602 			
       
  1603 			tbody[0].style.height = this.tBodyH+'px';
       
  1604 			tbody[0].style.overflow = 'auto';
       
  1605 			tbody[0].style.overflowX = 'hidden';
       
  1606 		} else { //IE returns 0
       
  1607 			// cont div is added to emulate fixed headers behaviour
       
  1608 			var contDiv = tf_CreateElm( 'div',['id',this.prfxContentDiv+this.id] );
       
  1609 			contDiv.className = this.contDivCssClass;
       
  1610 			this.tbl.parentNode.insertBefore(contDiv, this.tbl);
       
  1611 			contDiv.appendChild(this.tbl);
       
  1612 			this.contDiv = tf_Id(this.prfxContentDiv+this.id);
       
  1613 			//prevents headers moving during window scroll (IE)
       
  1614 			this.contDiv.style.position = 'relative';
       
  1615 			
       
  1616 			var theadH = 0;
       
  1617 			var theadTr = tf_Tag(thead[0],'tr');	
       
  1618 			for(var i=0; i<theadTr.length; i++)
       
  1619 			{//css below emulates fixed headers on IE<=6
       
  1620 				theadTr[i].style.cssText += 'position:relative; ' +
       
  1621 											'top:expression(offsetParent.scrollTop);';
       
  1622 				theadH += parseInt(theadTr[i].clientHeight);
       
  1623 			}
       
  1624 			
       
  1625 			this.contDiv.style.height = (this.tBodyH+theadH)+'px';
       
  1626 			
       
  1627 			var tfoot = tf_Tag(this.tbl,'tfoot');
       
  1628 			if( tfoot.length==0 ) return;
       
  1629 			
       
  1630 			var tfootTr = tf_Tag(tfoot[0],'tr');
       
  1631 				
       
  1632 			for(var j=0; j<tfootTr.length; j++)//css below emulates fixed footer on IE<=6
       
  1633 				tfootTr[j].style.cssText += 'position:relative; overflow-x: hidden; ' +
       
  1634 											'top: expression(parentNode.parentNode.offsetHeight >= ' +
       
  1635 											'offsetParent.offsetHeight ? 0 - parentNode.parentNode.offsetHeight + '+ 
       
  1636 											'offsetParent.offsetHeight + offsetParent.scrollTop : 0);';		
       
  1637 		}	
       
  1638 	},
       
  1639 	
       
  1640 	RemoveFixedHeaders: function()
       
  1641 	/*====================================================
       
  1642 		- Removes fixed headers
       
  1643 	=====================================================*/
       
  1644 	{
       
  1645 		if(!this.hasGrid || !this.fixedHeaders ) return;
       
  1646 		if( this.contDiv )//IE additional div
       
  1647 		{
       
  1648 			this.contDiv.parentNode.insertBefore(this.tbl, this.contDiv);
       
  1649 			this.contDiv.parentNode.removeChild( this.contDiv );
       
  1650 			this.contDiv = null;
       
  1651 			var thead = tf_Tag(this.tbl,'thead');
       
  1652 			if( thead.length==0 ) return;
       
  1653 			var theadTr = tf_Tag(thead[0],'tr');
       
  1654 			if( theadTr.length==0 ) return;
       
  1655 			for(var i=0; i<theadTr.length; i++)
       
  1656 				theadTr[i].style.cssText = '';
       
  1657 			var tfoot = tf_Tag(this.tbl,'tfoot');
       
  1658 			if( tfoot.length==0 ) return;		
       
  1659 			var tfootTr = tf_Tag(tfoot[0],'tr');	
       
  1660 			for(var j=0; j<tfootTr.length; j++)
       
  1661 			{
       
  1662 				tfootTr[j].style.position = 'relative';
       
  1663 				tfootTr[j].style.top = '';
       
  1664 				tfootTr[j].style.overeflowX = '';
       
  1665 			}
       
  1666 		} else {
       
  1667 			var tbody = tf_Tag(this.tbl,'tbody');
       
  1668 			if( tbody.length==0 ) return;
       
  1669 			tbody[0].style.height = this.prevTBodyH+'px';
       
  1670 			tbody[0].style.overflow = this.prevTBodyOverflow;
       
  1671 			tbody[0].style.overflowX = this.prevTBodyOverflowX;
       
  1672 		}
       
  1673 	},
       
  1674 	
       
  1675 	SetPaging: function()
       
  1676 	/*====================================================
       
  1677 		- Generates paging elements:
       
  1678 			- pages drop-down list
       
  1679 			- previous, next, first, last buttons
       
  1680 	=====================================================*/
       
  1681 	{
       
  1682 		if(!this.hasGrid && !this.isFirstLoad) return;
       
  1683 		if(!this.paging || (!this.isPagingRemoved && !this.isFirstLoad)) return;
       
  1684 		var start_row = this.refRow;
       
  1685 		var nrows = this.nbRows;
       
  1686 		this.nbPages = Math.ceil( (nrows-start_row)/this.pagingLength );//calculates page nb
       
  1687 	
       
  1688 		// Paging drop-down list selector
       
  1689 		if(this.pageSelectorType == this.fltTypeSlc)
       
  1690 		{
       
  1691 			var slcPages = tf_CreateElm( this.fltTypeSlc, ['id',this.prfxSlcPages+this.id] );
       
  1692 			slcPages.className = this.pgSlcCssClass;
       
  1693 			slcPages.onchange = this.Evt._OnSlcPagesChange;
       
  1694 		}
       
  1695 		// Paging input selector
       
  1696 		if(this.pageSelectorType == this.fltTypeInp)
       
  1697 		{
       
  1698 			var slcPages = tf_CreateElm( 
       
  1699 				this.fltTypeInp, 
       
  1700 				['id',this.prfxSlcPages+this.id],
       
  1701 				['value',this.currentPageNb]
       
  1702 			);
       
  1703 			slcPages.className = this.pgInpCssClass;
       
  1704 			slcPages.onkeypress = this.Evt._Paging._detectKey;
       
  1705 		}
       
  1706 		
       
  1707 		var btnNextSpan, btnPrevSpan, btnLastSpan, btnFirstSpan;// btns containers
       
  1708 		btnNextSpan = tf_CreateElm('span',['id',this.prfxBtnNextSpan+this.id]);
       
  1709 		btnPrevSpan = tf_CreateElm('span',['id',this.prfxBtnPrevSpan+this.id]);
       
  1710 		btnLastSpan = tf_CreateElm('span',['id',this.prfxBtnLastSpan+this.id]);
       
  1711 		btnFirstSpan = tf_CreateElm('span',['id',this.prfxBtnFirstSpan+this.id]);
       
  1712 		
       
  1713 		if(this.hasPagingBtns)
       
  1714 		{
       
  1715 			if(this.btnNextPageHtml==null)
       
  1716 			{// Next button
       
  1717 				var btn_next = tf_CreateElm( this.fltTypeInp,['id',this.prfxBtnNext+this.id],
       
  1718 					['type','button'],['value',this.btnNextPageText],['title','Next'] );
       
  1719 				btn_next.className = this.btnPageCssClass;
       
  1720 				btn_next.onclick = this.Evt._Paging.next;
       
  1721 				btnNextSpan.appendChild(btn_next);
       
  1722 			} else {
       
  1723 				btnNextSpan.innerHTML = this.btnNextPageHtml;
       
  1724 				btnNextSpan.onclick = this.Evt._Paging.next;
       
  1725 			}
       
  1726 			
       
  1727 			if(this.btnPrevPageHtml==null)
       
  1728 			{// Previous button
       
  1729 				var btn_prev = tf_CreateElm( this.fltTypeInp,['id',this.prfxBtnPrev+this.id],
       
  1730 					['type','button'],['value',this.btnPrevPageText],['title','Previous'] );
       
  1731 				btn_prev.className = this.btnPageCssClass;
       
  1732 				btn_prev.onclick = this.Evt._Paging.prev;
       
  1733 				btnPrevSpan.appendChild(btn_prev);
       
  1734 			} else { 
       
  1735 				btnPrevSpan.innerHTML = this.btnPrevPageHtml;
       
  1736 				btnPrevSpan.onclick = this.Evt._Paging.prev;
       
  1737 			}
       
  1738 			
       
  1739 			if(this.btnLastPageHtml==null)
       
  1740 			{// Last button
       
  1741 				var btn_last = tf_CreateElm( this.fltTypeInp,['id',this.prfxBtnLast+this.id],
       
  1742 					['type','button'],['value',this.btnLastPageText],['title','Last'] );
       
  1743 				btn_last.className = this.btnPageCssClass;
       
  1744 				btn_last.onclick = this.Evt._Paging.last;
       
  1745 				btnLastSpan.appendChild(btn_last);
       
  1746 			} else { 
       
  1747 				btnLastSpan.innerHTML = this.btnLastPageHtml;
       
  1748 				btnLastSpan.onclick = this.Evt._Paging.last;
       
  1749 			}
       
  1750 			
       
  1751 			if(this.btnFirstPageHtml==null)
       
  1752 			{// First button
       
  1753 				var btn_first = tf_CreateElm( this.fltTypeInp,['id',this.prfxBtnFirst+this.id],
       
  1754 					['type','button'],['value',this.btnFirstPageText],['title','First'] );
       
  1755 				btn_first.className = this.btnPageCssClass;
       
  1756 				btn_first.onclick = this.Evt._Paging.first;
       
  1757 				btnFirstSpan.appendChild(btn_first);
       
  1758 			} else { 
       
  1759 				btnFirstSpan.innerHTML = this.btnFirstPageHtml;
       
  1760 				btnFirstSpan.onclick = this.Evt._Paging.first;
       
  1761 			}			
       
  1762 		}//if this.hasPagingBtns
       
  1763 		
       
  1764 		// paging elements (buttons+drop-down list) are added to defined element
       
  1765 		if(this.pagingTgtId==null) this.SetTopDiv();
       
  1766 		var targetEl = ( this.pagingTgtId==null ) ? this.mDiv : tf_Id( this.pagingTgtId );
       
  1767 		
       
  1768 		/***	if paging previously removed this prevents IE memory leak with removeChild 
       
  1769 				used in RemovePaging method. For more info refer to
       
  1770 				http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2840253&SiteID=1	***/
       
  1771 		if ( targetEl.innerHTML!='' ) targetEl.innerHTML = '';
       
  1772 		/*** ***/
       
  1773 		
       
  1774 		targetEl.appendChild(btnPrevSpan);
       
  1775 		targetEl.appendChild(btnFirstSpan);
       
  1776 		
       
  1777 		var pgBeforeSpan = tf_CreateElm( 'span',['id',this.prfxPgBeforeSpan+this.id] );
       
  1778 		pgBeforeSpan.appendChild( tf_CreateText(' Page ') );
       
  1779 		pgBeforeSpan.className = this.nbPgSpanCssClass;
       
  1780 		targetEl.appendChild(pgBeforeSpan);
       
  1781 		targetEl.appendChild(slcPages);
       
  1782 		var pgAfterSpan = tf_CreateElm( 'span',['id',this.prfxPgAfterSpan+this.id] );
       
  1783 		pgAfterSpan.appendChild( tf_CreateText(' of ') );
       
  1784 		pgAfterSpan.className = this.nbPgSpanCssClass;
       
  1785 		targetEl.appendChild(pgAfterSpan)
       
  1786 		var pgspan = tf_CreateElm( 'span',['id',this.prfxPgSpan+this.id] );
       
  1787 		pgspan.className = this.nbPgSpanCssClass;
       
  1788 		pgspan.appendChild( tf_CreateText(' '+this.nbPages+' ') );
       
  1789 		targetEl.appendChild(pgspan);
       
  1790 		targetEl.appendChild(btnLastSpan);
       
  1791 		targetEl.appendChild(btnNextSpan);
       
  1792 	
       
  1793 		this.pagingSlc = tf_Id(this.prfxSlcPages+this.id); //to be easily re-used
       
  1794 		
       
  1795 		// if this.rememberGridValues==true this.SetPagingInfo() is called
       
  1796 		// in ResetGridValues() method
       
  1797 		if( !this.rememberGridValues || this.isPagingRemoved )
       
  1798 			this.SetPagingInfo();
       
  1799 		if( !this.fltGrid )
       
  1800 		{
       
  1801 			this.ValidateAllRows();
       
  1802 			this.SetPagingInfo(this.validRowsIndex);
       
  1803 		}
       
  1804 			
       
  1805 		this.pagingBtnEvents = this.Evt._Paging;
       
  1806 		this.isPagingRemoved = false;
       
  1807 	},
       
  1808 	
       
  1809 	RemovePaging: function()
       
  1810 	/*====================================================
       
  1811 		- Removes paging elements
       
  1812 	=====================================================*/
       
  1813 	{
       
  1814 		if(!this.hasGrid) return;
       
  1815 		if( this.pagingSlc==null ) return;
       
  1816 		var btnNextSpan, btnPrevSpan, btnLastSpan, btnFirstSpan;// btns containers
       
  1817 		var pgBeforeSpan, pgAfterSpan, pgspan;
       
  1818 		btnNextSpan = tf_Id(this.prfxBtnNextSpan+this.id);
       
  1819 		btnPrevSpan = tf_Id(this.prfxBtnPrevSpan+this.id);
       
  1820 		btnLastSpan = tf_Id(this.prfxBtnLastSpan+this.id);
       
  1821 		btnFirstSpan = tf_Id(this.prfxBtnFirstSpan+this.id);
       
  1822 		pgBeforeSpan = tf_Id(this.prfxPgBeforeSpan+this.id);//span containing 'Page' text
       
  1823 		pgAfterSpan = tf_Id(this.prfxPgAfterSpan+this.id);//span containing 'of' text
       
  1824 		pgspan = tf_Id(this.prfxPgSpan+this.id);//span containing nb of pages
       
  1825 		
       
  1826 		this.pagingSlc.parentNode.removeChild(this.pagingSlc);
       
  1827 		
       
  1828 		if( btnNextSpan!=null )
       
  1829 			btnNextSpan.parentNode.removeChild( btnNextSpan );
       
  1830 	
       
  1831 		if( btnPrevSpan!=null )
       
  1832 			btnPrevSpan.parentNode.removeChild( btnPrevSpan );
       
  1833 	
       
  1834 		if( btnLastSpan!=null )
       
  1835 			btnLastSpan.parentNode.removeChild( btnLastSpan );
       
  1836 	
       
  1837 		if( btnFirstSpan!=null )
       
  1838 			btnFirstSpan.parentNode.removeChild( btnFirstSpan );
       
  1839 	
       
  1840 		if( pgBeforeSpan!=null )
       
  1841 			pgBeforeSpan.parentNode.removeChild( pgBeforeSpan );
       
  1842 	
       
  1843 		if( pgAfterSpan!=null )
       
  1844 			pgAfterSpan.parentNode.removeChild( pgAfterSpan );
       
  1845 	
       
  1846 		if( pgspan!=null )
       
  1847 			pgspan.parentNode.removeChild( pgspan );
       
  1848 		
       
  1849 		this.pagingBtnEvents = null;	
       
  1850 		this.pagingSlc = null;
       
  1851 		this.isPagingRemoved = true;
       
  1852 	},
       
  1853 	
       
  1854 	SetRowsCounter: function()
       
  1855 	/*====================================================
       
  1856 		- Generates rows counter label
       
  1857 	=====================================================*/
       
  1858 	{
       
  1859 		if(!this.hasGrid && !this.isFirstLoad) return;
       
  1860 		if( this.rowsCounterSpan!=null ) return;
       
  1861 		var countDiv = tf_CreateElm( 'div',['id',this.prfxCounter+this.id] ); //rows counter container
       
  1862 		countDiv.className = this.totRowsCssClass;
       
  1863 		var countSpan = tf_CreateElm( 'span',['id',this.prfxTotRows+this.id] ); //rows counter label
       
  1864 		var countText = tf_CreateElm( 'span',['id',this.prfxTotRowsTxt+this.id] );
       
  1865 		countText.appendChild( tf_CreateText(this.rowsCounterText) );
       
  1866 		
       
  1867 		// counter is added to defined element
       
  1868 		if(this.rowsCounterTgtId==null) this.SetTopDiv();
       
  1869 		var targetEl = ( this.rowsCounterTgtId==null ) ? this.lDiv : tf_Id( this.rowsCounterTgtId );
       
  1870 		
       
  1871 		//IE only: clears all for sure
       
  1872 		if(this.rowsCounterDiv && tf_isIE)
       
  1873 			this.rowsCounterDiv.outerHTML = '';
       
  1874 		
       
  1875 		if( this.rowsCounterTgtId==null )
       
  1876 		{//default container: 'lDiv'
       
  1877 			countDiv.appendChild(countText);
       
  1878 			countDiv.appendChild(countSpan);
       
  1879 			targetEl.appendChild(countDiv);
       
  1880 		}
       
  1881 		else
       
  1882 		{// custom container, no need to append statusDiv
       
  1883 			targetEl.appendChild(countText);
       
  1884 			targetEl.appendChild(countSpan);
       
  1885 		}
       
  1886 		this.rowsCounterDiv = tf_Id( this.prfxCounter+this.id );
       
  1887 		this.rowsCounterSpan = tf_Id( this.prfxTotRows+this.id );
       
  1888 		
       
  1889 		this.RefreshNbRows();	
       
  1890 	},
       
  1891 	
       
  1892 	RemoveRowsCounter: function()
       
  1893 	/*====================================================
       
  1894 		- Removes rows counter label
       
  1895 	=====================================================*/
       
  1896 	{
       
  1897 		if(!this.hasGrid) return;
       
  1898 		if( this.rowsCounterSpan==null ) return;
       
  1899 		
       
  1900 		if(this.rowsCounterTgtId==null && this.rowsCounterDiv)
       
  1901 		{
       
  1902 			//IE only: clears all for sure
       
  1903 			if(tf_isIE) this.rowsCounterDiv.outerHTML = '';
       
  1904 			else
       
  1905 				this.rowsCounterDiv.parentNode.removeChild( 
       
  1906 					this.rowsCounterDiv
       
  1907 				);
       
  1908 		} else {
       
  1909 			tf_Id( this.rowsCounterTgtId ).innerHTML = '';
       
  1910 		}
       
  1911 		this.rowsCounterSpan = null;
       
  1912 		this.rowsCounterDiv = null;
       
  1913 	},
       
  1914 	
       
  1915 	SetStatusBar: function()
       
  1916 	/*====================================================
       
  1917 		- Generates status bar label
       
  1918 	=====================================================*/
       
  1919 	{
       
  1920 		if(!this.hasGrid && !this.isFirstLoad) return;
       
  1921 		var statusDiv = tf_CreateElm( 'div',['id',this.prfxStatus+this.id] ); //status bar container
       
  1922 		statusDiv.className = this.statusBarCssClass;
       
  1923 		var statusSpan = tf_CreateElm( 'span',['id',this.prfxStatusSpan+this.id] ); //status bar label
       
  1924 		var statusSpanText = tf_CreateElm( 'span',['id',this.prfxStatusTxt+this.id] );//preceding text
       
  1925 		statusSpanText.appendChild( tf_CreateText(this.statusBarText) );
       
  1926 	
       
  1927 		// target element container
       
  1928 		if(this.statusBarTgtId==null) this.SetTopDiv();
       
  1929 		var targetEl = ( this.statusBarTgtId==null ) ? this.lDiv : tf_Id( this.statusBarTgtId );
       
  1930 		
       
  1931 		if(this.statusBarDiv && tf_isIE)
       
  1932 			this.statusBarDiv.outerHTML = '';
       
  1933 		
       
  1934 		if( this.statusBarTgtId==null )
       
  1935 		{//default container: 'lDiv'
       
  1936 			statusDiv.appendChild(statusSpanText);
       
  1937 			statusDiv.appendChild(statusSpan);
       
  1938 			targetEl.appendChild(statusDiv);
       
  1939 		}
       
  1940 		else
       
  1941 		{// custom container, no need to append statusDiv
       
  1942 			targetEl.appendChild(statusSpanText);
       
  1943 			targetEl.appendChild(statusSpan);
       
  1944 		}
       
  1945 
       
  1946 		this.statusBarDiv = tf_Id( this.prfxStatus+this.id );
       
  1947 		this.statusBarSpan = tf_Id( this.prfxStatusSpan+this.id );
       
  1948 		this.statusBarSpanText = tf_Id( this.prfxStatusTxt+this.id );
       
  1949 	},
       
  1950 	
       
  1951 	RemoveStatusBar: function()
       
  1952 	/*====================================================
       
  1953 		- Removes status bar div
       
  1954 	=====================================================*/
       
  1955 	{
       
  1956 		if(!this.hasGrid) return;
       
  1957 		if(this.statusBarDiv)
       
  1958 		{
       
  1959 			this.statusBarDiv.innerHTML = '';
       
  1960 			this.statusBarDiv.parentNode.removeChild( 
       
  1961 				this.statusBarDiv
       
  1962 			);
       
  1963 			this.statusBarSpan = null;
       
  1964 			this.statusBarSpanText = null;
       
  1965 			this.statusBarDiv = null;
       
  1966 		}
       
  1967 	},
       
  1968 	
       
  1969 	SetResultsPerPage: function()
       
  1970 	/*====================================================
       
  1971 		- Generates results per page select + label
       
  1972 	=====================================================*/
       
  1973 	{
       
  1974 		if(!this.hasGrid && !this.isFirstLoad) return;
       
  1975 		if( this.resultsPerPageSlc!=null || this.resultsPerPage==null ) return;
       
  1976 		var slcR = tf_CreateElm( this.fltTypeSlc,['id',this.prfxSlcResults+this.id] );
       
  1977 		slcR.className = this.resultsSlcCssClass;
       
  1978 		var slcRText = this.resultsPerPage[0], slcROpts = this.resultsPerPage[1];
       
  1979 		var slcRSpan = tf_CreateElm( 'span',['id',this.prfxSlcResultsTxt+this.id] );
       
  1980 		slcRSpan.className = this.resultsSpanCssClass;
       
  1981 		
       
  1982 		// results per page select is added to defined element
       
  1983 		if(this.resultsPerPageTgtId==null) this.SetTopDiv();
       
  1984 		var targetEl = ( this.resultsPerPageTgtId==null ) ? this.rDiv : tf_Id( this.resultsPerPageTgtId );
       
  1985 		slcRSpan.appendChild(tf_CreateText(slcRText));
       
  1986 		targetEl.appendChild(slcRSpan);
       
  1987 		targetEl.appendChild(slcR);
       
  1988 		
       
  1989 		this.resultsPerPageSlc = tf_Id(this.prfxSlcResults+this.id);
       
  1990 		
       
  1991 		for(var r=0; r<slcROpts.length; r++)
       
  1992 		{
       
  1993 			var currOpt = new Option(slcROpts[r],slcROpts[r],false,false);
       
  1994 			this.resultsPerPageSlc.options[r] = currOpt;
       
  1995 		}
       
  1996 		slcR.onchange = this.Evt._OnSlcResultsChange;
       
  1997 	},
       
  1998 	
       
  1999 	RemoveResultsPerPage: function()
       
  2000 	/*====================================================
       
  2001 		- Removes results per page select + label
       
  2002 	=====================================================*/
       
  2003 	{
       
  2004 		if(!this.hasGrid) return;
       
  2005 		if( this.resultsPerPageSlc==null || this.resultsPerPage==null ) return;
       
  2006 		var slcR, slcRSpan;
       
  2007 		slcR = this.resultsPerPageSlc;
       
  2008 		slcRSpan = tf_Id( this.prfxSlcResultsTxt+this.id );
       
  2009 		if( slcR!=null )
       
  2010 			slcR.parentNode.removeChild( slcR );
       
  2011 		if( slcRSpan!=null )
       
  2012 			slcRSpan.parentNode.removeChild( slcRSpan );
       
  2013 		this.resultsPerPageSlc = null;
       
  2014 	},
       
  2015 	
       
  2016 	SetResetBtn: function()
       
  2017 	/*====================================================
       
  2018 		- Generates reset button
       
  2019 	=====================================================*/
       
  2020 	{
       
  2021 		if(!this.hasGrid && !this.isFirstLoad) return;
       
  2022 		if( this.btnResetEl!=null ) return;
       
  2023 		var resetspan = tf_CreateElm('span',['id',this.prfxResetSpan+this.id]);
       
  2024 		
       
  2025 		// reset button is added to defined element
       
  2026 		if(this.btnResetTgtId==null) this.SetTopDiv();
       
  2027 		var targetEl = ( this.btnResetTgtId==null ) ? this.rDiv : tf_Id( this.btnResetTgtId );
       
  2028 		targetEl.appendChild(resetspan);
       
  2029 			
       
  2030 		if(this.btnResetHtml==null)
       
  2031 		{	
       
  2032 			var fltreset = tf_CreateElm( 'a', ['href','javascript:void(0);'] );
       
  2033 			fltreset.className = this.btnResetCssClass;
       
  2034 			fltreset.appendChild(tf_CreateText(this.btnResetText));
       
  2035 			resetspan.appendChild(fltreset);
       
  2036 			fltreset.onclick = this.Evt._Clear;
       
  2037 		} else {
       
  2038 			resetspan.innerHTML = this.btnResetHtml;
       
  2039 			var resetEl = resetspan.firstChild;
       
  2040 			resetEl.onclick = this.Evt._Clear;
       
  2041 		}
       
  2042 		this.btnResetEl = tf_Id(this.prfxResetSpan+this.id).firstChild;	
       
  2043 	},
       
  2044 	
       
  2045 	RemoveResetBtn: function()
       
  2046 	/*====================================================
       
  2047 		- Removes reset button
       
  2048 	=====================================================*/
       
  2049 	{
       
  2050 		if(!this.hasGrid) return;
       
  2051 		if( this.btnResetEl==null ) return;
       
  2052 		var resetspan = tf_Id(this.prfxResetSpan+this.id);
       
  2053 		if( resetspan!=null )
       
  2054 			resetspan.parentNode.removeChild( resetspan );
       
  2055 		this.btnResetEl = null;	
       
  2056 	},
       
  2057 	
       
  2058 	RemoveExternalFlts: function()
       
  2059 	/*====================================================
       
  2060 		- removes external filters
       
  2061 	=====================================================*/
       
  2062 	{
       
  2063 		if( !this.isExternalFlt && !this.externalFltTgtIds ) return;
       
  2064 		for(var ct=0; ct<this.externalFltTgtIds.length; ct++ )
       
  2065 			if( tf_Id(this.externalFltTgtIds[ct]) )
       
  2066 				tf_Id(this.externalFltTgtIds[ct]).innerHTML = '';
       
  2067 	},
       
  2068 	
       
  2069 	SetSort: function()
       
  2070 	/*====================================================
       
  2071 		- Sets sorting feature by loading 
       
  2072 		WebFX Sortable Table 1.12 by Erik Arvidsson
       
  2073 		and TF adapter by Max Guglielmi
       
  2074 	=====================================================*/
       
  2075 	{
       
  2076 		if(tf_isImported(this.sortConfig.src))
       
  2077 			this.Evt._EnableSort();
       
  2078 		else
       
  2079 			this.IncludeFile(
       
  2080 				this.sortConfig.name, 
       
  2081 				this.sortConfig.src, 
       
  2082 				this.Evt._EnableSort
       
  2083 			);
       
  2084 	},
       
  2085 	
       
  2086 	RemoveSort: function()
       
  2087 	/*====================================================
       
  2088 		- removes sorting feature
       
  2089 	=====================================================*/
       
  2090 	{
       
  2091 		if(!this.sort) return;
       
  2092 		this.sort = false;
       
  2093 	},
       
  2094 	
       
  2095 	PopulateSelect: function(colIndex,isExternal,extSlcId)
       
  2096 	{ 
       
  2097 		this.EvtManager(
       
  2098 			this.Evt.name.populateselect,
       
  2099 			{ slcIndex:colIndex, slcExternal:isExternal, slcId:extSlcId }
       
  2100 		); 
       
  2101 	},
       
  2102 	_PopulateSelect: function(colIndex,isRefreshed,isExternal,extSlcId)
       
  2103 	/*====================================================
       
  2104 		- populates drop-down filters
       
  2105 	=====================================================*/
       
  2106 	{
       
  2107 		isExternal = (isExternal==undefined) ? false : isExternal;
       
  2108 		var slcId = this.fltIds[colIndex];
       
  2109 		if( tf_Id(slcId)==null && !isExternal ) return;
       
  2110 		if( tf_Id(extSlcId)==null && isExternal ) return;
       
  2111 		var slc = (!isExternal) ? tf_Id(slcId) : tf_Id(extSlcId);
       
  2112 		var o = this, row = this.tbl.rows;
       
  2113 		var fillMethod = this.slcFillingMethod.tf_LCase();
       
  2114 		var optArray = [], slcInnerHtml = '', opt0;
       
  2115 		var isCustomSlc = (this.hasCustomSlcOptions  //custom select test
       
  2116 							&& this.customSlcOptions.cols.tf_Has(colIndex));
       
  2117 		var optTxt = []; //custom selects text
       
  2118 		var activeFlt;
       
  2119 		if(isRefreshed && this.activeFilterId){
       
  2120 			activeFlt = this.activeFilterId.split('_')[0];
       
  2121 			activeFlt = activeFlt.split(this.prfxFlt)[1];
       
  2122 		}
       
  2123 
       
  2124 		/*** remember grid values ***/
       
  2125 		var flts_values = [], fltArr = [];
       
  2126 		if(this.rememberGridValues)
       
  2127 		{
       
  2128 			flts_values = tf_CookieValueArray(this.fltsValuesCookie);			
       
  2129 			fltArr = (flts_values[colIndex]!=undefined) 
       
  2130 						? flts_values[colIndex].split(' '+this.orOperator+' ') 
       
  2131 						: flts_values[colIndex] = [];			
       
  2132 		}
       
  2133 
       
  2134 		for(var k=this.refRow; k<this.nbRows; k++)
       
  2135 		{
       
  2136 			// always visible rows don't need to appear on selects as always valid
       
  2137 			if( this.hasVisibleRows && this.visibleRows.tf_Has(k) && !this.paging ) 
       
  2138 				continue;
       
  2139 
       
  2140 			var cell = tf_Tag(row[k],'td');
       
  2141 			var nchilds = cell.length;
       
  2142 
       
  2143 			if(nchilds == this.nbCells && !isCustomSlc)
       
  2144 			{// checks if row has exact cell #
       
  2145 				for(var j=0; j<nchilds; j++)// this loop retrieves cell data
       
  2146 				{
       
  2147 					if((colIndex==j && !isRefreshed) || 
       
  2148 						(colIndex==j && isRefreshed && ((row[k].style.display == '' && !this.paging) || 
       
  2149 						( this.paging && (!this.validRowsIndex || (this.validRowsIndex && this.validRowsIndex.tf_Has(k)))
       
  2150 							&& ((activeFlt==undefined || activeFlt==colIndex)  || (activeFlt!=colIndex && this.validRowsIndex.tf_Has(k) ))) )))
       
  2151 					{
       
  2152 						var cell_data = this.GetCellData(j, cell[j]);
       
  2153 						var cell_string = cell_data.tf_MatchCase(this.matchCase);//Váry Péter's patch
       
  2154 						// checks if celldata is already in array
       
  2155 						var isMatched = false;
       
  2156 						isMatched = optArray.tf_Has(cell_string,this.matchCase);
       
  2157 						
       
  2158 						if(!isMatched)
       
  2159 							optArray.push(cell_data);						
       
  2160 					}//if colIndex==j
       
  2161 				}//for j
       
  2162 			}//if
       
  2163 		}//for k
       
  2164 		
       
  2165 		//Retrieves custom values
       
  2166 		if(isCustomSlc)
       
  2167 		{
       
  2168 			var customValues = this.__getCustomValues(colIndex);
       
  2169 			optArray = customValues[0];
       
  2170 			optTxt = customValues[1];
       
  2171 		}
       
  2172 		
       
  2173 		if(this.sortSlc && !isCustomSlc)
       
  2174 			optArray.sort(this.matchCase ? null : tf_IgnoreCaseSort);
       
  2175 		
       
  2176 		if(this.sortNumAsc && this.sortNumAsc.tf_Has(colIndex))
       
  2177 		{//asc sort
       
  2178 			try{
       
  2179 				optArray.sort( tf_NumSortAsc ); 
       
  2180 				if(isCustomSlc) optTxt.sort( tf_NumSortAsc );
       
  2181 			} catch(e) {
       
  2182 				optArray.sort(); 
       
  2183 				if(isCustomSlc) optTxt.sort();
       
  2184 			}//in case there are alphanumeric values
       
  2185 		}
       
  2186 		if(this.sortNumDesc && this.sortNumDesc.tf_Has(colIndex))
       
  2187 		{//desc sort
       
  2188 			try{
       
  2189 				optArray.sort( tf_NumSortDesc ); 
       
  2190 				if(isCustomSlc) optTxt.sort( tf_NumSortDesc );
       
  2191 			} catch(e) {
       
  2192 				optArray.sort(); 
       
  2193 				if(isCustomSlc) optTxt.sort();
       
  2194 			}//in case there are alphanumeric values
       
  2195 		}
       
  2196 		
       
  2197 		AddOpts();//populates drop-down
       
  2198 		
       
  2199 		function AddOpt0()
       
  2200 		{// adds 1st option
       
  2201 			if( fillMethod == 'innerhtml' )
       
  2202 				slcInnerHtml += '<option value="">'+o.displayAllText+'</option>';
       
  2203 			else {
       
  2204 				var opt0 = tf_CreateOpt(o.displayAllText,'');			
       
  2205 				slc.appendChild(opt0);
       
  2206 			}
       
  2207 		}
       
  2208 		
       
  2209 		function AddOpts()
       
  2210 		{// populates select
       
  2211 			var slcValue = slc.value;
       
  2212 			slc.innerHTML = '';
       
  2213 			AddOpt0();			
       
  2214 			
       
  2215 			for(var y=0; y<optArray.length; y++)
       
  2216 			{			
       
  2217 				if( fillMethod == 'innerhtml' )
       
  2218 				{
       
  2219 					var slcAttr = '';
       
  2220 					var slcCustomTxt = (isCustomSlc) ? optTxt[y] : optArray[y];
       
  2221 					if( o.fillSlcOnDemand && slcValue==optArray[y] )
       
  2222 						slcAttr = 'selected="selected"';
       
  2223 					slcInnerHtml += '<option value="'+optArray[y]+'" '
       
  2224 										+slcAttr+'>'+slcCustomTxt+'</option>';
       
  2225 				} else {
       
  2226 					var opt;
       
  2227 					//fill select on demand
       
  2228 					if(o.fillSlcOnDemand && slcValue==optArray[y] && o['col'+colIndex]==o.fltTypeSlc)
       
  2229 						opt = tf_CreateOpt( (isCustomSlc) ? optTxt[y] : optArray[y],
       
  2230 											optArray[y],
       
  2231 											true );
       
  2232 					else{
       
  2233 						if( o['col'+colIndex]!=o.fltTypeMulti )
       
  2234 							opt = tf_CreateOpt( (isCustomSlc) ? optTxt[y] : optArray[y],
       
  2235 												optArray[y],
       
  2236 												(flts_values[colIndex]!=' ' && optArray[y]==flts_values[colIndex]) 
       
  2237 												? true : false 	);
       
  2238 						else
       
  2239 						{
       
  2240 							opt = tf_CreateOpt( (isCustomSlc) ? optTxt[y] : optArray[y],
       
  2241 												optArray[y],
       
  2242 												(fltArr.tf_Has(optArray[y].tf_MatchCase(o.matchCase),o.matchCase)) 
       
  2243 												? true : false 	);
       
  2244 						}
       
  2245 					}
       
  2246 					slc.appendChild(opt);
       
  2247 				}
       
  2248 			}// for y
       
  2249 
       
  2250 			if( fillMethod == 'innerhtml' )
       
  2251 				slc.innerHTML += slcInnerHtml;
       
  2252 				
       
  2253 			slc.setAttribute('filled','1');
       
  2254 		}// fn AddOpt
       
  2255 	},
       
  2256 	
       
  2257 	PopulateCheckList: function(colIndex, isExternal, extFltId)
       
  2258 	{
       
  2259 		this.EvtManager(
       
  2260 			this.Evt.name.populatechecklist,
       
  2261 			{ slcIndex:colIndex, slcExternal:isExternal, slcId:extFltId }
       
  2262 		); 
       
  2263 	},
       
  2264 	_PopulateCheckList: function(colIndex, isExternal, extFltId)
       
  2265 	/*====================================================
       
  2266 		- populates checklist filters
       
  2267 	=====================================================*/
       
  2268 	{
       
  2269 		isExternal = (isExternal==undefined) ? false : isExternal;
       
  2270 		var divFltId = this.prfxCheckListDiv+colIndex+'_'+this.id;
       
  2271 		if( tf_Id(divFltId)==null && !isExternal ) return;
       
  2272 		if( tf_Id(extFltId)==null && isExternal ) return;
       
  2273 		var flt = (!isExternal) ? this.checkListDiv[colIndex] : tf_Id(extFltId);
       
  2274 		var ul = tf_CreateElm('ul',['id',this.fltIds[colIndex]],['colIndex',colIndex]);
       
  2275 		ul.className = this.checkListCssClass;
       
  2276 		ul.onchange = this.Evt._OnSlcChange;
       
  2277 		var o = this, row = this.tbl.rows;
       
  2278 		var optArray = [];
       
  2279 		var isCustomSlc = (this.hasCustomSlcOptions  //custom select test
       
  2280 							&& this.customSlcOptions.cols.tf_Has(colIndex));
       
  2281 		var optTxt = []; //custom selects text
       
  2282 		var activeFlt;
       
  2283 		if(this.refreshFilters && this.activeFilterId){
       
  2284 			activeFlt = this.activeFilterId.split('_')[0];
       
  2285 			activeFlt = activeFlt.split(this.prfxFlt)[1];
       
  2286 		}		
       
  2287 		
       
  2288 		for(var k=this.refRow; k<this.nbRows; k++)
       
  2289 		{
       
  2290 			// always visible rows don't need to appear on selects as always valid
       
  2291 			if( this.hasVisibleRows && this.visibleRows.tf_Has(k) && !this.paging ) 
       
  2292 				continue;
       
  2293 
       
  2294 			var cells = tf_Tag(row[k],'td');
       
  2295 			var ncells = cells.length;
       
  2296 
       
  2297 			if(ncells == this.nbCells && !isCustomSlc)
       
  2298 			{// checks if row has exact cell #
       
  2299 				for(var j=0; j<ncells; j++)
       
  2300 				{// this loop retrieves cell data
       
  2301 					if((colIndex==j && !this.refreshFilters) || 
       
  2302 						(colIndex==j && this.refreshFilters && ((row[k].style.display == '' && !this.paging) || 
       
  2303 						( this.paging && ((activeFlt==undefined || activeFlt==colIndex ) ||(activeFlt!=colIndex && this.validRowsIndex.tf_Has(k))) ))))
       
  2304 					{
       
  2305 						var cell_data = this.GetCellData(j, cells[j]);
       
  2306 						var cell_string = cell_data.tf_MatchCase(this.matchCase);//Váry Péter's patch
       
  2307 						// checks if celldata is already in array
       
  2308 						var isMatched = false;
       
  2309 						isMatched = optArray.tf_Has(cell_string,this.matchCase);
       
  2310 						
       
  2311 						if(!isMatched)
       
  2312 							optArray.push(cell_data);
       
  2313 					}
       
  2314 				}
       
  2315 			}
       
  2316 		}
       
  2317 		
       
  2318 		//Retrieves custom values
       
  2319 		if(isCustomSlc)
       
  2320 		{
       
  2321 			var customValues = this.__getCustomValues(colIndex);
       
  2322 			optArray = customValues[0];
       
  2323 			optTxt = customValues[1];
       
  2324 		}
       
  2325 		
       
  2326 		if(this.sortSlc && !isCustomSlc)
       
  2327 			optArray.sort(this.matchCase ? null : tf_IgnoreCaseSort);
       
  2328 		
       
  2329 		if(this.sortNumAsc && this.sortNumAsc.tf_Has(colIndex))
       
  2330 		{//asc sort
       
  2331 			try{
       
  2332 				optArray.sort( tf_NumSortAsc ); 
       
  2333 				if(isCustomSlc) optTxt.sort( tf_NumSortAsc );
       
  2334 			} catch(e) {
       
  2335 				optArray.sort(); 
       
  2336 				if(isCustomSlc) optTxt.sort();
       
  2337 			}//in case there are alphanumeric values
       
  2338 		}
       
  2339 		if(this.sortNumDesc && this.sortNumDesc.tf_Has(colIndex))
       
  2340 		{//desc sort
       
  2341 			try{
       
  2342 				optArray.sort( tf_NumSortDesc ); 
       
  2343 				if(isCustomSlc) optTxt.sort( tf_NumSortDesc );
       
  2344 			} catch(e) {
       
  2345 				optArray.sort(); 
       
  2346 				if(isCustomSlc) optTxt.sort();
       
  2347 			}//in case there are alphanumeric values
       
  2348 		}
       
  2349 
       
  2350 		AddChecks();
       
  2351 			
       
  2352 		function AddCheck0()
       
  2353 		{// adds 1st option
       
  2354 			var li0 = tf_CreateCheckItem(o.fltIds[colIndex]+'_0', '', o.displayAllText);
       
  2355 			li0.className = o.checkListItemCssClass;
       
  2356 			ul.appendChild(li0);
       
  2357 			li0.check.onclick = function(){  
       
  2358 				o.__setCheckListValues(this); 
       
  2359 								
       
  2360 				if(o.refreshFilters){
       
  2361 					//o.activeFilterId = '';
       
  2362 					//o.RefreshFiltersGrid();
       
  2363 				}
       
  2364 				else
       
  2365 				ul.onchange.call(null);
       
  2366 			};
       
  2367 			
       
  2368 			if(tf_isIE)
       
  2369 			{//IE: label looses check capability
       
  2370 				li0.label.onclick = function(){ li0.check.click(); };
       
  2371 			}
       
  2372 		}
       
  2373 		
       
  2374 		function AddChecks()
       
  2375 		{		
       
  2376 			AddCheck0();
       
  2377 			
       
  2378 			var flts_values = [], fltArr = []; //remember grid values
       
  2379 			if(tf_CookieValueByIndex(o.fltsValuesCookie, colIndex)!=undefined)
       
  2380 				fltArr = tf_CookieValueByIndex(o.fltsValuesCookie, colIndex).split(' '+o.orOperator+' ');
       
  2381 
       
  2382 			for(var y=0; y<optArray.length; y++)
       
  2383 			{
       
  2384 				var li = tf_CreateCheckItem(
       
  2385 					o.fltIds[colIndex]+'_'+(y+1), 
       
  2386 					optArray[y], 
       
  2387 					(isCustomSlc) ? optTxt[y] : optArray[y]
       
  2388 				);
       
  2389 				li.className = o.checkListItemCssClass;
       
  2390 				ul.appendChild(li);
       
  2391 				li.check.onclick = function(){ o.__setCheckListValues(this); ul.onchange.call(null); };
       
  2392 				
       
  2393 				/*** remember grid values ***/
       
  2394 				if(o.rememberGridValues)
       
  2395 				{
       
  2396 					if(fltArr.tf_Has(optArray[y].tf_MatchCase(o.matchCase),o.matchCase))
       
  2397 					{
       
  2398 						li.check.checked = true;
       
  2399 						o.__setCheckListValues(li.check);
       
  2400 					}			
       
  2401 				}
       
  2402 				
       
  2403 				if(tf_isIE)
       
  2404 				{//IE: label looses check capability
       
  2405 					li.label.onclick = function(){ this.firstChild.click(); };	
       
  2406 				}
       
  2407 			}
       
  2408 		}
       
  2409 		
       
  2410 		if(this.fillSlcOnDemand)
       
  2411 			flt.innerHTML = '';
       
  2412 		flt.appendChild(ul);
       
  2413 		flt.setAttribute('filled','1');
       
  2414 		
       
  2415 		/*** remember grid values IE only, items remain un-checked ***/
       
  2416 		if(o.rememberGridValues && tf_isIE)
       
  2417 		{
       
  2418 			var slcIndexes = ul.getAttribute('indexes');
       
  2419 			if(slcIndexes != null)
       
  2420 			{
       
  2421 				var indSplit = slcIndexes.split(',');//items indexes
       
  2422 				for(var n=0; n<indSplit.length; n++)
       
  2423 				{
       
  2424 					var cChk = tf_Id(this.fltIds[colIndex]+'_'+indSplit[n]); //checked item
       
  2425 					if(cChk) cChk.checked = true;
       
  2426 				}
       
  2427 			}
       
  2428 		}
       
  2429 	},
       
  2430 	
       
  2431 	Filter: function()
       
  2432 	{
       
  2433 		this.EvtManager(this.Evt.name.filter); 
       
  2434 	},
       
  2435 	_Filter: function()
       
  2436 	/*====================================================
       
  2437 		- Filtering fn
       
  2438 		- retrieves data from each td in every single tr
       
  2439 		and compares to search string for current
       
  2440 		column
       
  2441 		- tr is hidden if all search strings are not 
       
  2442 		found
       
  2443 	=====================================================*/
       
  2444 	{
       
  2445 		if( !this.fltGrid || (!this.hasGrid && !this.isFirstLoad) ) return;
       
  2446 		//invokes eventual onbefore method
       
  2447 		if(this.onBeforeFilter) this.onBeforeFilter.call(null,this);
       
  2448 		var row = this.tbl.rows;	
       
  2449 		f = this.fObj!=undefined ? this.fObj : [];
       
  2450 		var hiddenrows = 0;
       
  2451 		this.validRowsIndex = [];
       
  2452 		var o = this;		
       
  2453 		
       
  2454 		// removes keyword highlighting
       
  2455 		this.UnhighlightAll();
       
  2456 
       
  2457 		// search args re-init
       
  2458 		this.searchArgs = this.GetFiltersValue(); 
       
  2459 		
       
  2460 		var num_cell_data, nbFormat;
       
  2461 		var re_le = new RegExp(this.leOperator), re_ge = new RegExp(this.geOperator);
       
  2462 		var re_l = new RegExp(this.lwOperator), re_g = new RegExp(this.grOperator);
       
  2463 		var re_d = new RegExp(this.dfOperator), re_lk = new RegExp(tf_RegexpEscape(this.lkOperator));
       
  2464 		var re_eq = new RegExp(this.eqOperator), re_st = new RegExp(this.stOperator);
       
  2465 		var re_en = new RegExp(this.enOperator), re_an = new RegExp(this.anOperator);
       
  2466 		var re_cr = new RegExp(this.curExp);
       
  2467 		
       
  2468 		function highlight(str,ok,cell){//keyword highlighting
       
  2469 			if( o.highlightKeywords && ok ){
       
  2470 				str = str.replace(re_lk,'');
       
  2471 				str = str.replace(re_eq,'');
       
  2472 				str = str.replace(re_st,'');
       
  2473 				str = str.replace(re_en,'');
       
  2474 				var w = str;
       
  2475 				if(re_le.test(str) || re_ge.test(str) || re_l.test(str) || re_g.test(str) || re_d.test(str))	
       
  2476 					w = tf_GetNodeText(cell);
       
  2477 				if(w!='')
       
  2478 					tf_HighlightWord( cell,w,o.highlightCssClass );
       
  2479 			}
       
  2480 		}
       
  2481 		
       
  2482 		//looks for search argument in current row
       
  2483 		function hasArg(sA,cell_data,j)
       
  2484 		{
       
  2485 			var occurence;
       
  2486 			//Search arg operator tests
       
  2487 			var hasLO = re_l.test(sA), hasLE = re_le.test(sA);
       
  2488 			var hasGR = re_g.test(sA), hasGE = re_ge.test(sA);
       
  2489 			var hasDF = re_d.test(sA), hasEQ = re_eq.test(sA);
       
  2490 			var hasLK = re_lk.test(sA), hasAN = re_an.test(sA);
       
  2491 			var hasST = re_st.test(sA), hasEN = re_en.test(sA);
       
  2492 			
       
  2493 			//Search arg dates tests
       
  2494 			var isLDate = ( hasLO && tf_isValidDate(sA.replace(re_l,''),dtType) );
       
  2495 			var isLEDate = ( hasLE && tf_isValidDate(sA.replace(re_le,''),dtType) );
       
  2496 			var isGDate = ( hasGR && tf_isValidDate(sA.replace(re_g,''),dtType) );
       
  2497 			var isGEDate = ( hasGE && tf_isValidDate(sA.replace(re_ge,''),dtType) );
       
  2498 			var isDFDate = ( hasDF && tf_isValidDate(sA.replace(re_d,''),dtType) );
       
  2499 			var isEQDate = ( hasEQ && tf_isValidDate(sA.replace(re_eq,''),dtType) );
       
  2500 						
       
  2501 			if( tf_isValidDate(cell_data,dtType) )
       
  2502 			{//dates
       
  2503 				var dte1 = tf_formatDate(cell_data,dtType);
       
  2504 				if(isLDate) 
       
  2505 				{// lower date
       
  2506 					var dte2 = tf_formatDate(sA.replace(re_l,''),dtType);
       
  2507 					occurence = (dte1 < dte2);
       
  2508 				}
       
  2509 				else if(isLEDate) 
       
  2510 				{// lower equal date
       
  2511 					var dte2 = tf_formatDate(sA.replace(re_le,''),dtType);
       
  2512 					occurence = (dte1 <= dte2);
       
  2513 				}
       
  2514 				else if(isGEDate) 
       
  2515 				{// greater equal date
       
  2516 					var dte2 = tf_formatDate(sA.replace(re_ge,''),dtType);
       
  2517 					occurence = (dte1 >= dte2);
       
  2518 				}
       
  2519 				else if(isGDate) 
       
  2520 				{// greater date
       
  2521 					var dte2 = tf_formatDate(sA.replace(re_g,''),dtType);
       
  2522 					occurence = (dte1 > dte2);
       
  2523 				}
       
  2524 				else if(isDFDate) 
       
  2525 				{// different date
       
  2526 					var dte2 = tf_formatDate(sA.replace(re_d,''),dtType);
       
  2527 					occurence = (dte1.toString() != dte2.toString());
       
  2528 				}
       
  2529 				else if(isEQDate) 
       
  2530 				{// equal date
       
  2531 					var dte2 = tf_formatDate(sA.replace(re_eq,''),dtType);
       
  2532 					occurence = (dte1.toString() == dte2.toString());
       
  2533 				}
       
  2534 				else if(re_lk.test(sA)) // searched keyword with * operator doesn't have to be a date
       
  2535 				{// like date
       
  2536 					occurence = o.__containsStr( sA.replace(re_lk,''),cell_data,null,false);
       
  2537 				}
       
  2538 				else if(tf_isValidDate(sA,dtType))
       
  2539 				{
       
  2540 					var dte2 = tf_formatDate(sA,dtType);
       
  2541 					occurence = (dte1.toString() == dte2.toString());
       
  2542 				}
       
  2543 			}
       
  2544 			
       
  2545 			else 
       
  2546 			{						
       
  2547 				//first numbers need to be formated
       
  2548 				if(o.hasColNbFormat && o.colNbFormat[j]!=null)
       
  2549 				{
       
  2550 					num_cell_data = tf_removeNbFormat(cell_data,o.colNbFormat[j]);
       
  2551 					nbFormat = o.colNbFormat[j];
       
  2552 				} else {
       
  2553 					if(o.thousandsSeparator==',' && o.decimalSeparator=='.')
       
  2554 					{
       
  2555 						num_cell_data = tf_removeNbFormat(cell_data,'us');
       
  2556 						nbFormat = 'us';
       
  2557 					} else {
       
  2558 						num_cell_data = tf_removeNbFormat(cell_data,'eu');
       
  2559 						nbFormat = 'eu';
       
  2560 					}
       
  2561 				}
       
  2562 				
       
  2563 				// first checks if there is any operator (<,>,<=,>=,!,*,=,{,})
       
  2564 				if(hasLE) //lower equal
       
  2565 					occurence = num_cell_data <= tf_removeNbFormat(sA.replace(re_le,''),nbFormat);
       
  2566 				
       
  2567 				else if(hasGE) //greater equal
       
  2568 					occurence = num_cell_data >= tf_removeNbFormat(sA.replace(re_ge,''),nbFormat);
       
  2569 				
       
  2570 				else if(hasLO) //lower
       
  2571 					occurence = num_cell_data < tf_removeNbFormat(sA.replace(re_l,''),nbFormat);
       
  2572 					
       
  2573 				else if(hasGR) //greater
       
  2574 					occurence = num_cell_data > tf_removeNbFormat(sA.replace(re_g,''),nbFormat);							
       
  2575 					
       
  2576 				else if(hasDF) //different
       
  2577 					occurence = o.__containsStr( sA.replace(re_d,''),cell_data ) ? false : true;
       
  2578 			
       
  2579 				else if(hasLK) //like
       
  2580 					occurence = o.__containsStr( sA.replace(re_lk,''),cell_data,null,false);
       
  2581 				
       
  2582 				else if(hasEQ) //equal
       
  2583 					occurence = o.__containsStr( sA.replace(re_eq,''),cell_data,null,true);
       
  2584 				
       
  2585 				else if(hasST) //starts with
       
  2586 					occurence = cell_data.indexOf(sA.replace(re_st,''))==0 ? true : false;
       
  2587 				
       
  2588 				else if(hasEN) //ends with
       
  2589 				{
       
  2590 					var searchArg = sA.replace(re_en,'');
       
  2591 					occurence = cell_data.lastIndexOf(searchArg,cell_data.length-1)==(cell_data.length-1)-(searchArg.length-1)
       
  2592 						&& cell_data.lastIndexOf(searchArg,cell_data.length-1) > -1
       
  2593 						? true : false;
       
  2594 				}
       
  2595 				
       
  2596 				else
       
  2597 					occurence = o.__containsStr( sA,cell_data,(f['col_'+j]==undefined) ? this.fltTypeInp : f['col_'+j] );
       
  2598 				
       
  2599 			}//else
       
  2600 			return occurence;
       
  2601 		}//fn
       
  2602 		
       
  2603 		for(var k=this.refRow; k<this.nbRows; k++)
       
  2604 		{
       
  2605 			/*** if table already filtered some rows are not visible ***/
       
  2606 			if(row[k].style.display == 'none') row[k].style.display = '';
       
  2607 					
       
  2608 			var cell = tf_Tag(row[k],'td');
       
  2609 			var nchilds = cell.length;			
       
  2610 			
       
  2611 			// checks if row has exact cell #
       
  2612 			if(nchilds != this.nbCells) continue;
       
  2613 	
       
  2614 			var occurence = [];
       
  2615 			var isRowValid = (this.searchType=='include') ? true : false;
       
  2616 			var singleFltRowValid = false; //only for single filter search
       
  2617 			
       
  2618 			for(var j=0; j<nchilds; j++)
       
  2619 			{// this loop retrieves cell data
       
  2620 				var sA = this.searchArgs[(this.singleSearchFlt) ? 0 : j]; //searched keyword
       
  2621 				var dtType = (this.hasColDateType) ? this.colDateType[j] : this.defaultDateType;
       
  2622 				if(sA=='') continue;
       
  2623 				
       
  2624 				var cell_data = this.GetCellData(j, cell[j]).tf_MatchCase(this.matchCase);
       
  2625 	
       
  2626 				var sAOrSplit = sA.split(this.orOperator);//multiple search parameter operator ||
       
  2627 				var hasMultiOrSA = (sAOrSplit.length>1) ? true : false;//multiple search || parameter boolean
       
  2628 				var sAAndSplit = sA.split('&&');//multiple search parameter operator &&
       
  2629 				var hasMultiAndSA = (sAAndSplit.length>1) ? true : false;//multiple search && parameter boolean
       
  2630 
       
  2631 				if(hasMultiOrSA || hasMultiAndSA)
       
  2632 				{//multiple sarch parameters
       
  2633 					var cS, occur = false;
       
  2634 					var s = (hasMultiOrSA) ? sAOrSplit : sAAndSplit;
       
  2635 					for(var w=0; w<s.length; w++)
       
  2636 					{
       
  2637 						cS = s[w].tf_Trim();
       
  2638 						occur = hasArg(cS,cell_data,j);
       
  2639 						highlight(cS,occur,cell[j]);
       
  2640 						if(hasMultiOrSA && occur) break;
       
  2641 						if(hasMultiAndSA && !occur) break;
       
  2642 					}
       
  2643 					occurence[j] = occur;
       
  2644 				}
       
  2645 				else {//single search parameter		
       
  2646 					occurence[j] = hasArg(sA.tf_Trim(),cell_data,j);
       
  2647 					highlight(sA,occurence[j],cell[j]);
       
  2648 				}//else single param
       
  2649 				
       
  2650 				if(!occurence[j]) isRowValid = (this.searchType=='include') ? false : true;
       
  2651 				if(this.singleSearchFlt && occurence[j]) singleFltRowValid = true;
       
  2652 				
       
  2653 			}//for j
       
  2654 			
       
  2655 			if(this.singleSearchFlt && singleFltRowValid) isRowValid = true;
       
  2656 			
       
  2657 			if(!isRowValid)
       
  2658 			{
       
  2659 				this.SetRowValidation(k,false);
       
  2660 				// always visible rows need to be counted as valid
       
  2661 				if( this.hasVisibleRows && this.visibleRows.tf_Has(k) && !this.paging)
       
  2662 					this.validRowsIndex.push(k);
       
  2663 				else
       
  2664 					hiddenrows++;
       
  2665 			} else {
       
  2666 				this.SetRowValidation(k,true);
       
  2667 				this.validRowsIndex.push(k);
       
  2668 				this.SetRowBg(k,this.validRowsIndex.length);
       
  2669 				if(this.onRowValidated) this.onRowValidated.call(null,this,k);
       
  2670 			}
       
  2671 			
       
  2672 		}// for k
       
  2673 		
       
  2674 		this.nbVisibleRows = this.validRowsIndex.length;
       
  2675 		this.nbHiddenRows = hiddenrows;
       
  2676 		this.isStartBgAlternate = false;
       
  2677 		if( this.rememberGridValues ) this.RememberFiltersValue(this.fltsValuesCookie);
       
  2678 		if(!this.paging) this.ApplyGridProps();//applies filter props after filtering process
       
  2679 		if(this.paging){ 
       
  2680 			this.startPagingRow = 0; 
       
  2681 			this.currentPageNb = 1;
       
  2682 			this.SetPagingInfo(this.validRowsIndex); 
       
  2683 		}//starts paging process
       
  2684 		//invokes eventual onafter function
       
  2685 		if(this.onAfterFilter) this.onAfterFilter.call(null,this);
       
  2686 	},
       
  2687 	
       
  2688 	SetPagingInfo: function( validRows )
       
  2689 	/*====================================================
       
  2690 		- calculates page # according to valid rows
       
  2691 		- refreshes paging select according to page #
       
  2692 		- Calls GroupByPage method
       
  2693 	=====================================================*/
       
  2694 	{
       
  2695 		var row = this.tbl.rows;
       
  2696 		var mdiv = ( this.pagingTgtId==null ) ? this.mDiv : tf_Id( this.pagingTgtId );
       
  2697 		var pgspan = tf_Id(this.prfxPgSpan+this.id);
       
  2698 		
       
  2699 		if( validRows!=undefined ) this.validRowsIndex = validRows;//stores valid rows index
       
  2700 		else 
       
  2701 		{
       
  2702 			this.validRowsIndex = [];//re-sets valid rows index
       
  2703 	
       
  2704 			for(var j=this.refRow; j<this.nbRows; j++)//counts rows to be grouped 
       
  2705 			{
       
  2706 				var isRowValid = row[j].getAttribute('validRow');
       
  2707 				if(isRowValid=='true' || isRowValid==null )
       
  2708 						this.validRowsIndex.push(j);
       
  2709 			}//for j
       
  2710 		}
       
  2711 	
       
  2712 		this.nbPages = Math.ceil( this.validRowsIndex.length/this.pagingLength );//calculates nb of pages
       
  2713 		pgspan.innerHTML = this.nbPages; //refresh page nb span 
       
  2714 		if(this.pageSelectorType==this.fltTypeSlc) 
       
  2715 			this.pagingSlc.innerHTML = '';//select clearing shortcut
       
  2716 		
       
  2717 		if( this.nbPages>0 )
       
  2718 		{
       
  2719 			mdiv.style.visibility = 'visible';
       
  2720 			if(this.pageSelectorType==this.fltTypeSlc)
       
  2721 				for(var z=0; z<this.nbPages; z++)
       
  2722 				{
       
  2723 					var currOpt = new Option((z+1),z*this.pagingLength,false,false);
       
  2724 					this.pagingSlc.options[z] = currOpt;
       
  2725 				}
       
  2726 			else this.pagingSlc.value = this.currentPageNb; //input type
       
  2727 			
       
  2728 		} else {/*** if no results paging select and buttons are hidden ***/
       
  2729 			mdiv.style.visibility = 'hidden';
       
  2730 		}
       
  2731 		this.GroupByPage( this.validRowsIndex );
       
  2732 	},
       
  2733 	
       
  2734 	GroupByPage: function( validRows )
       
  2735 	/*====================================================
       
  2736 		- Displays current page rows
       
  2737 	=====================================================*/
       
  2738 	{
       
  2739 		var row = this.tbl.rows;
       
  2740 		var paging_end_row = parseInt( this.startPagingRow ) + parseInt( this.pagingLength );
       
  2741 		
       
  2742 		if( validRows!=undefined ) this.validRowsIndex = validRows;//stores valid rows index
       
  2743 	
       
  2744 		for(h=0; h<this.validRowsIndex.length; h++)
       
  2745 		{//this loop shows valid rows of current page
       
  2746 			if( h>=this.startPagingRow && h<paging_end_row )
       
  2747 			{
       
  2748 				var r = row[ this.validRowsIndex[h] ];
       
  2749 				if(r.getAttribute('validRow')=='true' || r.getAttribute('validRow')==undefined)
       
  2750 					r.style.display = '';
       
  2751 				this.SetRowBg(this.validRowsIndex[h],h);
       
  2752 			} else {
       
  2753 				row[ this.validRowsIndex[h] ].style.display = 'none';
       
  2754 				this.RemoveRowBg(this.validRowsIndex[h]);
       
  2755 			}
       
  2756 		}
       
  2757 		
       
  2758 		this.nbVisibleRows = this.validRowsIndex.length;
       
  2759 		this.isStartBgAlternate = false;
       
  2760 		this.ApplyGridProps();//re-applies filter behaviours after filtering process
       
  2761 	},
       
  2762 	
       
  2763 	ApplyGridProps: function()
       
  2764 	/*====================================================
       
  2765 		- checks methods that should be called
       
  2766 		after filtering and/or paging process
       
  2767 	=====================================================*/
       
  2768 	{
       
  2769 		if( this.activeFlt && this.activeFlt.nodeName.tf_LCase()==this.fltTypeSlc )
       
  2770 		{// blurs active filter (IE)
       
  2771 			this.activeFlt.blur(); 
       
  2772 			if(this.activeFlt.parentNode) this.activeFlt.parentNode.focus(); 
       
  2773 		}
       
  2774 		
       
  2775 		if( this.visibleRows ) this.SetVisibleRows();//shows rows always visible
       
  2776 		if( this.colOperation ) this.SetColOperation();//makes operation on a col
       
  2777 		if( this.refreshFilters ) this.RefreshFiltersGrid();//re-populates drop-down filters
       
  2778 		var nr = (!this.paging && this.hasVisibleRows) 
       
  2779 					? (this.nbVisibleRows - this.visibleRows.length) : this.nbVisibleRows;
       
  2780 		if( this.rowsCounter ) this.RefreshNbRows( nr );//refreshes rows counter
       
  2781 	},
       
  2782 	
       
  2783 	RefreshNbRows: function(p)
       
  2784 	/*====================================================
       
  2785 		- Shows total number of filtered rows
       
  2786 	=====================================================*/
       
  2787 	{
       
  2788 		if(this.rowsCounterSpan == null) return;
       
  2789 		var totTxt;
       
  2790 		if(!this.paging)
       
  2791 		{
       
  2792 			if(p!=undefined && p!='') totTxt=p;
       
  2793 			else totTxt = (this.nbFilterableRows - this.nbHiddenRows - (this.hasVisibleRows ? this.visibleRows.length : 0) );
       
  2794 		} else {
       
  2795 			var paging_start_row = parseInt(this.startPagingRow)+((this.nbVisibleRows>0) ? 1 : 0);//paging start row
       
  2796 			var paging_end_row = (paging_start_row+this.pagingLength)-1 <= this.nbVisibleRows 
       
  2797 				? (paging_start_row+this.pagingLength)-1 : this.nbVisibleRows;
       
  2798 			totTxt = paging_start_row+'-'+paging_end_row+' / '+this.nbVisibleRows;
       
  2799 		} 
       
  2800 		this.rowsCounterSpan.innerHTML = totTxt;
       
  2801 	},
       
  2802 	
       
  2803 	ChangePage: function( index )
       
  2804 	{
       
  2805 		this.EvtManager(this.Evt.name.changepage,{ pgIndex:index });
       
  2806 	},
       
  2807 	_ChangePage: function( index )
       
  2808 	/*====================================================
       
  2809 		- Changes page
       
  2810 		- Param:
       
  2811 			- index: option index of paging select 
       
  2812 			(numeric value)
       
  2813 	=====================================================*/
       
  2814 	{
       
  2815 		if( !this.paging ) return;
       
  2816 		if( index==undefined ) 
       
  2817 			index = (this.pageSelectorType==this.fltTypeSlc) ? 
       
  2818 				this.pagingSlc.options.selectedIndex : (this.pagingSlc.value-1);
       
  2819 		if( index>=0 && index<=(this.nbPages-1) )
       
  2820 		{
       
  2821 			this.currentPageNb = parseInt(index)+1;
       
  2822 			if(this.pageSelectorType==this.fltTypeSlc)
       
  2823 				this.pagingSlc.options[index].selected = true;
       
  2824 			else
       
  2825 				this.pagingSlc.value = this.currentPageNb;
       
  2826 
       
  2827 			if( this.rememberPageNb ) this.RememberPageNb( this.pgNbCookie );
       
  2828 			this.startPagingRow = (this.pageSelectorType==this.fltTypeSlc)
       
  2829 				? this.pagingSlc.value : (index*this.pagingLength);
       
  2830 			this.GroupByPage();
       
  2831 		}
       
  2832 	},
       
  2833 	
       
  2834 	ChangeResultsPerPage: function()
       
  2835 	{
       
  2836 		this.EvtManager(this.Evt.name.changeresultsperpage);
       
  2837 	},
       
  2838 	_ChangeResultsPerPage: function()
       
  2839 	/*====================================================
       
  2840 		- calculates rows to be displayed in a page
       
  2841 		- method called by nb results per page select
       
  2842 	=====================================================*/
       
  2843 	{
       
  2844 		if( !this.paging ) return;
       
  2845 		var slcR = this.resultsPerPageSlc;
       
  2846 		var slcPagesSelIndex = (this.pageSelectorType==this.fltTypeSlc) 
       
  2847 			? this.pagingSlc.selectedIndex : parseInt(this.pagingSlc.value-1);
       
  2848 		this.pagingLength = parseInt(slcR.options[slcR.selectedIndex].value);
       
  2849 		this.startPagingRow = this.pagingLength*slcPagesSelIndex;
       
  2850 
       
  2851 		if( !isNaN(this.pagingLength) )
       
  2852 		{
       
  2853 			if( this.startPagingRow>=this.nbFilterableRows )
       
  2854 				this.startPagingRow = (this.nbFilterableRows-this.pagingLength);
       
  2855 			this.SetPagingInfo();
       
  2856 
       
  2857 			if(this.pageSelectorType==this.fltTypeSlc)
       
  2858 			{
       
  2859 				var slcIndex = (this.pagingSlc.options.length-1<=slcPagesSelIndex ) 
       
  2860 								? (this.pagingSlc.options.length-1) : slcPagesSelIndex;
       
  2861 				this.pagingSlc.options[slcIndex].selected = true;
       
  2862 			}
       
  2863 			if( this.rememberPageLen ) this.RememberPageLength( this.pgLenCookie );
       
  2864 		}//if isNaN
       
  2865 	},
       
  2866 	
       
  2867 	Sort: function()
       
  2868 	{
       
  2869 		this.EvtManager(this.Evt.name.sort);
       
  2870 	},
       
  2871 	
       
  2872 	GetColValues: function(colindex,num,exclude)
       
  2873 	/*====================================================
       
  2874 		- returns an array containing cell values of
       
  2875 		a column
       
  2876 		- needs following args:
       
  2877 			- column index (number)
       
  2878 			- a boolean set to true if we want only 
       
  2879 			numbers to be returned
       
  2880 			- array containing rows index to be excluded
       
  2881 			from returned values
       
  2882 	=====================================================*/
       
  2883 	{
       
  2884 		if( !this.fltGrid ) return;
       
  2885 		var row = this.tbl.rows;
       
  2886 		var colValues = [];
       
  2887 	
       
  2888 		for(var i=this.refRow; i<this.nbRows; i++)//iterates rows
       
  2889 		{
       
  2890 			var isExludedRow = false;
       
  2891 			if(exclude!=undefined && (typeof exclude).tf_LCase()=='object')
       
  2892 			{ // checks if current row index appears in exclude array
       
  2893 				isExludedRow = exclude.tf_Has(i); //boolean
       
  2894 			}
       
  2895 			var cell = tf_Tag(row[i],'td');
       
  2896 			var nchilds = cell.length;
       
  2897 			
       
  2898 			if(nchilds == this.nbCells && !isExludedRow)
       
  2899 			{// checks if row has exact cell # and is not excluded
       
  2900 				for(var j=0; j<nchilds; j++)// this loop retrieves cell data
       
  2901 				{
       
  2902 					if(j==colindex && row[i].style.display=='' )
       
  2903 					{
       
  2904 						var cell_data = this.GetCellData(j, cell[j]).tf_LCase();
       
  2905 						var nbFormat = this.colNbFormat ? this.colNbFormat[colindex] : null;
       
  2906 						(num) ? colValues.push( tf_removeNbFormat(cell_data,nbFormat) ) 
       
  2907 								: colValues.push( cell_data );
       
  2908 					}//if j==k
       
  2909 				}//for j
       
  2910 			}//if nchilds == this.nbCells
       
  2911 		}//for i
       
  2912 		return colValues;	
       
  2913 	},
       
  2914 	
       
  2915 	GetFilterValue: function(index)
       
  2916 	/*====================================================
       
  2917 		- Returns value of a specified filter
       
  2918 		- Params:
       
  2919 			- index: filter column index (numeric value)
       
  2920 	=====================================================*/
       
  2921 	{
       
  2922 		if( !this.fltGrid ) return;
       
  2923 		var fltValue;
       
  2924 		var flt = tf_Id(this.fltIds[index]);
       
  2925 		if(flt==null) return fltValue='';
       
  2926 		
       
  2927 		if( this['col'+index]!=this.fltTypeMulti && 
       
  2928 			this['col'+index]!=this.fltTypeCheckList )
       
  2929 			fltValue = flt.value;
       
  2930 		else if(this['col'+index] == this.fltTypeMulti)
       
  2931 		{//mutiple select
       
  2932 			fltValue = '';
       
  2933 			for(var j=0; j<flt.options.length; j++) 
       
  2934 				if(flt.options[j].selected)
       
  2935 					fltValue = fltValue.concat(
       
  2936 								flt.options[j].value+' ' +
       
  2937 								this.orOperator + ' '
       
  2938 								);
       
  2939 			//removes last operator ||
       
  2940 			fltValue = fltValue.substr(0,fltValue.length-4);
       
  2941 		}
       
  2942 		else if(this['col'+index]==this.fltTypeCheckList)
       
  2943 		{//checklist
       
  2944 			if(flt.getAttribute('value')!=null)
       
  2945 			{
       
  2946 				fltValue = flt.getAttribute('value');
       
  2947 				//removes last operator ||
       
  2948 				fltValue = fltValue.substr(0,fltValue.length-3);
       
  2949 			} else fltValue = '';
       
  2950 		}			
       
  2951 		return fltValue;
       
  2952 	},
       
  2953 	
       
  2954 	GetFiltersValue: function()
       
  2955 	/*====================================================
       
  2956 		- Returns the value of every single filter
       
  2957 	=====================================================*/
       
  2958 	{
       
  2959 		if( !this.fltGrid ) return;
       
  2960 		var searchArgs = [];
       
  2961 		for(var i=0; i<this.fltIds.length; i++)
       
  2962 			searchArgs.push(
       
  2963 				this.GetFilterValue(i).tf_MatchCase(this.matchCase).tf_Trim()
       
  2964 			);
       
  2965 		return searchArgs;
       
  2966 	},
       
  2967 	
       
  2968 	GetFilterId: function(index)
       
  2969 	/*====================================================
       
  2970 		- Returns filter id of a specified column
       
  2971 		- Params:
       
  2972 			- index: column index (numeric value)
       
  2973 	=====================================================*/
       
  2974 	{
       
  2975 		if( !this.fltGrid ) return;
       
  2976 		return this.fltIds[i];
       
  2977 	},
       
  2978 	
       
  2979 	GetFiltersByType: function(type,bool)
       
  2980 	/*====================================================
       
  2981 		- returns an array containing ids of filters of a 
       
  2982 		specified type (inputs or selects)
       
  2983 		- Note that hidden filters are also returned
       
  2984 		- Needs folllowing args:
       
  2985 			- filter type string ('input','select',
       
  2986 			'multiple')
       
  2987 			- optional boolean: if set true method
       
  2988 			returns column indexes otherwise filters ids
       
  2989 	=====================================================*/
       
  2990 	{
       
  2991 		if( !this.fltGrid ) return;
       
  2992 		var arr = [];
       
  2993 		for(var i=0; i<this.fltIds.length; i++)
       
  2994 		{
       
  2995 			var fltType = this['col'+i];
       
  2996 			if(fltType == type.tf_LCase())
       
  2997 			{
       
  2998 				var a = (bool) ? i : this.fltIds[i];
       
  2999 				arr.push(a);
       
  3000 			}
       
  3001 		}
       
  3002 		return arr;
       
  3003 	},
       
  3004 	
       
  3005 	GetCellsNb: function( rowIndex )
       
  3006 	/*====================================================
       
  3007 		- returns number of cells in a row
       
  3008 		- if rowIndex param is passed returns number of 
       
  3009 		cells of specified row (number)
       
  3010 	=====================================================*/
       
  3011 	{
       
  3012 		var tr = (rowIndex == undefined) ? this.tbl.rows[0] : this.tbl.rows[rowIndex];
       
  3013 		var n = tf_GetChildElms(tr);
       
  3014 		return n.childNodes.length;
       
  3015 	},
       
  3016 	
       
  3017 	GetRowsNb: function()
       
  3018 	/*====================================================
       
  3019 		- returns total nb of filterable rows starting 
       
  3020 		from reference row if defined
       
  3021 	=====================================================*/
       
  3022 	{
       
  3023 		var s = this.refRow==undefined ? 0 : this.refRow;
       
  3024 		var ntrs = this.tbl.rows.length;
       
  3025 		return parseInt(ntrs-s);
       
  3026 	},
       
  3027 	
       
  3028 	GetCellData: function(i, cell)
       
  3029 	/*====================================================
       
  3030 		- returns text content of a given cell
       
  3031 		- Params:
       
  3032 			- i: index of the column (number)
       
  3033 			- cell: td DOM object
       
  3034 	=====================================================*/
       
  3035 	{
       
  3036 		if(i==undefined || cell==null) return "";
       
  3037 		//First checks for customCellData event
       
  3038 		if(this.customCellData && this.customCellDataCols.tf_Has(i))
       
  3039 			return this.customCellData.call(null,this,cell,i);
       
  3040 		else
       
  3041 			return tf_GetNodeText(cell);
       
  3042 	},
       
  3043 	
       
  3044 	GetTableData: function()
       
  3045 	/*====================================================
       
  3046 		- returns an array containing table data:
       
  3047 		[rowindex,[value1,value2,value3...]]
       
  3048 	=====================================================*/
       
  3049 	{
       
  3050 		var row = this.tbl.rows;
       
  3051 		for(var k=this.refRow; k<this.nbRows; k++)
       
  3052 		{
       
  3053 			var rowData, cellData;
       
  3054 			rowData = [k,[]];
       
  3055 			var cells = tf_Tag(row[k],'td');
       
  3056 			for(var j=0; j<cells.length; j++)
       
  3057 			{// this loop retrieves cell data
       
  3058 				var cell_data = this.GetCellData(j, cells[j]);
       
  3059 				rowData[1].push( cell_data );
       
  3060 			}
       
  3061 			this.tblData.push( rowData )
       
  3062 		}
       
  3063 		return this.tblData;
       
  3064 	},
       
  3065 	
       
  3066 	GetFilteredData: function()
       
  3067 	/*====================================================
       
  3068 		- returns an array containing filtered data:
       
  3069 		[rowindex,[value1,value2,value3...]]
       
  3070 	=====================================================*/
       
  3071 	{
       
  3072 		if(!this.validRowsIndex) return [];
       
  3073 		var row = this.tbl.rows;
       
  3074 		var filteredData = [];
       
  3075 		for(var i=0; i<this.validRowsIndex.length; i++)
       
  3076 		{
       
  3077 			var rowData, cellData;
       
  3078 			rowData = [this.validRowsIndex[i],[]];
       
  3079 			var cells = tf_Tag(row[this.validRowsIndex[i]],'td');
       
  3080 			for(var j=0; j<cells.length; j++)
       
  3081 			{
       
  3082 				var cell_data = this.GetCellData(j, cells[j]);
       
  3083 				rowData[1].push( cell_data );
       
  3084 			}
       
  3085 			filteredData.push(rowData);
       
  3086 		}
       
  3087 		return filteredData;
       
  3088 	},
       
  3089 	
       
  3090 	GetFilteredDataCol: function(colIndex)
       
  3091 	/*====================================================
       
  3092 		- returns an array containing filtered data of a
       
  3093 		specified column. 
       
  3094 		- Params:
       
  3095 			- colIndex: index of the column (number)
       
  3096 		- returned array:
       
  3097 		[value1,value2,value3...]
       
  3098 	=====================================================*/
       
  3099 	{
       
  3100 		if(colIndex==undefined) return [];
       
  3101 		var data =  this.GetFilteredData();
       
  3102 		var colData = [];
       
  3103 		for(var i=0; i<data.length; i++)
       
  3104 		{
       
  3105 			var r = data[i];
       
  3106 			var d = r[1]; //cols values of current row
       
  3107 			var c = d[colIndex]; //data of searched column
       
  3108 			colData.push(c);
       
  3109 		}
       
  3110 		return colData;
       
  3111 	},
       
  3112 	
       
  3113 	GetRowDisplay: function(row)
       
  3114 	{
       
  3115 		if( !this.fltGrid && typeof row.tf_LCase!='object' ) return;
       
  3116 		return row.style.display;
       
  3117 	},
       
  3118 	
       
  3119 	SetRowValidation: function( rowIndex,isValid )
       
  3120 	/*====================================================
       
  3121 		- Validates/unvalidates row by setting 'validRow' 
       
  3122 		attribute and shows/hides row
       
  3123 		- Params:
       
  3124 			- rowIndex: index of the row (number)
       
  3125 			- isValid: boolean
       
  3126 	=====================================================*/
       
  3127 	{
       
  3128 		var row = this.tbl.rows[rowIndex];
       
  3129 		if( !row || (typeof isValid).tf_LCase()!='boolean' ) return;
       
  3130 	
       
  3131 		// always visible rows are valid
       
  3132 		if( this.hasVisibleRows && this.visibleRows.tf_Has(rowIndex) && !this.paging )
       
  3133 			isValid = true;
       
  3134 		
       
  3135 		var displayFlag = (isValid) ? '' : 'none';
       
  3136 		var validFlag = (isValid) ? 'true' : 'false';		
       
  3137 		row.style.display = displayFlag;
       
  3138 		
       
  3139 		if( this.paging ) 
       
  3140 			row.setAttribute('validRow',validFlag);
       
  3141 	},
       
  3142 	
       
  3143 	ValidateAllRows: function()
       
  3144 	/*====================================================
       
  3145 		- Validates all filterable rows
       
  3146 	=====================================================*/
       
  3147 	{
       
  3148 		if( !this.hasGrid ) return;
       
  3149 		this.validRowsIndex = [];
       
  3150 		for(var k=this.refRow; k<this.nbFilterableRows; k++)
       
  3151 		{
       
  3152 			this.SetRowValidation(k,true);
       
  3153 			this.validRowsIndex.push(k);
       
  3154 		}
       
  3155 	},
       
  3156 	
       
  3157 	SetFilterValue: function(index,searcharg,doFilter)
       
  3158 	/*====================================================
       
  3159 		- Inserts value in a specified filter
       
  3160 		- Params:
       
  3161 			- index: filter column index (numeric value)
       
  3162 			- searcharg: search string
       
  3163 			- doFilter: optional boolean for multiple
       
  3164 			selects: executes filtering when multiple 
       
  3165 			select populated... IE only!
       
  3166 	=====================================================*/
       
  3167 	{
       
  3168 		if( (!this.fltGrid && !this.isFirstLoad) || tf_Id(this.fltIds[index])==null ) return;
       
  3169 		var slc = tf_Id(this.fltIds[index]);
       
  3170 		var execFilter = (doFilter==undefined) ? true : doFilter;
       
  3171 		searcharg = (searcharg==undefined) ? '' : searcharg;
       
  3172 		
       
  3173 		if( this['col'+index]!=this.fltTypeMulti && 
       
  3174 			this['col'+index]!=this.fltTypeCheckList )
       
  3175 			slc.value = searcharg;
       
  3176 			
       
  3177 		else if(this['col'+index] == this.fltTypeMulti)
       
  3178 		{//multiple selects
       
  3179 			var s = searcharg.split(' '+this.orOperator+' ');
       
  3180 			var ct = 0; //keywords counter
       
  3181 			for(var j=0; j<slc.options.length; j++) 
       
  3182 			{
       
  3183 				if(s=='') slc.options[j].selected = false;
       
  3184 				if(slc.options[j].value=='') slc.options[j].selected = false;
       
  3185 				if(slc.options[j].value!='' && s.tf_Has(slc.options[j].value,true))
       
  3186 				{
       
  3187 					if(tf_isIE)
       
  3188 					{// IE multiple selection work-around
       
  3189 						//when last value reached filtering can be executed
       
  3190 						var filter = (ct==(s.length-1) && execFilter) ? true : false;
       
  3191 						this.__deferMultipleSelection(slc,j,filter);
       
  3192 						ct++;
       
  3193 					}					
       
  3194 					else
       
  3195 						slc.options[j].selected = true;
       
  3196 				}//if
       
  3197 			}//for j
       
  3198 		}
       
  3199 		
       
  3200 		else if(this['col'+index]==this.fltTypeCheckList)
       
  3201 		{//checklist
       
  3202 			searcharg = searcharg.tf_MatchCase(this.matchCase);
       
  3203 			var s = searcharg.split(' '+this.orOperator+' ');
       
  3204 			var fltValue = slc.setAttribute('value','');
       
  3205 			var fltIndex = slc.setAttribute('indexes','');
       
  3206 			for(var k=0; k<tf_Tag(slc,'li').length; k++) 
       
  3207 			{
       
  3208 				var li = tf_Tag(slc,'li')[k];
       
  3209 				var lbl = tf_Tag(li,'label')[0];
       
  3210 				var chk = tf_Tag(li,'input')[0];
       
  3211 				var lblTxt = tf_GetNodeText(lbl).tf_MatchCase(this.matchCase);
       
  3212 				if(lblTxt!='' && s.tf_Has(lblTxt,true))
       
  3213 				{
       
  3214 					chk.checked = true;
       
  3215 					this.__setCheckListValues(chk);
       
  3216 				}
       
  3217 				else{ 
       
  3218 					chk.checked = false;
       
  3219 					this.__setCheckListValues(chk);
       
  3220 				}
       
  3221 			}
       
  3222 		}
       
  3223 	},
       
  3224 
       
  3225 	SetColWidths: function(rowIndex)
       
  3226 	/*====================================================
       
  3227 		- sets coluun widths in pixels
       
  3228 	=====================================================*/
       
  3229 	{
       
  3230 		if( !this.fltGrid || !this.hasColWidth ) return;
       
  3231 		var o = this, rIndex;
       
  3232 		if(rowIndex==undefined) rIndex = this.tbl.rows[0].style.display!='none' ? 0 : 1;
       
  3233 		else rIndex = rowIndex;
       
  3234 		setWidths( this.tbl.rows[rIndex] );
       
  3235 
       
  3236 		function setWidths( row )
       
  3237 		{
       
  3238 			if( !o && (o.nbCells!=o.colWidth.length) ) return;
       
  3239 			if( o.nbCells==row.cells.length )
       
  3240 				for(var k=0; k<o.nbCells; k++)
       
  3241 					row.cells[k].style.width = o.colWidth[k];
       
  3242 		}
       
  3243 	},
       
  3244 	
       
  3245 	SetVisibleRows: function()
       
  3246 	/*====================================================
       
  3247 		- makes a row always visible
       
  3248 		- Note this works only if paging is false
       
  3249 	=====================================================*/
       
  3250 	{
       
  3251 		if( this.hasGrid && this.hasVisibleRows && !this.paging )
       
  3252 		{
       
  3253 			for(var i=0; i<this.visibleRows.length; i++)
       
  3254 			{
       
  3255 				if(this.visibleRows[i]<=this.nbRows)//row index cannot be > nrows
       
  3256 					this.SetRowValidation(this.visibleRows[i],true);
       
  3257 			}//for i
       
  3258 		}//if hasGrid
       
  3259 	},
       
  3260 	
       
  3261 	SetRowBg: function(rIndex,index)
       
  3262 	/*====================================================
       
  3263 		- sets row background color
       
  3264 		- Params:
       
  3265 			- rIndex: row index (numeric value)
       
  3266 			- index: valid row collection index needed to
       
  3267 			calculate bg color
       
  3268 	=====================================================*/
       
  3269 	{
       
  3270 		if(!this.alternateBgs || isNaN(rIndex)) return;
       
  3271 		var rows = this.tbl.rows;
       
  3272 		var i = (index==undefined) ? rIndex : index;
       
  3273 		this.RemoveRowBg(rIndex);
       
  3274 		tf_addClass(
       
  3275 			rows[rIndex],
       
  3276 			(i%2 == 0) ? this.rowBgEvenCssClass : this.rowBgOddCssClass
       
  3277 		);
       
  3278 	},
       
  3279 	
       
  3280 	RemoveRowBg: function(index)
       
  3281 	/*====================================================
       
  3282 		- removes row background color
       
  3283 		- Params:
       
  3284 			- index: row index (numeric value)
       
  3285 	=====================================================*/
       
  3286 	{
       
  3287 		if(isNaN(index)) return;
       
  3288 		var rows = this.tbl.rows;
       
  3289 		tf_removeClass(rows[index],this.rowBgOddCssClass);
       
  3290 		tf_removeClass(rows[index],this.rowBgEvenCssClass);
       
  3291 	},
       
  3292 	
       
  3293 	SetAlternateRows: function()
       
  3294 	/*====================================================
       
  3295 		- alternates row colors for better readability
       
  3296 	=====================================================*/
       
  3297 	{
       
  3298 		if( !this.hasGrid && !this.isFirstLoad ) return;
       
  3299 		var rows = this.tbl.rows;
       
  3300 		var noValidRowsIndex = this.validRowsIndex==null;
       
  3301 		var beginIndex = (noValidRowsIndex) ? this.refRow : 0; //1st index
       
  3302 		var indexLen = (noValidRowsIndex) // nb indexes
       
  3303 			? (this.nbFilterableRows+beginIndex) : this.validRowsIndex.length;
       
  3304 
       
  3305 		for(var j=beginIndex; j<indexLen; j++)//alternates bg color
       
  3306 		{
       
  3307 			var rIndex = (noValidRowsIndex) ? j : this.validRowsIndex[j];
       
  3308 			this.SetRowBg(rIndex);
       
  3309 		}
       
  3310 	},
       
  3311 	
       
  3312 	RemoveAlternateRows: function()
       
  3313 	/*====================================================
       
  3314 		- removes alternate row colors
       
  3315 	=====================================================*/
       
  3316 	{
       
  3317 		if(!this.hasGrid) return;
       
  3318 		var row = this.tbl.rows;
       
  3319 		for(var i=this.refRow; i<this.nbRows; i++)
       
  3320 			this.RemoveRowBg(i);
       
  3321 		this.isStartBgAlternate = true;
       
  3322 	},
       
  3323 	
       
  3324 	SetColOperation: function()
       
  3325 	/*====================================================
       
  3326 		- Calculates values of a column
       
  3327 		- params are stored in 'colOperation' table's
       
  3328 		attribute
       
  3329 			- colOperation['id'] contains ids of elements 
       
  3330 			showing result (array)
       
  3331 			- colOperation['col'] contains index of 
       
  3332 			columns (array)
       
  3333 			- colOperation['operation'] contains operation
       
  3334 			type (array, values: sum, mean)
       
  3335 			- colOperation['write_method'] array defines 
       
  3336 			which method to use for displaying the 
       
  3337 			result (innerHTML, setValue, createTextNode).
       
  3338 			Note that innerHTML is the default value.
       
  3339 			- colOperation['tot_row_index'] defines in 
       
  3340 			which row results are displayed (integers array)
       
  3341 			
       
  3342 		- changes made by nuovella: 
       
  3343 		(1) optimized the routine (now it will only 
       
  3344 		process each column once),
       
  3345 		(2) added calculations for the median, lower and 
       
  3346 		upper quartile.
       
  3347 	=====================================================*/
       
  3348 	{
       
  3349 		if( !this.isFirstLoad && !this.hasGrid ) return;
       
  3350 		
       
  3351 		if(this.onBeforeOperation) this.onBeforeOperation.call(null,this);
       
  3352 		
       
  3353 		var labelId = this.colOperation['id'];
       
  3354 		var colIndex = this.colOperation['col'];
       
  3355 		var operation = this.colOperation['operation'];
       
  3356 		var outputType = this.colOperation['write_method'];
       
  3357 		var totRowIndex = this.colOperation['tot_row_index'];
       
  3358 		var excludeRow = this.colOperation['exclude_row'];
       
  3359 		var decimalPrecision = this.colOperation['decimal_precision']!=undefined
       
  3360 								? this.colOperation['decimal_precision'] : 2;
       
  3361 		
       
  3362 		//nuovella: determine unique list of columns to operate on
       
  3363 		var ucolIndex =[]; 
       
  3364 		var ucolMax=0;
       
  3365 		
       
  3366 		ucolIndex[ucolMax]=colIndex[0];
       
  3367 		
       
  3368 		for(var i=1; i<colIndex.length; i++)
       
  3369 		{
       
  3370 			saved=0;
       
  3371 			//see if colIndex[i] is already in the list of unique indexes
       
  3372 			for(var j=0; j<=ucolMax; j++ )
       
  3373 			{
       
  3374 				if (ucolIndex[j]==colIndex[i])
       
  3375 					saved=1;
       
  3376 			}
       
  3377 			if (saved==0)
       
  3378 			{//if not saved then, save the index;
       
  3379 				ucolMax++;
       
  3380 				ucolIndex[ucolMax]=colIndex[i];
       
  3381 			}
       
  3382 		}// for i
       
  3383 		
       
  3384 		if( (typeof labelId).tf_LCase()=='object' 
       
  3385 			&& (typeof colIndex).tf_LCase()=='object' 
       
  3386 			&& (typeof operation).tf_LCase()=='object' )
       
  3387 		{
       
  3388 			var row = this.tbl.rows;
       
  3389 			var colvalues = [];
       
  3390 			
       
  3391 			for(var ucol=0; ucol<=ucolMax; ucol++)
       
  3392 			{
       
  3393 				//this retrieves col values 
       
  3394 				//use ucolIndex because we only want to pass through this loop once for each column
       
  3395 				//get the values in this unique column
       
  3396 				colvalues.push( this.GetColValues(ucolIndex[ucol],true,excludeRow) );
       
  3397 				
       
  3398 			   //next: calculate all operations for this column
       
  3399 			   var result, nbvalues=0,  temp;
       
  3400 			   var meanValue=0, sumValue=0, minValue=null, maxValue=null, q1Value=null, medValue=null, q3Value=null;
       
  3401 			   var meanFlag=0, sumFlag=0, minFlag=0, maxFlag=0, q1Flag=0, medFlag=0, q3Flag=0;
       
  3402 			   var theList=[];
       
  3403 			   var opsThisCol=[], decThisCol=[], labThisCol=[], oTypeThisCol=[];
       
  3404 			   var mThisCol=-1;
       
  3405 				
       
  3406 				for(var i=0; i<colIndex.length; i++)
       
  3407 				{
       
  3408 					 if (colIndex[i]==ucolIndex[ucol])
       
  3409 					 {
       
  3410 						mThisCol++;
       
  3411 						opsThisCol[mThisCol]=operation[i].tf_LCase();
       
  3412 						decThisCol[mThisCol]=decimalPrecision[i];
       
  3413 						labThisCol[mThisCol]=labelId[i]; 
       
  3414 						oTypeThisCol = (outputType != undefined && (typeof outputType).tf_LCase()=='object') 
       
  3415 											? outputType[i] : null;
       
  3416 						
       
  3417 						switch( opsThisCol[mThisCol] )
       
  3418 						{			
       
  3419 							case 'mean':
       
  3420 								meanFlag=1;
       
  3421 							break;
       
  3422 							case 'sum':
       
  3423 								sumFlag=1;
       
  3424 							break;
       
  3425 							case 'min':
       
  3426 								minFlag=1;
       
  3427 							break;
       
  3428 							case 'max':
       
  3429 								maxFlag=1;
       
  3430 							break;
       
  3431 							case 'median':
       
  3432 								medFlag=1;	
       
  3433 								break;
       
  3434 							case 'q1':
       
  3435 								q1Flag=1;
       
  3436 							break;
       
  3437 							case 'q3':
       
  3438 								q3Flag=1;
       
  3439 							break;
       
  3440 						}
       
  3441 					}		
       
  3442 				}
       
  3443 				
       
  3444 				for(var j=0; j<colvalues[ucol].length; j++ )
       
  3445 				{
       
  3446 					if ((q1Flag==1)||(q3Flag==1) || (medFlag==1))
       
  3447 					{//sort the list for calculation of median and quartiles
       
  3448 						if (j<colvalues[ucol].length -1)
       
  3449 						{
       
  3450 							for(k=j+1;k<colvalues[ucol].length; k++) {
       
  3451 				  
       
  3452 								if( eval(colvalues[ucol][k]) < eval(colvalues[ucol][j]))
       
  3453 								{
       
  3454 									temp = colvalues[ucol][j];            
       
  3455 									colvalues[ucol][j] = colvalues[ucol][k];              
       
  3456 									colvalues[ucol][k] = temp;            
       
  3457 								}
       
  3458 							}
       
  3459 						}
       
  3460 					}
       
  3461 					var cvalue = parseFloat(colvalues[ucol][j]);
       
  3462 					theList[j]=parseFloat( cvalue );
       
  3463 	
       
  3464 					if( !isNaN(cvalue) )
       
  3465 					{
       
  3466 						nbvalues++;
       
  3467 						if ((sumFlag==1)|| (meanFlag==1)) sumValue += parseFloat( cvalue );
       
  3468 						if (minFlag==1) 
       
  3469 						{
       
  3470 							if (minValue==null)
       
  3471 							{
       
  3472 								minValue = parseFloat( cvalue );
       
  3473 							}
       
  3474 							else minValue= parseFloat( cvalue )<minValue? parseFloat( cvalue ): minValue;
       
  3475 						}
       
  3476 						if (maxFlag==1) {
       
  3477 							if (maxValue==null)
       
  3478 							{maxValue = parseFloat( cvalue );}
       
  3479 						else {maxValue= parseFloat( cvalue )>maxValue? parseFloat( cvalue ): maxValue;}
       
  3480 						}
       
  3481 					}
       
  3482 				}//for j
       
  3483 				if (meanFlag==1) meanValue = sumValue/nbvalues;
       
  3484 				if (medFlag==1)
       
  3485 				{
       
  3486 						var aux = 0;
       
  3487 						if(nbvalues%2 == 1) 
       
  3488 						{
       
  3489 							aux = Math.floor(nbvalues/2);
       
  3490 							medValue = theList[aux];   
       
  3491 						}
       
  3492 					else medValue = (theList[nbvalues/2]+theList[((nbvalues/2)-1)])/2;
       
  3493 				}
       
  3494 				if (q1Flag==1)
       
  3495 				{	
       
  3496 					var posa=0.0;
       
  3497 					posa = Math.floor(nbvalues/4);
       
  3498 					if (4*posa == nbvalues) {q1Value = (theList[posa-1] + theList[posa])/2;}
       
  3499 					else {q1Value = theList[posa];}
       
  3500 				}
       
  3501 				if (q3Flag==1)
       
  3502 				{
       
  3503 					var posa=0.0;
       
  3504 					var posb=0.0;
       
  3505 					posa = Math.floor(nbvalues/4);
       
  3506 					if (4*posa == nbvalues)
       
  3507 					{
       
  3508 						posb = 3*posa;
       
  3509 						q3Value = (theList[posb] + theList[posb-1])/2;  
       
  3510 					}
       
  3511 					else
       
  3512 						q3Value = theList[nbvalues-posa-1];
       
  3513 				}
       
  3514 				
       
  3515 				for(var i=0; i<=mThisCol; i++ )
       
  3516 				{
       
  3517 				   switch( opsThisCol[i] )
       
  3518 				   {			
       
  3519 						case 'mean':
       
  3520 							result=meanValue;
       
  3521 						break;
       
  3522 						case 'sum':
       
  3523 							result=sumValue;
       
  3524 						break;
       
  3525 						case 'min':
       
  3526 							result=minValue;
       
  3527 						break;
       
  3528 						case 'max':
       
  3529 							result=maxValue;
       
  3530 						break;
       
  3531 						case 'median':
       
  3532 							result=medValue;	
       
  3533 							break;
       
  3534 						case 'q1':
       
  3535 							result=q1Value;
       
  3536 						break;
       
  3537 						case 'q3':
       
  3538 							result=q3Value;
       
  3539 						break;
       
  3540 				  }		
       
  3541 					
       
  3542 				var precision = decThisCol[i]!=undefined && !isNaN( decThisCol[i] )
       
  3543 									? decThisCol[i] : 2;
       
  3544 
       
  3545 				if(oTypeThisCol!=null && result)
       
  3546 				{//if outputType is defined
       
  3547 					result = result.toFixed( precision );
       
  3548 					if( tf_Id( labThisCol[i] )!=undefined )
       
  3549 					{
       
  3550 						switch( oTypeThisCol.tf_LCase() )
       
  3551 						{
       
  3552 							case 'innerhtml':							
       
  3553 								if (isNaN(result) || !isFinite(result) || (nbvalues==0)) 
       
  3554 									tf_Id( labThisCol[i] ).innerHTML = '.';
       
  3555 								else
       
  3556 									tf_Id( labThisCol[i] ).innerHTML = result;
       
  3557 							break;
       
  3558 							case 'setvalue':
       
  3559 								tf_Id( labThisCol[i] ).value = result;
       
  3560 							break;
       
  3561 							case 'createtextnode':
       
  3562 								var oldnode = tf_Id( labThisCol[i] ).firstChild;
       
  3563 								var txtnode = tf_CreateText( result );
       
  3564 								tf_Id( labThisCol[i] ).replaceChild( txtnode,oldnode );
       
  3565 							break;
       
  3566 						}//switch
       
  3567 					}
       
  3568 				} else {
       
  3569 					try
       
  3570 					{      
       
  3571 						if (isNaN(result) || !isFinite(result) || (nbvalues==0)) 
       
  3572 							tf_Id( labThisCol[i] ).innerHTML = '.';
       
  3573 						else
       
  3574 							 tf_Id( labThisCol[i] ).innerHTML = result.toFixed( precision );
       
  3575 					} catch(e){ }//catch
       
  3576 				}//else
       
  3577 			 }//for i
       
  3578 			//eventual row(s) with result are always visible
       
  3579 			if(totRowIndex!=undefined && row[totRowIndex[ucol]]) 
       
  3580 				row[totRowIndex[ucol]].style.display = '';
       
  3581 			}//for ucol
       
  3582 		}//if typeof
       
  3583 		
       
  3584 		if(this.onAfterOperation) this.onAfterOperation.call(null,this);
       
  3585 	},
       
  3586 	
       
  3587 	SetPage: function( cmd )
       
  3588 	/*====================================================
       
  3589 		- If paging set true shows page according to
       
  3590 		param value (string or number):
       
  3591 			- strings: 'next','previous','last','first' or
       
  3592 			- number: page number
       
  3593 	=====================================================*/
       
  3594 	{
       
  3595 		if( this.hasGrid && this.paging )
       
  3596 		{
       
  3597 			var btnEvt = this.pagingBtnEvents, cmdtype = typeof cmd;
       
  3598 			if(cmdtype=='string')
       
  3599 			{
       
  3600 				switch(cmd.tf_LCase())
       
  3601 				{
       
  3602 					case 'next':
       
  3603 						btnEvt.next();
       
  3604 					break;
       
  3605 					case 'previous':
       
  3606 						btnEvt.prev();
       
  3607 					break;
       
  3608 					case 'last':
       
  3609 						btnEvt.last();
       
  3610 					break;
       
  3611 					case 'first':
       
  3612 						btnEvt.first();
       
  3613 					break;
       
  3614 					default:
       
  3615 						btnEvt.next();
       
  3616 					break;
       
  3617 				}//switch
       
  3618 			}
       
  3619 			if(cmdtype=='number') this.ChangePage( (cmd-1) );
       
  3620 		}// this.hasGrid 
       
  3621 	},
       
  3622 	
       
  3623 	RefreshFiltersGrid: function()
       
  3624 	/*====================================================
       
  3625 		- retrieves select, multiple and checklist filters
       
  3626 		- calls method repopulating filters
       
  3627 	=====================================================*/
       
  3628 	{
       
  3629 		var slcA1 = this.GetFiltersByType( this.fltTypeSlc,true );
       
  3630 		var slcA2 = this.GetFiltersByType( this.fltTypeMulti,true );
       
  3631 		var slcA3 = this.GetFiltersByType( this.fltTypeCheckList,true );
       
  3632 		var slcIndex = slcA1.concat(slcA2);
       
  3633 		slcIndex = slcIndex.concat(slcA3);
       
  3634 
       
  3635 		if( this.activeFilterId!=null )//for paging
       
  3636 		{
       
  3637 			var activeFlt = this.activeFilterId.split('_')[0];
       
  3638 			activeFlt = activeFlt.split(this.prfxFlt)[1];
       
  3639 			var slcSelectedValue;
       
  3640 			for(var i=0; i<slcIndex.length; i++)
       
  3641 			{
       
  3642 				var curSlc = tf_Id(this.fltIds[slcIndex[i]]);
       
  3643 				slcSelectedValue = this.GetFilterValue( slcIndex[i] );
       
  3644 				//if(activeFlt==slcIndex[i] && slcA3.tf_Has(slcIndex[i]) && slcSelectedValue!=this.displayAllText) continue;
       
  3645 				if(activeFlt!=slcIndex[i] || (this.paging && slcA1.tf_Has(slcIndex[i]) && activeFlt==slcIndex[i] ) || 
       
  3646 					( !this.paging && (slcA3.tf_Has(slcIndex[i]) || slcA2.tf_Has(slcIndex[i]) ) /*&& activeFlt==slcIndex[i]*/) || 
       
  3647 					slcSelectedValue==this.displayAllText )
       
  3648 					//(this.paging && (!slcA3.tf_Has(slcIndex[i]) && !slcA2.tf_Has(slcIndex[i]) && activeFlt==slcIndex[i]) ) )
       
  3649 				{
       
  3650 					if(slcA3.tf_Has(slcIndex[i]))
       
  3651 						this.checkListDiv[slcIndex[i]].innerHTML = '';
       
  3652 					else curSlc.innerHTML = '';
       
  3653 					
       
  3654 					if(this.fillSlcOnDemand) { //1st option needs to be inserted
       
  3655 						var opt0 = tf_CreateOpt(this.displayAllText,'');
       
  3656 						curSlc.appendChild( opt0 );
       
  3657 					}
       
  3658 					
       
  3659 					if(slcA3.tf_Has(slcIndex[i]))
       
  3660 						this._PopulateCheckList(slcIndex[i]);
       
  3661 					else
       
  3662 						this._PopulateSelect(slcIndex[i],true);
       
  3663 						
       
  3664 					this.SetFilterValue(slcIndex[i],slcSelectedValue);
       
  3665 				}
       
  3666 			}// for i
       
  3667 		}
       
  3668 	},
       
  3669 	
       
  3670 	RememberFiltersValue: function( name )
       
  3671 	/*==============================================
       
  3672 		- stores filters' values in a cookie
       
  3673 		when Filter() method is called
       
  3674 		- Params:
       
  3675 			- name: cookie name (string)
       
  3676 		- credits to Florent Hirchy
       
  3677 	===============================================*/
       
  3678 	{
       
  3679 		var flt_values = [];
       
  3680 		for(var i=0; i<this.fltIds.length; i++)
       
  3681 		{//creates an array with filters' values
       
  3682 			value = this.GetFilterValue(i);
       
  3683 			if (value == '') value = ' ';
       
  3684 			flt_values.push(value);
       
  3685 		}
       
  3686 		flt_values.push(this.fltIds.length); //adds array size
       
  3687 		tf_WriteCookie(
       
  3688 			name,
       
  3689 			flt_values,
       
  3690 			this.cookieDuration
       
  3691 		); //writes cookie  
       
  3692 	},
       
  3693 	
       
  3694 	RememberPageNb: function( name )
       
  3695 	/*==============================================
       
  3696 		- stores page number value in a cookie
       
  3697 		when ChangePage method is called
       
  3698 		- Params:
       
  3699 			- name: cookie name (string)
       
  3700 	===============================================*/
       
  3701 	{
       
  3702 		tf_WriteCookie(
       
  3703 			name,
       
  3704 			this.currentPageNb,
       
  3705 			this.cookieDuration
       
  3706 		); //writes cookie  
       
  3707 	},
       
  3708 	
       
  3709 	RememberPageLength: function( name )
       
  3710 	/*==============================================
       
  3711 		- stores page length value in a cookie
       
  3712 		when ChangePageLength method is called
       
  3713 		- Params:
       
  3714 			- name: cookie name (string)
       
  3715 	===============================================*/
       
  3716 	{
       
  3717 		tf_WriteCookie(
       
  3718 			name,
       
  3719 			this.resultsPerPageSlc.selectedIndex,
       
  3720 			this.cookieDuration
       
  3721 		); //writes cookie
       
  3722 	},
       
  3723 	
       
  3724 	ResetValues: function()
       
  3725 	{ 
       
  3726 		this.EvtManager(this.Evt.name.resetvalues); 
       
  3727 	},
       
  3728 	
       
  3729 	_ResetValues: function()
       
  3730 	/*==============================================
       
  3731 		- re-sets grid values when page is 
       
  3732 		re-loaded. It invokes ResetGridValues,
       
  3733 		ResetPage and ResetPageLength methods
       
  3734 		- Params:
       
  3735 			- name: cookie name (string)
       
  3736 	===============================================*/
       
  3737 	{
       
  3738 		if(this.rememberGridValues && this.fillSlcOnDemand) //only fillSlcOnDemand
       
  3739 			this.ResetGridValues(this.fltsValuesCookie);
       
  3740 		if(this.rememberPageLen) this.ResetPageLength( this.pgLenCookie );
       
  3741 		if(this.rememberPageNb) this.ResetPage( this.pgNbCookie );		
       
  3742 	},	
       
  3743 	
       
  3744 	ResetGridValues: function( name )
       
  3745 	/*==============================================
       
  3746 		- re-sets filters' values when page is 
       
  3747 		re-loaded if load on demand is enabled
       
  3748 		- Params:
       
  3749 			- name: cookie name (string)
       
  3750 		- credits to Florent Hirchy
       
  3751 	===============================================*/
       
  3752 	{
       
  3753 		if(!this.fillSlcOnDemand) return;
       
  3754 		var flts = tf_ReadCookie(name); //reads the cookie
       
  3755 		var reg = new RegExp(',','g');	
       
  3756 		var flts_values = flts.split(reg); //creates an array with filters' values
       
  3757 		var slcFltsIndex = this.GetFiltersByType(this.fltTypeSlc, true);
       
  3758 		var multiFltsIndex = this.GetFiltersByType(this.fltTypeMulti, true);
       
  3759 		
       
  3760 		if(flts_values[(flts_values.length-1)] == this.fltIds.length)
       
  3761 		{//if the number of columns is the same as before page reload
       
  3762 			for(var i=0; i<(flts_values.length - 1); i++)
       
  3763 			{			
       
  3764 				if (flts_values[i]==' ') continue;				
       
  3765 				if(this['col'+i]==this.fltTypeSlc || this['col'+i]==this.fltTypeMulti)
       
  3766 				{// if fillSlcOnDemand, drop-down needs to contain stored value(s) for filtering
       
  3767 					var slc = tf_Id( this.fltIds[i] );
       
  3768 					slc.options[0].selected = false;
       
  3769 					
       
  3770 					if( slcFltsIndex.tf_Has(i) )
       
  3771 					{//selects
       
  3772 						var opt = tf_CreateOpt(flts_values[i],flts_values[i],true);
       
  3773 						slc.appendChild(opt);
       
  3774 						this.hasStoredValues = true;
       
  3775 					}
       
  3776 					if(multiFltsIndex.tf_Has(i))
       
  3777 					{//multiple select
       
  3778 						var s = flts_values[i].split(' '+this.orOperator+' ');
       
  3779 						for(j=0; j<s.length; j++)
       
  3780 						{
       
  3781 							if(s[j]=='') continue;
       
  3782 							var opt = tf_CreateOpt(s[j],s[j],true);
       
  3783 							slc.appendChild(opt);
       
  3784 							this.hasStoredValues = true;
       
  3785 							
       
  3786 							if(tf_isIE)
       
  3787 							{// IE multiple selection work-around
       
  3788 								this.__deferMultipleSelection(slc,j,false);
       
  3789 								hasStoredValues = false;
       
  3790 							}
       
  3791 						}
       
  3792 					}// if multiFltsIndex
       
  3793 				}
       
  3794 				else if(this['col'+i]==this.fltTypeCheckList)
       
  3795 				{
       
  3796 					var divChk = this.checkListDiv[i];
       
  3797 					divChk.title = divChk.innerHTML;
       
  3798 					divChk.innerHTML = '';
       
  3799 					
       
  3800 					var ul = tf_CreateElm('ul',['id',this.fltIds[i]],['colIndex',i]);
       
  3801 					ul.className = this.checkListCssClass;
       
  3802 
       
  3803 					var li0 = tf_CreateCheckItem(this.fltIds[i]+'_0', '', this.displayAllText);
       
  3804 					li0.className = this.checkListItemCssClass;
       
  3805 					ul.appendChild(li0);
       
  3806 
       
  3807 					divChk.appendChild(ul);
       
  3808 					
       
  3809 					var s = flts_values[i].split(' '+this.orOperator+' ');
       
  3810 					for(j=0; j<s.length; j++)
       
  3811 					{
       
  3812 						if(s[j]=='') continue;
       
  3813 						var li = tf_CreateCheckItem(this.fltIds[i]+'_'+(j+1), s[j], s[j]);
       
  3814 						li.className = this.checkListItemCssClass;
       
  3815 						ul.appendChild(li);
       
  3816 						li.check.checked = true;
       
  3817 						this.__setCheckListValues(li.check);
       
  3818 						this.hasStoredValues = true;
       
  3819 					}					
       
  3820 				}
       
  3821 			}//end for
       
  3822 			
       
  3823 			if(!this.hasStoredValues && this.paging) this.SetPagingInfo();
       
  3824 		}//end if
       
  3825 	},
       
  3826 	
       
  3827 	ResetPage: function( name )
       
  3828 	{
       
  3829 		this.EvtManager(this.Evt.name.resetpage);
       
  3830 	},
       
  3831 	_ResetPage: function( name )
       
  3832 	/*==============================================
       
  3833 		- re-sets page nb at page re-load
       
  3834 		- Params:
       
  3835 			- name: cookie name (string)
       
  3836 	===============================================*/
       
  3837 	{
       
  3838 		var pgnb = tf_ReadCookie(name); //reads the cookie
       
  3839 		if( pgnb!='' ) 
       
  3840 			this.ChangePage((pgnb-1));
       
  3841 	},
       
  3842 	
       
  3843 	ResetPageLength: function( name )
       
  3844 	{
       
  3845 		this.EvtManager(this.Evt.name.resetpagelength);
       
  3846 	},
       
  3847 	_ResetPageLength: function( name )
       
  3848 	/*==============================================
       
  3849 		- re-sets page length at page re-load
       
  3850 		- Params:
       
  3851 			- name: cookie name (string)
       
  3852 	===============================================*/
       
  3853 	{
       
  3854 		if(!this.paging) return;
       
  3855 		var pglenIndex = tf_ReadCookie(name); //reads the cookie
       
  3856 		
       
  3857 		if( pglenIndex!='' )
       
  3858 		{
       
  3859 			this.resultsPerPageSlc.options[pglenIndex].selected = true;
       
  3860 			this.ChangeResultsPerPage();
       
  3861 		}
       
  3862 	},
       
  3863 	
       
  3864 	SetLoader: function()
       
  3865 	/*====================================================
       
  3866 		- generates loader div
       
  3867 	=====================================================*/
       
  3868 	{
       
  3869 		if( this.loaderDiv!=null ) return;
       
  3870 		var containerDiv = tf_CreateElm( 'div',['id',this.prfxLoader+this.id] );
       
  3871 		containerDiv.className = this.loaderCssClass;// for ie<=6
       
  3872 		//containerDiv.style.display = 'none';
       
  3873 		var targetEl = (this.loaderTgtId==null) 
       
  3874 			? (this.gridLayout ? this.tblCont : this.tbl.parentNode) : tf_Id( this.loaderTgtId );
       
  3875 		if(this.loaderTgtId==null) targetEl.insertBefore(containerDiv, this.tbl);
       
  3876 		else targetEl.appendChild( containerDiv );
       
  3877 		this.loaderDiv = tf_Id(this.prfxLoader+this.id);
       
  3878 		if(this.loaderHtml==null) 
       
  3879 			this.loaderDiv.appendChild( tf_CreateText(this.loaderText) );
       
  3880 		else this.loaderDiv.innerHTML = this.loaderHtml;
       
  3881 	},
       
  3882 	
       
  3883 	RemoveLoader: function()
       
  3884 	/*====================================================
       
  3885 		- removes loader div
       
  3886 	=====================================================*/
       
  3887 	{
       
  3888 		if( this.loaderDiv==null ) return;
       
  3889 		var targetEl = (this.loaderTgtId==null) 
       
  3890 			? (this.gridLayout ? this.tblCont : this.tbl.parentNode) : tf_Id( this.loaderTgtId );
       
  3891 		targetEl.removeChild(this.loaderDiv);
       
  3892 		this.loaderDiv = null;
       
  3893 	},
       
  3894 	
       
  3895 	ShowLoader: function(p)
       
  3896 	/*====================================================
       
  3897 		- displays/hides loader div
       
  3898 	=====================================================*/
       
  3899 	{
       
  3900 		if(!this.loader || !this.loaderDiv) return;
       
  3901 		if(this.loaderDiv.style.display==p) return;
       
  3902 		var o = this;
       
  3903 
       
  3904 		function displayLoader(){ 
       
  3905 			if(!o.loaderDiv) return;
       
  3906 			if(o.onShowLoader && p!='none') 
       
  3907 				o.onShowLoader.call(null,o);
       
  3908 			o.loaderDiv.style.display = p;
       
  3909 			if(o.onHideLoader && p=='none') 
       
  3910 				o.onHideLoader.call(null,o);
       
  3911 		}
       
  3912 
       
  3913 		var t = (p=='none') ? this.loaderCloseDelay : 1;
       
  3914 		window.setTimeout(displayLoader,t);
       
  3915 	},
       
  3916 	
       
  3917 	StatusMsg: function(t)
       
  3918 	/*====================================================
       
  3919 		- sets status messages
       
  3920 	=====================================================*/
       
  3921 	{
       
  3922 		if(t==undefined) this.StatusMsg('');
       
  3923 		if(this.status) this.WinStatusMsg(t);
       
  3924 		if(this.statusBar) this.StatusBarMsg(t);
       
  3925 	},
       
  3926 	
       
  3927 	StatusBarMsg: function(t)
       
  3928 	/*====================================================
       
  3929 		- sets status bar messages
       
  3930 	=====================================================*/
       
  3931 	{
       
  3932 		if(!this.statusBar || !this.statusBarSpan) return;
       
  3933 		var o = this;
       
  3934 		function setMsg(){
       
  3935 			o.statusBarSpan.innerHTML = t;
       
  3936 		}
       
  3937 		var d = (t=='') ? (this.statusBarCloseDelay) : 1;
       
  3938 		window.setTimeout(setMsg,d);
       
  3939 	},
       
  3940 	
       
  3941 	WinStatusMsg: function(t)
       
  3942 	/*====================================================
       
  3943 		- sets window status messages
       
  3944 	=====================================================*/
       
  3945 	{
       
  3946 		if(!this.status) return;
       
  3947 		window.status = t;
       
  3948 	},
       
  3949 	
       
  3950 	ClearFilters: function()
       
  3951 	{ 
       
  3952 		this.EvtManager(this.Evt.name.clear); 
       
  3953 	},	
       
  3954 	_ClearFilters: function()
       
  3955 	/*====================================================
       
  3956 		- clears grid filters
       
  3957 	=====================================================*/
       
  3958 	{
       
  3959 		if( !this.fltGrid ) return;
       
  3960 		for(var i=0; i<this.fltIds.length; i++)
       
  3961 			this.SetFilterValue(i,'');
       
  3962 		if(this.refreshFilters){
       
  3963 			this.activeFilterId = '';	
       
  3964 			this.RefreshFiltersGrid();
       
  3965 		}
       
  3966 		if(this.rememberPageLen) tf_RemoveCookie(this.pgLenCookie);
       
  3967 		if(this.rememberPageNb) tf_RemoveCookie(this.pgNbCookie);
       
  3968 	},
       
  3969 	
       
  3970 	UnhighlightAll: function()
       
  3971 	/*====================================================
       
  3972 		- removes keyword highlighting
       
  3973 	=====================================================*/
       
  3974 	{
       
  3975 		if( this.highlightKeywords && this.searchArgs!=null )
       
  3976 			for(var y=0; y<this.searchArgs.length; y++)
       
  3977 				tf_UnhighlightWord( 
       
  3978 					this.tbl,this.searchArgs[y],
       
  3979 					this.highlightCssClass 
       
  3980 				);
       
  3981 	},
       
  3982 	
       
  3983 	RefreshGrid: function()
       
  3984 	/*====================================================
       
  3985 		- Re-generates filters grid
       
  3986 	=====================================================*/
       
  3987 	{
       
  3988 		this.RemoveGrid();
       
  3989 		setFilterGrid(this.id, this.startRow, this.fObj);
       
  3990 	},
       
  3991 	
       
  3992 	__resetGrid: function()
       
  3993 	/*====================================================
       
  3994 		- Only used by AddGrid() method
       
  3995 		- Resets filtering grid bar if previously removed
       
  3996 	=====================================================*/
       
  3997 	{
       
  3998 		if( this.isFirstLoad ) return;
       
  3999 		
       
  4000 		// grid was removed, grid row element is stored in this.fltGridEl property
       
  4001 		this.tbl.rows[this.filtersRowIndex].parentNode.insertBefore( 
       
  4002 			this.fltGridEl,
       
  4003 			this.tbl.rows[this.filtersRowIndex]
       
  4004 		);
       
  4005 		
       
  4006 		if( this.isExternalFlt )
       
  4007 		{// filters are appended in external placeholders elements
       
  4008 			for(var ct=0; ct<this.externalFltTgtIds.length; ct++ )
       
  4009 				if( tf_Id(this.externalFltTgtIds[ct]) )
       
  4010 					tf_Id(this.externalFltTgtIds[ct]).appendChild(this.externalFltEls[ct]);
       
  4011 		}
       
  4012 		
       
  4013 		this.nbFilterableRows = this.GetRowsNb();
       
  4014 		this.nbVisibleRows = this.nbFilterableRows;
       
  4015 		this.nbRows = this.tbl.rows.length;
       
  4016 		this.sort = true;
       
  4017 		
       
  4018 		/*** 	ie bug work-around, filters need to be re-generated
       
  4019 				since row is empty; insertBefore method doesn't seem to work properly 
       
  4020 				with previously generated DOM nodes modified by innerHTML 	***/
       
  4021 		if( this.tbl.rows[this.filtersRowIndex].innerHTML=='' )
       
  4022 		{
       
  4023 			this.tbl.deleteRow(this.filtersRowIndex);
       
  4024 			this.RemoveGrid();
       
  4025 			this.RemoveExternalFlts();
       
  4026 			this.fltIds = [];
       
  4027 			this.isFirstLoad = true;
       
  4028 			this.AddGrid();
       
  4029 			
       
  4030 		}
       
  4031 		
       
  4032 		this.hasGrid = true;
       
  4033 	},
       
  4034 	
       
  4035 	__deferMultipleSelection: function(slc,index,filter)
       
  4036 	/*====================================================
       
  4037 		- IE bug: it seems there is no way to make 
       
  4038 		multiple selections programatically, only last 
       
  4039 		selection is kept (multiple select previously 
       
  4040 		populated via DOM)
       
  4041 		- Turn-around: defer selection with a setTimeout
       
  4042 		If you find an alternative elegant solution to 
       
  4043 		this let me know ;-)
       
  4044 		- For the moment only this solution seems 
       
  4045 		to work!
       
  4046 		- Params: 
       
  4047 			- slc = select object (select obj)
       
  4048 			- index to be selected (integer)
       
  4049 			- execute filtering (boolean)
       
  4050 	=====================================================*/
       
  4051 	{
       
  4052 		if(slc.nodeName.tf_LCase() != 'select') return;
       
  4053 		var doFilter = (filter==undefined) ? false : filter;
       
  4054 		var o = this;
       
  4055 		window.setTimeout(
       
  4056 			function(){
       
  4057 				slc.options[0].selected = false;
       
  4058 				
       
  4059 				if(slc.options[index].value=='') 
       
  4060 					slc.options[index].selected = false;
       
  4061 				else
       
  4062 				slc.options[index].selected = true; 
       
  4063 				if(doFilter) o.Filter();
       
  4064 			},
       
  4065 			.1
       
  4066 		);
       
  4067 	},
       
  4068 	
       
  4069 	__getCustomValues: function(colIndex)
       
  4070 	/*====================================================
       
  4071 		- Returns an array [[values],[texts]] with 
       
  4072 		custom values for a given filter
       
  4073 		- Param: column index (integer)
       
  4074 	=====================================================*/
       
  4075 	{
       
  4076 		if(colIndex==undefined) return;
       
  4077 		var isCustomSlc = (this.hasCustomSlcOptions  //custom select test
       
  4078 							&& this.customSlcOptions.cols.tf_Has(colIndex));
       
  4079 		if(!isCustomSlc) return;
       
  4080 		var optTxt = [], optArray = [];
       
  4081 		var index = this.customSlcOptions.cols.tf_IndexByValue(colIndex);
       
  4082 		var slcValues = this.customSlcOptions.values[index];
       
  4083 		var slcTexts = this.customSlcOptions.texts[index];
       
  4084 		var slcSort = this.customSlcOptions.sorts[index];
       
  4085 		for(var r=0; r<slcValues.length; r++)
       
  4086 		{
       
  4087 			optArray.push(slcValues[r]);
       
  4088 			if(slcTexts[r]!=undefined)
       
  4089 				optTxt.push(slcTexts[r]);
       
  4090 			else
       
  4091 				optTxt.push(slcValues[r]);
       
  4092 		}
       
  4093 		if(slcSort)
       
  4094 		{
       
  4095 			optArray.sort();
       
  4096 			optTxt.sort();
       
  4097 		}
       
  4098 		return [optArray,optTxt];
       
  4099 	},
       
  4100 	
       
  4101 	__setCheckListValues: function(o)
       
  4102 	/*====================================================
       
  4103 		- Sets checked items information of a checklist
       
  4104 	=====================================================*/
       
  4105 	{
       
  4106 		if(o==null) return;
       
  4107 		var chkValue = o.value; //checked item value
       
  4108 		var chkIndex = parseInt(o.id.split('_')[2]);
       
  4109 		var filterTag = 'ul', itemTag = 'li';
       
  4110 		var n = o;
       
  4111 		
       
  4112 		//ul tag search
       
  4113 		while(n.nodeName.tf_LCase() != filterTag)
       
  4114 			n = n.parentNode;
       
  4115 
       
  4116 		if(n.nodeName.tf_LCase() != filterTag) return;
       
  4117 		
       
  4118 		var li = n.childNodes[chkIndex];
       
  4119 		var colIndex = n.getAttribute('colIndex');
       
  4120 		var fltValue = n.getAttribute('value'); //filter value (ul tag)
       
  4121 		var fltIndexes = n.getAttribute('indexes'); //selected items (ul tag)
       
  4122 
       
  4123 		if(o.checked)		
       
  4124 		{
       
  4125 			if(chkValue=='')
       
  4126 			{//show all item
       
  4127 				if((fltIndexes!=null && fltIndexes!=''))
       
  4128 				{
       
  4129 					var indSplit = fltIndexes.split(this.separator);//items indexes
       
  4130 					for(var u=0; u<indSplit.length; u++)
       
  4131 					{//checked items loop
       
  4132 						var cChk = tf_Id(this.fltIds[colIndex]+'_'+indSplit[u]); //checked item
       
  4133 						if(cChk)
       
  4134 						{ 
       
  4135 							cChk.checked = false;
       
  4136 							tf_removeClass(
       
  4137 								n.childNodes[indSplit[u]],
       
  4138 								this.checkListSlcItemCssClass
       
  4139 							);
       
  4140 						}
       
  4141 					}
       
  4142 				}
       
  4143 				n.setAttribute('value', '');
       
  4144 				n.setAttribute('indexes', '');
       
  4145 				
       
  4146 			} else {
       
  4147 				fltValue = (fltValue) ? fltValue : '';
       
  4148 				chkValue = (fltValue+' '+chkValue +' '+this.orOperator).tf_Trim();
       
  4149 				chkIndex = fltIndexes + chkIndex + this.separator;
       
  4150 				n.setAttribute('value', chkValue );
       
  4151 				n.setAttribute('indexes', chkIndex);
       
  4152 				//1st option unchecked
       
  4153 				if(tf_Id(this.fltIds[colIndex]+'_0'))
       
  4154 					tf_Id(this.fltIds[colIndex]+'_0').checked = false; 
       
  4155 			}
       
  4156 			
       
  4157 			if(li.nodeName.tf_LCase() == itemTag)
       
  4158 			{
       
  4159 				tf_removeClass(n.childNodes[0],this.checkListSlcItemCssClass);
       
  4160 				tf_addClass(li,this.checkListSlcItemCssClass);
       
  4161 			}
       
  4162 		} else { //removes values and indexes
       
  4163 			if(chkValue!='')
       
  4164 			{
       
  4165 				var replaceValue = new RegExp(tf_RegexpEscape(chkValue+' '+this.orOperator));
       
  4166 				fltValue = fltValue.replace(replaceValue,'');
       
  4167 				n.setAttribute('value', fltValue);
       
  4168 				
       
  4169 				var replaceIndex = new RegExp(tf_RegexpEscape(chkIndex + this.separator));
       
  4170 				fltIndexes = fltIndexes.replace(replaceIndex,'');
       
  4171 				n.setAttribute('indexes', fltIndexes);
       
  4172 			}
       
  4173 			if(li.nodeName.tf_LCase() == itemTag)
       
  4174 				tf_removeClass(li,this.checkListSlcItemCssClass);
       
  4175 		}
       
  4176 			
       
  4177 	},
       
  4178 	
       
  4179 	__containsStr: function(arg,data,fltType,forceMatch)
       
  4180 	/*==============================================
       
  4181 		- Checks if data contains searched arg,
       
  4182 		returns a boolean
       
  4183 		- Params:
       
  4184 			- arg: searched string
       
  4185 			- data: data string
       
  4186 			- fltType: filter type (string, 
       
  4187 			exact match by default for selects - 
       
  4188 			optional)
       
  4189 			- forceMatch: boolean forcing exact
       
  4190 			match (optional)
       
  4191 	===============================================*/
       
  4192 	{
       
  4193 		// Improved by Cedric Wartel (cwl)
       
  4194 		// automatic exact match for selects and special characters are now filtered
       
  4195 		var regexp;
       
  4196 		var modifier = (this.matchCase) ? 'g' : 'gi';
       
  4197 		var exactMatch = (forceMatch==undefined) ? this.exactMatch : forceMatch;
       
  4198 		if(exactMatch || (fltType!=this.fltTypeInp && fltType!=undefined))//Váry Péter's patch
       
  4199 			regexp = new RegExp('(^\\s*)'+tf_RegexpEscape(arg)+'(\\s*$)', modifier);							
       
  4200 		else
       
  4201 			regexp = new RegExp(tf_RegexpEscape(arg), modifier);
       
  4202 		return regexp.test(data);
       
  4203 	},
       
  4204 	
       
  4205 	IncludeFile: function(fileId, filePath, callback, type)
       
  4206 	{
       
  4207 		var ftype = (type==undefined) ? 'script' : type;
       
  4208 		var isImported = tf_isImported(filePath, ftype);
       
  4209 		if( isImported ) return;
       
  4210 		
       
  4211 		var o = this, isLoaded = false, file;			
       
  4212 		var head = tf_Tag(document,'head')[0];
       
  4213 		
       
  4214 		if(ftype.tf_LCase() == 'link')
       
  4215 			file = tf_CreateElm(
       
  4216 						'link', ['id',fileId], ['type','text/css'],
       
  4217 						['rel','stylesheet'], ['href',filePath]
       
  4218 					);
       
  4219 		else
       
  4220 			file = tf_CreateElm(
       
  4221 						'script', ['id',fileId], 
       
  4222 						['type','text/javascript'], ['src',filePath]
       
  4223 					);
       
  4224 
       
  4225 		file.onload = file.onreadystatechange = function()
       
  4226 		{
       
  4227 			if (!isLoaded && 
       
  4228 				(!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) 
       
  4229 			{
       
  4230 				isLoaded = true;
       
  4231 				if (typeof callback === 'function')
       
  4232 					callback(o);
       
  4233 			}
       
  4234 		}
       
  4235 		head.appendChild(file);
       
  4236 	},
       
  4237 	
       
  4238 	/*====================================================
       
  4239 		- Additional public methods for developers
       
  4240 	=====================================================*/
       
  4241 	
       
  4242 	HasGrid: function()
       
  4243 	/*====================================================
       
  4244 		- checks if table has a filter grid
       
  4245 		- returns a boolean
       
  4246 	=====================================================*/
       
  4247 	{
       
  4248 		return this.hasGrid;
       
  4249 	},
       
  4250 	
       
  4251 	GetFiltersId: function()
       
  4252 	/*====================================================
       
  4253 		- returns an array containing filters ids
       
  4254 		- Note that hidden filters are also returned
       
  4255 	=====================================================*/
       
  4256 	{
       
  4257 		if( !this.hasGrid ) return;
       
  4258 		return this.fltIds;
       
  4259 	},
       
  4260 	
       
  4261 	GetValidRowsIndex: function()
       
  4262 	/*====================================================
       
  4263 		- returns an array containing valid rows indexes 
       
  4264 		(valid rows upon filtering)
       
  4265 	=====================================================*/
       
  4266 	{
       
  4267 		if( !this.hasGrid ) return;
       
  4268 		return this.validRowsIndex;
       
  4269 	},
       
  4270 	
       
  4271 	GetFiltersRowIndex: function()
       
  4272 	/*====================================================
       
  4273 		- Returns the index of the row containing the 
       
  4274 		filters
       
  4275 	=====================================================*/
       
  4276 	{
       
  4277 		if( !this.hasGrid ) return;
       
  4278 		return this.filtersRowIndex;
       
  4279 	},
       
  4280 	
       
  4281 	GetHeadersRowIndex: function()
       
  4282 	/*====================================================
       
  4283 		- Returns the index of the headers row
       
  4284 	=====================================================*/
       
  4285 	{
       
  4286 		if( !this.hasGrid ) return;
       
  4287 		return this.headersRow;
       
  4288 	},
       
  4289 	
       
  4290 	GetStartRowIndex: function()
       
  4291 	/*====================================================
       
  4292 		- Returns the index of the row from which will 
       
  4293 		start the filtering process (1st filterable row)
       
  4294 	=====================================================*/
       
  4295 	{
       
  4296 		if( !this.hasGrid ) return;
       
  4297 		return this.refRow;
       
  4298 	},
       
  4299 	
       
  4300 	GetLastRowIndex: function()
       
  4301 	/*====================================================
       
  4302 		- Returns the index of the last row
       
  4303 	=====================================================*/
       
  4304 	{
       
  4305 		if( !this.hasGrid ) return;
       
  4306 		return (this.nbRows-1);
       
  4307 	},
       
  4308 	
       
  4309 	AddPaging: function(filterTable)
       
  4310 	/*====================================================
       
  4311 		- Adds paging feature if filter grid bar is 
       
  4312 		already set
       
  4313 		- Param(s):
       
  4314 			- execFilter: if true table is filtered 
       
  4315 			(boolean)
       
  4316 	=====================================================*/
       
  4317 	{
       
  4318 		if( !this.hasGrid || this.paging ) return;
       
  4319 		this.paging = true; 
       
  4320 		this.isPagingRemoved = true; 
       
  4321 		this.SetPaging();
       
  4322 		if(filterTable) this.Filter();
       
  4323 	}	
       
  4324 	
       
  4325 }
       
  4326 
       
  4327 /* --- */
       
  4328 
       
  4329 /*====================================================
       
  4330 	- General TF utility fns below
       
  4331 =====================================================*/
       
  4332 
       
  4333 function tf_GetChildElms(n)
       
  4334 /*====================================================
       
  4335 	- checks passed node is a ELEMENT_NODE nodeType=1
       
  4336 	- removes TEXT_NODE nodeType=3  
       
  4337 =====================================================*/
       
  4338 {
       
  4339 	if(n!=undefined && n.nodeType == 1)
       
  4340 	{
       
  4341 		var enfants = n.childNodes;
       
  4342 		for(var i=0; i<enfants.length; i++)
       
  4343 		{
       
  4344 			var child = enfants[i];
       
  4345 			if(child.nodeType == 3)
       
  4346 			{ 
       
  4347 				n.removeChild(child);
       
  4348 				i = -1;
       
  4349 			}
       
  4350 		}
       
  4351 		return n;	
       
  4352 	}
       
  4353 }
       
  4354 
       
  4355 function tf_GetNodeText(n)
       
  4356 /*====================================================
       
  4357 	- returns text + text of child nodes of a node
       
  4358 =====================================================*/
       
  4359 {
       
  4360 	/*if(n.innerText) return n.innerText.tf_Trim();
       
  4361 	var s = '';
       
  4362 	var enfants = n.childNodes;
       
  4363 	for(var i=0; i<enfants.length; i++)
       
  4364 	{
       
  4365 		var child = enfants[i];
       
  4366 		if(child.nodeType == 3) s+= child.data;
       
  4367 		else s+= tf_GetNodeText(child).tf_Trim();
       
  4368 	}*/
       
  4369 	var s = n.textContent || n.innerText || n.innerHTML.replace(/\<[^<>]+>/g, '');
       
  4370 	return s.replace(/^\s+/, '').replace(/\s+$/, '');
       
  4371 
       
  4372 	return s.tf_Trim();
       
  4373 }
       
  4374 
       
  4375 function tf_isObj(varname)
       
  4376 /*====================================================
       
  4377 	- checks if var exists and is an object
       
  4378 	- returns a boolean
       
  4379 =====================================================*/
       
  4380 {
       
  4381 	var isO = false;
       
  4382 	if( window[varname] && (typeof window[varname]).tf_LCase()=='object' )
       
  4383 		isO = true;
       
  4384 	return isO;
       
  4385 }
       
  4386 
       
  4387 function tf_isFn(fn)
       
  4388 /*====================================================
       
  4389 	- checks if passed param is a function
       
  4390 	- returns a boolean
       
  4391 =====================================================*/
       
  4392 {
       
  4393 	var isFn = false;
       
  4394 	if(fn && (typeof fn).tf_LCase() == 'function')
       
  4395 		isFn = true;
       
  4396 	return isFn;
       
  4397 }
       
  4398 
       
  4399 function tf_Id(id)
       
  4400 /*====================================================
       
  4401 	- this is just a getElementById shortcut
       
  4402 =====================================================*/
       
  4403 {
       
  4404 	return document.getElementById( id );
       
  4405 }
       
  4406 
       
  4407 function tf_Tag(o,tagname)
       
  4408 /*====================================================
       
  4409 	- this is just a getElementsByTagName shortcut
       
  4410 =====================================================*/
       
  4411 {
       
  4412 	return o.getElementsByTagName( tagname );
       
  4413 }
       
  4414 
       
  4415 function tf_RegexpEscape(s)
       
  4416 /*====================================================
       
  4417 	- escapes special characters [\^$.|?*+() 
       
  4418 	for regexp
       
  4419 	- Many thanks to Cedric Wartel for this fn
       
  4420 =====================================================*/
       
  4421 {
       
  4422 	// traite les caractères spéciaux [\^$.|?*+()
       
  4423 	//remplace le carctère c par \c
       
  4424 	function escape(e)
       
  4425 	{
       
  4426 		a = new RegExp('\\'+e,'g');
       
  4427 		s = s.replace(a,'\\'+e);
       
  4428 	}
       
  4429 
       
  4430 	chars = new Array('\\','[','^','$','.','|','?','*','+','(',')');
       
  4431 	//for(e in chars) escape(chars[e]); // compatibility issue with prototype
       
  4432 	for(var e=0; e<chars.length; e++) escape(chars[e]);
       
  4433 	return s;
       
  4434 }
       
  4435 
       
  4436 function tf_CreateElm(tag)
       
  4437 /*====================================================
       
  4438 	- creates an html element with its attributes
       
  4439 	- accepts the following params:
       
  4440 		- a string defining the html tag
       
  4441 		to create
       
  4442 		- an undetermined # of arrays containing the
       
  4443 		couple 'attribute name','value' ['id','myId']
       
  4444 =====================================================*/
       
  4445 {
       
  4446 	if(tag==undefined || tag==null || tag=='') return;
       
  4447 	var el = document.createElement( tag );		
       
  4448 	if(arguments.length>1)
       
  4449 	{
       
  4450 		for(var i=0; i<arguments.length; i++)
       
  4451 		{
       
  4452 			var argtype = typeof arguments[i];
       
  4453 			switch( argtype.tf_LCase() )
       
  4454 			{
       
  4455 				case 'object':
       
  4456 					if( arguments[i].length==2 )
       
  4457 					{						
       
  4458 						el.setAttribute( arguments[i][0],arguments[i][1] );
       
  4459 					}//if array length==2
       
  4460 				break;
       
  4461 			}//switch
       
  4462 		}//for i
       
  4463 	}//if args
       
  4464 	return el;	
       
  4465 }
       
  4466 
       
  4467 function tf_CreateText(node)
       
  4468 /*====================================================
       
  4469 	- this is just a document.createTextNode shortcut
       
  4470 =====================================================*/
       
  4471 {
       
  4472 	return document.createTextNode( node );
       
  4473 }
       
  4474 
       
  4475 function tf_CreateOpt(text,value,isSel)
       
  4476 /*====================================================
       
  4477 	- creates an option element and returns it:
       
  4478 		- text: displayed text (string)
       
  4479 		- value: option value (string)
       
  4480 		- isSel: is selected option (boolean)
       
  4481 =====================================================*/
       
  4482 {
       
  4483 	var isSelected = isSel ? true : false;
       
  4484 	var opt = (isSelected) 
       
  4485 		? tf_CreateElm('option',['value',value],['selected','true'])
       
  4486 		: tf_CreateElm('option',['value',value]);
       
  4487 	opt.appendChild(tf_CreateText(text));
       
  4488 	return opt;
       
  4489 }
       
  4490 
       
  4491 function tf_CreateCheckItem(chkIndex, chkValue, labelText)
       
  4492 /*====================================================
       
  4493 	- creates an checklist item and returns it
       
  4494 	- accepts the following params:
       
  4495 		- chkIndex: index of check item (number)
       
  4496 		- chkValue: check item value (string)
       
  4497 		- labelText: check item label text (string)
       
  4498 =====================================================*/
       
  4499 {
       
  4500 	if(chkIndex==undefined || chkValue==undefined || labelText==undefined )
       
  4501 		return;
       
  4502 	var li = tf_CreateElm('li');
       
  4503 	var label = tf_CreateElm('label',['for',chkIndex]);
       
  4504 	var check = tf_CreateElm( 'input',
       
  4505 					['id',chkIndex],
       
  4506 					['name',chkIndex],
       
  4507 					['type','checkbox'],
       
  4508 					['value',chkValue] );
       
  4509 	label.appendChild(check);
       
  4510 	label.appendChild(tf_CreateText(labelText));
       
  4511 	li.appendChild(label);
       
  4512 	li.label = label;
       
  4513 	li.check = check;
       
  4514 	return li;
       
  4515 }
       
  4516 
       
  4517 function tf_HighlightWord( node,word,cssClass )
       
  4518 /*====================================================
       
  4519 	- highlights keyword found in passed node
       
  4520 	- accepts the following params:
       
  4521 		- node
       
  4522 		- word to search
       
  4523 		- css class name for highlighting
       
  4524 =====================================================*/
       
  4525 {
       
  4526 	// Iterate into this nodes childNodes
       
  4527 	if(node.hasChildNodes) 
       
  4528 		for( var i=0; i<node.childNodes.length; i++ )
       
  4529 			tf_HighlightWord(node.childNodes[i],word,cssClass);
       
  4530 
       
  4531 	// And do this node itself
       
  4532 	if(node.nodeType == 3) 
       
  4533 	{ // text node
       
  4534 		var tempNodeVal = node.nodeValue.tf_LCase();
       
  4535 		var tempWordVal = word.tf_LCase();
       
  4536 		if(tempNodeVal.indexOf(tempWordVal) != -1) 
       
  4537 		{
       
  4538 			var pn = node.parentNode;
       
  4539 			if(pn.className != cssClass) 
       
  4540 			{
       
  4541 				// word has not already been highlighted!
       
  4542 				var nv = node.nodeValue;
       
  4543 				var ni = tempNodeVal.indexOf(tempWordVal);
       
  4544 				// Create a load of replacement nodes
       
  4545 				var before = tf_CreateText(nv.substr(0,ni));
       
  4546 				var docWordVal = nv.substr(ni,word.length);
       
  4547 				var after = tf_CreateText(nv.substr(ni+word.length));
       
  4548 				var hiwordtext = tf_CreateText(docWordVal);
       
  4549 				var hiword = tf_CreateElm('span');
       
  4550 				hiword.className = cssClass;
       
  4551 				hiword.appendChild(hiwordtext);
       
  4552 				pn.insertBefore(before,node);
       
  4553 				pn.insertBefore(hiword,node);
       
  4554 				pn.insertBefore(after,node);
       
  4555 				pn.removeChild(node);
       
  4556 			}
       
  4557 		}
       
  4558 	}// if node.nodeType == 3
       
  4559 }
       
  4560 
       
  4561 function tf_UnhighlightWord( node,word,cssClass )
       
  4562 /*====================================================
       
  4563 	- removes highlights found in passed node
       
  4564 	- accepts the following params:
       
  4565 		- node
       
  4566 		- word to search
       
  4567 		- css class name for highlighting
       
  4568 =====================================================*/
       
  4569 {
       
  4570 	// Iterate into this nodes childNodes
       
  4571 	if(node.hasChildNodes)
       
  4572 		for( var i=0; i<node.childNodes.length; i++ )
       
  4573 			tf_UnhighlightWord(node.childNodes[i],word,cssClass);
       
  4574 
       
  4575 	// And do this node itself
       
  4576 	if(node.nodeType == 3) 
       
  4577 	{ // text node
       
  4578 		var tempNodeVal = node.nodeValue.tf_LCase();
       
  4579 		var tempWordVal = word.tf_LCase();
       
  4580 		if(tempNodeVal.indexOf(tempWordVal) != -1)
       
  4581 		{
       
  4582 			var pn = node.parentNode;
       
  4583 			if(pn.className == cssClass)
       
  4584 			{
       
  4585 				var prevSib = pn.previousSibling;
       
  4586 				var nextSib = pn.nextSibling;
       
  4587 				nextSib.nodeValue = prevSib.nodeValue + node.nodeValue + nextSib.nodeValue;
       
  4588 				prevSib.nodeValue = '';
       
  4589 				node.nodeValue = '';
       
  4590 			}
       
  4591 		}
       
  4592 	}// if node.nodeType == 3
       
  4593 }
       
  4594 
       
  4595 function tf_addEvent(obj,event_name,func_name)
       
  4596 {
       
  4597 	if (obj.attachEvent)
       
  4598 		obj.attachEvent('on'+event_name, func_name);
       
  4599 	else if(obj.addEventListener)
       
  4600 		obj.addEventListener(event_name,func_name,true);
       
  4601 	else
       
  4602 		obj['on'+event_name] = func_name;
       
  4603 }
       
  4604 
       
  4605 function tf_removeEvent(obj,event_name,func_name)
       
  4606 {
       
  4607 	if (obj.detachEvent)
       
  4608 		obj.detachEvent('on'+event_name,func_name);
       
  4609 	else if(obj.removeEventListener)
       
  4610 		obj.removeEventListener(event_name,func_name,true);
       
  4611 	else
       
  4612 		obj['on'+event_name] = null;
       
  4613 }
       
  4614 
       
  4615 function tf_NumSortAsc(a, b){ return (a-b); }
       
  4616 
       
  4617 function tf_NumSortDesc(a, b){ return (b-a); }
       
  4618 
       
  4619 function tf_IgnoreCaseSort(a, b) {
       
  4620 	var x = a.tf_LCase();
       
  4621 	var y = b.tf_LCase();
       
  4622 	return ((x < y) ? -1 : ((x > y) ? 1 : 0));
       
  4623 }
       
  4624 
       
  4625 String.prototype.tf_MatchCase = function (mc) 
       
  4626 {
       
  4627 	if (!mc) return this.tf_LCase();
       
  4628 	else return this.toString();
       
  4629 }
       
  4630 
       
  4631 String.prototype.tf_Trim = function()
       
  4632 {//optimised by Anthony Maes
       
  4633 	return this.replace(/(^[\s\xA0]*)|([\s\xA0]*$)/g,'');
       
  4634 }
       
  4635 
       
  4636 String.prototype.tf_LCase = function()
       
  4637 {
       
  4638 	return this.toLowerCase();
       
  4639 }
       
  4640 
       
  4641 String.prototype.tf_UCase = function()
       
  4642 {
       
  4643 	return this.toUpperCase();
       
  4644 }
       
  4645 
       
  4646 Array.prototype.tf_Has = function(s,mc) 
       
  4647 {
       
  4648 	//return this.indexOf(s) >= 0;
       
  4649 	var sCase = (mc==undefined) ? false : mc;
       
  4650 	for (i=0; i<this.length; i++)
       
  4651 		if (this[i].toString().tf_MatchCase(sCase)==s) return true;
       
  4652 	return false;
       
  4653 }
       
  4654 
       
  4655 Array.prototype.tf_IndexByValue = function(s,mc) 
       
  4656 {
       
  4657 	var sCase = (mc==undefined) ? false : mc;
       
  4658 	for (i=0; i<this.length; i++)
       
  4659 		if (this[i].toString().tf_MatchCase(sCase)==s) return i;
       
  4660 	return (-1);
       
  4661 }
       
  4662 
       
  4663 // Is this IE 6? the ultimate browser sniffer ;-)
       
  4664 //window['tf_isIE'] = (window.innerHeight) ? false : true;
       
  4665 window['tf_isIE'] = (window.innerHeight) ? false : /msie|MSIE 6/.test(navigator.userAgent) ? true : false;
       
  4666 window['tf_isIE7'] = (window.innerHeight) ? false : /msie|MSIE 7/.test(navigator.userAgent) ? true : false;
       
  4667 
       
  4668 function tf_hasClass(elm,cl) 
       
  4669 {
       
  4670 	return elm.className.match(new RegExp('(\\s|^)'+cl+'(\\s|$)'));
       
  4671 }
       
  4672 
       
  4673 function tf_addClass(elm,cl) 
       
  4674 {
       
  4675 	if (!tf_hasClass(elm,cl))
       
  4676 		elm.className += ' '+cl;
       
  4677 }
       
  4678 
       
  4679 function tf_removeClass(elm,cl) 
       
  4680 {
       
  4681 	if ( !tf_hasClass(elm,cl) ) return;
       
  4682 	var reg = new RegExp('(\\s|^)'+cl+'(\\s|$)');
       
  4683 	elm.className = elm.className.replace(reg,' ');
       
  4684 }
       
  4685 
       
  4686 function tf_isValidDate(dateStr, format) 
       
  4687 {
       
  4688 	if (format == null) { format = 'DMY'; }
       
  4689 	format = format.toUpperCase();
       
  4690 	if (format.length != 3) { format = 'DMY'; }
       
  4691 	if ( (format.indexOf('M') == -1) || (format.indexOf('D') == -1) ||
       
  4692 		(format.indexOf('Y') == -1) ) { format = 'DMY'; }
       
  4693 	if (format.substring(0, 1) == 'Y') { // If the year is first
       
  4694 		  var reg1 = /^\d{2}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
       
  4695 		  var reg2 = /^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$/;
       
  4696 	} else if (format.substring(1, 2) == 'Y') { // If the year is second
       
  4697 		  var reg1 = /^\d{1,2}(\-|\/|\.)\d{2}\1\d{1,2}$/;
       
  4698 		  var reg2 = /^\d{1,2}(\-|\/|\.)\d{4}\1\d{1,2}$/;
       
  4699 	} else { // The year must be third
       
  4700 		  var reg1 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{2}$/;
       
  4701 		  var reg2 = /^\d{1,2}(\-|\/|\.)\d{1,2}\1\d{4}$/;
       
  4702 	}
       
  4703 	// If it doesn't conform to the right format (with either a 2 digit year or 4 digit year), fail
       
  4704 	if ( (reg1.test(dateStr) == false) && (reg2.test(dateStr) == false) ) { return false; }
       
  4705 	var parts = dateStr.split(RegExp.$1); // Split into 3 parts based on what the divider was
       
  4706 	// Check to see if the 3 parts end up making a valid date
       
  4707 	if (format.substring(0, 1) == 'M') { var mm = parts[0]; } else
       
  4708 		if (format.substring(1, 2) == 'M') { var mm = parts[1]; } else { var mm = parts[2]; }
       
  4709 	if (format.substring(0, 1) == 'D') { var dd = parts[0]; } else
       
  4710 		if (format.substring(1, 2) == 'D') { var dd = parts[1]; } else { var dd = parts[2]; }
       
  4711 	if (format.substring(0, 1) == 'Y') { var yy = parts[0]; } else
       
  4712 		if (format.substring(1, 2) == 'Y') { var yy = parts[1]; } else { var yy = parts[2]; }
       
  4713 	if (parseFloat(yy) <= 50) { yy = (parseFloat(yy) + 2000).toString(); }
       
  4714 	if (parseFloat(yy) <= 99) { yy = (parseFloat(yy) + 1900).toString(); }
       
  4715 	var dt = new Date(parseFloat(yy), parseFloat(mm)-1, parseFloat(dd), 0, 0, 0, 0);
       
  4716 	if (parseFloat(dd) != dt.getDate()) { return false; }
       
  4717 	if (parseFloat(mm)-1 != dt.getMonth()) { return false; }
       
  4718 	return true;
       
  4719 }
       
  4720 
       
  4721 function tf_formatDate(dateStr, format)
       
  4722 {
       
  4723 	if(format==null) format = 'DMY';
       
  4724 	var oDate, parts;
       
  4725 	
       
  4726 	function y2kDate(yr){
       
  4727 		if(yr == undefined) return 0;
       
  4728 		if(yr.length>2) return yr;
       
  4729 		var y;
       
  4730 		if(yr <= 99 && yr>50) //>50 belong to 1900
       
  4731 			y = '19' + yr;
       
  4732 		if(yr<50 || yr =='00') //<50 belong to 2000
       
  4733 			y = '20' + yr;
       
  4734 		return y;
       
  4735 	}
       
  4736 	
       
  4737 	switch(format.toUpperCase())
       
  4738 	{
       
  4739 		case 'DMY':
       
  4740 			parts = dateStr.replace(/^(0?[1-9]|[12][0-9]|3[01])([- \/.])(0?[1-9]|1[012])([- \/.])((\d\d)?\d\d)$/,'$1 $3 $5').split(' ');
       
  4741 			oDate = new Date(y2kDate(parts[2]),parts[1]-1,parts[0]);
       
  4742 		break;
       
  4743 		case 'MDY':
       
  4744 			parts = dateStr.replace(/^(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])([- \/.])((\d\d)?\d\d)$/,'$1 $3 $5').split(' ');
       
  4745 			oDate = new Date(y2kDate(parts[2]),parts[0]-1,parts[1]);
       
  4746 		break;
       
  4747 		case 'YMD':
       
  4748 			parts = dateStr.replace(/^((\d\d)?\d\d)([- \/.])(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])$/,'$1 $4 $6').split(' ');
       
  4749 			oDate = new Date(y2kDate(parts[0]),parts[1]-1,parts[2]);
       
  4750 		break;
       
  4751 		default: //in case format is not correct
       
  4752 			parts = dateStr.replace(/^(0?[1-9]|[12][0-9]|3[01])([- \/.])(0?[1-9]|1[012])([- \/.])((\d\d)?\d\d)$/,'$1 $3 $5').split(' ');
       
  4753 			oDate = new Date(y2kDate(parts[2]),parts[1]-1,parts[0]);
       
  4754 		break;
       
  4755 	}
       
  4756 	return oDate;
       
  4757 }
       
  4758 
       
  4759 function tf_removeNbFormat(data,format)
       
  4760 {
       
  4761 	if(data==null) return;
       
  4762 	if(format==null) format = 'us';
       
  4763 	var n = data;
       
  4764 	if( format.tf_LCase()=='us' )
       
  4765 		n =+ n.replace(/[^\d\.-]/g,'');
       
  4766 	else
       
  4767 		n =+ n.replace(/[^\d\,-]/g,'').replace(',','.');
       
  4768 	return n;
       
  4769 }
       
  4770 
       
  4771 function tf_isImported(filePath,type)
       
  4772 {
       
  4773 	var isImported = false; 
       
  4774 	var importType = (type==undefined) ? 'script' : type;
       
  4775 	var files = tf_Tag(document,importType);
       
  4776 	for (var i=0; i<files.length; i++)
       
  4777 	{
       
  4778 		if(files[i].src == undefined) continue;
       
  4779 		if(files[i].src.match(filePath))
       
  4780 		{
       
  4781 			isImported = true;	
       
  4782 			break;
       
  4783 		}
       
  4784 	}
       
  4785 	return isImported;
       
  4786 }
       
  4787 
       
  4788 function tf_WriteCookie(name, value, hours)
       
  4789 {
       
  4790 	var expire = '';
       
  4791 	if(hours != null)
       
  4792 	{
       
  4793 		expire = new Date((new Date()).getTime() + hours * 3600000);
       
  4794 		expire = '; expires=' + expire.toGMTString();
       
  4795 	}
       
  4796 	document.cookie = name + '=' + escape(value) + expire;
       
  4797 }
       
  4798 
       
  4799 function tf_ReadCookie(name)
       
  4800 {
       
  4801 	var cookieValue = '';
       
  4802 	var search = name + '=';
       
  4803 	if(document.cookie.length > 0)
       
  4804 	{ 
       
  4805 		offset = document.cookie.indexOf(search);
       
  4806 		if (offset != -1)
       
  4807 		{ 
       
  4808 			offset += search.length;
       
  4809 			end = document.cookie.indexOf(';', offset);
       
  4810 			if (end == -1) end = document.cookie.length;
       
  4811 			cookieValue = unescape(document.cookie.substring(offset, end))
       
  4812 		}
       
  4813 	}
       
  4814 	return cookieValue;
       
  4815 }
       
  4816 
       
  4817 function tf_CookieValueArray(name)
       
  4818 {
       
  4819 	var val = tf_ReadCookie(name); //reads the cookie
       
  4820 	var arr = val.split(','); //creates an array with filters' values
       
  4821 	return arr;
       
  4822 }
       
  4823 
       
  4824 function tf_CookieValueByIndex(name, index)
       
  4825 {
       
  4826 	var val = tf_CookieValueArray(name); //reads the cookie
       
  4827 	return val[index];
       
  4828 }
       
  4829 
       
  4830 function tf_RemoveCookie(name)
       
  4831 {
       
  4832 	tf_WriteCookie(name,'',-1);
       
  4833 }
       
  4834 /* --- */
       
  4835 
       
  4836 /*====================================================
       
  4837 	- Backward compatibility fns
       
  4838 =====================================================*/
       
  4839 function grabEBI(id){ return tf_Id( id ); }
       
  4840 function grabTag(obj,tagname){ return tf_Tag(obj,tagname); }
       
  4841 function tf_GetCellText(n){ return tf_GetNodeText(n); }
       
  4842 function tf_isObject(varname){ return tf_isObj(varname); }
       
  4843 /* --- */