UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,367 lines (1,090 loc) • 43.7 kB
"use strict"; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var $ = require("../core/renderer"), eventsEngine = require("../events/core/events_engine"), dataUtils = require("../core/element_data"), getPublicElement = require("../core/utils/dom").getPublicElement, devices = require("../core/devices"), commonUtils = require("../core/utils/common"), noop = commonUtils.noop, isDefined = require("../core/utils/type").isDefined, arrayUtils = require("../core/utils/array"), typeUtils = require("../core/utils/type"), windowUtils = require("../core/utils/window"), iteratorUtils = require("../core/utils/iterator"), extend = require("../core/utils/extend").extend, messageLocalization = require("../localization/message"), registerComponent = require("../core/component_registrator"), eventUtils = require("../events/utils"), SelectBox = require("./select_box"), clickEvent = require("../events/click"), caret = require("./text_box/utils.caret"), browser = require("../core/utils/browser"), FilterCreator = require("../core/utils/selection_filter").SelectionFilterCreator, deferredUtils = require("../core/utils/deferred"), compileSetter = require("../core/utils/data").compileSetter, when = deferredUtils.when, Deferred = deferredUtils.Deferred, BindableTemplate = require("./widget/bindable_template"), inArray = require("../core/utils/array").inArray, each = require("../core/utils/iterator").each; var TAGBOX_TAG_DATA_KEY = "dxTagData"; var TAGBOX_CLASS = "dx-tagbox", TAGBOX_TAG_CONTAINER_CLASS = "dx-tag-container", TAGBOX_TAG_CLASS = "dx-tag", TAGBOX_MULTI_TAG_CLASS = "dx-tagbox-multi-tag", TAGBOX_CUSTOM_TAG_CLASS = "dx-tag-custom", TAGBOX_TAG_REMOVE_BUTTON_CLASS = "dx-tag-remove-button", TAGBOX_ONLY_SELECT_CLASS = "dx-tagbox-only-select", TAGBOX_SINGLE_LINE_CLASS = "dx-tagbox-single-line", TAGBOX_POPUP_WRAPPER_CLASS = "dx-tagbox-popup-wrapper", LIST_SELECT_ALL_CHECKBOX_CLASS = "dx-list-select-all-checkbox", TAGBOX_TAG_CONTENT_CLASS = "dx-tag-content", TAGBOX_DEFAULT_FIELD_TEMPLATE_CLASS = "dx-tagbox-default-template", TAGBOX_CUSTOM_FIELD_TEMPLATE_CLASS = "dx-tagbox-custom-template", NATIVE_CLICK_CLASS = "dx-native-click", TEXTEDITOR_CONTAINER_CLASS = "dx-texteditor-container"; var TAGBOX_MOUSE_WHEEL_DELTA_MULTIPLIER = -0.3; /** * @name dxTagBox * @isEditor * @publicName dxTagBox * @inherits dxSelectBox * @module ui/tag_box * @export default */ var TagBox = SelectBox.inherit({ _supportedKeys: function _supportedKeys() { var parent = this.callBase(); return extend(parent, { backspace: function backspace(e) { if (!this._isCaretAtTheStart()) { return; } e.preventDefault(); e.stopPropagation(); this._isTagRemoved = true; var $tagToDelete = this._$focusedTag || this._tagElements().last(); if (this._$focusedTag) { this._moveTagFocus("prev", true); } if ($tagToDelete.length === 0) { return; } this._preserveFocusedTag = true; this._removeTagElement($tagToDelete); delete this._preserveFocusedTag; }, del: function del(e) { if (!this._$focusedTag || !this._isCaretAtTheStart()) { return; } e.preventDefault(); e.stopPropagation(); this._isTagRemoved = true; var $tagToDelete = this._$focusedTag; this._moveTagFocus("next", true); this._preserveFocusedTag = true; this._removeTagElement($tagToDelete); delete this._preserveFocusedTag; }, enter: function enter(e) { var isListItemFocused = this._list && this._list.option("focusedElement") !== null, isCustomItem = this.option("acceptCustomValue") && !isListItemFocused; if (isCustomItem) { e.preventDefault(); this._searchValue() !== "" && this._customItemAddedHandler(); return; } if (!this.option("opened")) { return; } e.preventDefault(); this._keyboardProcessor._childProcessors[0].process(e); }, leftArrow: function leftArrow(e) { if (!this._isCaretAtTheStart()) { return; } var rtlEnabled = this.option("rtlEnabled"); if (this._isEditable() && rtlEnabled && !this._$focusedTag) { return; } e.preventDefault(); var direction = rtlEnabled ? "next" : "prev"; this._moveTagFocus(direction); !this.option("multiline") && this._scrollContainer(direction); }, rightArrow: function rightArrow(e) { if (!this._isCaretAtTheStart()) { return; } var rtlEnabled = this.option("rtlEnabled"); if (this._isEditable() && !rtlEnabled && !this._$focusedTag) { return; } e.preventDefault(); var direction = rtlEnabled ? "prev" : "next"; this._moveTagFocus(direction); !this.option("multiline") && this._scrollContainer(direction); } }); }, _isCaretAtTheStart: function _isCaretAtTheStart() { var position = caret(this._input()); return position.start === 0 && position.end === 0; }, _moveTagFocus: function _moveTagFocus(direction, clearOnBoundary) { if (!this._$focusedTag) { var tagElements = this._tagElements(); this._$focusedTag = direction === "next" ? tagElements.first() : tagElements.last(); this._toggleFocusClass(true, this._$focusedTag); return; } var $nextFocusedTag = this._$focusedTag[direction]("." + TAGBOX_TAG_CLASS); if ($nextFocusedTag.length > 0) { this._replaceFocusedTag($nextFocusedTag); } else if (clearOnBoundary || direction === "next" && this._isEditable()) { this._clearTagFocus(); } }, _replaceFocusedTag: function _replaceFocusedTag($nextFocusedTag) { this._toggleFocusClass(false, this._$focusedTag); this._$focusedTag = $nextFocusedTag; this._toggleFocusClass(true, this._$focusedTag); }, _clearTagFocus: function _clearTagFocus() { if (!this._$focusedTag) { return; } this._toggleFocusClass(false, this._$focusedTag); delete this._$focusedTag; }, _focusClassTarget: function _focusClassTarget($element) { if ($element && $element.length && $element[0] !== this._focusTarget()[0]) { return $element; } return this.callBase(); }, _scrollContainer: function _scrollContainer(direction) { if (this.option("multiline") || !windowUtils.hasWindow()) { return; } if (!this._$tagsContainer) { return; } var scrollPosition = this._getScrollPosition(direction); this._$tagsContainer.scrollLeft(scrollPosition); }, _getScrollPosition: function _getScrollPosition(direction) { if (direction === "start" || direction === "end") { return this._getBorderPosition(direction); } return this._$focusedTag ? this._getFocusedTagPosition(direction) : this._getBorderPosition("end"); }, _getBorderPosition: function _getBorderPosition(direction) { var rtlEnabled = this.option("rtlEnabled"), isScrollLeft = direction === "end" ^ rtlEnabled, isScrollReverted = rtlEnabled && !browser.webkit, scrollSign = !rtlEnabled || browser.webkit || browser.msie ? 1 : -1; return isScrollLeft ^ !isScrollReverted ? 0 : scrollSign * (this._$tagsContainer.get(0).scrollWidth - this._$tagsContainer.outerWidth()); }, _getFocusedTagPosition: function _getFocusedTagPosition(direction) { var rtlEnabled = this.option("rtlEnabled"), isScrollLeft = direction === "next" ^ rtlEnabled, scrollOffset = this._$focusedTag.position().left, scrollLeft = this._$tagsContainer.scrollLeft(); if (isScrollLeft) { scrollOffset += this._$focusedTag.outerWidth(true) - this._$tagsContainer.outerWidth(); } if (isScrollLeft ^ scrollOffset < 0) { var scrollCorrection = rtlEnabled && browser.msie ? -1 : 1; scrollLeft += scrollOffset * scrollCorrection; } return scrollLeft; }, _setNextValue: noop, _getDefaultOptions: function _getDefaultOptions() { return extend(this.callBase(), { /** * @name dxTagBoxOptions.value * @publicName value * @type Array<string,number,Object> */ value: [], showDropDownButton: false, maxFilterLength: 1500, /** * @name dxTagBoxOptions.tagTemplate * @publicName tagTemplate * @type template|function * @default "tag" * @type_function_param1 itemData:object * @type_function_param2 itemElement:dxElement * @type_function_return string|Node|jQuery */ tagTemplate: "tag", selectAllText: messageLocalization.format("dxList-selectAll"), /** * @name dxTagBoxOptions.hideSelectedItems * @publicName hideSelectedItems * @type boolean * @default false */ hideSelectedItems: false, /** * @name dxTagBoxOptions.selectedItems * @publicName selectedItems * @type Array<string,number,Object> * @readonly */ selectedItems: [], /** * @name dxTagBoxOptions.selectAllMode * @publicName selectAllMode * @type Enums.SelectAllMode * @default 'page' */ selectAllMode: 'page', /** * @name dxTagBoxOptions.onSelectAllValueChanged * @publicName onSelectAllValueChanged * @extends Action * @type function(e) * @type_function_param1 e:object * @type_function_param1_field4 value:boolean * @action */ onSelectAllValueChanged: null, /** * @name dxTagBoxOptions.maxDisplayedTags * @publicName maxDisplayedTags * @type number * @default undefined */ maxDisplayedTags: undefined, /** * @name dxTagBoxOptions.showMultiTagOnly * @publicName showMultiTagOnly * @type boolean * @default true */ showMultiTagOnly: true, /** * @name dxTagBoxOptions.onMultiTagPreparing * @publicName onMultiTagPreparing * @extends Action * @type function(e) * @type_function_param1 e:object * @type_function_param1_field4 multiTagElement:dxElement * @type_function_param1_field5 selectedItems:Array<string,number,Object> * @type_function_param1_field6 text:string * @type_function_param1_field7 cancel:boolean * @action */ onMultiTagPreparing: null, /** * @name dxTagBoxOptions.multiline * @publicName multiline * @type boolean * @default true */ multiline: true, /** * @name dxTagBoxOptions.useSubmitBehavior * @publicName useSubmitBehavior * @type boolean * @default true * @hidden */ useSubmitBehavior: true /** * @name dxTagBoxOptions.applyValueMode * @publicName applyValueMode * @type Enums.EditorApplyValueMode * @default "instantly" */ /** * @name dxTagBoxOptions.onSelectionChanged * @publicName onSelectionChanged * @extends Action * @type function(e) * @type_function_param1 e:object * @type_function_param1_field4 addedItems:Array<string,number,Object> * @type_function_param1_field5 removedItems:Array<string,number,Object> * @action */ /** * @name dxTagBoxOptions.closeAction * @publicName closeAction * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.hiddenAction * @publicName hiddenAction * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.itemRender * @publicName itemRender * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.openAction * @publicName openAction * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.shownAction * @publicName shownAction * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.valueChangeEvent * @publicName valueChangeEvent * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.maxLength * @publicName maxLength * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.onCopy * @publicName onCopy * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.onCut * @publicName onCut * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.onPaste * @publicName onPaste * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.spellcheck * @publicName spellcheck * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.displayValue * @publicName displayValue * @hidden * @inheritdoc */ /** * @name dxTagBoxOptions.selectedItem * @publicName selectedItem * @hidden * @inheritdoc */ }); }, _init: function _init() { this.callBase(); this._selectedItems = []; this._initSelectAllValueChangedAction(); }, _initActions: function _initActions() { this.callBase(); this._initMultiTagPreparingAction(); }, _initMultiTagPreparingAction: function _initMultiTagPreparingAction() { this._multiTagPreparingAction = this._createActionByOption("onMultiTagPreparing", { beforeExecute: function (e) { this._multiTagPreparingHandler(e.args[0]); }.bind(this) }); }, _compileDisplaySetter: function _compileDisplaySetter() { var displayGetterExpr = this._displayGetterExpr(); this._displaySetter = displayGetterExpr && compileSetter(displayGetterExpr); }, _initDataExpressions: function _initDataExpressions() { this.callBase(); this._compileDisplaySetter(); }, _multiTagPreparingHandler: function _multiTagPreparingHandler(args) { var selectedCount = this._getValue().length; if (!this.option("showMultiTagOnly")) { args.text = messageLocalization.getFormatter("dxTagBox-moreSelected")(selectedCount - this.option("maxDisplayedTags") + 1); } else { args.text = messageLocalization.getFormatter("dxTagBox-selected")(selectedCount); } }, _initTemplates: function _initTemplates() { this.callBase(); this._defaultTemplates["tag"] = new BindableTemplate(function ($container, data) { if (this._displayGetterExpr()) { data = this._displayGetter(data); } var $tagContent = $("<div>").addClass(TAGBOX_TAG_CONTENT_CLASS); $("<span>").text(data).appendTo($tagContent); $("<div>").addClass(TAGBOX_TAG_REMOVE_BUTTON_CLASS).appendTo($tagContent); $container.append($tagContent); }.bind(this), [this._displayGetterExpr()], this.option("integrationOptions.watchMethod")); }, _toggleSubmitElement: function _toggleSubmitElement(enabled) { if (enabled) { this._renderSubmitElement(); this._setSubmitValue(); } else { this._$submitElement && this._$submitElement.remove(); delete this._$submitElement; } }, _renderSubmitElement: function _renderSubmitElement() { if (!this.option("useSubmitBehavior")) { return; } this._$submitElement = $("<select>").attr("multiple", "multiple").css("display", "none").appendTo(this.$element()); }, _setSubmitValue: function _setSubmitValue() { if (!this.option("useSubmitBehavior")) { return; } var value = this._getValue(), useDisplayText = this.option("valueExpr") === "this", $options = []; for (var i = 0, n = value.length; i < n; i++) { $options.push($("<option>").val(useDisplayText ? this._displayGetter(value[i]) : value[i]).attr("selected", "selected")); } this._$submitElement.empty(); this._$submitElement.append($options); }, _initMarkup: function _initMarkup() { this._tagElementsCache = $(); var isSingleLineMode = !this.option("multiline"); this.$element().addClass(TAGBOX_CLASS).toggleClass(TAGBOX_ONLY_SELECT_CLASS, !(this.option("searchEnabled") || this.option("acceptCustomValue"))).toggleClass(TAGBOX_SINGLE_LINE_CLASS, isSingleLineMode); // TODO: texteditor render methods order research this._initTagTemplate(); this.callBase(); }, _render: function _render() { this.callBase(); this._renderTagRemoveAction(); this._renderSingleLineScroll(); this._scrollContainer("start"); }, _initTagTemplate: function _initTagTemplate() { this._tagTemplate = this._getTemplateByOption("tagTemplate"); }, _renderField: function _renderField() { var isDefaultFieldTemplate = !isDefined(this.option("fieldTemplate")); this.$element().toggleClass(TAGBOX_DEFAULT_FIELD_TEMPLATE_CLASS, isDefaultFieldTemplate).toggleClass(TAGBOX_CUSTOM_FIELD_TEMPLATE_CLASS, !isDefaultFieldTemplate); this.callBase(); }, _renderTagRemoveAction: function _renderTagRemoveAction() { var tagRemoveAction = this._createAction(this._removeTagHandler.bind(this)); var eventName = eventUtils.addNamespace(clickEvent.name, "dxTagBoxTagRemove"); eventsEngine.off(this._$tagsContainer, eventName); eventsEngine.on(this._$tagsContainer, eventName, "." + TAGBOX_TAG_REMOVE_BUTTON_CLASS, function (e) { tagRemoveAction({ event: e }); }); this._renderTypingEvent(); }, _renderSingleLineScroll: function _renderSingleLineScroll() { var mouseWheelEvent = eventUtils.addNamespace("dxmousewheel", this.NAME), $element = this.$element(), isMultiline = this.option("multiline"); eventsEngine.off($element, mouseWheelEvent); if (devices.real().deviceType !== "desktop") { this._$tagsContainer && this._$tagsContainer.css("overflowX", isMultiline ? "" : "auto"); return; } if (isMultiline) { return; } eventsEngine.on($element, mouseWheelEvent, this._tagContainerMouseWheelHandler.bind(this)); }, _tagContainerMouseWheelHandler: function _tagContainerMouseWheelHandler(e) { var scrollLeft = this._$tagsContainer.scrollLeft(); this._$tagsContainer.scrollLeft(scrollLeft + e.delta * TAGBOX_MOUSE_WHEEL_DELTA_MULTIPLIER); return false; }, _renderTypingEvent: function _renderTypingEvent() { eventsEngine.on(this._input(), eventUtils.addNamespace("keydown", this.NAME), function (e) { if (!this._isControlKey(e.key) && this._isEditable()) { this._clearTagFocus(); } }.bind(this)); }, _popupWrapperClass: function _popupWrapperClass() { return this.callBase() + " " + TAGBOX_POPUP_WRAPPER_CLASS; }, _renderInput: function _renderInput() { this.callBase(); this._renderPreventBlur(this._inputWrapper()); }, _renderInputValueImpl: function _renderInputValueImpl() { this._renderMultiSelect(); }, _loadInputValue: function _loadInputValue() { return when(); }, _clearTextValue: function _clearTextValue() { this._input().val(""); }, _focusInHandler: function _focusInHandler(e) { this.callBase(e); this._scrollContainer("end"); }, _restoreInputText: function _restoreInputText() { this._clearTextValue(); }, _focusOutHandler: function _focusOutHandler(e) { this.callBase(e); this._clearTagFocus(); this._scrollContainer("start"); }, _getFirstPopupElement: function _getFirstPopupElement() { return this.option("showSelectionControls") ? this._popup._wrapper().find("." + LIST_SELECT_ALL_CHECKBOX_CLASS) : this.callBase(); }, _initSelectAllValueChangedAction: function _initSelectAllValueChangedAction() { this._selectAllValueChangeAction = this._createActionByOption("onSelectAllValueChanged"); }, _renderList: function _renderList() { this.callBase(); this._setListDataSourceFilter(); if (!this.option("showSelectionControls")) { return; } var $selectAllCheckBox = this._list.$element().find("." + LIST_SELECT_ALL_CHECKBOX_CLASS), selectAllCheckbox = $selectAllCheckBox.dxCheckBox("instance"); selectAllCheckbox.registerKeyHandler("tab", this._popupElementTabHandler.bind(this)); selectAllCheckbox.registerKeyHandler("escape", this._popupElementEscHandler.bind(this)); }, _listConfig: function _listConfig() { var that = this, selectionMode = this.option("showSelectionControls") ? "all" : "multiple"; return extend(this.callBase(), { selectionMode: selectionMode, selectAllText: this.option("selectAllText"), onSelectAllValueChanged: function onSelectAllValueChanged(e) { that._selectAllValueChangeAction({ value: e.value }); }, selectAllMode: this.option("selectAllMode"), selectedItems: this._selectedItems, onFocusedItemChanged: null }); }, _renderMultiSelect: function _renderMultiSelect() { this._$tagsContainer = this.$element().find("." + TEXTEDITOR_CONTAINER_CLASS).addClass(TAGBOX_TAG_CONTAINER_CLASS).addClass(NATIVE_CLICK_CLASS); this._renderInputSize(); this._renderTags(); this._popup && this._popup.refreshPosition(); }, _listItemClickHandler: function _listItemClickHandler(e) { !this.option("showSelectionControls") && this._clearTextValue(); if (this.option("applyValueMode") === "useButtons") { return; } this.callBase(e); }, _renderInputSize: function _renderInputSize() { var $input = this._input(); $input.prop("size", $input.val() ? $input.val().length + 2 : 1); }, _renderInputSubstitution: function _renderInputSubstitution() { this.callBase(); this._renderInputSize(); }, _getValue: function _getValue() { return this.option("value") || []; }, _multiTagRequired: function _multiTagRequired() { var values = this._getValue(), maxDisplayedTags = this.option("maxDisplayedTags"); return isDefined(maxDisplayedTags) && values.length > maxDisplayedTags; }, _renderMultiTag: function _renderMultiTag($input) { var item, $tag = $("<div>").addClass(TAGBOX_TAG_CLASS).addClass(TAGBOX_MULTI_TAG_CLASS); var args = { multiTagElement: getPublicElement($tag), selectedItems: this.option("selectedItems") }; this._multiTagPreparingAction(args); if (args.cancel) { return false; } $tag.data(TAGBOX_TAG_DATA_KEY, args.text); $tag.insertBefore($input); if (this._displaySetter) { item = {}; this._displaySetter(item, args.text); } this._tagTemplate.render({ model: item || args.text, container: getPublicElement($tag) }); return $tag; }, _getFilteredItems: function _getFilteredItems(values) { var creator = new FilterCreator(values); var selectedItems = this._list && this._list.option("selectedItems") || this.option("selectedItems"), clientFilterFunction = creator.getLocalFilter(this._valueGetter), filteredItems = selectedItems.filter(clientFilterFunction), selectedItemsAlreadyLoaded = filteredItems.length === values.length, d = new Deferred(); if (selectedItemsAlreadyLoaded) { return d.resolve(filteredItems).promise(); } else { var dataSourceFilter = this._dataSource.filter(), filterExpr = creator.getCombinedFilter(this.option("valueExpr"), dataSourceFilter), filterLength = encodeURI(JSON.stringify(filterExpr)).length, resultFilter = filterLength > this.option("maxFilterLength") ? undefined : filterExpr; this._dataSource.store().load({ filter: resultFilter }).done(function (items) { d.resolve(items.filter(clientFilterFunction)); }); return d.promise(); } }, _createTagData: function _createTagData(values, filteredItems) { var items = []; iteratorUtils.each(values, function (valueIndex, value) { var item = filteredItems[valueIndex]; if (isDefined(item)) { this._selectedItems.push(item); items.splice(valueIndex, 0, item); } else { var selectedItem = this.option("selectedItem"), customItem = this._valueGetter(selectedItem) === value ? selectedItem : value; items.splice(valueIndex, 0, customItem); } }.bind(this)); return items; }, _loadTagData: function _loadTagData() { var values = this._getValue(), tagData = new Deferred(); this._selectedItems = []; this._getFilteredItems(values).done(function (filteredItems) { var items = this._createTagData(values, filteredItems); tagData.resolve(items); }.bind(this)).fail(tagData.reject.bind(this)); return tagData.promise(); }, _renderTags: function _renderTags() { this._loadTagData().always(function (items) { this._renderTagsCore(items); }.bind(this)); this._renderEmptyState(); if (!this._preserveFocusedTag) { this._clearTagFocus(); } }, _renderTagsCore: function _renderTagsCore(items) { this._renderInputAddons(); this.option("selectedItems", this._selectedItems.slice()); this._cleanTags(); var $multiTag = this._multiTagRequired() && this._renderMultiTag(this._input()), showMultiTagOnly = this.option("showMultiTagOnly"), maxDisplayedTags = this.option("maxDisplayedTags"); items.forEach(function (item, index) { if ($multiTag && showMultiTagOnly || $multiTag && !showMultiTagOnly && index - maxDisplayedTags >= -1) { return false; } this._renderTag(item, $multiTag || this._input()); }.bind(this)); this._scrollContainer("end"); this._refreshTagElements(); }, _cleanTags: function _cleanTags() { if (this._multiTagRequired()) { this._tagElements().remove(); } else { var $tags = this._tagElements(), values = this._getValue(); each($tags, function (_, tag) { var $tag = $(tag), index = inArray($tag.data(TAGBOX_TAG_DATA_KEY), values); if (index < 0) { $tag.remove(); } }); } }, _renderEmptyState: function _renderEmptyState() { var isEmpty = !(this._getValue().length || this._selectedItems.length || this._searchValue()); this._toggleEmptiness(isEmpty); this._renderDisplayText(); }, _renderDisplayText: function _renderDisplayText() { this._renderInputSize(); }, _refreshTagElements: function _refreshTagElements() { this._tagElementsCache = this.$element().find("." + TAGBOX_TAG_CLASS); }, _tagElements: function _tagElements() { return this._tagElementsCache; }, _applyTagTemplate: function _applyTagTemplate(item, $tag) { this._tagTemplate.render({ model: item, container: getPublicElement($tag) }); }, _renderTag: function _renderTag(item, $input) { var value = this._valueGetter(item); if (!isDefined(value)) { return; } var $tag = this._getTag(value); if ($tag) { var displayValue = this._displayGetter(item); if (isDefined(displayValue)) { $tag.empty(); this._applyTagTemplate(item, $tag); } $tag.removeClass(TAGBOX_CUSTOM_TAG_CLASS); } else { $tag = this._createTag(value, $input); if (isDefined(item)) { this._applyTagTemplate(item, $tag); } else { $tag.addClass(TAGBOX_CUSTOM_TAG_CLASS); this._applyTagTemplate(value, $tag); } } }, _getTag: function _getTag(value) { var $tags = this._tagElements(), tagsLength = $tags.length; var result = false; for (var i = 0; i < tagsLength; i++) { var $tag = $tags[i], tagData = dataUtils.data($tag, TAGBOX_TAG_DATA_KEY); if (value === tagData || commonUtils.equalByValue(value, tagData)) { result = $($tag); break; } } return result; }, _createTag: function _createTag(value, $input) { return $("<div>").addClass(TAGBOX_TAG_CLASS).data(TAGBOX_TAG_DATA_KEY, value).insertBefore($input); }, _toggleEmptinessEventHandler: function _toggleEmptinessEventHandler() { this._toggleEmptiness(!this._getValue().length && !this._searchValue().length); }, _customItemAddedHandler: function _customItemAddedHandler(e) { this.callBase(e); this._input().val(""); }, _removeTagHandler: function _removeTagHandler(args) { var e = args.event; e.stopPropagation(); var $tag = $(e.target).closest("." + TAGBOX_TAG_CLASS); this._removeTagElement($tag); }, _removeTagElement: function _removeTagElement($tag) { if ($tag.hasClass(TAGBOX_MULTI_TAG_CLASS)) { if (!this.option("showMultiTagOnly")) { this.option("value", this._getValue().slice(0, this.option("maxDisplayedTags"))); } else { this.reset(); } return; } var itemValue = $tag.data(TAGBOX_TAG_DATA_KEY); this._removeTagWithUpdate(itemValue); this._refreshTagElements(); }, _updateField: noop, _removeTagWithUpdate: function _removeTagWithUpdate(itemValue) { var value = this._getValue().slice(); this._removeTag(value, itemValue); this.option("value", value); if (value.length === 0) { this._clearTagFocus(); } }, _getCurrentValue: function _getCurrentValue() { return this._lastValue(); }, _selectionChangeHandler: function _selectionChangeHandler(e) { if (this.option("applyValueMode") === "useButtons") { return; } var value = this._getValue().slice(); iteratorUtils.each(e.removedItems || [], function (_, removedItem) { this._removeTag(value, this._valueGetter(removedItem)); }.bind(this)); iteratorUtils.each(e.addedItems || [], function (_, addedItem) { this._addTag(value, this._valueGetter(addedItem)); }.bind(this)); this._updateWidgetHeight(); this.option("value", value); }, _removeTag: function _removeTag(value, item) { var index = this._valueIndex(item, value); if (index >= 0) { value.splice(index, 1); } }, _addTag: function _addTag(value, item) { var index = this._valueIndex(item); if (index < 0) { value.push(item); } }, _fieldRenderData: function _fieldRenderData() { return this._selectedItems.slice(); }, _completeSelection: function _completeSelection(value) { if (!this.option("showSelectionControls")) { this._setValue(value); } }, _setValue: function _setValue(value) { if (value === null) { return; } var useButtons = this.option("applyValueMode") === "useButtons", valueIndex = this._valueIndex(value), values = (useButtons ? this._list.option("selectedItemKeys") : this._getValue()).slice(); if (valueIndex >= 0) { values.splice(valueIndex, 1); } else { values.push(value); } if (this.option("applyValueMode") === "useButtons") { this._list.option("selectedItemKeys", values); } else { this.option("value", values); } }, _isSelectedValue: function _isSelectedValue(value, cache) { return this._valueIndex(value, null, cache) > -1; }, _valueIndex: function _valueIndex(value, values, cache) { var result = -1; if (cache && (typeof value === "undefined" ? "undefined" : _typeof(value)) !== "object") { if (!cache.indexByValues) { cache.indexByValues = {}; values = values || this._getValue(); values.forEach(function (value, index) { cache.indexByValues[value] = index; }); } if (value in cache.indexByValues) { return cache.indexByValues[value]; } } values = values || this._getValue(); iteratorUtils.each(values, function (index, selectedValue) { if (this._isValueEquals(value, selectedValue)) { result = index; return false; } }.bind(this)); return result; }, _lastValue: function _lastValue() { var values = this._getValue(), lastValue = values[values.length - 1]; return isDefined(lastValue) ? lastValue : null; }, _valueChangeEventHandler: noop, _shouldRenderSearchEvent: function _shouldRenderSearchEvent() { return this.option("searchEnabled") || this.option("acceptCustomValue"); }, _searchHandler: function _searchHandler(e) { if (this.option("searchEnabled") && !!e && !this._isTagRemoved) { this.callBase(e); } this._updateWidgetHeight(); delete this._isTagRemoved; }, _updateWidgetHeight: function _updateWidgetHeight() { var element = this.$element(), originalHeight = element.height(); this._renderInputSize(); var currentHeight = element.height(); if (this._popup && this.option("opened") && this._isEditable() && currentHeight !== originalHeight) { this._popup.repaint(); } }, _refreshSelected: function _refreshSelected() { this._list && this._list.option("selectedItems", this._selectedItems); }, _resetListDataSourceFilter: function _resetListDataSourceFilter() { var dataSource = this._getDataSource(); if (!dataSource) { return; } delete this._userFilter; dataSource.filter(null); dataSource.reload(); }, _setListDataSourceFilter: function _setListDataSourceFilter() { if (!this.option("hideSelectedItems") || !this._list) { return; } var dataSource = this._getDataSource(); if (!dataSource) { return; } var valueGetterExpr = this._valueGetterExpr(); if (typeUtils.isString(valueGetterExpr) && valueGetterExpr !== "this") { var filter = this._dataSourceFilterExpr(); if (this._userFilter === undefined) { this._userFilter = dataSource.filter() || null; } this._userFilter && filter.push(this._userFilter); filter.length ? dataSource.filter(filter) : dataSource.filter(null); } else { dataSource.filter(this._dataSourceFilterFunction.bind(this)); } dataSource.load(); }, _dataSourceFilterExpr: function _dataSourceFilterExpr() { var filter = []; iteratorUtils.each(this._getValue(), function (index, value) { filter.push(["!", [this._valueGetterExpr(), value]]); }.bind(this)); return filter; }, _dataSourceFilterFunction: function _dataSourceFilterFunction(itemData) { var itemValue = this._valueGetter(itemData), result = true; iteratorUtils.each(this._getValue(), function (index, value) { if (this._isValueEquals(value, itemValue)) { result = false; return false; } }.bind(this)); return result; }, _applyButtonHandler: function _applyButtonHandler() { this.option("value", this._getSortedListValues()); this._clearTextValue(); this._clearFilter(); this.callBase(); }, _getSortedListValues: function _getSortedListValues() { var listValues = this._getListValues(), currentValue = this.option("value"), sortFunction = function sortFunction(item1, item2) { return currentValue.indexOf(item2) - currentValue.indexOf(item1); }; return currentValue ? listValues.sort(sortFunction) : listValues; }, _getListValues: function _getListValues() { if (!this._list) { return []; } var that = this, selectedItems = this._getPlainItems(this._list.option("selectedItems")), result = []; iteratorUtils.each(selectedItems, function (index, item) { result[index] = that._valueGetter(item); }); return result; }, _renderOpenedState: function _renderOpenedState() { this.callBase(); if (this.option("applyValueMode") === "useButtons" && !this.option("opened")) { this._refreshSelected(); } }, _clean: function _clean() { this.callBase(); delete this._defaultTagTemplate; delete this._tagTemplate; }, _optionChanged: function _optionChanged(args) { switch (args.name) { case "onSelectAllValueChanged": this._initSelectAllValueChangedAction(); break; case "onMultiTagPreparing": this._initMultiTagPreparingAction(); this._renderTags(); break; case "hideSelectedItems": if (args.value) { this._setListDataSourceFilter(); } else { this._resetListDataSourceFilter(); } break; case "useSubmitBehavior": this._toggleSubmitElement(args.value); break; case "displayExpr": this.callBase(args); this._initTemplates(); this._compileDisplaySetter(); this._invalidate(); break; case "tagTemplate": this._initTagTemplate(); this._invalidate(); break; case "selectAllText": this._setListOption("selectAllText", this.option("selectAllText")); break; case "value": this.callBase(args); this._setListDataSourceFilter(); break; case "maxDisplayedTags": case "showMultiTagOnly": this._renderTags(); break; case "selectAllMode": this._setListOption(args.name, args.value); break; case "selectedItem": break; case "selectedItems": var addedItems = arrayUtils.removeDuplicates(args.value, args.previousValue), removedItems = arrayUtils.removeDuplicates(args.previousValue, args.value); this._selectionChangedAction({ addedItems: addedItems, removedItems: removedItems }); break; case "multiline": this.$element().toggleClass(TAGBOX_SINGLE_LINE_CLASS, !args.value); this._renderSingleLineScroll(); break; case "maxFilterLength": break; default: this.callBase(args); } }, _getActualSearchValue: function _getActualSearchValue() { return this.callBase() || this._searchValue(); }, _popupHidingHandler: function _popupHidingHandler() { this.callBase(); this._clearFilter(); }, reset: function reset() { this.option("value", []); this._clearFilter(); this._clearSelectedItem(); } }); registerComponent("dxTagBox", TagBox); module.exports = TagBox;