1
0
Fork 0
mirror of https://github.com/koalyptus/TableFilter.git synced 2024-04-27 20:32:54 +02:00

Merge pull request #682 from koalyptus/feature-registering

Feature registering
This commit is contained in:
koalyptus 2019-02-16 22:02:55 +11:00 committed by GitHub
commit 0a69a99dc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 1026 additions and 1183 deletions

4
dist/starter.html vendored
View file

@ -1,10 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>tablefilter v0.6.76 - Starter</title>
<title>tablefilter v0.6.78 - Starter</title>
</head>
<body>
<h1>tablefilter v0.6.76</h1>
<h1>tablefilter v0.6.78</h1>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1880
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{
"name": "tablefilter",
"version": "0.6.77",
"version": "0.6.78",
"description": "A Javascript library making HTML tables filterable and a bit more",
"license": "MIT",
"author": {
@ -40,17 +40,17 @@
"tag": "next"
},
"devDependencies": {
"@babel/core": "7.2.2",
"@babel/core": "7.3.3",
"@babel/preset-env": "7.3.1",
"babel-eslint": "10.0.0",
"babel-loader": "^8.0.2",
"babel-preset-env": "1.7.0",
"clean-webpack-plugin": "^1.0.0",
"codecov": "3.1.0",
"codecov": "3.2.0",
"diacritics": "1.3.0",
"esdoc": "1.1.0",
"esdoc-standard-plugin": "1.0.0",
"eslint": "5.0.1",
"eslint": "5.14.0",
"format-number": "3.0.0",
"grunt": "^1.0.1",
"grunt-cli": "1.3.2",

View file

@ -1,19 +1,3 @@
import {DateType} from './modules/dateType';
import {Help} from './modules/help';
import {State} from './modules/state';
import {GridLayout} from './modules/gridLayout';
import {Loader} from './modules/loader';
import {HighlightKeyword} from './modules/highlightKeywords';
import {PopupFilter} from './modules/popupFilter';
import {MarkActiveColumns} from './modules/markActiveColumns';
import {RowsCounter} from './modules/rowsCounter';
import {StatusBar} from './modules/statusBar';
import {ClearButton} from './modules/clearButton';
import {AlternateRows} from './modules/alternateRows';
import {NoResults} from './modules/noResults';
import {Paging} from './modules/paging';
import {Toolbar} from './modules/toolbar';
/**
* Filter types
*/
@ -132,75 +116,3 @@ export const IP_ADDRESS = 'ipaddress';
* @type {Number}
*/
export const AUTO_FILTER_DELAY = 750;
/**
* TableFilter features definitions
* @type {Object}
*/
export const FEATURES = {
dateType: {
class: DateType,
name: 'dateType'
},
help: {
class: Help,
name: 'help',
enforce: true
},
state: {
class: State,
name: 'state'
},
markActiveColumns: {
class: MarkActiveColumns,
name: 'markActiveColumns'
},
gridLayout: {
class: GridLayout,
name: 'gridLayout'
},
loader: {
class: Loader,
name: 'loader'
},
highlightKeyword: {
class: HighlightKeyword,
name: 'highlightKeyword',
property: 'highlightKeywords'
},
popupFilter: {
class: PopupFilter,
name: 'popupFilter',
property: 'popupFilters'
},
rowsCounter: {
class: RowsCounter,
name: 'rowsCounter'
},
statusBar: {
class: StatusBar,
name: 'statusBar'
},
clearButton: {
class: ClearButton,
name: 'clearButton',
property: 'btnReset'
},
alternateRows: {
class: AlternateRows,
name: 'alternateRows'
},
noResults: {
class: NoResults,
name: 'noResults'
},
paging: {
class: Paging,
name: 'paging'
},
toolbar: {
class: Toolbar,
name: 'toolbar',
enforce: true
}
};

View file

@ -21,7 +21,7 @@ export default class AdapterEzEditTable extends Feature {
* @param {Object} cfg Configuration options for ezEditTable library
*/
constructor(tf, cfg) {
super(tf, cfg.name);
super(tf, AdapterEzEditTable);
/**
* Module description
@ -505,3 +505,5 @@ export default class AdapterEzEditTable extends Feature {
this.initialized = false;
}
}
AdapterEzEditTable.meta = {altName: 'advancedGrid'};

View file

@ -33,7 +33,7 @@ export default class ColOps extends Feature {
* @param {Object} opts Configuration object
*/
constructor(tf, opts) {
super(tf, opts.name);
super(tf, ColOps);
/**
* Callback fired before columns operations start

View file

@ -23,7 +23,7 @@ export default class ColsVisibility extends Feature {
* @param {Object} Configuration object
*/
constructor(tf, f) {
super(tf, f.name);
super(tf, ColsVisibility);
// Configuration object
let cfg = this.config;

View file

@ -18,7 +18,7 @@ export default class FiltersVisibility extends Feature {
* @param {Object} Configuration object
*/
constructor(tf, f) {
super(tf, f.name);
super(tf, FiltersVisibility);
/**
* Module name

View file

@ -20,7 +20,7 @@ export default class AdapterSortableTable extends Feature {
* @param {Object} opts Configuration object
*/
constructor(tf, opts) {
super(tf, opts.name);
super(tf, AdapterSortableTable);
/**
* Module name
@ -508,6 +508,8 @@ export default class AdapterSortableTable extends Feature {
}
AdapterSortableTable.meta = {altName: 'sort'};
//Converters
function ipAddress(value) {
let vals = value.split('.');

View file

@ -1,3 +1,4 @@
import {toCamelCase} from './string';
const NOT_IMPLEMENTED = 'Not implemented.';
@ -8,9 +9,11 @@ export class Feature {
/**
* Creates an instance of Feature
* @param {Object} tf TableFilter instance
* @param {String} feature Feature name known by TableFilter
* @param {Class} feature Feature class for TableFilter registration
*/
constructor(tf, feature) {
constructor(tf, cls) {
cls.meta = cls.meta || {};
/**
* TableFilter instance
* @type {TableFilter}
@ -18,16 +21,18 @@ export class Feature {
this.tf = tf;
/**
* Feature name
* Feature name is the camelised class name as per TableFilter's
* convention
* @type {String}
*/
this.feature = feature;
this.feature = cls.meta.altName || cls.meta.name
|| toCamelCase(cls.name);
/**
* TableFilter feature setting
* @type {Boolean}
*/
this.enabled = tf[feature];
this.enabled = tf[this.feature];
/**
* TableFilter configuration

View file

@ -14,9 +14,10 @@ export class AlternateRows extends Feature {
* @param {Object} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'alternateRows');
super(tf, AlternateRows);
let config = this.config;
/**
* Css class for even rows (default: 'even')
* @type {String}

View file

@ -18,8 +18,8 @@ export class BaseDropdown extends Feature {
* Creates an instance of BaseDropdown
* @param {TableFilter} tf
*/
constructor(tf) {
super(tf, 'baseDropdown');
constructor(tf, cls) {
super(tf, cls);
let f = this.config;
@ -33,7 +33,7 @@ export class BaseDropdown extends Feature {
f.filter_options_sorter :
null;
// TODO: move here all properties shared by Dropdown CheckList
// TODO: move here all properties shared by Dropdown and CheckList
/**
* Has custom options

View file

@ -22,7 +22,7 @@ export class CheckList extends BaseDropdown {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'checkList');
super(tf, CheckList);
let f = this.config;

View file

@ -15,7 +15,7 @@ export class ClearButton extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'btnReset');
super(tf, ClearButton);
let f = this.config.btn_reset || {};
@ -137,3 +137,6 @@ export class ClearButton extends Feature {
this.initialized = false;
}
}
// TODO: remove as soon as feature name is fixed
ClearButton.meta = {altName: 'btnReset'};

View file

@ -17,7 +17,7 @@ export class DateType extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'dateType');
super(tf, DateType);
/**
* Global locale

View file

@ -19,7 +19,7 @@ export class Dropdown extends BaseDropdown {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'dropdown');
super(tf, Dropdown);
// Configuration object
let f = this.config;

View file

@ -17,7 +17,7 @@ export class GridLayout extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'gridLayout');
super(tf, GridLayout);
let f = this.config.grid_layout || {};

View file

@ -86,7 +86,7 @@ export class Hash {
}
/**
* Converts a URL hash into a state JSON object
* Converts a URL hash into a JSON object
*
* @param {String} hash URL hash fragment
* @returns {Object} JSON object

View file

@ -21,7 +21,7 @@ export class Help extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'help');
super(tf, Help);
let f = this.config.help_instructions || {};
@ -238,3 +238,6 @@ export class Help extends Feature {
}
}
// TODO: remove as soon as feature name is fixed
Help.meta = {alwaysInstantiate: true};

View file

@ -172,3 +172,9 @@ export class HighlightKeyword {
this.highlight(cell, term, this.highlightCssClass);
}
}
// TODO: remove as soon as feature name is fixed
HighlightKeyword.meta = {
name: 'highlightKeyword',
altName: 'highlightKeywords'
};

View file

@ -44,7 +44,7 @@ export class Loader extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'loader');
super(tf, Loader);
let f = this.config.loader || {};

View file

@ -16,7 +16,7 @@ export class MarkActiveColumns extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'markActiveColumns');
super(tf, MarkActiveColumns);
let config = this.config.mark_active_columns || {};

View file

@ -17,7 +17,7 @@ export class NoResults extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'noResults');
super(tf, NoResults);
//configuration object
let f = this.config.no_results_message || {};

View file

@ -21,7 +21,7 @@ export class Paging extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'paging');
super(tf, Paging);
// Configuration object
let f = this.config.paging || {};

View file

@ -19,7 +19,7 @@ export class PopupFilter extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'popupFilters');
super(tf, PopupFilter);
// Configuration object
let f = this.config.popup_filters || {};
@ -456,3 +456,6 @@ export class PopupFilter extends Feature {
}
}
// TODO: remove as soon as feature name is fixed
PopupFilter.meta = {altName: 'popupFilters'};

View file

@ -17,7 +17,7 @@ export class RowsCounter extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'rowsCounter');
super(tf, RowsCounter);
// TableFilter configuration
let f = this.config.rows_counter || {};

View file

@ -19,7 +19,7 @@ export class State extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'state');
super(tf, State);
let cfg = this.config.state || {};

View file

@ -30,7 +30,7 @@ export class StatusBar extends Feature {
* @param {TableFilter} tf TableFilter instance
*/
constructor(tf) {
super(tf, 'statusBar');
super(tf, StatusBar);
// Configuration object
let f = this.config.status_bar || {};

View file

@ -29,7 +29,7 @@ export class Toolbar extends Feature {
* @memberof Toolbar
*/
constructor(tf) {
super(tf, 'toolbar');
super(tf, Toolbar);
// Configuration object
let f = this.config.toolbar || {};
@ -219,3 +219,6 @@ export class Toolbar extends Feature {
this.initialized = false;
}
}
// TODO: remove as soon as feature name is fixed
Toolbar.meta = {alwaysInstantiate: true};

View file

@ -74,3 +74,18 @@ export const contains = (term, data, exactMatch = false, caseSensitive = false,
}
return regexp.test(data);
};
/**
* Camelize a string, cutting the string by multiple separators like
* hyphens, underscores and spaces.
* @param {String} text text to camelize
* @return {String} camelized text
*/
export const toCamelCase = (text = '') => {
return text.replace(/^([A-Z])|[\s-_]+(\w)/g, (match, p1, p2) => {
if (p2) {
return p2.toUpperCase();
}
return p1.toLowerCase();
});
};

View file

@ -2,7 +2,7 @@ import {addEvt, cancelEvt, stopEvt, targetEvt, isKeyPressed} from './event';
import {
addClass, createElm, elm, getText, getFirstTextNode, removeClass, tag
} from './dom';
import {contains, matchCase, rgxEsc, trim} from './string';
import {contains, matchCase, rgxEsc, trim, toCamelCase} from './string';
import {
isArray, isEmpty, isFn, isNumber, isObj, isString, isUndef, EMPTY_FN,
isBoolean
@ -17,16 +17,36 @@ import {root} from './root';
import {Emitter} from './emitter';
import {Dropdown} from './modules/dropdown';
import {CheckList} from './modules/checkList';
import {DateType} from './modules/dateType';
import {Help} from './modules/help';
import {State} from './modules/state';
import {GridLayout} from './modules/gridLayout';
import {Loader} from './modules/loader';
import {HighlightKeyword} from './modules/highlightKeywords';
import {PopupFilter} from './modules/popupFilter';
import {MarkActiveColumns} from './modules/markActiveColumns';
import {RowsCounter} from './modules/rowsCounter';
import {StatusBar} from './modules/statusBar';
import {ClearButton} from './modules/clearButton';
import {AlternateRows} from './modules/alternateRows';
import {NoResults} from './modules/noResults';
import {Paging} from './modules/paging';
import {Toolbar} from './modules/toolbar';
import {
INPUT, SELECT, MULTIPLE, CHECKLIST, NONE,
ENTER_KEY, TAB_KEY, ESC_KEY, UP_ARROW_KEY, DOWN_ARROW_KEY,
CELL_TAG, AUTO_FILTER_DELAY, NUMBER, DATE, FORMATTED_NUMBER,
FEATURES
CELL_TAG, AUTO_FILTER_DELAY, NUMBER, DATE, FORMATTED_NUMBER
} from './const';
let doc = root.document;
const FEATURES = [
DateType, Help, State, MarkActiveColumns, GridLayout, Loader,
HighlightKeyword, PopupFilter, RowsCounter, StatusBar, ClearButton,
AlternateRows, NoResults, Paging, Toolbar
];
/**
* Makes HTML tables filterable and a bit more :)
*
@ -399,8 +419,7 @@ export class TableFilter {
* Enable/disable single filter mode
* @type {Boolean|Object}
*/
this.singleFlt = isObj(f.single_filter) ||
Boolean(f.single_filter);
this.singleFlt = isObj(f.single_filter) || Boolean(f.single_filter);
/**
* Specify columns to be excluded from single filter search, by default
@ -926,10 +945,8 @@ export class TableFilter {
*/
this.ExtRegistry = {};
// conditionally instantiate required features
this.instantiateFeatures(
Object.keys(FEATURES).map((item) => FEATURES[item])
);
// instantiate features if needed
this.instantiateFeatures(FEATURES);
}
/**
@ -949,20 +966,16 @@ export class TableFilter {
//loads theme
this.loadThemes();
const { dateType, help, state, markActiveColumns, gridLayout, loader,
highlightKeyword, popupFilter, rowsCounter, statusBar, clearButton,
alternateRows, noResults, paging, toolbar } = FEATURES;
//explicitly initialise features in given order
this.initFeatures([
dateType,
help,
state,
markActiveColumns,
gridLayout,
loader,
highlightKeyword,
popupFilter
DateType,
Help,
State,
MarkActiveColumns,
GridLayout,
Loader,
HighlightKeyword,
PopupFilter
]);
//filters grid is not generated
@ -1035,13 +1048,13 @@ export class TableFilter {
}
this.initFeatures([
rowsCounter,
statusBar,
clearButton,
alternateRows,
noResults,
paging,
toolbar
RowsCounter,
StatusBar,
ClearButton,
AlternateRows,
NoResults,
Paging,
Toolbar
]);
this.setColWidths();
@ -1250,47 +1263,41 @@ export class TableFilter {
}
/**
* Istantiate the collection of features required by the
* configuration and add them to the features registry. A feature is
* described by a `class` and `name` fields and and optional `property`
* field:
* {
* class: AClass,
* name: 'aClass'
* }
* Conditionally istantiate each feature class in passed collection if
* required by configuration and add it to the features registry. A feature
* class meta information contains a `name` field and optional `altName` and
* `alwaysInstantiate` fields
* @param {Array} [features=[]]
* @private
*/
instantiateFeatures(features = []) {
features.forEach((feature) => {
// TODO: remove the property field.
// Due to naming convention inconsistencies, a `property`
// field is added to allow a conditional instanciation based
// on that property on TableFilter, if supplied.
feature.property = feature.property || feature.name;
if (!this.hasConfig || this[feature.property] === true ||
feature.enforce === true) {
let {class: Cls, name} = feature;
features.forEach(featureCls => {
let Cls = featureCls;
// assign meta info if not present
Cls.meta = Cls.meta || {name: null, altName: null};
Cls.meta.name = toCamelCase(Cls.name);
let {name, altName, alwaysInstantiate} = Cls.meta;
let prop = altName || name;
if (!this.hasConfig || this[prop] === true
|| Boolean(alwaysInstantiate)) {
this.Mod[name] = this.Mod[name] || new Cls(this);
}
});
}
/**
* Initialise the passed features collection. A feature is described by a
* `class` and `name` fields and and optional `property` field:
* {
* class: AClass,
* name: 'aClass'
* }
* Initialise each feature class in passed collection.
* @param {Array} [features=[]]
* @private
*/
initFeatures(features = []) {
features.forEach((feature) => {
let {property, name} = feature;
if (this[property] === true && this.Mod[name]) {
features.forEach(featureCls => {
let {name, altName} = featureCls.meta;
let prop = altName || name;
if (this[prop] === true && this.Mod[name]) {
this.Mod[name].init();
}
});

View file

@ -6,6 +6,7 @@ var tf = new TableFilter('demo', {
tf.init();
var clearButton = tf.feature('clearButton');
module('Sanity checks');
test('Clear button component', function() {
deepEqual(typeof clearButton, 'object', 'ClearButton instanciated');