diff --git a/dist/frappe-datatable.cjs.js b/dist/frappe-datatable.cjs.js
index e89047f..1751590 100644
--- a/dist/frappe-datatable.cjs.js
+++ b/dist/frappe-datatable.cjs.js
@@ -177,6 +177,548 @@ $.scrollTop = function scrollTop(element, pixels) {
});
};
+/**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+function isObject(value) {
+ var type = typeof value;
+ return value != null && (type == 'object' || type == 'function');
+}
+
+var isObject_1 = isObject;
+
+var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+/** Detect free variable `global` from Node.js. */
+var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
+
+var _freeGlobal = freeGlobal;
+
+/** Detect free variable `self`. */
+var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+/** Used as a reference to the global object. */
+var root = _freeGlobal || freeSelf || Function('return this')();
+
+var _root = root;
+
+/**
+ * Gets the timestamp of the number of milliseconds that have elapsed since
+ * the Unix epoch (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @since 2.4.0
+ * @category Date
+ * @returns {number} Returns the timestamp.
+ * @example
+ *
+ * _.defer(function(stamp) {
+ * console.log(_.now() - stamp);
+ * }, _.now());
+ * // => Logs the number of milliseconds it took for the deferred invocation.
+ */
+var now = function() {
+ return _root.Date.now();
+};
+
+var now_1 = now;
+
+/** Built-in value references. */
+var Symbol = _root.Symbol;
+
+var _Symbol = Symbol;
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var nativeObjectToString = objectProto.toString;
+
+/** Built-in value references. */
+var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
+
+/**
+ * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the raw `toStringTag`.
+ */
+function getRawTag(value) {
+ var isOwn = hasOwnProperty.call(value, symToStringTag),
+ tag = value[symToStringTag];
+
+ try {
+ value[symToStringTag] = undefined;
+ var unmasked = true;
+ } catch (e) {}
+
+ var result = nativeObjectToString.call(value);
+ if (unmasked) {
+ if (isOwn) {
+ value[symToStringTag] = tag;
+ } else {
+ delete value[symToStringTag];
+ }
+ }
+ return result;
+}
+
+var _getRawTag = getRawTag;
+
+/** Used for built-in method references. */
+var objectProto$1 = Object.prototype;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var nativeObjectToString$1 = objectProto$1.toString;
+
+/**
+ * Converts `value` to a string using `Object.prototype.toString`.
+ *
+ * @private
+ * @param {*} value The value to convert.
+ * @returns {string} Returns the converted string.
+ */
+function objectToString(value) {
+ return nativeObjectToString$1.call(value);
+}
+
+var _objectToString = objectToString;
+
+/** `Object#toString` result references. */
+var nullTag = '[object Null]';
+var undefinedTag = '[object Undefined]';
+
+/** Built-in value references. */
+var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
+
+/**
+ * The base implementation of `getTag` without fallbacks for buggy environments.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+function baseGetTag(value) {
+ if (value == null) {
+ return value === undefined ? undefinedTag : nullTag;
+ }
+ return (symToStringTag$1 && symToStringTag$1 in Object(value))
+ ? _getRawTag(value)
+ : _objectToString(value);
+}
+
+var _baseGetTag = baseGetTag;
+
+/**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+function isObjectLike(value) {
+ return value != null && typeof value == 'object';
+}
+
+var isObjectLike_1 = isObjectLike;
+
+/** `Object#toString` result references. */
+var symbolTag = '[object Symbol]';
+
+/**
+ * Checks if `value` is classified as a `Symbol` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+ * @example
+ *
+ * _.isSymbol(Symbol.iterator);
+ * // => true
+ *
+ * _.isSymbol('abc');
+ * // => false
+ */
+function isSymbol(value) {
+ return typeof value == 'symbol' ||
+ (isObjectLike_1(value) && _baseGetTag(value) == symbolTag);
+}
+
+var isSymbol_1 = isSymbol;
+
+/** Used as references for various `Number` constants. */
+var NAN = 0 / 0;
+
+/** Used to match leading and trailing whitespace. */
+var reTrim = /^\s+|\s+$/g;
+
+/** Used to detect bad signed hexadecimal string values. */
+var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
+
+/** Used to detect binary string values. */
+var reIsBinary = /^0b[01]+$/i;
+
+/** Used to detect octal string values. */
+var reIsOctal = /^0o[0-7]+$/i;
+
+/** Built-in method references without a dependency on `root`. */
+var freeParseInt = parseInt;
+
+/**
+ * Converts `value` to a number.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to process.
+ * @returns {number} Returns the number.
+ * @example
+ *
+ * _.toNumber(3.2);
+ * // => 3.2
+ *
+ * _.toNumber(Number.MIN_VALUE);
+ * // => 5e-324
+ *
+ * _.toNumber(Infinity);
+ * // => Infinity
+ *
+ * _.toNumber('3.2');
+ * // => 3.2
+ */
+function toNumber(value) {
+ if (typeof value == 'number') {
+ return value;
+ }
+ if (isSymbol_1(value)) {
+ return NAN;
+ }
+ if (isObject_1(value)) {
+ var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
+ value = isObject_1(other) ? (other + '') : other;
+ }
+ if (typeof value != 'string') {
+ return value === 0 ? value : +value;
+ }
+ value = value.replace(reTrim, '');
+ var isBinary = reIsBinary.test(value);
+ return (isBinary || reIsOctal.test(value))
+ ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
+ : (reIsBadHex.test(value) ? NAN : +value);
+}
+
+var toNumber_1 = toNumber;
+
+/** Error message constants. */
+var FUNC_ERROR_TEXT = 'Expected a function';
+
+/* Built-in method references for those with the same name as other `lodash` methods. */
+var nativeMax = Math.max;
+var nativeMin = Math.min;
+
+/**
+ * Creates a debounced function that delays invoking `func` until after `wait`
+ * milliseconds have elapsed since the last time the debounced function was
+ * invoked. The debounced function comes with a `cancel` method to cancel
+ * delayed `func` invocations and a `flush` method to immediately invoke them.
+ * Provide `options` to indicate whether `func` should be invoked on the
+ * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
+ * with the last arguments provided to the debounced function. Subsequent
+ * calls to the debounced function return the result of the last `func`
+ * invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
+ * invoked on the trailing edge of the timeout only if the debounced function
+ * is invoked more than once during the `wait` timeout.
+ *
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+ * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+ *
+ * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+ * for details over the differences between `_.debounce` and `_.throttle`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} [wait=0] The number of milliseconds to delay.
+ * @param {Object} [options={}] The options object.
+ * @param {boolean} [options.leading=false]
+ * Specify invoking on the leading edge of the timeout.
+ * @param {number} [options.maxWait]
+ * The maximum time `func` is allowed to be delayed before it's invoked.
+ * @param {boolean} [options.trailing=true]
+ * Specify invoking on the trailing edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // Avoid costly calculations while the window size is in flux.
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+ *
+ * // Invoke `sendMail` when clicked, debouncing subsequent calls.
+ * jQuery(element).on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
+ *
+ * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
+ * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', debounced);
+ *
+ * // Cancel the trailing debounced invocation.
+ * jQuery(window).on('popstate', debounced.cancel);
+ */
+function debounce(func, wait, options) {
+ var lastArgs,
+ lastThis,
+ maxWait,
+ result,
+ timerId,
+ lastCallTime,
+ lastInvokeTime = 0,
+ leading = false,
+ maxing = false,
+ trailing = true;
+
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = toNumber_1(wait) || 0;
+ if (isObject_1(options)) {
+ leading = !!options.leading;
+ maxing = 'maxWait' in options;
+ maxWait = maxing ? nativeMax(toNumber_1(options.maxWait) || 0, wait) : maxWait;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+
+ function invokeFunc(time) {
+ var args = lastArgs,
+ thisArg = lastThis;
+
+ lastArgs = lastThis = undefined;
+ lastInvokeTime = time;
+ result = func.apply(thisArg, args);
+ return result;
+ }
+
+ function leadingEdge(time) {
+ // Reset any `maxWait` timer.
+ lastInvokeTime = time;
+ // Start the timer for the trailing edge.
+ timerId = setTimeout(timerExpired, wait);
+ // Invoke the leading edge.
+ return leading ? invokeFunc(time) : result;
+ }
+
+ function remainingWait(time) {
+ var timeSinceLastCall = time - lastCallTime,
+ timeSinceLastInvoke = time - lastInvokeTime,
+ timeWaiting = wait - timeSinceLastCall;
+
+ return maxing
+ ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
+ : timeWaiting;
+ }
+
+ function shouldInvoke(time) {
+ var timeSinceLastCall = time - lastCallTime,
+ timeSinceLastInvoke = time - lastInvokeTime;
+
+ // Either this is the first call, activity has stopped and we're at the
+ // trailing edge, the system time has gone backwards and we're treating
+ // it as the trailing edge, or we've hit the `maxWait` limit.
+ return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
+ (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
+ }
+
+ function timerExpired() {
+ var time = now_1();
+ if (shouldInvoke(time)) {
+ return trailingEdge(time);
+ }
+ // Restart the timer.
+ timerId = setTimeout(timerExpired, remainingWait(time));
+ }
+
+ function trailingEdge(time) {
+ timerId = undefined;
+
+ // Only invoke if we have `lastArgs` which means `func` has been
+ // debounced at least once.
+ if (trailing && lastArgs) {
+ return invokeFunc(time);
+ }
+ lastArgs = lastThis = undefined;
+ return result;
+ }
+
+ function cancel() {
+ if (timerId !== undefined) {
+ clearTimeout(timerId);
+ }
+ lastInvokeTime = 0;
+ lastArgs = lastCallTime = lastThis = timerId = undefined;
+ }
+
+ function flush() {
+ return timerId === undefined ? result : trailingEdge(now_1());
+ }
+
+ function debounced() {
+ var time = now_1(),
+ isInvoking = shouldInvoke(time);
+
+ lastArgs = arguments;
+ lastThis = this;
+ lastCallTime = time;
+
+ if (isInvoking) {
+ if (timerId === undefined) {
+ return leadingEdge(lastCallTime);
+ }
+ if (maxing) {
+ // Handle invocations in a tight loop.
+ timerId = setTimeout(timerExpired, wait);
+ return invokeFunc(lastCallTime);
+ }
+ }
+ if (timerId === undefined) {
+ timerId = setTimeout(timerExpired, wait);
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ debounced.flush = flush;
+ return debounced;
+}
+
+var debounce_1 = debounce;
+
+/** Error message constants. */
+var FUNC_ERROR_TEXT$1 = 'Expected a function';
+
+/**
+ * Creates a throttled function that only invokes `func` at most once per
+ * every `wait` milliseconds. The throttled function comes with a `cancel`
+ * method to cancel delayed `func` invocations and a `flush` method to
+ * immediately invoke them. Provide `options` to indicate whether `func`
+ * should be invoked on the leading and/or trailing edge of the `wait`
+ * timeout. The `func` is invoked with the last arguments provided to the
+ * throttled function. Subsequent calls to the throttled function return the
+ * result of the last `func` invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
+ * invoked on the trailing edge of the timeout only if the throttled function
+ * is invoked more than once during the `wait` timeout.
+ *
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+ * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+ *
+ * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+ * for details over the differences between `_.throttle` and `_.debounce`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
+ * @param {Object} [options={}] The options object.
+ * @param {boolean} [options.leading=true]
+ * Specify invoking on the leading edge of the timeout.
+ * @param {boolean} [options.trailing=true]
+ * Specify invoking on the trailing edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // Avoid excessively updating the position while scrolling.
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+ *
+ * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
+ * jQuery(element).on('click', throttled);
+ *
+ * // Cancel the trailing throttled invocation.
+ * jQuery(window).on('popstate', throttled.cancel);
+ */
+function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT$1);
+ }
+ if (isObject_1(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+ return debounce_1(func, wait, {
+ 'leading': leading,
+ 'maxWait': wait,
+ 'trailing': trailing
+ });
+}
+
+var throttle_1 = throttle;
+
function camelCaseToDash(str) {
return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
}
@@ -269,47 +811,16 @@ function isNumeric(val) {
return !isNaN(val);
}
-// https://stackoverflow.com/a/27078401
-function throttle(func, wait, options) {
- var context, args, result;
- var timeout = null;
- var previous = 0;
- if (!options) options = {};
+let throttle$1 = throttle_1;
- let later = function () {
- previous = options.leading === false ? 0 : Date.now();
- timeout = null;
- result = func.apply(context, args);
- if (!timeout) context = args = null;
- };
-
- return function () {
- var now = Date.now();
- if (!previous && options.leading === false) previous = now;
- let remaining = wait - (now - previous);
- context = this;
- args = arguments;
- if (remaining <= 0 || remaining > wait) {
- if (timeout) {
- clearTimeout(timeout);
- timeout = null;
- }
- previous = now;
- result = func.apply(context, args);
- if (!timeout) context = args = null;
- } else if (!timeout && options.trailing !== false) {
- timeout = setTimeout(later, remaining);
- }
- return result;
- };
-}
+let debounce$2 = debounce_1;
function promisify(fn, context = null) {
return (...args) => {
return new Promise(resolve => {
setTimeout(() => {
- fn.apply(context, args);
- resolve('done', fn.name);
+ const out = fn.apply(context, args);
+ resolve(out);
}, 0);
});
};
@@ -335,6 +846,7 @@ class DataManager {
this.sortRows = promisify(this.sortRows, this);
this.switchColumn = promisify(this.switchColumn, this);
this.removeColumn = promisify(this.removeColumn, this);
+ this.filterRows = promisify(this.filterRows, this);
}
init(data) {
@@ -716,6 +1228,25 @@ class DataManager {
return column;
}
+ filterRows(keyword, colIndex) {
+ let rowsToHide = [];
+ let rowsToShow = [];
+ const cells = this.rows.map(row => row[colIndex]);
+
+ cells.forEach(cell => {
+ const hay = cell.content.toLowerCase();
+ const needle = (keyword || '').toLowerCase();
+
+ if (!needle || hay.includes(needle)) {
+ rowsToShow.push(cell.rowIndex);
+ } else {
+ rowsToHide.push(cell.rowIndex);
+ }
+ });
+
+ return {rowsToHide, rowsToShow};
+ }
+
getRowCount() {
return this.rowCount;
}
@@ -839,7 +1370,19 @@ class ColumnManager {
if (!$('.data-table-col', this.header)) {
// insert html
- $('thead', this.header).innerHTML = this.rowmanager.getRowHTML(columns, { isHeader: 1 });
+
+ let html = this.rowmanager.getRowHTML(columns, { isHeader: 1 });
+ if (this.options.enableInlineFilters) {
+ html += this.rowmanager.getRowHTML(columns, { isFilter: 1 });
+ }
+
+ $('thead', this.header).innerHTML = html;
+
+ this.$filterRow = $('.data-table-row[data-is-filter]', this.header);
+ // hide filter row immediately, so it doesn't disturb layout
+ $.style(this.$filterRow, {
+ display: 'none'
+ });
} else {
// refresh dom state
const $cols = $.each('.data-table-col', this.header);
@@ -872,6 +1415,7 @@ class ColumnManager {
this.bindDropdown();
this.bindResizeColumn();
this.bindMoveColumn();
+ this.bindFilter();
}
bindDropdown() {
@@ -1073,6 +1617,51 @@ class ColumnManager {
});
}
+ toggleFilter() {
+ this.isFilterShown = this.isFilterShown || false;
+
+ if (this.isFilterShown) {
+ $.style(this.$filterRow, {
+ display: 'none'
+ });
+ } else {
+ $.style(this.$filterRow, {
+ display: ''
+ });
+ }
+
+ this.isFilterShown = !this.isFilterShown;
+ this.style.setBodyStyle();
+ }
+
+ focusFilter(colIndex) {
+ if (!this.isFilterShown) return;
+
+ const $filterInput = $(`[data-col-index="${colIndex}"] .data-table-filter`, this.$filterRow);
+ $filterInput.focus();
+ }
+
+ bindFilter() {
+ const handler = e => {
+ const $filterCell = $.closest('.data-table-col', e.target);
+ const { colIndex } = $.data($filterCell);
+ const keyword = e.target.value;
+
+ this.datamanager.filterRows(keyword, colIndex)
+ .then(({ rowsToHide, rowsToShow }) => {
+ rowsToHide.map(rowIndex => {
+ const $tr = $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
+ $tr.classList.add('hide');
+ });
+ rowsToShow.map(rowIndex => {
+ const $tr = $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
+ $tr.classList.remove('hide');
+ });
+ });
+ };
+ $.on(this.header, 'keydown', '.data-table-filter', debounce$2(handler, 300));
+ }
+
sortRows(colIndex, sortOrder) {
return this.datamanager.sortRows(colIndex, sortOrder);
}
@@ -1104,7 +1693,7 @@ class ColumnManager {
setColumnHeaderWidth(colIndex) {
colIndex = +colIndex;
this.$columnMap = this.$columnMap || [];
- const selector = `[data-col-index="${colIndex}"][data-is-header] .content`;
+ const selector = `.data-table-header [data-col-index="${colIndex}"] .content`;
const { width } = this.getColumn(colIndex);
let $column = this.$columnMap[colIndex];
@@ -1261,6 +1850,14 @@ class CellManager {
this.keyboard.on('esc', () => {
this.deactivateEditing();
});
+
+ this.keyboard.on('ctrl+f', (e) => {
+ const $cell = $.closest('.data-table-col', e.target);
+ let { colIndex } = $.data($cell);
+
+ this.activateFilter(colIndex);
+ return true;
+ });
}
bindKeyboardSelection() {
@@ -1309,7 +1906,7 @@ class CellManager {
this.selectArea($(e.delegatedTarget));
};
- $.on(this.bodyScrollable, 'mousemove', '.data-table-col', throttle(selectArea, 50));
+ $.on(this.bodyScrollable, 'mousemove', '.data-table-col', throttle$1(selectArea, 50));
}
focusCell($cell, { skipClearSelection = 0 } = {}) {
@@ -1615,6 +2212,16 @@ class CellManager {
copyTextToClipboard(values);
}
+ activateFilter(colIndex) {
+ this.columnmanager.toggleFilter();
+ this.columnmanager.focusFilter(colIndex);
+
+ if (!this.columnmanager.isFilterShown) {
+ // put focus back on cell
+ this.$focusedCell.focus();
+ }
+ }
+
updateCell(colIndex, rowIndex, value) {
const cell = this.datamanager.updateCell(colIndex, rowIndex, {
content: value
@@ -1699,11 +2306,12 @@ class CellManager {
}
getCellHTML(cell) {
- const { rowIndex, colIndex, isHeader } = cell;
+ const { rowIndex, colIndex, isHeader, isFilter } = cell;
const dataAttr = makeDataAttributeString({
rowIndex,
colIndex,
- isHeader
+ isHeader,
+ isFilter
});
return `
@@ -1728,7 +2336,12 @@ class CellManager {
const hasDropdown = isHeader && cell.dropdown !== false;
const dropdown = hasDropdown ? `
@@ -1743,7 +2356,7 @@ class CellManager {
getEditCellHTML() {
return `
-
+
`;
}
@@ -1938,12 +2551,27 @@ class RowManager {
getRowHTML(row, props) {
const dataAttr = makeDataAttributeString(props);
+ if (props.isFilter) {
+ row = row.map(cell => (Object.assign(cell, {
+ content: this.getFilterInput({ colIndex: cell.colIndex }),
+ format: value => value,
+ isFilter: 1,
+ isHeader: undefined,
+ editable: false
+ })));
+ }
+
return `
${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')}
`;
}
+
+ getFilterInput(props) {
+ const dataAttr = makeDataAttributeString(props);
+ return `
`;
+ }
}
class BodyRenderer {
@@ -2064,7 +2692,7 @@ class Style {
bindResizeWindow() {
if (this.options.layout === 'fluid') {
- $.on(window, 'resize', throttle(() => {
+ $.on(window, 'resize', throttle$1(() => {
this.distributeRemainingWidth();
this.refreshColumnWidth();
this.setBodyStyle();
@@ -2136,7 +2764,7 @@ class Style {
}
setupMinWidth() {
- $.each('.data-table-col', this.header).map(col => {
+ $.each('.data-table-col[data-is-header]', this.header).map(col => {
const width = $.style($('.content', col), 'width');
const {
colIndex
@@ -2273,7 +2901,8 @@ const KEYCODES = {
40: 'down',
9: 'tab',
27: 'esc',
- 67: 'c'
+ 67: 'c',
+ 70: 'f'
};
class Keyboard {
@@ -2297,7 +2926,7 @@ class Keyboard {
if (listeners && listeners.length > 0) {
for (let listener of listeners) {
- const preventBubbling = listener();
+ const preventBubbling = listener(e);
if (preventBubbling === undefined || preventBubbling === true) {
e.preventDefault();
}
@@ -2363,7 +2992,8 @@ var DEFAULT_OPTIONS = {
enableLogs: false,
layout: 'fixed', // fixed, fluid
noDataMessage: 'No Data',
- cellHeight: null
+ cellHeight: null,
+ enableInlineFilters: false
};
class DataTable {
@@ -2537,14 +3167,14 @@ var version = "0.0.2";
var description = "A modern datatable library for the web";
var main = "dist/frappe-datatable.cjs.js";
var scripts = {"start":"npm run dev","build":"rollup -c","dev":"rollup -c -w","test":"mocha --compilers js:babel-core/register --colors ./test/*.spec.js","test:watch":"mocha --compilers js:babel-core/register --colors -w ./test/*.spec.js"};
-var devDependencies = {"chai":"3.5.0","cssnano":"^3.10.0","deepmerge":"^2.0.1","eslint":"3.19.0","eslint-loader":"1.7.1","mocha":"3.3.0","postcss-cssnext":"^3.1.0","postcss-nested":"^3.0.0","precss":"^3.1.0","rollup-plugin-json":"^2.3.0","rollup-plugin-postcss":"^1.2.8","rollup-plugin-uglify":"^3.0.0"};
+var devDependencies = {"chai":"3.5.0","cssnano":"^3.10.0","deepmerge":"^2.0.1","eslint":"3.19.0","eslint-loader":"1.7.1","mocha":"3.3.0","postcss-cssnext":"^3.1.0","postcss-nested":"^3.0.0","precss":"^3.1.0","rollup-plugin-commonjs":"^8.3.0","rollup-plugin-json":"^2.3.0","rollup-plugin-node-resolve":"^3.0.3","rollup-plugin-postcss":"^1.2.8","rollup-plugin-uglify":"^3.0.0"};
var repository = {"type":"git","url":"https://github.com/frappe/datatable.git"};
var keywords = ["datatable","data","grid","table"];
var author = "Faris Ansari";
var license = "MIT";
var bugs = {"url":"https://github.com/frappe/datatable/issues"};
var homepage = "https://frappe.github.io/datatable";
-var dependencies = {"clusterize.js":"^0.18.0","sortablejs":"^1.7.0"};
+var dependencies = {"clusterize.js":"^0.18.0","lodash":"^4.17.5","sortablejs":"^1.7.0"};
var packageJson = {
name: name,
version: version,
diff --git a/dist/frappe-datatable.css b/dist/frappe-datatable.css
index 69ec17f..90ab6d1 100644
--- a/dist/frappe-datatable.css
+++ b/dist/frappe-datatable.css
@@ -24,6 +24,12 @@
padding: 0;
}
+.data-table .input-style {
+ outline: none;
+ width: 100%;
+ border: none;
+ }
+
.data-table *, .data-table *:focus {
outline: none;
border-radius: 0px;
@@ -80,6 +86,10 @@
opacity: 0.5;
}
+.data-table .hide {
+ display: none;
+ }
+
.body-scrollable {
max-height: 500px;
overflow: auto;
@@ -195,7 +205,6 @@
.data-table-col .edit-cell {
display: none;
- // position: absolute;
padding: 8px;
padding: 0.5rem;
background: #fff;
@@ -203,12 +212,6 @@
height: 100%;
}
-.data-table-col .edit-cell input {
- outline: none;
- width: 100%;
- border: none;
- }
-
.data-table-col.selected .content {
border: 2px solid rgb(82, 146, 247);
}
diff --git a/dist/frappe-datatable.js b/dist/frappe-datatable.js
index 672256d..d059008 100644
--- a/dist/frappe-datatable.js
+++ b/dist/frappe-datatable.js
@@ -176,6 +176,548 @@ $.scrollTop = function scrollTop(element, pixels) {
});
};
+/**
+ * Checks if `value` is the
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(_.noop);
+ * // => true
+ *
+ * _.isObject(null);
+ * // => false
+ */
+function isObject(value) {
+ var type = typeof value;
+ return value != null && (type == 'object' || type == 'function');
+}
+
+var isObject_1 = isObject;
+
+var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+/** Detect free variable `global` from Node.js. */
+var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
+
+var _freeGlobal = freeGlobal;
+
+/** Detect free variable `self`. */
+var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
+
+/** Used as a reference to the global object. */
+var root = _freeGlobal || freeSelf || Function('return this')();
+
+var _root = root;
+
+/**
+ * Gets the timestamp of the number of milliseconds that have elapsed since
+ * the Unix epoch (1 January 1970 00:00:00 UTC).
+ *
+ * @static
+ * @memberOf _
+ * @since 2.4.0
+ * @category Date
+ * @returns {number} Returns the timestamp.
+ * @example
+ *
+ * _.defer(function(stamp) {
+ * console.log(_.now() - stamp);
+ * }, _.now());
+ * // => Logs the number of milliseconds it took for the deferred invocation.
+ */
+var now = function() {
+ return _root.Date.now();
+};
+
+var now_1 = now;
+
+/** Built-in value references. */
+var Symbol = _root.Symbol;
+
+var _Symbol = Symbol;
+
+/** Used for built-in method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var nativeObjectToString = objectProto.toString;
+
+/** Built-in value references. */
+var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
+
+/**
+ * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the raw `toStringTag`.
+ */
+function getRawTag(value) {
+ var isOwn = hasOwnProperty.call(value, symToStringTag),
+ tag = value[symToStringTag];
+
+ try {
+ value[symToStringTag] = undefined;
+ var unmasked = true;
+ } catch (e) {}
+
+ var result = nativeObjectToString.call(value);
+ if (unmasked) {
+ if (isOwn) {
+ value[symToStringTag] = tag;
+ } else {
+ delete value[symToStringTag];
+ }
+ }
+ return result;
+}
+
+var _getRawTag = getRawTag;
+
+/** Used for built-in method references. */
+var objectProto$1 = Object.prototype;
+
+/**
+ * Used to resolve the
+ * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var nativeObjectToString$1 = objectProto$1.toString;
+
+/**
+ * Converts `value` to a string using `Object.prototype.toString`.
+ *
+ * @private
+ * @param {*} value The value to convert.
+ * @returns {string} Returns the converted string.
+ */
+function objectToString(value) {
+ return nativeObjectToString$1.call(value);
+}
+
+var _objectToString = objectToString;
+
+/** `Object#toString` result references. */
+var nullTag = '[object Null]';
+var undefinedTag = '[object Undefined]';
+
+/** Built-in value references. */
+var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
+
+/**
+ * The base implementation of `getTag` without fallbacks for buggy environments.
+ *
+ * @private
+ * @param {*} value The value to query.
+ * @returns {string} Returns the `toStringTag`.
+ */
+function baseGetTag(value) {
+ if (value == null) {
+ return value === undefined ? undefinedTag : nullTag;
+ }
+ return (symToStringTag$1 && symToStringTag$1 in Object(value))
+ ? _getRawTag(value)
+ : _objectToString(value);
+}
+
+var _baseGetTag = baseGetTag;
+
+/**
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
+ * and has a `typeof` result of "object".
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ * @example
+ *
+ * _.isObjectLike({});
+ * // => true
+ *
+ * _.isObjectLike([1, 2, 3]);
+ * // => true
+ *
+ * _.isObjectLike(_.noop);
+ * // => false
+ *
+ * _.isObjectLike(null);
+ * // => false
+ */
+function isObjectLike(value) {
+ return value != null && typeof value == 'object';
+}
+
+var isObjectLike_1 = isObjectLike;
+
+/** `Object#toString` result references. */
+var symbolTag = '[object Symbol]';
+
+/**
+ * Checks if `value` is classified as a `Symbol` primitive or object.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+ * @example
+ *
+ * _.isSymbol(Symbol.iterator);
+ * // => true
+ *
+ * _.isSymbol('abc');
+ * // => false
+ */
+function isSymbol(value) {
+ return typeof value == 'symbol' ||
+ (isObjectLike_1(value) && _baseGetTag(value) == symbolTag);
+}
+
+var isSymbol_1 = isSymbol;
+
+/** Used as references for various `Number` constants. */
+var NAN = 0 / 0;
+
+/** Used to match leading and trailing whitespace. */
+var reTrim = /^\s+|\s+$/g;
+
+/** Used to detect bad signed hexadecimal string values. */
+var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
+
+/** Used to detect binary string values. */
+var reIsBinary = /^0b[01]+$/i;
+
+/** Used to detect octal string values. */
+var reIsOctal = /^0o[0-7]+$/i;
+
+/** Built-in method references without a dependency on `root`. */
+var freeParseInt = parseInt;
+
+/**
+ * Converts `value` to a number.
+ *
+ * @static
+ * @memberOf _
+ * @since 4.0.0
+ * @category Lang
+ * @param {*} value The value to process.
+ * @returns {number} Returns the number.
+ * @example
+ *
+ * _.toNumber(3.2);
+ * // => 3.2
+ *
+ * _.toNumber(Number.MIN_VALUE);
+ * // => 5e-324
+ *
+ * _.toNumber(Infinity);
+ * // => Infinity
+ *
+ * _.toNumber('3.2');
+ * // => 3.2
+ */
+function toNumber(value) {
+ if (typeof value == 'number') {
+ return value;
+ }
+ if (isSymbol_1(value)) {
+ return NAN;
+ }
+ if (isObject_1(value)) {
+ var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
+ value = isObject_1(other) ? (other + '') : other;
+ }
+ if (typeof value != 'string') {
+ return value === 0 ? value : +value;
+ }
+ value = value.replace(reTrim, '');
+ var isBinary = reIsBinary.test(value);
+ return (isBinary || reIsOctal.test(value))
+ ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
+ : (reIsBadHex.test(value) ? NAN : +value);
+}
+
+var toNumber_1 = toNumber;
+
+/** Error message constants. */
+var FUNC_ERROR_TEXT = 'Expected a function';
+
+/* Built-in method references for those with the same name as other `lodash` methods. */
+var nativeMax = Math.max;
+var nativeMin = Math.min;
+
+/**
+ * Creates a debounced function that delays invoking `func` until after `wait`
+ * milliseconds have elapsed since the last time the debounced function was
+ * invoked. The debounced function comes with a `cancel` method to cancel
+ * delayed `func` invocations and a `flush` method to immediately invoke them.
+ * Provide `options` to indicate whether `func` should be invoked on the
+ * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
+ * with the last arguments provided to the debounced function. Subsequent
+ * calls to the debounced function return the result of the last `func`
+ * invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
+ * invoked on the trailing edge of the timeout only if the debounced function
+ * is invoked more than once during the `wait` timeout.
+ *
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+ * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+ *
+ * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+ * for details over the differences between `_.debounce` and `_.throttle`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to debounce.
+ * @param {number} [wait=0] The number of milliseconds to delay.
+ * @param {Object} [options={}] The options object.
+ * @param {boolean} [options.leading=false]
+ * Specify invoking on the leading edge of the timeout.
+ * @param {number} [options.maxWait]
+ * The maximum time `func` is allowed to be delayed before it's invoked.
+ * @param {boolean} [options.trailing=true]
+ * Specify invoking on the trailing edge of the timeout.
+ * @returns {Function} Returns the new debounced function.
+ * @example
+ *
+ * // Avoid costly calculations while the window size is in flux.
+ * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+ *
+ * // Invoke `sendMail` when clicked, debouncing subsequent calls.
+ * jQuery(element).on('click', _.debounce(sendMail, 300, {
+ * 'leading': true,
+ * 'trailing': false
+ * }));
+ *
+ * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
+ * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
+ * var source = new EventSource('/stream');
+ * jQuery(source).on('message', debounced);
+ *
+ * // Cancel the trailing debounced invocation.
+ * jQuery(window).on('popstate', debounced.cancel);
+ */
+function debounce(func, wait, options) {
+ var lastArgs,
+ lastThis,
+ maxWait,
+ result,
+ timerId,
+ lastCallTime,
+ lastInvokeTime = 0,
+ leading = false,
+ maxing = false,
+ trailing = true;
+
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT);
+ }
+ wait = toNumber_1(wait) || 0;
+ if (isObject_1(options)) {
+ leading = !!options.leading;
+ maxing = 'maxWait' in options;
+ maxWait = maxing ? nativeMax(toNumber_1(options.maxWait) || 0, wait) : maxWait;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+
+ function invokeFunc(time) {
+ var args = lastArgs,
+ thisArg = lastThis;
+
+ lastArgs = lastThis = undefined;
+ lastInvokeTime = time;
+ result = func.apply(thisArg, args);
+ return result;
+ }
+
+ function leadingEdge(time) {
+ // Reset any `maxWait` timer.
+ lastInvokeTime = time;
+ // Start the timer for the trailing edge.
+ timerId = setTimeout(timerExpired, wait);
+ // Invoke the leading edge.
+ return leading ? invokeFunc(time) : result;
+ }
+
+ function remainingWait(time) {
+ var timeSinceLastCall = time - lastCallTime,
+ timeSinceLastInvoke = time - lastInvokeTime,
+ timeWaiting = wait - timeSinceLastCall;
+
+ return maxing
+ ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
+ : timeWaiting;
+ }
+
+ function shouldInvoke(time) {
+ var timeSinceLastCall = time - lastCallTime,
+ timeSinceLastInvoke = time - lastInvokeTime;
+
+ // Either this is the first call, activity has stopped and we're at the
+ // trailing edge, the system time has gone backwards and we're treating
+ // it as the trailing edge, or we've hit the `maxWait` limit.
+ return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
+ (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
+ }
+
+ function timerExpired() {
+ var time = now_1();
+ if (shouldInvoke(time)) {
+ return trailingEdge(time);
+ }
+ // Restart the timer.
+ timerId = setTimeout(timerExpired, remainingWait(time));
+ }
+
+ function trailingEdge(time) {
+ timerId = undefined;
+
+ // Only invoke if we have `lastArgs` which means `func` has been
+ // debounced at least once.
+ if (trailing && lastArgs) {
+ return invokeFunc(time);
+ }
+ lastArgs = lastThis = undefined;
+ return result;
+ }
+
+ function cancel() {
+ if (timerId !== undefined) {
+ clearTimeout(timerId);
+ }
+ lastInvokeTime = 0;
+ lastArgs = lastCallTime = lastThis = timerId = undefined;
+ }
+
+ function flush() {
+ return timerId === undefined ? result : trailingEdge(now_1());
+ }
+
+ function debounced() {
+ var time = now_1(),
+ isInvoking = shouldInvoke(time);
+
+ lastArgs = arguments;
+ lastThis = this;
+ lastCallTime = time;
+
+ if (isInvoking) {
+ if (timerId === undefined) {
+ return leadingEdge(lastCallTime);
+ }
+ if (maxing) {
+ // Handle invocations in a tight loop.
+ timerId = setTimeout(timerExpired, wait);
+ return invokeFunc(lastCallTime);
+ }
+ }
+ if (timerId === undefined) {
+ timerId = setTimeout(timerExpired, wait);
+ }
+ return result;
+ }
+ debounced.cancel = cancel;
+ debounced.flush = flush;
+ return debounced;
+}
+
+var debounce_1 = debounce;
+
+/** Error message constants. */
+var FUNC_ERROR_TEXT$1 = 'Expected a function';
+
+/**
+ * Creates a throttled function that only invokes `func` at most once per
+ * every `wait` milliseconds. The throttled function comes with a `cancel`
+ * method to cancel delayed `func` invocations and a `flush` method to
+ * immediately invoke them. Provide `options` to indicate whether `func`
+ * should be invoked on the leading and/or trailing edge of the `wait`
+ * timeout. The `func` is invoked with the last arguments provided to the
+ * throttled function. Subsequent calls to the throttled function return the
+ * result of the last `func` invocation.
+ *
+ * **Note:** If `leading` and `trailing` options are `true`, `func` is
+ * invoked on the trailing edge of the timeout only if the throttled function
+ * is invoked more than once during the `wait` timeout.
+ *
+ * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+ * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+ *
+ * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+ * for details over the differences between `_.throttle` and `_.debounce`.
+ *
+ * @static
+ * @memberOf _
+ * @since 0.1.0
+ * @category Function
+ * @param {Function} func The function to throttle.
+ * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
+ * @param {Object} [options={}] The options object.
+ * @param {boolean} [options.leading=true]
+ * Specify invoking on the leading edge of the timeout.
+ * @param {boolean} [options.trailing=true]
+ * Specify invoking on the trailing edge of the timeout.
+ * @returns {Function} Returns the new throttled function.
+ * @example
+ *
+ * // Avoid excessively updating the position while scrolling.
+ * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+ *
+ * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
+ * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
+ * jQuery(element).on('click', throttled);
+ *
+ * // Cancel the trailing throttled invocation.
+ * jQuery(window).on('popstate', throttled.cancel);
+ */
+function throttle(func, wait, options) {
+ var leading = true,
+ trailing = true;
+
+ if (typeof func != 'function') {
+ throw new TypeError(FUNC_ERROR_TEXT$1);
+ }
+ if (isObject_1(options)) {
+ leading = 'leading' in options ? !!options.leading : leading;
+ trailing = 'trailing' in options ? !!options.trailing : trailing;
+ }
+ return debounce_1(func, wait, {
+ 'leading': leading,
+ 'maxWait': wait,
+ 'trailing': trailing
+ });
+}
+
+var throttle_1 = throttle;
+
function camelCaseToDash(str) {
return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
}
@@ -268,47 +810,16 @@ function isNumeric(val) {
return !isNaN(val);
}
-// https://stackoverflow.com/a/27078401
-function throttle(func, wait, options) {
- var context, args, result;
- var timeout = null;
- var previous = 0;
- if (!options) options = {};
+let throttle$1 = throttle_1;
- let later = function () {
- previous = options.leading === false ? 0 : Date.now();
- timeout = null;
- result = func.apply(context, args);
- if (!timeout) context = args = null;
- };
-
- return function () {
- var now = Date.now();
- if (!previous && options.leading === false) previous = now;
- let remaining = wait - (now - previous);
- context = this;
- args = arguments;
- if (remaining <= 0 || remaining > wait) {
- if (timeout) {
- clearTimeout(timeout);
- timeout = null;
- }
- previous = now;
- result = func.apply(context, args);
- if (!timeout) context = args = null;
- } else if (!timeout && options.trailing !== false) {
- timeout = setTimeout(later, remaining);
- }
- return result;
- };
-}
+let debounce$2 = debounce_1;
function promisify(fn, context = null) {
return (...args) => {
return new Promise(resolve => {
setTimeout(() => {
- fn.apply(context, args);
- resolve('done', fn.name);
+ const out = fn.apply(context, args);
+ resolve(out);
}, 0);
});
};
@@ -334,6 +845,7 @@ class DataManager {
this.sortRows = promisify(this.sortRows, this);
this.switchColumn = promisify(this.switchColumn, this);
this.removeColumn = promisify(this.removeColumn, this);
+ this.filterRows = promisify(this.filterRows, this);
}
init(data) {
@@ -715,6 +1227,25 @@ class DataManager {
return column;
}
+ filterRows(keyword, colIndex) {
+ let rowsToHide = [];
+ let rowsToShow = [];
+ const cells = this.rows.map(row => row[colIndex]);
+
+ cells.forEach(cell => {
+ const hay = cell.content.toLowerCase();
+ const needle = (keyword || '').toLowerCase();
+
+ if (!needle || hay.includes(needle)) {
+ rowsToShow.push(cell.rowIndex);
+ } else {
+ rowsToHide.push(cell.rowIndex);
+ }
+ });
+
+ return {rowsToHide, rowsToShow};
+ }
+
getRowCount() {
return this.rowCount;
}
@@ -838,7 +1369,19 @@ class ColumnManager {
if (!$('.data-table-col', this.header)) {
// insert html
- $('thead', this.header).innerHTML = this.rowmanager.getRowHTML(columns, { isHeader: 1 });
+
+ let html = this.rowmanager.getRowHTML(columns, { isHeader: 1 });
+ if (this.options.enableInlineFilters) {
+ html += this.rowmanager.getRowHTML(columns, { isFilter: 1 });
+ }
+
+ $('thead', this.header).innerHTML = html;
+
+ this.$filterRow = $('.data-table-row[data-is-filter]', this.header);
+ // hide filter row immediately, so it doesn't disturb layout
+ $.style(this.$filterRow, {
+ display: 'none'
+ });
} else {
// refresh dom state
const $cols = $.each('.data-table-col', this.header);
@@ -871,6 +1414,7 @@ class ColumnManager {
this.bindDropdown();
this.bindResizeColumn();
this.bindMoveColumn();
+ this.bindFilter();
}
bindDropdown() {
@@ -1072,6 +1616,51 @@ class ColumnManager {
});
}
+ toggleFilter() {
+ this.isFilterShown = this.isFilterShown || false;
+
+ if (this.isFilterShown) {
+ $.style(this.$filterRow, {
+ display: 'none'
+ });
+ } else {
+ $.style(this.$filterRow, {
+ display: ''
+ });
+ }
+
+ this.isFilterShown = !this.isFilterShown;
+ this.style.setBodyStyle();
+ }
+
+ focusFilter(colIndex) {
+ if (!this.isFilterShown) return;
+
+ const $filterInput = $(`[data-col-index="${colIndex}"] .data-table-filter`, this.$filterRow);
+ $filterInput.focus();
+ }
+
+ bindFilter() {
+ const handler = e => {
+ const $filterCell = $.closest('.data-table-col', e.target);
+ const { colIndex } = $.data($filterCell);
+ const keyword = e.target.value;
+
+ this.datamanager.filterRows(keyword, colIndex)
+ .then(({ rowsToHide, rowsToShow }) => {
+ rowsToHide.map(rowIndex => {
+ const $tr = $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
+ $tr.classList.add('hide');
+ });
+ rowsToShow.map(rowIndex => {
+ const $tr = $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
+ $tr.classList.remove('hide');
+ });
+ });
+ };
+ $.on(this.header, 'keydown', '.data-table-filter', debounce$2(handler, 300));
+ }
+
sortRows(colIndex, sortOrder) {
return this.datamanager.sortRows(colIndex, sortOrder);
}
@@ -1103,7 +1692,7 @@ class ColumnManager {
setColumnHeaderWidth(colIndex) {
colIndex = +colIndex;
this.$columnMap = this.$columnMap || [];
- const selector = `[data-col-index="${colIndex}"][data-is-header] .content`;
+ const selector = `.data-table-header [data-col-index="${colIndex}"] .content`;
const { width } = this.getColumn(colIndex);
let $column = this.$columnMap[colIndex];
@@ -1260,6 +1849,14 @@ class CellManager {
this.keyboard.on('esc', () => {
this.deactivateEditing();
});
+
+ this.keyboard.on('ctrl+f', (e) => {
+ const $cell = $.closest('.data-table-col', e.target);
+ let { colIndex } = $.data($cell);
+
+ this.activateFilter(colIndex);
+ return true;
+ });
}
bindKeyboardSelection() {
@@ -1308,7 +1905,7 @@ class CellManager {
this.selectArea($(e.delegatedTarget));
};
- $.on(this.bodyScrollable, 'mousemove', '.data-table-col', throttle(selectArea, 50));
+ $.on(this.bodyScrollable, 'mousemove', '.data-table-col', throttle$1(selectArea, 50));
}
focusCell($cell, { skipClearSelection = 0 } = {}) {
@@ -1614,6 +2211,16 @@ class CellManager {
copyTextToClipboard(values);
}
+ activateFilter(colIndex) {
+ this.columnmanager.toggleFilter();
+ this.columnmanager.focusFilter(colIndex);
+
+ if (!this.columnmanager.isFilterShown) {
+ // put focus back on cell
+ this.$focusedCell.focus();
+ }
+ }
+
updateCell(colIndex, rowIndex, value) {
const cell = this.datamanager.updateCell(colIndex, rowIndex, {
content: value
@@ -1698,11 +2305,12 @@ class CellManager {
}
getCellHTML(cell) {
- const { rowIndex, colIndex, isHeader } = cell;
+ const { rowIndex, colIndex, isHeader, isFilter } = cell;
const dataAttr = makeDataAttributeString({
rowIndex,
colIndex,
- isHeader
+ isHeader,
+ isFilter
});
return `
@@ -1727,7 +2335,12 @@ class CellManager {
const hasDropdown = isHeader && cell.dropdown !== false;
const dropdown = hasDropdown ? `
${getDropdownHTML()}
` : '';
- const contentHTML = (!cell.isHeader && cell.column.format) ? cell.column.format(cell.content) : cell.content;
+ let contentHTML;
+ if (cell.isHeader || cell.isFilter || !cell.column.format) {
+ contentHTML = cell.content;
+ } else {
+ contentHTML = cell.column.format(cell.content);
+ }
return `
@@ -1742,7 +2355,7 @@ class CellManager {
getEditCellHTML() {
return `
-
+
`;
}
@@ -1937,12 +2550,27 @@ class RowManager {
getRowHTML(row, props) {
const dataAttr = makeDataAttributeString(props);
+ if (props.isFilter) {
+ row = row.map(cell => (Object.assign(cell, {
+ content: this.getFilterInput({ colIndex: cell.colIndex }),
+ format: value => value,
+ isFilter: 1,
+ isHeader: undefined,
+ editable: false
+ })));
+ }
+
return `
${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')}
`;
}
+
+ getFilterInput(props) {
+ const dataAttr = makeDataAttributeString(props);
+ return `
`;
+ }
}
class BodyRenderer {
@@ -2063,7 +2691,7 @@ class Style {
bindResizeWindow() {
if (this.options.layout === 'fluid') {
- $.on(window, 'resize', throttle(() => {
+ $.on(window, 'resize', throttle$1(() => {
this.distributeRemainingWidth();
this.refreshColumnWidth();
this.setBodyStyle();
@@ -2135,7 +2763,7 @@ class Style {
}
setupMinWidth() {
- $.each('.data-table-col', this.header).map(col => {
+ $.each('.data-table-col[data-is-header]', this.header).map(col => {
const width = $.style($('.content', col), 'width');
const {
colIndex
@@ -2272,7 +2900,8 @@ const KEYCODES = {
40: 'down',
9: 'tab',
27: 'esc',
- 67: 'c'
+ 67: 'c',
+ 70: 'f'
};
class Keyboard {
@@ -2296,7 +2925,7 @@ class Keyboard {
if (listeners && listeners.length > 0) {
for (let listener of listeners) {
- const preventBubbling = listener();
+ const preventBubbling = listener(e);
if (preventBubbling === undefined || preventBubbling === true) {
e.preventDefault();
}
@@ -2362,7 +2991,8 @@ var DEFAULT_OPTIONS = {
enableLogs: false,
layout: 'fixed', // fixed, fluid
noDataMessage: 'No Data',
- cellHeight: null
+ cellHeight: null,
+ enableInlineFilters: false
};
class DataTable {
@@ -2536,14 +3166,14 @@ var version = "0.0.2";
var description = "A modern datatable library for the web";
var main = "dist/frappe-datatable.cjs.js";
var scripts = {"start":"npm run dev","build":"rollup -c","dev":"rollup -c -w","test":"mocha --compilers js:babel-core/register --colors ./test/*.spec.js","test:watch":"mocha --compilers js:babel-core/register --colors -w ./test/*.spec.js"};
-var devDependencies = {"chai":"3.5.0","cssnano":"^3.10.0","deepmerge":"^2.0.1","eslint":"3.19.0","eslint-loader":"1.7.1","mocha":"3.3.0","postcss-cssnext":"^3.1.0","postcss-nested":"^3.0.0","precss":"^3.1.0","rollup-plugin-json":"^2.3.0","rollup-plugin-postcss":"^1.2.8","rollup-plugin-uglify":"^3.0.0"};
+var devDependencies = {"chai":"3.5.0","cssnano":"^3.10.0","deepmerge":"^2.0.1","eslint":"3.19.0","eslint-loader":"1.7.1","mocha":"3.3.0","postcss-cssnext":"^3.1.0","postcss-nested":"^3.0.0","precss":"^3.1.0","rollup-plugin-commonjs":"^8.3.0","rollup-plugin-json":"^2.3.0","rollup-plugin-node-resolve":"^3.0.3","rollup-plugin-postcss":"^1.2.8","rollup-plugin-uglify":"^3.0.0"};
var repository = {"type":"git","url":"https://github.com/frappe/datatable.git"};
var keywords = ["datatable","data","grid","table"];
var author = "Faris Ansari";
var license = "MIT";
var bugs = {"url":"https://github.com/frappe/datatable/issues"};
var homepage = "https://frappe.github.io/datatable";
-var dependencies = {"clusterize.js":"^0.18.0","sortablejs":"^1.7.0"};
+var dependencies = {"clusterize.js":"^0.18.0","lodash":"^4.17.5","sortablejs":"^1.7.0"};
var packageJson = {
name: name,
version: version,
diff --git a/index.html b/index.html
index 1a2690f..a4c587b 100644
--- a/index.html
+++ b/index.html
@@ -70,6 +70,7 @@
layout: 'fluid',
columns,
data,
+ enableInlineFilters: true,
getEditor(colIndex, rowIndex, value, parent) {
// editing obj only for date field
if (colIndex != 6) return;
diff --git a/package.json b/package.json
index f93bd5e..757f77a 100644
--- a/package.json
+++ b/package.json
@@ -20,7 +20,9 @@
"postcss-cssnext": "^3.1.0",
"postcss-nested": "^3.0.0",
"precss": "^3.1.0",
+ "rollup-plugin-commonjs": "^8.3.0",
"rollup-plugin-json": "^2.3.0",
+ "rollup-plugin-node-resolve": "^3.0.3",
"rollup-plugin-postcss": "^1.2.8",
"rollup-plugin-uglify": "^3.0.0"
},
@@ -42,6 +44,7 @@
"homepage": "https://frappe.github.io/datatable",
"dependencies": {
"clusterize.js": "^0.18.0",
+ "lodash": "^4.17.5",
"sortablejs": "^1.7.0"
}
}
diff --git a/rollup.config.js b/rollup.config.js
index e006303..5aacb6b 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -1,5 +1,7 @@
import json from 'rollup-plugin-json';
// import uglify from 'rollup-plugin-uglify';
+import nodeResolve from 'rollup-plugin-node-resolve';
+import commonjs from 'rollup-plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import nested from 'postcss-nested';
import cssnext from 'postcss-cssnext';
@@ -18,6 +20,8 @@ const dev = {
},
plugins: [
json(),
+ nodeResolve(),
+ commonjs(),
postcss({
extract: 'dist/frappe-datatable.css',
plugins: [
diff --git a/src/cellmanager.js b/src/cellmanager.js
index b03cb31..eeff133 100644
--- a/src/cellmanager.js
+++ b/src/cellmanager.js
@@ -107,6 +107,14 @@ export default class CellManager {
this.keyboard.on('esc', () => {
this.deactivateEditing();
});
+
+ this.keyboard.on('ctrl+f', (e) => {
+ const $cell = $.closest('.data-table-col', e.target);
+ let { colIndex } = $.data($cell);
+
+ this.activateFilter(colIndex);
+ return true;
+ });
}
bindKeyboardSelection() {
@@ -461,6 +469,16 @@ export default class CellManager {
copyTextToClipboard(values);
}
+ activateFilter(colIndex) {
+ this.columnmanager.toggleFilter();
+ this.columnmanager.focusFilter(colIndex);
+
+ if (!this.columnmanager.isFilterShown) {
+ // put focus back on cell
+ this.$focusedCell.focus();
+ }
+ }
+
updateCell(colIndex, rowIndex, value) {
const cell = this.datamanager.updateCell(colIndex, rowIndex, {
content: value
@@ -545,11 +563,12 @@ export default class CellManager {
}
getCellHTML(cell) {
- const { rowIndex, colIndex, isHeader } = cell;
+ const { rowIndex, colIndex, isHeader, isFilter } = cell;
const dataAttr = makeDataAttributeString({
rowIndex,
colIndex,
- isHeader
+ isHeader,
+ isFilter
});
return `
@@ -574,7 +593,12 @@ export default class CellManager {
const hasDropdown = isHeader && cell.dropdown !== false;
const dropdown = hasDropdown ? `
${getDropdownHTML()}
` : '';
- const contentHTML = (!cell.isHeader && cell.column.format) ? cell.column.format(cell.content) : cell.content;
+ let contentHTML;
+ if (cell.isHeader || cell.isFilter || !cell.column.format) {
+ contentHTML = cell.content;
+ } else {
+ contentHTML = cell.column.format(cell.content);
+ }
return `
@@ -589,7 +613,7 @@ export default class CellManager {
getEditCellHTML() {
return `
-
+
`;
}
diff --git a/src/columnmanager.js b/src/columnmanager.js
index 4fc0a1a..c5286b6 100644
--- a/src/columnmanager.js
+++ b/src/columnmanager.js
@@ -1,6 +1,6 @@
import $ from './dom';
import Sortable from 'sortablejs';
-import { getDefault, linkProperties } from './utils';
+import { getDefault, linkProperties, debounce } from './utils';
export default class ColumnManager {
constructor(instance) {
@@ -31,7 +31,19 @@ export default class ColumnManager {
if (!$('.data-table-col', this.header)) {
// insert html
- $('thead', this.header).innerHTML = this.rowmanager.getRowHTML(columns, { isHeader: 1 });
+
+ let html = this.rowmanager.getRowHTML(columns, { isHeader: 1 });
+ if (this.options.enableInlineFilters) {
+ html += this.rowmanager.getRowHTML(columns, { isFilter: 1 });
+ }
+
+ $('thead', this.header).innerHTML = html;
+
+ this.$filterRow = $('.data-table-row[data-is-filter]', this.header);
+ // hide filter row immediately, so it doesn't disturb layout
+ $.style(this.$filterRow, {
+ display: 'none'
+ });
} else {
// refresh dom state
const $cols = $.each('.data-table-col', this.header);
@@ -64,6 +76,7 @@ export default class ColumnManager {
this.bindDropdown();
this.bindResizeColumn();
this.bindMoveColumn();
+ this.bindFilter();
}
bindDropdown() {
@@ -265,6 +278,51 @@ export default class ColumnManager {
});
}
+ toggleFilter() {
+ this.isFilterShown = this.isFilterShown || false;
+
+ if (this.isFilterShown) {
+ $.style(this.$filterRow, {
+ display: 'none'
+ });
+ } else {
+ $.style(this.$filterRow, {
+ display: ''
+ });
+ }
+
+ this.isFilterShown = !this.isFilterShown;
+ this.style.setBodyStyle();
+ }
+
+ focusFilter(colIndex) {
+ if (!this.isFilterShown) return;
+
+ const $filterInput = $(`[data-col-index="${colIndex}"] .data-table-filter`, this.$filterRow);
+ $filterInput.focus();
+ }
+
+ bindFilter() {
+ const handler = e => {
+ const $filterCell = $.closest('.data-table-col', e.target);
+ const { colIndex } = $.data($filterCell);
+ const keyword = e.target.value;
+
+ this.datamanager.filterRows(keyword, colIndex)
+ .then(({ rowsToHide, rowsToShow }) => {
+ rowsToHide.map(rowIndex => {
+ const $tr = $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
+ $tr.classList.add('hide');
+ });
+ rowsToShow.map(rowIndex => {
+ const $tr = $(`.data-table-row[data-row-index="${rowIndex}"]`, this.bodyScrollable);
+ $tr.classList.remove('hide');
+ });
+ });
+ };
+ $.on(this.header, 'keydown', '.data-table-filter', debounce(handler, 300));
+ }
+
sortRows(colIndex, sortOrder) {
return this.datamanager.sortRows(colIndex, sortOrder);
}
@@ -296,7 +354,7 @@ export default class ColumnManager {
setColumnHeaderWidth(colIndex) {
colIndex = +colIndex;
this.$columnMap = this.$columnMap || [];
- const selector = `[data-col-index="${colIndex}"][data-is-header] .content`;
+ const selector = `.data-table-header [data-col-index="${colIndex}"] .content`;
const { width } = this.getColumn(colIndex);
let $column = this.$columnMap[colIndex];
diff --git a/src/datamanager.js b/src/datamanager.js
index 486bd77..8359c1f 100644
--- a/src/datamanager.js
+++ b/src/datamanager.js
@@ -6,6 +6,7 @@ export default class DataManager {
this.sortRows = promisify(this.sortRows, this);
this.switchColumn = promisify(this.switchColumn, this);
this.removeColumn = promisify(this.removeColumn, this);
+ this.filterRows = promisify(this.filterRows, this);
}
init(data) {
@@ -387,6 +388,25 @@ export default class DataManager {
return column;
}
+ filterRows(keyword, colIndex) {
+ let rowsToHide = [];
+ let rowsToShow = [];
+ const cells = this.rows.map(row => row[colIndex]);
+
+ cells.forEach(cell => {
+ const hay = cell.content.toLowerCase();
+ const needle = (keyword || '').toLowerCase();
+
+ if (!needle || hay.includes(needle)) {
+ rowsToShow.push(cell.rowIndex);
+ } else {
+ rowsToHide.push(cell.rowIndex);
+ }
+ });
+
+ return {rowsToHide, rowsToShow};
+ }
+
getRowCount() {
return this.rowCount;
}
diff --git a/src/defaults.js b/src/defaults.js
index e164c1e..f306723 100644
--- a/src/defaults.js
+++ b/src/defaults.js
@@ -46,5 +46,6 @@ export default {
enableLogs: false,
layout: 'fixed', // fixed, fluid
noDataMessage: 'No Data',
- cellHeight: null
+ cellHeight: null,
+ enableInlineFilters: false
};
diff --git a/src/keyboard.js b/src/keyboard.js
index 099b8dc..abd9e96 100644
--- a/src/keyboard.js
+++ b/src/keyboard.js
@@ -12,7 +12,8 @@ const KEYCODES = {
40: 'down',
9: 'tab',
27: 'esc',
- 67: 'c'
+ 67: 'c',
+ 70: 'f'
};
export default class Keyboard {
@@ -36,7 +37,7 @@ export default class Keyboard {
if (listeners && listeners.length > 0) {
for (let listener of listeners) {
- const preventBubbling = listener();
+ const preventBubbling = listener(e);
if (preventBubbling === undefined || preventBubbling === true) {
e.preventDefault();
}
diff --git a/src/rowmanager.js b/src/rowmanager.js
index 1e6fc86..0ab1a51 100644
--- a/src/rowmanager.js
+++ b/src/rowmanager.js
@@ -187,10 +187,25 @@ export default class RowManager {
getRowHTML(row, props) {
const dataAttr = makeDataAttributeString(props);
+ if (props.isFilter) {
+ row = row.map(cell => (Object.assign(cell, {
+ content: this.getFilterInput({ colIndex: cell.colIndex }),
+ format: value => value,
+ isFilter: 1,
+ isHeader: undefined,
+ editable: false
+ })));
+ }
+
return `
${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')}
`;
}
+
+ getFilterInput(props) {
+ const dataAttr = makeDataAttributeString(props);
+ return `
`;
+ }
}
diff --git a/src/style.css b/src/style.css
index 121e544..9ed0c29 100644
--- a/src/style.css
+++ b/src/style.css
@@ -27,6 +27,12 @@
padding: 0;
}
+ .input-style {
+ outline: none;
+ width: 100%;
+ border: none;
+ }
+
*, *:focus {
outline: none;
border-radius: 0px;
@@ -80,6 +86,10 @@
background: palevioletred;
opacity: 0.5;
}
+
+ .hide {
+ display: none;
+ }
}
.body-scrollable {
@@ -188,17 +198,10 @@
.edit-cell {
display: none;
- // position: absolute;
padding: var(--spacer-2);
background: #fff;
z-index: 1;
height: 100%;
-
- input {
- outline: none;
- width: 100%;
- border: none;
- }
}
&.selected .content {
diff --git a/src/style.js b/src/style.js
index f0afea9..fdea46a 100644
--- a/src/style.js
+++ b/src/style.js
@@ -99,7 +99,7 @@ export default class Style {
}
setupMinWidth() {
- $.each('.data-table-col', this.header).map(col => {
+ $.each('.data-table-col[data-is-header]', this.header).map(col => {
const width = $.style($('.content', col), 'width');
const {
colIndex
diff --git a/src/utils.js b/src/utils.js
index 83f91b8..e2d2be5 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,3 +1,6 @@
+import _throttle from 'lodash/throttle';
+import _debounce from 'lodash/debounce';
+
export function camelCaseToDash(str) {
return str.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`);
}
@@ -148,47 +151,16 @@ export function isNumeric(val) {
return !isNaN(val);
}
-// https://stackoverflow.com/a/27078401
-export function throttle(func, wait, options) {
- var context, args, result;
- var timeout = null;
- var previous = 0;
- if (!options) options = {};
+export let throttle = _throttle;
- let later = function () {
- previous = options.leading === false ? 0 : Date.now();
- timeout = null;
- result = func.apply(context, args);
- if (!timeout) context = args = null;
- };
-
- return function () {
- var now = Date.now();
- if (!previous && options.leading === false) previous = now;
- let remaining = wait - (now - previous);
- context = this;
- args = arguments;
- if (remaining <= 0 || remaining > wait) {
- if (timeout) {
- clearTimeout(timeout);
- timeout = null;
- }
- previous = now;
- result = func.apply(context, args);
- if (!timeout) context = args = null;
- } else if (!timeout && options.trailing !== false) {
- timeout = setTimeout(later, remaining);
- }
- return result;
- };
-};
+export let debounce = _debounce;
export function promisify(fn, context = null) {
return (...args) => {
return new Promise(resolve => {
setTimeout(() => {
- fn.apply(context, args);
- resolve('done', fn.name);
+ const out = fn.apply(context, args);
+ resolve(out);
}, 0);
});
};
diff --git a/yarn.lock b/yarn.lock
index 4e90ed7..6f874e1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -192,6 +192,10 @@ browserslist@^3.1:
caniuse-lite "^1.0.30000808"
electron-to-chromium "^1.3.33"
+builtin-modules@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
+
caller-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
@@ -741,6 +745,10 @@ estree-walker@^0.3.0:
version "0.3.1"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.3.1.tgz#e6b1a51cf7292524e7237c312e5fe6660c1ce1aa"
+estree-walker@^0.5.0:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.1.tgz#64fc375053abc6f57d73e9bd2f004644ad3c5854"
+
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
@@ -1073,6 +1081,10 @@ is-glob@^2.0.0, is-glob@^2.0.1:
dependencies:
is-extglob "^1.0.0"
+is-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
+
is-my-json-valid@^2.10.0:
version "2.17.1"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471"
@@ -1327,10 +1339,20 @@ lodash@^4.0.0, lodash@^4.3.0:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
+lodash@^4.17.5:
+ version "4.17.5"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
+
macaddress@^0.2.8:
version "0.2.8"
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
+magic-string@^0.22.4:
+ version "0.22.4"
+ resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.4.tgz#31039b4e40366395618c1d6cf8193c53917475ff"
+ dependencies:
+ vlq "^0.2.1"
+
math-expression-evaluator@^1.2.14:
version "1.2.17"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
@@ -2341,7 +2363,7 @@ resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
-resolve@^1.1.6:
+resolve@^1.1.6, resolve@^1.4.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
dependencies:
@@ -2368,12 +2390,30 @@ rimraf@^2.2.8, rimraf@^2.6.1:
dependencies:
glob "^7.0.5"
+rollup-plugin-commonjs@^8.3.0:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-8.3.0.tgz#91b4ba18f340951e39ed7b1901f377a80ab3f9c3"
+ dependencies:
+ acorn "^5.2.1"
+ estree-walker "^0.5.0"
+ magic-string "^0.22.4"
+ resolve "^1.4.0"
+ rollup-pluginutils "^2.0.1"
+
rollup-plugin-json@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-json/-/rollup-plugin-json-2.3.0.tgz#3c07a452c1b5391be28006fbfff3644056ce0add"
dependencies:
rollup-pluginutils "^2.0.1"
+rollup-plugin-node-resolve@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.0.3.tgz#8f57b253edd00e5b0ad0aed7b7e9cf5982e98fa4"
+ dependencies:
+ builtin-modules "^1.1.0"
+ is-module "^1.0.0"
+ resolve "^1.1.6"
+
rollup-plugin-postcss@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rollup-plugin-postcss/-/rollup-plugin-postcss-1.2.8.tgz#3389f4235521cd6a019ab6316cadccb0046c11f3"
@@ -2652,6 +2692,10 @@ viewport-dimensions@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/viewport-dimensions/-/viewport-dimensions-0.2.0.tgz#de740747db5387fd1725f5175e91bac76afdf36c"
+vlq@^0.2.1:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
+
whet.extend@~0.9.9:
version "0.9.9"
resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"