diff --git a/Gruntfile.js b/Gruntfile.js index bcec89aa..874f454a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -236,7 +236,7 @@ module.exports = function (grunt) { grunt.registerTask('default', ['jshint', 'toes5', 'requirejs', 'concat', 'uglify', 'cssmin', 'copy', 'qunit']); grunt.registerTask('build', ['jshint', 'toes5', 'requirejs', 'concat', /*'uglify',*/ 'cssmin', 'copy']); grunt.registerTask('dev', ['jshint', 'toes5', 'concat', 'cssmin', 'copy']); - grunt.registerTask('build-requirejs', ['requirejs:compile-main', 'requirejs:compile-main']); + grunt.registerTask('build-requirejs', ['requirejs:compile-main']); grunt.registerTask('toes5', ['babel:build-main','babel:build-extensions']); grunt.registerTask('test', ['qunit']); }; diff --git a/dist/_core_.js b/dist/_core_.js new file mode 100644 index 00000000..a6b9667a --- /dev/null +++ b/dist/_core_.js @@ -0,0 +1,3590 @@ + /*------------------------------------------------------------------------ + - HTML Table Filter Generator v3.0 + - By Max Guglielmi (tablefilter.free.fr) + - Licensed under the MIT License +--------------------------------------------------------------------------- + - Special credit to: + Cedric Wartel, cnx.claude@free.fr, Florent Hirchy, Váry Péter, + Anthony Maes, Nuovella Williams, Fuggerbit, Venkata Seshagiri Rao + Raya, Piepiax, Manuel Kern, Baladhandayutham for active contribution + and/or inspiration +------------------------------------------------------------------------ */ +define(function (require) { + +var global = this, + evt = require('event').Event, + dom = require('dom').Dom, + str = require('string').Str, + cookie = require('cookie').Cookie, + types = require('types').Types, + array = require('array').Arr, + hlp = require('helpers').Helpers, + dateHelper = require('date').DateHelper, + isValidDate = dateHelper.isValid, + formatDate = dateHelper.format, + Sort = require('sort').Sort, + doc = global.document; + +/** + * TF object constructor + * @param {String} id Table id + * @param {Number} row index indicating the 1st row + * @param {Object} configuration object + */ +function TableFilter(id) { + if(arguments.length === 0){ return; } + + this.id = id; + this.version = '3.0'; + this.year = new Date().getFullYear(); + this.tbl = dom.id(id); + this.startRow = null; + this.refRow = null; + this.headersRow = null; + this.cfg = {}; + this.nbFilterableRows = null; + this.nbRows = null; + this.nbCells = null; + this._hasGrid = false; + this.enableModules = false; + + if(!this.tbl || str.lower(this.tbl.nodeName) !== 'table' || + this.getRowsNb() === 0){ + throw new Error( + 'Could not instantiate TF object: HTML table not found.'); + } + + if(arguments.length>1){ + for(var i=0; i 1){ + this.filtersRowIndex = this.headersRow+1; + } else { + this.filtersRowIndex = 1; + this.headersRow = 0; + } + } + + //defines tag of the cells containing filters (td/th) + this.fltCellTag = f.filters_cell_tag!=='th' || + f.filters_cell_tag!=='td' ? 'td' : f.filters_cell_tag; + + //stores filters ids + this.fltIds = []; + //stores filters DOM elements + this.fltElms = []; + //stores filters values + this.searchArgs = null; + //stores table data + this.tblData = []; + //stores valid rows indexes (rows visible upon filtering) + this.validRowsIndex = null; + //stores filters row element + this.fltGridEl = null; + //is first load boolean + this.isFirstLoad = true; + //container div for paging elements, reset btn etc. + this.infDiv = null; + //div for rows counter + this.lDiv = null; + //div for reset button and results per page select + this.rDiv = null; + //div for paging elements + this.mDiv = null; + //table container div for fixed headers (IE only) + this.contDiv = null; + + //defines css class for div containing paging elements, rows counter etc. + this.infDivCssClass = f.inf_div_css_class || 'inf'; + //defines css class for left div + this.lDivCssClass = f.left_div_css_class || 'ldiv'; + //defines css class for right div + this.rDivCssClass = f.right_div_css_class || 'rdiv'; + //defines css class for mid div + this.mDivCssClass = f.middle_div_css_class || 'mdiv'; + //table container div css class + this.contDivCssClass = f.content_div_css_class || 'cont'; + + /*** filters' grid appearance ***/ + //stylesheet file + this.stylesheet = f.stylesheet || this.basePath+'filtergrid.css'; + this.stylesheetId = this.id + '_style'; + //defines css class for filters row + this.fltsRowCssClass = f.flts_row_css_class || 'fltrow'; + //enables/disables icons (paging, reset button) + this.enableIcons = f.enable_icons===false ? false : true; + //enables/disbles rows alternating bg colors + this.alternateBgs = f.alternate_rows===true ? true : false; + //defines widths of columns + this.hasColWidth = f.col_width===true ? true : false; + this.colWidth = this.hasColWidth ? f.col_width : null; + //enables/disables fixed headers + this.fixedHeaders = f.fixed_headers===true ? true : false; + //tbody height if fixed headers enabled + this.tBodyH = !isNaN(f.tbody_height) ? f.tbody_height : 200; + //defines css class for filters + this.fltCssClass = f.flt_css_class || 'flt'; + //defines css class for multiple selects filters + this.fltMultiCssClass = f.flt_multi_css_class || 'flt_multi'; + //defines css class for filters + this.fltSmallCssClass = f.flt_small_css_class || 'flt_s'; + //defines css class for single-filter + this.singleFltCssClass = f.single_flt_css_class || 'single_flt'; + this.isStartBgAlternate = true; + + /*** filters' grid behaviours ***/ + //enables/disables enter key + this.enterKey = f.enter_key===false ? false : true; + //enables/disables alternative fn call + this.isModFilterFn = f.mod_filter_fn===true ? true : false; + // used by tf_DetectKey fn + this.modFilterFn = this.isModFilterFn ? f.mod_filter_fn : null; + //calls function before filtering starts + this.onBeforeFilter = types.isFn(f.on_before_filter) ? + f.on_before_filter : null; + //calls function after filtering + this.onAfterFilter = types.isFn(f.on_after_filter) ? + f.on_after_filter : null; + //enables/disables case sensitivity + this.matchCase = f.match_case===true ? true : false; + //enables/disbles exact match for search + this.exactMatch = f.exact_match===true ? true : false; + //refreshes drop-down lists upon validation + this.linkedFilters = f.linked_filters===true ? true : false; + //wheter excluded options are disabled + this.disableExcludedOptions = f.disable_excluded_options===true ? + true : false; + //stores active filter element + this.activeFlt = null; + //id of active filter + this.activeFilterId = null; + //enables/disbles column operation(sum,mean) + this.hasColOperation = f.col_operation ? true : false; + this.colOperation = null; + //enables always visible rows + this.hasVisibleRows = f.rows_always_visible ? true : false; + //array containing always visible rows + this.visibleRows = this.hasVisibleRows ? f.rows_always_visible : []; + //defines search type: include or exclude + this.searchType = f.search_type || 'include'; + //enables/disables external filters generation + this.isExternalFlt = f.external_flt_grid===true ? true : false; + //array containing ids of external elements containing filters + this.externalFltTgtIds = f.external_flt_grid_ids || null; + //stores filters elements if isExternalFlt is true + this.externalFltEls = []; + //delays any filtering process if loader true + this.execDelay = !isNaN(f.exec_delay) ? parseInt(f.exec_delay,10) : 100; + //calls function when filters grid loaded + this.onFiltersLoaded = types.isFn(f.on_filters_loaded) ? + f.on_filters_loaded : null; + //enables/disables single filter search + this.singleSearchFlt = f.single_search_filter===true ? true : false; + //calls function after row is validated + this.onRowValidated = types.isFn(f.on_row_validated) ? + f.on_row_validated : null; + //array defining columns for customCellData event + this.customCellDataCols = f.custom_cell_data_cols ? + f.custom_cell_data_cols : []; + //calls custom function for retrieving cell data + this.customCellData = types.isFn(f.custom_cell_data) ? + f.custom_cell_data : null; + //input watermark text array + this.watermark = f.watermark || ''; + this.isWatermarkArray = types.isArray(this.watermark); + //id of toolbar container element + this.toolBarTgtId = f.toolbar_target_id || null; + //enables/disables help div + this.helpInstructions = f.help_instructions || false; + //popup filters + this.popUpFilters = f.popup_filters===true ? true : false; + //active columns color + this.markActiveColumns = f.mark_active_columns===true ? true : false; + //defines css class for active column header + this.activeColumnsCssClass = f.active_columns_css_class || + 'activeHeader'; + //calls function before active column header is marked + this.onBeforeActiveColumn = types.isFn(f.on_before_active_column) ? + f.on_before_active_column : null; + //calls function after active column header is marked + this.onAfterActiveColumn = types.isFn(f.on_after_active_column) ? + f.on_after_active_column : null; + + /*** select filter's customisation and behaviours ***/ + //defines 1st option text + this.displayAllText = f.display_all_text || ''; + //enables/disables empty option in combo-box filters + this.enableEmptyOption = f.enable_empty_option===true ? true : false; + //defines empty option text + this.emptyText = f.empty_text || '(Empty)'; + //enables/disables non empty option in combo-box filters + this.enableNonEmptyOption = f.enable_non_empty_option===true ? + true : false; + //defines empty option text + this.nonEmptyText = f.non_empty_text || '(Non empty)'; + //enables/disables onChange event on combo-box + this.onSlcChange = f.on_change===false ? false : true; + //enables/disables select options sorting + this.sortSlc = f.sort_select===false ? false : true; + //enables/disables ascending numeric options sorting + this.isSortNumAsc = f.sort_num_asc===true ? true : false; + this.sortNumAsc = this.isSortNumAsc ? f.sort_num_asc : null; + //enables/disables descending numeric options sorting + this.isSortNumDesc = f.sort_num_desc===true ? true : false; + this.sortNumDesc = this.isSortNumDesc ? f.sort_num_desc : null; + //enabled selects are populated on demand + this.fillSlcOnDemand = f.fill_slc_on_demand===true ? true : false; + this.hasCustomSlcOptions = types.isObj(f.custom_slc_options) ? + true : false; + this.customSlcOptions = types.isArray(f.custom_slc_options) ? + f.custom_slc_options : null; + + /*** Filter operators ***/ + this.rgxOperator = f.regexp_operator || 'rgx:'; + this.emOperator = f.empty_operator || '[empty]'; + this.nmOperator = f.nonempty_operator || '[nonempty]'; + this.orOperator = f.or_operator || '||'; + this.anOperator = f.and_operator || '&&'; + this.grOperator = f.greater_operator || '>'; + this.lwOperator = f.lower_operator || '<'; + this.leOperator = f.lower_equal_operator || '<='; + this.geOperator = f.greater_equal_operator || '>='; + this.dfOperator = f.different_operator || '!'; + this.lkOperator = f.like_operator || '*'; + this.eqOperator = f.equal_operator || '='; + this.stOperator = f.start_with_operator || '{'; + this.enOperator = f.end_with_operator || '}'; + this.curExp = f.cur_exp || '^[¥£€$]'; + this.separator = f.separator || ','; + + /*** rows counter ***/ + //show/hides rows counter + this.rowsCounter = f.rows_counter===true ? true : false; + + /*** status bar ***/ + //show/hides status bar + this.statusBar = f.status_bar===true ? true : false; + + /*** loader ***/ + //enables/disables loader/spinner indicator + this.loader = f.loader===true ? true : false; + + /*** validation - reset buttons/links ***/ + //show/hides filter's validation button + this.displayBtn = f.btn===true ? true : false; + //defines validation button text + this.btnText = f.btn_text || (!this.enableIcons ? 'Go' : ''); + //defines css class for validation button + this.btnCssClass = f.btn_css_class || + (!this.enableIcons ? 'btnflt' : 'btnflt_icon'); + //show/hides reset link + this.btnReset = f.btn_reset===true ? true : false; + //defines css class for reset button + this.btnResetCssClass = f.btn_reset_css_class || 'reset'; + //callback function before filters are cleared + this.onBeforeReset = types.isFn(f.on_before_reset) ? + f.on_before_reset : null; + //callback function after filters are cleared + this.onAfterReset = types.isFn(f.on_after_reset) ? + f.on_after_reset : null; + + /*** paging ***/ + //enables/disables table paging + this.paging = f.paging===true ? true : false; + this.nbVisibleRows = 0; //nb visible rows + this.nbHiddenRows = 0; //nb hidden rows + + /*** webfx sort adapter ***/ + //enables/disables default table sorting + this.sort = f.sort===true ? true : false; + //indicates if sort is set (used in tfAdapter.sortabletable.js) + this.isSortEnabled = false; + //indicates if tables was sorted + this.sorted = false; + this.sortConfig = f.sort_config || {}; + this.sortConfig.name = this.sortConfig['name']!==undefined ? + f.sort_config.name : 'sortabletable'; + this.sortConfig.src = this.sortConfig['src']!==undefined ? + f.sort_config.src : this.basePath+'sortabletable.js'; + this.sortConfig.adapterSrc = + this.sortConfig['adapter_src']!==undefined ? + f.sort_config.adapter_src : + this.basePath+'tfAdapter.sortabletable.js'; + this.sortConfig.initialize = + this.sortConfig['initialize']!==undefined ? + f.sort_config.initialize : + function(o){ + if(o.SetSortTable){ o.SetSortTable(); } + }; + this.sortConfig.sortTypes = + types.isArray(this.sortConfig['sort_types']) ? + f.sort_config.sort_types : []; + this.sortConfig.sortCol = this.sortConfig['sort_col']!==undefined ? + f.sort_config.sort_col : null; + this.sortConfig.asyncSort = + this.sortConfig['async_sort']===true ? true : false; + this.sortConfig.triggerIds = + types.isArray(this.sortConfig['sort_trigger_ids']) ? + f.sort_config.sort_trigger_ids : []; + + /*** ezEditTable extension ***/ + //enables/disables table selection feature + this.selectable = f.selectable===true ? true : false; + //enables/disables editable table feature + this.editable = f.editable===true ? true : false; + this.ezEditTableConfig = f.ezEditTable_config || {}; + this.ezEditTableConfig.name = + this.ezEditTableConfig['name']!==undefined ? + f.ezEditTable_config.name : 'ezedittable'; + this.ezEditTableConfig.src = this.ezEditTableConfig['src']!==undefined ? + f.ezEditTable_config.src : + this.basePath+'ezEditTable/ezEditTable.js'; + //ezEditTable stylesheet not imported by default as filtergrid.css + //applies + this.ezEditTableConfig.loadStylesheet = + this.ezEditTableConfig['loadStylesheet']===true ? true : false; + this.ezEditTableConfig.stylesheet = + this.ezEditTableConfig['stylesheet'] || + this.basePath+'ezEditTable/ezEditTable.css'; + this.ezEditTableConfig.stylesheetName = + this.ezEditTableConfig['stylesheetName']!==undefined ? + f.ezEditTable_config.stylesheetName : 'ezEditTableCss'; + this.ezEditTableConfig.err = 'Failed to instantiate EditTable ' + + 'object.\n"ezEditTable" module may not be available.'; + + /*** onkeyup event ***/ + //enables/disables onkeyup event, table is filtered when user stops + //typing + this.onKeyUp = f.on_keyup===true ? true : false; + //onkeyup delay timer (msecs) + this.onKeyUpDelay = !isNaN(f.on_keyup_delay) ? + f.on_keyup_delay : 900; + this.isUserTyping = null; //typing indicator + this.onKeyUpTimer = undefined; + + /*** keyword highlighting ***/ + //enables/disables keyword highlighting + this.highlightKeywords = f.highlight_keywords===true ? true : false; + + /*** data types ***/ + //defines default date type (european DMY) + this.defaultDateType = f.default_date_type || 'DMY'; + //defines default thousands separator + //US = ',' EU = '.' + this.thousandsSeparator = f.thousands_separator || ','; + //defines default decimal separator + //US & javascript = '.' EU = ',' + this.decimalSeparator = f.decimal_separator || '.'; + //enables number format per column + this.hasColNbFormat = f.col_number_format===true ? true : false; + //array containing columns nb formats + this.colNbFormat = types.isArray(this.hasColNbFormat) ? + f.col_number_format : null; + //enables date type per column + this.hasColDateType = f.col_date_type===true ? true : false; + //array containing columns date type + this.colDateType = types.isArray(this.hasColDateType) ? + f.col_date_type : null; + + /*** status messages ***/ + //filtering + this.msgFilter = f.msg_filter || 'Filtering data...'; + //populating drop-downs + this.msgPopulate = f.msg_populate || 'Populating filter...'; + //populating drop-downs + this.msgPopulateCheckList = f.msg_populate_checklist || + 'Populating list...'; + //changing paging page + this.msgChangePage = f.msg_change_page || 'Collecting paging data...'; + //clearing filters + this.msgClear = f.msg_clear || 'Clearing filters...'; + //changing nb results/page + this.msgChangeResults = f.msg_change_results || + 'Changing results per page...'; + //re-setting grid values + this.msgResetValues = f.msg_reset_grid_values || + 'Re-setting filters values...'; + //re-setting page + this.msgResetPage = f.msg_reset_page || 'Re-setting page...'; + //re-setting page length + this.msgResetPageLength = f.msg_reset_page_length || + 'Re-setting page length...'; + //table sorting + this.msgSort = f.msg_sort || 'Sorting data...'; + //extensions loading + this.msgLoadExtensions = f.msg_load_extensions || + 'Loading extensions...'; + //themes loading + this.msgLoadThemes = f.msg_load_themes || 'Loading theme(s)...'; + + /*** ids prefixes ***/ + //css class name added to table + this.prfxTf = 'TF'; + //filters (inputs - selects) + this.prfxFlt = 'flt'; + //validation button + this.prfxValButton = 'btn'; + //container div for paging elements, rows counter etc. + this.prfxInfDiv = 'inf_'; + //left div + this.prfxLDiv = 'ldiv_'; + //right div + this.prfxRDiv = 'rdiv_'; + //middle div + this.prfxMDiv = 'mdiv_'; + //table container if fixed headers enabled + this.prfxContentDiv = 'cont_'; + //checklist filter container div + this.prfxCheckListDiv = 'chkdiv_'; + //pages select + this.prfxSlcPages = 'slcPages_'; + //results per page select + this.prfxSlcResults = 'slcResults_'; + //label preciding results per page select + this.prfxSlcResultsTxt = 'slcResultsTxt_'; + //span containing next page button + this.prfxBtnNextSpan = 'btnNextSpan_'; + //span containing previous page button + this.prfxBtnPrevSpan = 'btnPrevSpan_'; + //span containing last page button + this.prfxBtnLastSpan = 'btnLastSpan_'; + //span containing first page button + this.prfxBtnFirstSpan = 'btnFirstSpan_'; + //next button + this.prfxBtnNext = 'btnNext_'; + //previous button + this.prfxBtnPrev = 'btnPrev_'; + //last button + this.prfxBtnLast = 'btnLast_'; + //first button + this.prfxBtnFirst = 'btnFirst_'; + //span for tot nb pages + this.prfxPgSpan = 'pgspan_'; + //span preceding pages select (contains 'Page') + this.prfxPgBeforeSpan = 'pgbeforespan_'; + //span following pages select (contains ' of ') + this.prfxPgAfterSpan = 'pgafterspan_'; + //rows counter div + this.prfxCounter = 'counter_'; + //nb displayed rows label + this.prfxTotRows = 'totrows_span_'; + //label preceding nb rows label + this.prfxTotRowsTxt = 'totRowsTextSpan_'; + //span containing reset button + this.prfxResetSpan = 'resetspan_'; + //loader div + this.prfxLoader = 'load_'; + //status bar div + this.prfxStatus = 'status_'; + //status bar label + this.prfxStatusSpan = 'statusSpan_'; + //text preceding status bar label + this.prfxStatusTxt = 'statusText_'; + //filter values cookie + this.prfxCookieFltsValues = 'tf_flts_'; + //page nb cookie + this.prfxCookiePageNb = 'tf_pgnb_'; + //page length cookie + this.prfxCookiePageLen = 'tf_pglen_'; + //div containing grid elements if grid_layout true + this.prfxMainTblCont = 'gridCont_'; + //div containing table if grid_layout true + this.prfxTblCont = 'tblCont_'; + //div containing headers table if grid_layout true + this.prfxHeadTblCont = 'tblHeadCont_'; + //headers' table if grid_layout true + this.prfxHeadTbl = 'tblHead_'; + //id of td containing the filter if grid_layout true + this.prfxGridFltTd = '_td_'; + //id of th containing column header if grid_layout true + this.prfxGridTh = 'tblHeadTh_'; + //id prefix for help elements + this.prfxHelpSpan = 'helpSpan_'; + //id prefix for help elements + this.prfxHelpDiv = 'helpDiv_'; + //id prefix for pop-up filter span + this.prfxPopUpSpan = 'popUpSpan_'; + //id prefix for pop-up div containing filter + this.prfxPopUpDiv = 'popUpDiv_'; + + /*** cookies ***/ + this.hasStoredValues = false; + //remembers filters values on page load + this.rememberGridValues = f.remember_grid_values===true ? + true : false; + //cookie storing filter values + this.fltsValuesCookie = this.prfxCookieFltsValues + this.id; + //remembers page nb on page load + this.rememberPageNb = this.paging && f.remember_page_number ? + true : false; + //cookie storing page nb + this.pgNbCookie = this.prfxCookiePageNb + this.id; + //remembers page length on page load + this.rememberPageLen = this.paging && f.remember_page_length ? + true : false; + //cookie storing page length + this.pgLenCookie = this.prfxCookiePageLen + this.id; + + /*** extensions ***/ + //imports external script + this.hasExtensions = f.extensions===true ? true : false; + this.extensions = this.hasExtensions ? f.extensions : null; + + /*** themes ***/ + this.enableDefaultTheme = f.enable_default_theme===true ? + true : false; + //imports themes + this.hasThemes = (f.enable_default_theme || + (f.themes && types.isObj(f.themes))) ? true : false; + this.themes = this.hasThemes ? f.themes : null; + //themes path + this.themesPath = f.themes_path || this.basePath+'TF_Themes/'; + + // Components + this.Cpt = { + loader: null, + alternateRows: null, + colOps: null, + rowsCounter: null, + gridLayout: null, + store: null, + highlightKeywords: null, + paging: null, + checkList: null, + dropdown: null, + popupFilter: null, + clearButton: null, + help: null, + statusBar: null + }; + + /*** TF events ***/ + var o = this; + this.Evt = { + name: { + filter: 'Filter', + dropdown: 'dropdown', + checklist: 'checkList', + changepage: 'changePage', + clear: 'Clear', + changeresultsperpage: 'changeResults', + resetvalues: 'ResetValues', + resetpage: 'resetPage', + resetpagelength: 'resetPageLength', + sort: 'Sort', + loadextensions: 'LoadExtensions', + loadthemes: 'LoadThemes' + }, + getKeyCode: function(evt){ + return evt.charCode ? evt.charCode : + (evt.keyCode ? evt.keyCode: (evt.which ? evt.which : 0)); + }, + /*==================================================== + - Detects key for a given element + =====================================================*/ + _DetectKey: function(e) { + if(!o.enterKey){ return; } + var _evt = e || global.event; + if(_evt){ + var key = o.Evt.getKeyCode(_evt); + if(key===13){ + o._filter(); + evt.cancel(_evt); + evt.stop(_evt); + } else { + o.isUserTyping = true; + global.clearInterval(o.onKeyUpTimer); + o.onKeyUpTimer = undefined; + } + }//if evt + }, + /*==================================================== + - onkeyup event for text filters + =====================================================*/ + _OnKeyUp: function(e) { + if(!o.onKeyUp){ + return; + } + var _evt = e || global.event; + var key = o.Evt.getKeyCode(_evt); + o.isUserTyping = false; + + function filter() { + global.clearInterval(o.onKeyUpTimer); + o.onKeyUpTimer = undefined; + if(!o.isUserTyping){ + o.filter(); + o.isUserTyping = null; + } + } + + if(key!==13 && key!==9 && key!==27 && key!==38 && key!==40) { + if(o.onKeyUpTimer===undefined){ + o.onKeyUpTimer = global.setInterval(filter, o.onKeyUpDelay); + } + } else { + global.clearInterval(o.onKeyUpTimer); + o.onKeyUpTimer = undefined; + } + }, + /*==================================================== + - onkeydown event for input filters + =====================================================*/ + _OnKeyDown: function(e) { + if(!o.onKeyUp) { return; } + o.isUserTyping = true; + }, + /*==================================================== + - onblur event for input filters + =====================================================*/ + _OnInpBlur: function(e) { + if(o.onKeyUp){ + o.isUserTyping = false; + global.clearInterval(o.onKeyUpTimer); + } + if(o.ezEditTable){ + if(o.editable){ + o.ezEditTable.Editable.Set(); + } + if(o.selectable){ + o.ezEditTable.Selection.Set(); + } + } + }, + /*==================================================== + - onfocus event for input filters + =====================================================*/ + _OnInpFocus: function(e) { + var _evt = e || global.event; + o.activeFilterId = this.getAttribute('id'); + o.activeFlt = dom.id(o.activeFilterId); + if(o.popUpFilters){ + evt.cancel(_evt); + evt.stop(_evt); + } + if(o.ezEditTable){ + if(o.editable){ + o.ezEditTable.Editable.Remove(); + } + if(o.selectable){ + o.ezEditTable.Selection.Remove(); + } + } + }, + /*==================================================== + - onfocus event for select filters + =====================================================*/ + _OnSlcFocus: function(e) { + var _evt = e || global.event; + o.activeFilterId = this.getAttribute('id'); + o.activeFlt = dom.id(o.activeFilterId); + // select is populated when element has focus + if(o.fillSlcOnDemand && this.getAttribute('filled') === '0'){ + var ct = this.getAttribute('ct'); + o.Cpt.dropdown._build(ct); + } + if(o.popUpFilters){ + evt.cancel(_evt); + evt.stop(_evt); + } + }, + /*==================================================== + - onchange event for select filters + =====================================================*/ + _OnSlcChange: function(e) { + if(!o.activeFlt){ return; } + var colIndex = o.activeFlt.getAttribute('colIndex'); + //Checks filter is a checklist and caller is not null + // if(o.activeFlt && colIndex && + // o['col'+colIndex]===o.fltTypeCheckList && + // !o.Evt._OnSlcChange.caller){ return; } + var _evt = e || global.event; + if(o.popUpFilters){ evt.stop(_evt); } + if(o.onSlcChange){ o.filter(); } + }, + /*==================================================== + - onblur event for select filters + =====================================================*/ + _OnSlcBlur: function(e) {}, + /*==================================================== + - onclick event for checklist filters + =====================================================*/ + _OnCheckListClick: function() { + if(o.fillSlcOnDemand && this.getAttribute('filled') === '0'){ + var ct = this.getAttribute('ct'); + o.Cpt.checkList._build(ct); + o.Cpt.checkList.checkListDiv[ct].onclick = null; + o.Cpt.checkList.checkListDiv[ct].title = ''; + } + }, + /*==================================================== + - onclick event for checklist filter container + =====================================================*/ + _OnCheckListFocus: function(e) { + o.activeFilterId = this.firstChild.getAttribute('id'); + o.activeFlt = dom.id(o.activeFilterId); + }, + _OnCheckListBlur: function(e){}, + /*==================================================== + - onclick event for validation button + (btn property) + =====================================================*/ + _OnBtnClick: function() { + o.filter(); + }, + _OnSlcPagesChangeEvt: null, //used by sort adapter + /*==================================================== + - onclick event slc parent node (enables filters) + IE only + =====================================================*/ + _EnableSlc: function() { + this.firstChild.disabled = false; + this.firstChild.focus(); + this.onclick = null; + }, + + _Paging: { //used by sort adapter + nextEvt: null, + prevEvt: null, + lastEvt: null, + firstEvt: null + } + }; +} + +TableFilter.prototype = { + /*==================================================== + - initialises filtering grid bar behaviours and + layout + =====================================================*/ + init: function(){ + if(this._hasGrid){ + return; + } + if(!this.tbl){ + this.tbl = dom.id(this.id); + } + if(this.gridLayout){ + this.refRow = this.startRow===null ? 0 : this.startRow; + } + if(this.popUpFilters && + ((this.filtersRowIndex === 0 && this.headersRow === 1) || + this.gridLayout)){ + this.headersRow = 0; + } + var f = this.cfg, + n = this.singleSearchFlt ? 1 : this.nbCells, + inpclass; + + if(window['tf_'+this.id] === undefined){ + window['tf_'+this.id] = this; + } + + //loads stylesheet if not imported + //Issues with browsers != IE, IE rules in this case + this.includeFile(this.stylesheetId, this.stylesheet, null, 'link'); + + //loads theme + if(this.hasThemes){ this._LoadThemes(); } + + if(this.rememberGridValues || this.rememberPageNb || + this.rememberPageLen){ + var Store = require('modules/store').Store; + this.Cpt.store = new Store(this); + } + + if(this.gridLayout){ + var GridLayout = require('modules/gridLayout').GridLayout; + this.Cpt.gridLayout = new GridLayout(this); + this.Cpt.gridLayout.init(); + } + + if(this.loader){ + if(!this.Cpt.loader){ + var Loader = require('modules/loader').Loader; + this.Cpt.loader = new Loader(this); + } + } + + if(this.highlightKeywords){ + var Highlight = + require('modules/highlightKeywords').HighlightKeyword; + this.Cpt.highlightKeyword = new Highlight(this); + } + + if(this.popUpFilters){ + if(!this.Cpt.popupFilter){ + var PopupFilter = require('modules/popupFilter').PopupFilter; + this.Cpt.popupFilter = new PopupFilter(this); + } + this.Cpt.popupFilter.init(); + } + + //filters grid is not generated + if(!this.fltGrid){ + this.refRow = this.refRow-1; + if(this.gridLayout){ + this.refRow = 0; + } + this.nbFilterableRows = this.getRowsNb(); + this.nbVisibleRows = this.nbFilterableRows; + this.nbRows = this.nbFilterableRows + this.refRow; + } else { + if(this.isFirstLoad){ + var fltrow; + if(!this.gridLayout){ + var thead = dom.tag(this.tbl,'thead'); + if(thead.length > 0){ + fltrow = thead[0].insertRow(this.filtersRowIndex); + } else { + fltrow = this.tbl.insertRow(this.filtersRowIndex); + } + + if(this.headersRow > 1 && + this.filtersRowIndex <= this.headersRow && + !this.popUpFilters){ + this.headersRow++; + } + if(this.popUpFilters){ + this.headersRow++; + } + + fltrow.className = this.fltsRowCssClass; + //Disable for grid_layout + if(this.isExternalFlt && + (!this.gridLayout || this.popUpFilters)){ + fltrow.style.display = 'none'; + } + } + + this.nbFilterableRows = this.getRowsNb(); + this.nbVisibleRows = this.nbFilterableRows; + this.nbRows = this.tbl.rows.length; + + for(var i=0; i'; + + //Paging buttons + this.btnPrevPageHtml = ''; + this.btnNextPageHtml = ''; + this.btnFirstPageHtml = ''; + this.btnLastPageHtml = ''; + + //Loader + this.loader = true; + this.loaderHtml = '
'; + this.loaderText = null; + }, + + /*==================================================== + - removes a filter grid + =====================================================*/ + remove: function(){ + if(this.fltGrid && this._hasGrid){ + var rows = this.tbl.rows; + if(this.paging){ + this.Cpt.paging.destroy(); + } + if(this.statusBar){ + // this.RemoveStatusBar(); + this.Cpt.statusBar.destroy(); + } + if(this.rowsCounter){ + this.Cpt.rowsCounter.destroy(); + } + if(this.btnReset){ + // this.RemoveResetBtn(); + this.Cpt.clearButton.destroy(); + } + if(this.helpInstructions /*|| !this.helpInstructions*/){ + this.Cpt.help.destroy(); + } + if(this.isExternalFlt && !this.popUpFilters){ + this.RemoveExternalFlts(); + } + if(this.infDiv){ + this.removeToolbar(); + } + if(this.highlightKeywords){ + this.Cpt.highlightKeyword.unhighlightAll(); + } + if(this.sort){ + this.RemoveSort(); + } + if(this.loader){ + this.Cpt.loader.remove(); + } + if(this.popUpFilters){ + this.Cpt.popupFilter.destroy(); + } + if(this.markActiveColumns){ + this.clearActiveColumns(); + } + if(this.editable || this.selectable){ + this.RemoveEditable(); + } + //this loop shows all rows and removes validRow attribute + for(var j=this.refRow; j 0 && !ezEditConfig.startRow){ + startRow = undefined; + } + //otherwise startRow config property if any or TableFilter refRow + else{ + startRow = ezEditConfig.startRow || o.refRow; + } + + ezEditConfig.scroll_into_view = ezEditConfig.scroll_into_view===false ? + false : true; + ezEditConfig.base_path = ezEditConfig.base_path || + o.basePath + 'ezEditTable/'; + ezEditConfig.editable = o.editable = o.cfg.editable; + ezEditConfig.selection = o.selectable = o.cfg.selectable; + + if(o.selectable){ + ezEditConfig.default_selection = + ezEditConfig.default_selection || 'row'; + } + //CSS Styles + ezEditConfig.active_cell_css = ezEditConfig.active_cell_css || + 'ezETSelectedCell'; + + o._lastValidRowIndex = 0; + o._lastRowIndex = 0; + + if(o.selectable){ + //Row navigation needs to be calculated according to TableFilter's + //validRowsIndex array + var onAfterSelection = function(et, selectedElm, e){ + //table is not filtered + if(!o.validRowsIndex){ + return; + } + var validIndexes = o.validRowsIndex, + validIdxLen = validIndexes.length, + row = et.defaultSelection !== 'row' ? + selectedElm.parentNode : selectedElm, + //cell for default_selection = 'both' or 'cell' + cell = selectedElm.nodeName==='TD' ? selectedElm : null, + keyCode = e !== undefined ? et.Event.GetKey(e) : 0, + isRowValid = array.has(validIndexes, row.rowIndex), + nextRowIndex, + //pgup/pgdown keys + d = (keyCode === 34 || keyCode === 33 ? + (o.pagingLength || et.nbRowsPerPage) : 1); + + //If next row is not valid, next valid filtered row needs to be + //calculated + if(!isRowValid){ + //Selection direction up/down + if(row.rowIndex>o._lastRowIndex){ + //last row + if(row.rowIndex >= validIndexes[validIdxLen-1]){ + nextRowIndex = validIndexes[validIdxLen-1]; + } else { + var calcRowIndex = (o._lastValidRowIndex + d); + if(calcRowIndex > (validIdxLen-1)){ + nextRowIndex = validIndexes[validIdxLen-1]; + } else { + nextRowIndex = validIndexes[calcRowIndex]; + } + } + } else{ + //first row + if(row.rowIndex <= validIndexes[0]){ + nextRowIndex = validIndexes[0]; + } else { + var v = validIndexes[o._lastValidRowIndex - d]; + nextRowIndex = v ? v : validIndexes[0]; + } + } + o._lastRowIndex = row.rowIndex; + DoSelection(nextRowIndex); + } else { + //If filtered row is valid, special calculation for + //pgup/pgdown keys + if(keyCode!==34 && keyCode!==33){ + o._lastValidRowIndex = array.indexByValue(validIndexes, + row.rowIndex); + o._lastRowIndex = row.rowIndex; + } else { + if(keyCode === 34){ //pgdown + //last row + if((o._lastValidRowIndex + d) <= (validIdxLen-1)){ + nextRowIndex = validIndexes[ + o._lastValidRowIndex + d]; + } else { + nextRowIndex = [validIdxLen-1]; + } + } else { //pgup + //first row + if((o._lastValidRowIndex - d) <= validIndexes[0]){ + nextRowIndex = validIndexes[0]; + } else { + nextRowIndex = validIndexes[ + o._lastValidRowIndex - d]; + } + } + o._lastRowIndex = nextRowIndex; + o._lastValidRowIndex = array.indexByValue(validIndexes, + nextRowIndex); + DoSelection(nextRowIndex); + } + } + + //Next valid filtered row needs to be selected + var DoSelection = function(nextRowIndex){ + if(et.defaultSelection === 'row'){ + et.Selection.SelectRowByIndex(nextRowIndex); + } else { + et.ClearSelections(); + var cellIndex = selectedElm.cellIndex, + row = o.tbl.rows[nextRowIndex]; + if(et.defaultSelection === 'both'){ + et.Selection.SelectRowByIndex(nextRowIndex); + } + if(row){ + et.Selection.SelectCell(row.cells[cellIndex]); + } + } + //Table is filtered + if(o.validRowsIndex.length !== o.getRowsNb()){ + var r = o.tbl.rows[nextRowIndex]; + if(r){ + r.scrollIntoView(false); + } + if(cell){ + if(cell.cellIndex===(o.getCellsNb()-1) && + o.gridLayout){ + o.tblCont.scrollLeft = 100000000; + } + else if(cell.cellIndex===0 && o.gridLayout){ + o.tblCont.scrollLeft = 0; + } else { + cell.scrollIntoView(false); + } + } + } + }; + }; + + //Page navigation has to be enforced whenever selected row is out of + //the current page range + var onBeforeSelection = function(et, selectedElm, e){ + var row = et.defaultSelection !== 'row' ? + selectedElm.parentNode : selectedElm; + if(o.paging){ + if(o.nbPages>1){ + //page length is re-assigned in case it has changed + et.nbRowsPerPage = o.pagingLength; + var validIndexes = o.validRowsIndex, + validIdxLen = validIndexes.length, + pagingEndRow = parseInt(o.startPagingRow, 10) + + parseInt(o.pagingLength, 10); + var rowIndex = row.rowIndex; + if((rowIndex === validIndexes[validIdxLen-1]) && + o.currentPageNb!=o.nbPages){ + // o.SetPage('last'); + o.Cpt.paging.setPage('last'); + } + else if((rowIndex == validIndexes[0]) && + o.currentPageNb!==1){ + // o.SetPage('first'); + o.Cpt.paging.setPage('first'); + } + else if(rowIndex > validIndexes[pagingEndRow-1] && + rowIndex < validIndexes[validIdxLen-1]){ + // o.SetPage('next'); + o.Cpt.paging.setPage('next'); + } + else if(rowIndex < validIndexes[o.startPagingRow] && + rowIndex > validIndexes[0]){ + // o.SetPage('previous'); + o.Cpt.paging.setPage('previous'); + } + } + } + }; + + //Selected row needs to be visible when paging is activated + if(o.paging){ + o.onAfterChangePage = function(tf, i){ + var et = tf.ezEditTable; + var row = et.Selection.GetActiveRow(); + if(row){ + row.scrollIntoView(false); + } + var cell = et.Selection.GetActiveCell(); + if(cell){ + cell.scrollIntoView(false); + } + }; + } + + //Rows navigation when rows are filtered is performed with the + //EditTable row selection callback events + if(ezEditConfig.default_selection==='row'){ + var fnB = ezEditConfig.on_before_selected_row; + ezEditConfig.on_before_selected_row = function(){ + onBeforeSelection(arguments[0], arguments[1], arguments[2]); + if(fnB){ + fnB.call( + null, arguments[0], arguments[1], arguments[2]); + } + }; + var fnA = ezEditConfig.on_after_selected_row; + ezEditConfig.on_after_selected_row = function(){ + onAfterSelection(arguments[0], arguments[1], arguments[2]); + if(fnA){ + fnA.call( + null, arguments[0], arguments[1], arguments[2]); + } + }; + } else { + var fnD = ezEditConfig.on_before_selected_cell; + ezEditConfig.on_before_selected_cell = function(){ + onBeforeSelection(arguments[0], arguments[1], arguments[2]); + if(fnD){ + fnD.call( + null, arguments[0], arguments[1], arguments[2]); + } + }; + var fnC = ezEditConfig.on_after_selected_cell; + ezEditConfig.on_after_selected_cell = function(){ + onAfterSelection(arguments[0], arguments[1], arguments[2]); + if(fnC){ + fnC.call( + null, arguments[0], arguments[1], arguments[2]); + } + }; + } + } + if(o.editable){ + //Added or removed rows, TF rows number needs to be re-calculated + var fnE = ezEditConfig.on_added_dom_row; + ezEditConfig.on_added_dom_row = function(){ + o.nbFilterableRows++; + if(!o.paging){ + o.Cpt.rowsCounter.refresh(); + } else { + o.nbRows++; + o.nbVisibleRows++; + o.nbFilterableRows++; + o.paging=false; + o.Cpt.paging.destroy(); + o.Cpt.paging.addPaging(); + } + if(o.alternateBgs){ + o.Cpt.alternateRows.init(); + } + if(fnE){ + fnE.call(null, arguments[0], arguments[1], arguments[2]); + } + }; + if(ezEditConfig.actions && ezEditConfig.actions['delete']){ + var fnF = ezEditConfig.actions['delete'].on_after_submit; + ezEditConfig.actions['delete'].on_after_submit = function(){ + o.nbFilterableRows--; + if(!o.paging){ + o.Cpt.rowsCounter.refresh(); + } else { + o.nbRows--; + o.nbVisibleRows--; + o.nbFilterableRows--; + o.paging=false; + o.Cpt.paging.destroy(); + o.Cpt.paging.addPaging(false); + } + if(o.alternateBgs){ + o.Cpt.alternateRows.init(); + } + if(fnF){ + fnF.call(null, arguments[0], arguments[1]); + } + }; + } + } + + try{ + o.ezEditTable = new EditTable(o.id, ezEditConfig, startRow); + o.ezEditTable.Init(); + } catch(e) { console.log(ezEditConfig.err); } + }, + + /*==================================================== + - IE bug: it seems there is no way to make + multiple selections programatically, only last + selection is kept (multiple select previously + populated via DOM) + - Work-around: defer selection with a setTimeout + If you find a more elegant solution to + this let me know ;-) + - For the moment only this solution seems to work! + - Params: + - slc = select object (select obj) + - index to be selected (integer) + - execute filtering (boolean) + =====================================================*/ + // __deferMultipleSelection: function(slc,index,filter){ + // if(str.lower(slc.nodeName)!=='select'){ + // return; + // } + // var doFilter = filter===undefined ? false : filter; + // var o = this; + // global.setTimeout(function(){ + // slc.options[0].selected = false; + + // if(slc.options[index].value===''){ + // slc.options[index].selected = false; + // } + // else{ + // slc.options[index].selected = true; + // if(doFilter){ + // o.filter(); + // } + // } + // }, 0.1); + // }, + + /*==================================================== + - Returns an array [[values],[texts]] with + custom values for a given filter + - Param: column index (integer) + =====================================================*/ + // _getCustomValues: function(colIndex){ + // if(!colIndex){ + // return; + // } + // //custom select test + // var isCustomSlc = this.hasCustomSlcOptions && + // array.has(this.customSlcOptions.cols, colIndex); + // if(!isCustomSlc){ + // return; + // } + // var optTxt = [], optArray = []; + // var index = array.indexByValue(this.customSlcOptions.cols, colIndex); + // var slcValues = this.customSlcOptions.values[index]; + // var slcTexts = this.customSlcOptions.texts[index]; + // var slcSort = this.customSlcOptions.sorts[index]; + // for(var r=0; r