UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

1,168 lines (1,010 loc) 75.8 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); require('./kendo.datepicker.js'); require('./kendo.numerictextbox.js'); require('./kendo.dropdownlist.js'); require('./kendo.buttongroup.js'); require('./kendo.binder.js'); require('./kendo.html.button.js'); require('./kendo.icons.js'); require('./kendo.pane.js'); require('./kendo.calendar.js'); require('./kendo.core.js'); require('./kendo.licensing.js'); require('@progress/kendo-licensing'); require('./kendo.selectable.js'); require('./kendo.userevents.js'); require('./kendo.html.icon.js'); require('./kendo.html.base.js'); require('@progress/kendo-svg-icons'); require('./kendo.popup.js'); require('./kendo.dateinput.js'); require('./kendo.label.js'); require('./kendo.floatinglabel.js'); require('@progress/kendo-dateinputs-common'); require('./kendo.actionsheet.js'); require('./prefix-suffix-containers-BmDm564f.js'); require('./kendo.list.js'); require('./kendo.data.js'); require('./kendo.data.odata.js'); require('./kendo.data.xml.js'); require('./dropdowns-loader-Bc4IELFi.js'); require('./kendo.mobile.scroller.js'); require('./kendo.fx.js'); require('./kendo.draganddrop.js'); require('./kendo.virtuallist.js'); require('./valueMapper-q_OtZ-Tj.js'); require('./kendo.togglebutton.js'); require('./kendo.button.js'); require('./kendo.badge.js'); require('./kendo.view.js'); const __meta__ = { id: "filtermenu", name: "Filtering Menu", category: "framework", depends: [ "datepicker", "numerictextbox", "dropdownlist", "buttongroup", "binder", "html.button", "icons" ], advanced: true }; (function($, undefined$1) { var kendo = window.kendo, ui = kendo.ui, support = kendo.support, encode = kendo.htmlEncode, AUTOCOMPLETEVALUE = support.browser.chrome ? "disabled" : "off", POPUP = "kendoPopup", INIT = "init", OPEN = "open", REFRESH = "refresh", CHANGE = "change", NS = ".kendoFilterMenu", COLUMN_HEADER_SELECTOR = ".k-table-th", EQ = "Is equal to", NEQ = "Is not equal to", roles = { "number": "numerictextbox", "date": "datepicker" }, mobileRoles = { "string": "text", "number": "number", "date": "date" }, isFunction = kendo.isFunction, Widget = ui.Widget; var actionsFilterButtonsContainer = ({ actionsCssClass, messages }) => `<div class="k-actions-stretched ${actionsCssClass ? actionsCssClass : "k-actions"}">` + kendo.html.renderButton(`<button title="${messages.filter}">${encode(messages.filter)}</button>`, { type: "submit", themeColor: "primary", icon: "filter" }) + kendo.html.renderButton(`<button title="${messages.clear}">${encode(messages.clear)}</button>`, { type: "reset", icon: "filter-clear" }) + '</div>'; var booleanTemplate = ({ field, format, ns, messages, extra, operators, type, role, values, componentType }) => '<div class="k-filter-menu-container">' + `<div class="k-filter-help-text">${encode(messages.info)}</div>` + '<label>' + `<input type="radio" data-${ns}bind="checked: filters[0].value" value="true" name="filters[0].value"/>` + `${encode(messages.isTrue)}` + '</label>' + '<label>' + `<input type="radio" data-${ns}bind="checked: filters[0].value" value="false" name="filters[0].value"/>` + `${encode(messages.isFalse)}` + '</label>' + actionsFilterButtonsContainer({ messages }) + '</div>'; var modernBooleanTemplate = ({ field, format, ns, messages, extra, operators, type, role, values, componentType }) => { var inputIdForTrue = kendo.guid(), inputIdForFalse = kendo.guid(); return '<div class="k-filter-menu-container">' + '<div>' + '<ul class="k-radio-list k-reset">' + '<li>' + `<input type="radio" class="k-radio k-radio-md" id="${inputIdForTrue}" data-${ns}bind="checked: filters[0].value" value="true" name="filters[0].value" />` + `<label class="k-radio-label" for="${inputIdForTrue}">${encode(messages.isTrue)}</label>` + '</li>' + '<li>' + `<input type="radio" class="k-radio k-radio-md" id="${inputIdForFalse}" data-${ns}bind="checked: filters[0].value" value="false" name="filters[0].value" />` + `<label class="k-radio-label" for="${inputIdForFalse}">${encode(messages.isFalse)}</label>` + '</li>' + '</ul>' + actionsFilterButtonsContainer({ actionsCssClass: "k-columnmenu-actions", messages }) + '</div>' + '</div>'; }; var customBooleanTemplate = ({ field, format, ns, messages, extra, operators, type, role, values, componentType }) => '<div class="k-filter-menu-container">' + `<div class="k-filter-help-text">${encode(messages.info)}</div>` + '<label>' + `<span class="k-textbox k-input k-input-md k-rounded-md k-input-solid"><input class="k-input-inner" data-${ns}bind="value: filters[0].value" name="filters[0].value"/></span>` + '</label>' + actionsFilterButtonsContainer({ messages }) + '</div>'; var logicTemplate = ({ ns, messages, componentType }) => (componentType === "modern" ? `<ul data-${ns}role="buttongroup" data-bind="events: { select: onLogicChange }">` + `<li data-${ns}value="and">${encode(messages.and)}</li>` + `<li data-${ns}value="or">${encode(messages.or)}</li>` + '</ul>' : `<select title="${messages.logic}" class="k-filter-and" data-${ns}bind="value: logic" data-${ns}role="dropdownlist">` + `<option value="and">${encode(messages.and)}</option>` + `<option value="or">${encode(messages.or)}</option>` + '</select>' ); var defaultTemplate = ({ field, format, ns, messages, extra, operators, type, role, values, componentType }) => '<div class="k-filter-menu-container">' + (componentType === "classic" ? `<div class="k-filter-help-text">${encode(messages.info)}</div>` : '') + `<select title="${messages.operator}" data-${ns}bind="value: filters[0].operator" data-${ns}role="dropdownlist">` + `${Object.keys(operators || {}).map((op) => `<option value="${op}">${operators[op]}</option>` )}` + '</select>' + (values ? `<select title="${messages.value}" data-${ns}bind="value:filters[0].value" data-${ns}text-field="text" data-${ns}value-field="value" data-${ns}source='${kendo.stringify(values).replace(/\'/g,"&#39;")}' data-${ns}role="dropdownlist" data-${ns}option-label="${messages.selectValue}" data-${ns}value-primitive="true">` + '</select>' : `<input title="${messages.value}" data-${ns}bind="value:filters[0].value" class="k-input-inner" type="text" ${role ? `data-${ns}role="${role}"` : ""} />` ) + (extra ? logicTemplate({ ns, messages, componentType }) + `<select title="${messages.additionalOperator}" data-${ns}bind="value: filters[1].operator" data-${ns}role="dropdownlist">` + `${Object.keys(operators || {}).map((op) => `<option value="${op}">${encode(operators[op])}</option>` )}` + '</select>' + (values ? `<select title="${messages.additionalValue}" data-${ns}bind="value:filters[1].value" data-${ns}text-field="text" data-${ns}value-field="value" data-${ns}source='${kendo.stringify(values).replace(/\'/g,"&#39;")}' data-${ns}role="dropdownlist" data-${ns}option-label="${messages.selectValue}" data-${ns}value-primitive="true">` + '</select>' : `<input title="${messages.additionalValue}" data-${ns}bind="value: filters[1].value" class="k-input-inner" type="text" ${role ? `data-${ns}role="${role}"` : ""}/>` ) : '') + actionsFilterButtonsContainer({ messages }) + '</div>'; var defaultMobileTemplate = ({ field, title, format, ns, messages, extra, operators, filterMenuGuid, type, role, inputType, values }) => `<div data-${ns}role="view" class="k-grid-filter-menu">` + `<div data-${ns}role="header" class="k-appbar k-appbar-primary">` + kendo.html.renderButton(`<button class="k-header-cancel" title="${messages.cancel}" aria-label="${messages.cancel}"></button>`, { icon: "chevron-left", fillMode: "flat" }) + `<span class="k-spacer"></span>` + `<span>${encode(messages.filter)} ${encode(messages.into)} ${encode(title)}</span>` + `<span class="k-spacer"></span>` + kendo.html.renderButton(`<button class="k-header-done" title="${messages.done}" aria-label="${messages.done}"></button>`, { icon: "check", fillMode: "flat" }) + '</div>' + `<form title="${messages.title}" class="k-filter-menu">` + '<ul class="k-reset">' + '<li>' + `<span class="k-list-title k-filter-help-text">${encode(messages.info)}</span>` + '<ul class="k-listgroup k-listgroup-flush">' + '<li class="k-item k-listgroup-item">' + '<label class="k-listgroup-form-row k-label">' + `<span class="k-listgroup-form-field-label k-filter-operator-text">${messages.operator}</span>` + '<span class="k-listgroup-form-field-wrapper">' + `<select id="operator_${filterMenuGuid}" title="${messages.operator}" class="k-filter-operator" data-${ns}bind="value: filters[0].operator" autocomplete="${AUTOCOMPLETEVALUE}" >` + `${Object.keys(operators || {}).map((op) => `<option value="${op}">${encode(operators[op])}</option>` )}` + '</select>' + '</span>' + '</label>' + '</li>' + '<li class="k-item k-listgroup-item">' + '<label class="k-listgroup-form-row k-label">' + `<span class="k-listgroup-form-field-label k-filter-input-text">${messages.value}</span>` + '<span class="k-listgroup-form-field-wrapper">' + (values ? `<select id="value_${filterMenuGuid}" title="${messages.value}" data-${ns}bind="value:filters[0].value" autocomplete="${AUTOCOMPLETEVALUE}" >` + `<option value="">${messages.selectValue}</option>` + `${Object.keys(values || {}).map((val) => `<option value="${values[val].value}">${encode(values[val].text)}</option>` )}` + '</select>' : `<input id="value_${filterMenuGuid}" title="${messages.value}" data-${ns}bind="value:filters[0].value" class="k-value-input" type="${inputType}" autocomplete="${AUTOCOMPLETEVALUE}" />` ) + '</span>' + '</label>' + '</li>' + '</ul>' + (extra ? '<ul class="k-listgroup k-listgroup-flush">' + '<li class="k-item k-listgroup-item">' + '<label class="k-listgroup-form-row k-label">' + `<span class="k-listgroup-form-field-label k-filter-logic-and-text">${messages.and}</span>` + '<span class="k-listgroup-form-field-wrapper">' + `<input id="and_${filterMenuGuid}" title="${messages.and}" type="radio" name="logic"data-${ns}bind="checked: logic" value="and" autocomplete="${AUTOCOMPLETEVALUE}" />` + '</span>' + '</label>' + '</li>' + '<li class="k-item k-listgroup-item">' + '<label class="k-listgroup-form-row k-label">' + `<span class="k-listgroup-form-field-label k-filter-logic-or-text">${messages.or}</span>` + '<span class="k-listgroup-form-field-wrapper">' + `<input id="or_${filterMenuGuid}" title="${messages.or}" type="radio" name="logic" data-${ns}bind="checked: logic" value="or" autocomplete="${AUTOCOMPLETEVALUE}" />` + '</span>' + '</label>' + '</li>' + '</ul>' + '<ul class="k-listgroup k-listgroup-flush">' + '<li class="k-item k-listgroup-item">' + '<label class="k-listgroup-form-row k-label">' + `<span class="k-listgroup-form-field-label k-filter-operator-text">${messages.additionalOperator}</span>` + '<span class="k-listgroup-form-field-wrapper">' + `<select id="additionalOperator_${filterMenuGuid}" title="${messages.additionalOperator}" class="k-filter-operator" data-${ns}bind="value: filters[1].operator" autocomplete="${AUTOCOMPLETEVALUE}" >` + `${Object.keys(operators || {}).map((op) => `<option value="${op}">${operators[op]}</option>` )}` + '</select>' + '</span>' + '</label>' + '</li>' + '<li class="k-item k-listgroup-item">' + '<label class="k-listgroup-form-row k-label">' + `<span class="k-listgroup-form-field-label k-filter-input-text">${messages.additionalValue}</span>` + '<span class="k-listgroup-form-field-wrapper">' + (values ? `<select id="additionalValue_${filterMenuGuid}" title="${messages.additionalValue}" data-${ns}bind="value:filters[1].value" autocomplete="${AUTOCOMPLETEVALUE}" >` + `<option value="">${messages.selectValue}</option>` + `${Object.keys(values || {}).map((val) => `<option value="${values[val].value}">${encode(values[val].text)}</option>` )}` + '</select>' : `<input id="additionalValue_${filterMenuGuid}" title="${messages.additionalValue}" data-${ns}bind="value:filters[1].value" class="k-value-input" type="${inputType}" autocomplete="${AUTOCOMPLETEVALUE}" />` ) + '</span>' + '</label>' + '</li>' + '</ul>' : '') + '</li>' + '<li class="k-item k-clear-wrap">' + '<span class="k-list-title">&nbsp;</span>' + '<ul class="k-listgroup k-listgroup-flush">' + '<li class="k-listgroup-item">' + `<span class="k-link k-label k-clear" title="${messages.clear}" aria-label="${messages.clear}">` + `${encode(messages.clear)}` + '</span>' + '</li>' + '</ul>' + '</li>' + '</ul>' + '</form>' + '</div>'; var booleanMobileTemplate = ({ field, title, format, ns, messages, extra, operators, filterMenuGuid, type, role, inputType, values }) => `<div data-${ns}role="view" class="k-grid-filter-menu">` + `<div data-${ns}role="header" class="k-appbar k-appbar-primary">` + kendo.html.renderButton(`<button class="k-header-cancel" title="${messages.cancel}" aria-label="${messages.cancel}"></button>`, { icon: "chevron-left", fillMode: "flat" }) + `<span class="k-spacer"></span>` + `<span>${encode(messages.filter)} ${encode(messages.into)} ${encode(title)}</span>` + `<span class="k-spacer"></span>` + kendo.html.renderButton(`<button class="k-header-done" title="${messages.done}" aria-label="${messages.done}"></button>`, { icon: "check", fillMode: "flat" }) + '</div>' + `<form title="${messages.title}" class="k-filter-menu">` + '<ul class="k-reset">' + '<li>' + `<span class="k-list-title k-filter-help-text">${encode(messages.info)}</span>` + '<ul class="k-listgroup k-listgroup-flush k-multicheck-bool-wrap">' + '<li class="k-item k-listgroup-item">' + '<label class="k-listgroup-form-row k-label">' + `<span class="k-listgroup-form-field-label k-item-title">${encode(messages.isTrue)}</span>` + '<span class="k-listgroup-form-field-wrapper"></span>' + `<input id="true_${filterMenuGuid}" title="${messages.isTrue}" type="radio" data-${ns}bind="checked: filters[0].value" value="true" name="filters[0].value" autocomplete="${AUTOCOMPLETEVALUE}" />` + '</span>' + '</label>' + '</li>' + '<li class="k-item k-listgroup-item">' + '<label class="k-listgroup-form-row k-label">' + `<span for="false_${filterMenuGuid}" class="k-listgroup-form-field-label k-item-title">${encode(messages.isFalse)}</span>` + '<span class="k-listgroup-form-field-wrapper">' + `<input id="false_${filterMenuGuid}" title="${messages.isFalse}" type="radio" data-${ns}bind="checked: filters[0].value" value="false" name="filters[0].value" autocomplete="${AUTOCOMPLETEVALUE}" />` + '</span>' + '</label>' + '</li>' + '</ul>' + '</li>' + '<li class="k-item k-clear-wrap">' + '<span class="k-list-title">&nbsp;</span>' + '<ul class="k-listgroup k-listgroup-flush">' + '<li class="k-listgroup-item">' + `<span class="k-link k-label k-clear" title="${messages.clear}" aria-label="${messages.clear}">` + `${encode(messages.clear)}` + '</span>' + '</li>' + '</ul>' + '</li>' + '</ul>' + '</form>' + '</div>'; function removeFiltersForField(expression, field) { if (expression.filters) { expression.filters = $.grep(expression.filters, function(filter) { removeFiltersForField(filter, field); if (filter.filters) { return filter.filters.length; } else { return filter.field != field; } }); } } function convertItems(items) { var idx, length, item, value, text, result; if (items && items.length) { result = []; for (idx = 0, length = items.length; idx < length; idx++) { item = items[idx]; text = item.text !== "" ? item.text || item.value || item : item.text; value = item.value == null ? (item.text || item) : item.value; result[idx] = { text: text, value: value }; } } return result; } function clearFilter(filters, field) { return $.grep(filters, function(expr) { if (expr.filters) { expr.filters = $.grep(expr.filters, function(nested) { return nested.field != field; }); return expr.filters.length; } return expr.field != field; }); } var FilterMenu = Widget.extend({ init: function(element, options) { var that = this, type = "string", operators, initial, field, columnHeader; options = options || {}; options.componentType = options.componentType || "classic"; Widget.fn.init.call(that, element, options); operators = that.operators = options.operators || {}; element = that.element; options = that.options; that.dataSource = DataSource.create(options.dataSource); that.field = options.field || element.attr(kendo.attr("field")); columnHeader = $(element.closest(COLUMN_HEADER_SELECTOR)); if (columnHeader.length) { that.appendTo = columnHeader.find(options.appendTo); } else { that.appendTo = $(options.appendTo); } that.link = that._createLink() || $(); that.model = that.dataSource.reader.model; that._parse = function(value) { return value != null ? (value + "") : value; }; if (that.model && that.model.fields) { field = that.model.fields[that.field]; if (field) { type = field.type || "string"; if (field.parse) { that._parse = field.parse.bind(field); } } } if (options.values) { type = "enums"; } that.type = type; operators = operators[type] || options.operators[type]; for (initial in operators) { // get the first operator break; } that._defaultFilter = function(isExtra) { const defaultFilterModel = { field: that.field, operator: initial || "eq", value: "" }; if (!that.form) { return defaultFilterModel; } const fromChildren = that.form.children(); const targetElement = isExtra ? fromChildren.last() : fromChildren.first(); const widget = kendo.widgetInstance(targetElement.find("input")); if (widget) { return { field: that.field, operator: initial || "eq", value: widget.value() }; } return defaultFilterModel; }; that._refreshHandler = that.refresh.bind(that); that.dataSource.bind(CHANGE, that._refreshHandler); if (options.appendToElement) { // force creation if used in column menu that._init(); } else { that.refresh(); //refresh if DataSource is fitered before menu is created } }, _init: function() { var that = this, ui = that.options.ui, setUI = isFunction(ui), attrRole = kendo.attr("role"), role; that.pane = that.options.pane; if (that.pane) { that._isMobile = true; } if (!setUI) { role = ui || roles[that.type]; } if (that._isMobile) { that._createMobileForm(role); } else { that._createForm(role); } that.form .on("submit" + NS, that._submit.bind(that)) .on("reset" + NS, that._reset.bind(that)); if (setUI) { that.form.find(".k-input-inner") .removeClass("k-input-inner") .each(function() { ui($(this)); }); } else { that.form .find(".k-input-inner[" + attrRole + "]") .removeClass("k-input-inner"); that.form .find(".k-input-inner:not([data-role]):not(.k-numerictextbox>.k-input-inner)") .wrap("<span class='k-textbox k-input k-input-md k-rounded-md k-input-solid'></span>"); } that.refresh(); that.trigger(INIT, { field: that.field, container: that.form }); if (that.options.cycleForm) { kendo.cycleForm(that.form); } }, _createForm: function(role) { var that = this, options = that.options, operators = that.operators || {}, type = that.type; operators = operators[type] || options.operators[type]; that.form = $('<form title="' + encode(that.options.messages.title) + '" class="k-filter-menu"/>') .html(kendo.template(that._getTemplate())({ field: that.field, format: options.format, ns: kendo.ns, messages: options.messages, extra: options.extra, operators: operators, type: type, role: role, values: convertItems(options.values), componentType: that.options.componentType })); if (!options.appendToElement) { that.popup = that.form[POPUP]({ anchor: that.link, copyAnchorStyles: false, open: that._open.bind(that), activate: that._activate.bind(that), close: function() { if (that.options.closeCallback) { that.options.closeCallback(that.element); } } }).data(POPUP); } else { that.element.append(that.form); that.popup = that.element.closest(".k-column-menu.k-popup").data(POPUP); } that.form .on("keydown" + NS, that._keydown.bind(that)); }, _getTemplate: function() { var that = this, hasCustomTemplate = isFunction(that.options.ui); if (that.type === 'boolean') { if (hasCustomTemplate) { return customBooleanTemplate; } else if (that.options.componentType === 'modern') { return modernBooleanTemplate; } else { return booleanTemplate; } } else { return defaultTemplate; } }, _createMobileForm: function(role) { var that = this, options = that.options, operators = that.operators || {}, filterMenuGuid = kendo.guid(), type = that.type; operators = operators[type] || options.operators[type]; that.form = $("<div />") .html(kendo.template(type === "boolean" ? booleanMobileTemplate : defaultMobileTemplate)({ field: that.field, title: options.title || that.field, format: options.format, ns: kendo.ns, messages: options.messages, extra: options.extra, operators: operators, filterMenuGuid: filterMenuGuid, type: type, role: role, inputType: mobileRoles[type], values: convertItems(options.values) })); that.view = that.pane.append(that.form.html()); that.form = that.view.element.find("form"); that.view.element .on("click", ".k-header-done", function(e) { that.form.submit(); e.preventDefault(); }) .on("click", ".k-header-cancel", function(e) { that._closeForm(); e.preventDefault(); }) .on("click", ".k-clear", function(e) { that._mobileClear(); e.preventDefault(); }); that.view.bind("showStart", function() { that.refresh(); }); that.view.bind("transitionEnd", function(e) { if (e.type === "show") { that.trigger(OPEN, { field: that.field, container: that.form }); } }); }, _createLink: function() { var that = this, element = that.element, appendTarget = that.appendTo.length ? element.find(that.appendTo) : element, options = that.options, title = kendo.format(options.messages.buttonTitle, that.options.title || that.field), link; if (options.appendToElement) { return; } link = element.addClass("k-filterable").find(".k-grid-filter-menu"); if (!link[0]) { link = appendTarget .append('<a class="k-grid-filter-menu k-grid-header-menu" href="#" aria-hidden="true" title="' + title + '" >' + kendo.ui.icon("filter") + '</a>') .find(".k-grid-filter-menu"); } link.attr("tabindex", -1) .on("click" + NS, that._click.bind(that)); return link; }, refresh: function() { var that = this, expression = that.dataSource.filter() || { filters: [], logic: "and" }; var defaultFilters = [ that._defaultFilter() ]; var defaultOperator = that._defaultFilter().operator; if (that.options.extra || (defaultOperator !== "isnull" && defaultOperator !== "isnullorempty" && defaultOperator !== "isnotnullorempty" && defaultOperator !== "isnotnull" && defaultOperator !== "isempty" && defaultOperator !== "isnotempty")) { defaultFilters.push(that._defaultFilter(true)); } that.filterModel = kendo.observable({ logic: "and", filters: defaultFilters }); if (that.form) { //NOTE: binding the form element directly causes weird error in IE when grid is bound through MVVM and column is sorted kendo.bind(that.form.children().first(), that.filterModel); if (that.options.componentType === "modern" && that.options.extra && that.type !== "boolean" && !that._isMobile) { that.filterModel.bind("change", function() { var roleAttribute = kendo.attr("role"); var buttongroup = that.form.find("[" + roleAttribute + "='buttongroup']").data('kendoButtonGroup'); var index = this.logic === "and" ? 0 : 1; buttongroup.select(buttongroup.element.children().eq(index)); }); that.filterModel.set("onLogicChange",that._logicChangeHandler); } } if (that._bind(expression)) { that.link.addClass("k-active"); } else { that.link.removeClass("k-active"); } }, _logicChangeHandler: function(e) { var valueAttribute = kendo.attr('value'); var logic = e.sender.current().attr(valueAttribute); this.set('logic', logic); }, destroy: function() { var that = this; Widget.fn.destroy.call(that); if (that.form) { kendo.unbind(that.form); kendo.destroy(that.form); that.form.off(NS); if (that.popup) { that.popup.destroy(); that.popup = null; } that.form = null; } if (that.view) { that.view.purge(); that.view = null; } that.link.off(NS); if (that._refreshHandler) { that.dataSource.unbind(CHANGE, that._refreshHandler); that.dataSource = null; } that.element = that.link = that._refreshHandler = that.filterModel = null; }, _bind: function(expression) { var that = this, filters = expression.filters, idx, length, found = false, current = 0, filterModel = that.filterModel, currentFilter, filter; for (idx = 0, length = filters.length; idx < length; idx++) { filter = filters[idx]; if (filter.field == that.field) { filterModel.set("logic", expression.logic); currentFilter = filterModel.filters[current]; if (!currentFilter) { filterModel.filters.push({ field: that.field }); currentFilter = filterModel.filters[current]; } currentFilter.set("value", that._parse(filter.value)); currentFilter.set("operator", filter.operator); current++; found = true; } else if (filter.filters) { found = found || that._bind(filter); } } return found; }, _stripFilters: function(filters) { return $.grep(filters, function(filter) { return (filter.value !== "" && filter.value != null) || (filter.operator === "isnull" || filter.operator === "isnotnull" || filter.operator === "isempty" || filter.operator === "isnotempty" || filter.operator == "isnullorempty" || filter.operator == "isnotnullorempty"); }); }, _merge: function(expression) { var that = this, logic = expression.logic || "and", filters = this._stripFilters(expression.filters), filter, result = that.dataSource.filter() || { filters: [], logic: "and" }, idx, length; removeFiltersForField(result, that.field); for (idx = 0, length = filters.length; idx < length; idx++) { filter = filters[idx]; filter.value = that._parse(filter.value); } if (filters.length) { if (result.filters.length) { expression.filters = filters; if (result.logic !== "and") { result.filters = [ { logic: result.logic, filters: result.filters }]; result.logic = "and"; } if (filters.length > 1) { result.filters.push(expression); } else { result.filters.push(filters[0]); } } else { result.filters = filters; result.logic = logic; } } return result; }, filter: function(expression) { var filters = this._stripFilters(expression.filters); if (filters.length && this.trigger("change", { filter: { logic: expression.logic, filters: filters }, field: this.field })) { return; } expression = this._merge(expression); if (expression.filters.length) { this.dataSource.filter(expression); } }, clear: function(expression) { var that = this; expression = expression || $.extend(true, {}, { filters: [] }, that.dataSource.filter()) || { filters: [] }; if (this.trigger("change", { filter: null, field: that.field })) { return; } that._removeFilter(expression); }, _mobileClear: function() { var that = this; var viewElement = that.view.element; if (that.type === "boolean") { var booleanRadioButton = viewElement.find("[type='radio']:checked"); var booleanRadioButtonValue = booleanRadioButton.val(); booleanRadioButton.val(""); booleanRadioButton.trigger("change"); booleanRadioButton.val(booleanRadioButtonValue); booleanRadioButton.prop("checked", false); } else { var operatorSelects = viewElement.find("select"); operatorSelects.each(function(i, e) { var input = $(e); input.val(input.find("option").first().val()); input.trigger("change"); }); if (that.type === "string" || that.type === "date" || that.type === "number") { var valueInputs = viewElement.find(".k-value-input"); valueInputs.each(function(i, e) { var input = $(e); input.val(""); input.trigger("change"); }); } if (that.options.extra) { var andLogicRadio = viewElement.find("[name=logic]").first(); andLogicRadio.prop("checked", true); andLogicRadio.trigger("change"); } } }, _removeFilter: function(expression) { var that = this; expression.filters = $.grep(expression.filters, function(filter) { if (filter.filters) { filter.filters = clearFilter(filter.filters, that.field); return filter.filters.length; } return filter.field != that.field; }); if (!expression.filters.length) { expression = null; } that.dataSource.filter(expression); }, _submit: function(e) { e.preventDefault(); e.stopPropagation(); var expression = this.filterModel.toJSON(); var containsFilters = $.grep(expression.filters, function(filter) { return filter.value !== "" && filter.value !== null; }); if (this._checkForNullOrEmptyFilter(expression) || (containsFilters && containsFilters.length)) { this.filter(expression); } else { var currentExpression = this.dataSource.filter(); if (currentExpression) { currentExpression.filters.push(expression); expression = currentExpression; } this.clear(expression); } this._closeForm(); }, _checkForNullOrEmptyFilter: function(expression) { if (!expression || !expression.filters || !expression.filters.length) { return false; } var firstNullOrEmpty = false; var secondNullOrEmpty = false; var operator; if (expression.filters[0]) { operator = expression.filters[0].operator; firstNullOrEmpty = operator == "isnull" || operator == "isnotnull" || operator == "isnotempty" || operator == "isempty" || operator == "isnullorempty" || operator == "isnotnullorempty"; } if (expression.filters[1]) { operator = expression.filters[1].operator; secondNullOrEmpty = operator == "isnull" || operator == "isnotnull" || operator == "isnotempty" || operator == "isempty" || operator == "isnullorempty" || operator == "isnotnullorempty"; } return (!this.options.extra && firstNullOrEmpty) || (this.options.extra && (firstNullOrEmpty || secondNullOrEmpty)); }, _reset: function() { this.clear(); if (this.options.search && this.container) { this.container.find("label").parent().show(); } this._closeForm(); }, _closeForm: function() { if (this._isMobile) { this.pane.navigate("", this.options.animations.right); } else { this.popup.close(); } }, _click: function(e) { e.preventDefault(); e.stopPropagation(); if (!this.popup && !this.pane) { this._init(); } if (this._isMobile) { this.pane.navigate(this.view, this.options.animations.left); } else { this.popup.toggle(); } }, _open: function() { var popup; $(".k-filter-menu").not(this.form).each(function() { popup = $(this).data(POPUP); if (popup) { popup.close(); } }); }, _activate: function() { this.form.find(":kendoFocusable").first().trigger("focus"); this.trigger(OPEN, { field: this.field, container: this.form }); }, _keydown: function(e) { var target = $(e.target), instance; if (e.keyCode == kendo.keys.ESC) { instance = kendo.widgetInstance(target.find("select")); if (target.hasClass("k-picker") && instance && instance.popup.visible()) { e.stopPropagation(); return; } target.closest(".k-popup").getKendoPopup().close(); } }, events: [ INIT, "change", OPEN ], options: { name: "FilterMenu", extra: true, appendToElement: false, type: "string", operators: { string: { eq: EQ, neq: NEQ, startswith: "Starts with", contains: "Contains", doesnotcontain: "Does not contain", endswith: "Ends with", isnull: "Is null", isnotnull: "Is not null", isempty: "Is empty", isnotempty: "Is not empty", isnullorempty: "Has no value", isnotnullorempty: "Has value" }, number: { eq: EQ, neq: NEQ, gte: "Is greater than or equal to", gt: "Is greater than", lte: "Is less than or equal to", lt: "Is less than", isnull: "Is null", isnotnull: "Is not null" }, date: { eq: EQ, neq: NEQ, gte: "Is after or equal to", gt: "Is after", lte: "Is before or equal to", lt: "Is before", isnull: "Is null", isnotnull: "Is not null" }, enums: { eq: EQ, neq: NEQ, isnull: "Is null", isnotnull: "Is not null" } }, messages: { info: "Show items with value that:", title: "Show items with value that:", isTrue: "is true", isFalse: "is false", filter: "Filter", clear: "Clear", and: "And", or: "Or", selectValue: "-Select value-", operator: "Operator", value: "Value", additionalValue: "Additional value", additionalOperator: "Additional operator", logic: "Filters logic", cancel: "Cancel", done: "Done", into: "in", buttonTitle: "{0} filter column settings" }, animations: { left: "slide", right: "slide:right" }, componentType: 'classic', cycleForm: true, appendTo: null } }); var multiCheckNS = ".kendoFilterMultiCheck"; function filterValuesForField(expression, field) { if (expression.filters) { expression.filters = $.grep(expression.filters, function(filter) { filterValuesForField(filter, field); if (filter.filters) { return filter.filters.length; } else { return filter.field == field && filter.operator == "eq"; } }); } } function flatFilterValues(expression) { if (expression.logic == "and" && expression.filters.length > 1) { return []; } if (expression.filters) { return $.map(expression.filters, function(filter) { return flatFilterValues(filter); }); } else if (expression.value !== undefined$1) { return [expression.value]; } else { return []; } } function distinct(items, field) { var getter = kendo.getter(field, true), result = [], index = 0, seen = {}; while (index < items.length) { var item = items[index++], text = getter(item); if (text !== undefined$1 && !seen.hasOwnProperty(text)) { result.push(item); seen[text] = true; } } return result; } function removeDuplicates(dataSelector, dataTextField) { return function(e) { var items = dataSelector(e); return distinct(items, dataTextField); }; } var DataSource = kendo.data.DataSource; var multiCheckMobileTemplate = ({ field, title, ns, messages, search, checkAll }) => `<div data-${ns}role="view" class="k-grid-filter-menu">` + `<div data-${ns}role="header" class="k-appbar k-appbar-primary">` + kendo.html.renderButton(`<button class="k-header-cancel" title="${messages.cancel}" aria-label="${messages.cancel}"></button>`, { icon: "chevron-left", fillMode: "flat" }) + `<span class="k-spacer"></span>` + `<span>${encode(messages.filter)} ${encode(messages.into)} ${encode(title)}</span>` + `<span class="k-spacer"></span>` + kendo.html.renderButton(`<button class="k-header-done" title="${messages.done}" aria-label="${messages.done}"></button>`, { icon: "check", fillMode: "flat" }) + '</div>' + '<div class="k-stretched-view k-content">' + '<form class="k-filter-menu">' + (search ? '<div class="k-list-filter">' + '<span class="k-searchbox k-input k-input-md k-input-solid k-rounded-md">' + '<span class="k-input-icon k-icon k-svg-icon k-svg-i-search">' + kendo.ui.icon("search") + '</span>' + `<input class="k-input-inner" placeholder="${messages.search}" title="${messages.search}" autocomplete="${AUTOCOMPLETEVALUE}"