import { shortcut, extend, emptyFn, isKey, remove, deepClone, createWidget, toPix, bind, last, initial, i18nText, nextTick, Events, AbsoluteLayout, VerticalAdaptLayout, isNotNull, makeObject, each, Func, map, concat, values, filter, contains, isNull, endWith, pushDistinct, Selection } from "@/core"; import { Single, Combo, Msg } from "@/base"; import { MultiSelectInsertTrigger } from "./multiselect.insert.trigger"; import { MultiSelectPopupView } from "./multiselect.popup.view"; import { MultiSelectBar, TriggerIconButton } from "@/case"; import { MultiSelectCheckSelectedSwitcher } from "./trigger/switcher.checkselected"; @shortcut() export class MultiSelectInsertCombo extends Single { static xtype = "bi.multi_select_insert_combo"; static REQ_GET_DATA_LENGTH = "1"; static REQ_GET_ALL_DATA = "-1"; static EVENT_FOCUS = "EVENT_FOCUS"; static EVENT_BLUR = "EVENT_BLUR"; static EVENT_STOP = "EVENT_STOP"; static EVENT_SEARCHING = "EVENT_SEARCHING"; static EVENT_CLICK_ITEM = "EVENT_CLICK_ITEM"; static EVENT_CONFIRM = "EVENT_CONFIRM"; static EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; _defaultConfig() { return extend(super._defaultConfig(...arguments), { baseCls: "bi-multi-select-insert-combo", itemsCreator: emptyFn, valueFormatter: emptyFn, height: 24, itemHeight: BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, allowEdit: true, }); } _init() { const self = this, o = this.options; super._init(...arguments); const triggerBtn = createWidget({ type: TriggerIconButton.xtype, width: o.height, height: o.height, cls: "multi-select-trigger-icon-button", }); function assertShowValue() { if (isKey(self._startValue)) { if (self.storeValue.type === Selection.All) { remove(self.storeValue.value, self._startValue); self.storeValue.assist = self.storeValue.assist || []; pushDistinct(self.storeValue.assist, self._startValue); } else { pushDistinct(self.storeValue.value, self._startValue); remove(self.storeValue.assist, self._startValue); } } self.trigger.getSearcher().setState(self.storeValue); self.numberCounter.setButtonChecked(self.storeValue); } this.storeValue = deepClone(o.value) || {}; // 标记正在请求数据 this.requesting = false; this.trigger = createWidget({ type: "bi.multi_select_insert_trigger", allowEdit: o.allowEdit, height: toPix(o.height, o.simple ? 1 : 2), text: o.text, watermark: o.watermark, defaultText: o.defaultText, // adapter: this.popup, masker: { offset: { left: 0, top: 0, right: 0, bottom: BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT + 1, }, }, valueFormatter: o.valueFormatter, itemsCreator: bind(this._itemsCreator4Trigger, this), itemFormatter: o.itemFormatter, itemHeight: o.itemHeight, value: this.storeValue, }); this.trigger.on(MultiSelectInsertTrigger.EVENT_FOCUS, () => { self.fireEvent(MultiSelectInsertCombo.EVENT_FOCUS); }); this.trigger.on(MultiSelectInsertTrigger.EVENT_BLUR, () => { self.fireEvent(MultiSelectInsertCombo.EVENT_BLUR); }); this.trigger.on(MultiSelectInsertTrigger.EVENT_START, function () { self._setStartValue(""); this.getSearcher().setValue(self.storeValue); }); this.trigger.on(MultiSelectInsertTrigger.EVENT_STOP, () => { self._setStartValue(""); self.fireEvent(MultiSelectInsertCombo.EVENT_STOP); }); this.trigger.on(MultiSelectInsertTrigger.EVENT_PAUSE, function () { self._addItem(assertShowValue, true); self.fireEvent( MultiSelectInsertCombo.EVENT_ADD_ITEM, this.getSearcher().getKeyword() ); }); this.trigger.on( MultiSelectInsertTrigger.EVENT_SEARCHING, function (keywords) { const lastKeyword = last(keywords); keywords = initial(keywords || []); if (keywords.length > 0) { self._joinKeywords(keywords, () => { if (endWith(lastKeyword, BI.BlankSplitChar)) { self.combo.setValue(self.storeValue); assertShowValue(); self.combo.populate(); self._setStartValue(""); } else { self.combo.setValue(self.storeValue); assertShowValue(); } self._dataChange = true; }); this.getSearcher().getKeywordsLength() > 2000 && Msg.alert( i18nText("BI-Basic_Prompt"), i18nText("BI-Basic_Too_Much_Value_Get_Two_Thousand") ); } self.fireEvent(MultiSelectInsertCombo.EVENT_SEARCHING); } ); this.trigger.on( MultiSelectInsertTrigger.EVENT_CHANGE, function (value, obj) { if (obj instanceof MultiSelectBar) { self._joinAll(this.getValue(), () => { assertShowValue(); self.fireEvent(MultiSelectInsertCombo.EVENT_CLICK_ITEM); }); } else { self._join(this.getValue(), () => { assertShowValue(); self.fireEvent(MultiSelectInsertCombo.EVENT_CLICK_ITEM); }); } self._dataChange = true; } ); this.trigger.on( MultiSelectInsertTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, () => { // counter的值随点击项的改变而改变, 点击counter的时候不需要setValue(counter会请求刷新计数) // 只需要更新查看面板的selectedValue用以请求已选数据 self.numberCounter.updateSelectedValue(self.storeValue); } ); this.trigger.on( MultiSelectInsertTrigger.EVENT_COUNTER_CLICK, () => { if (!self.combo.isViewVisible()) { self.combo.showView(); } } ); this.combo = createWidget({ type: Combo.xtype, cls: o.simple ? "bi-border-bottom" : "bi-border bi-border-radius", toggle: !o.allowEdit, el: this.trigger, adjustLength: 1, container: o.container, popup: { type: "bi.multi_select_popup_view", ref() { self.popup = this; self.trigger.setAdapter(this); self.numberCounter.setAdapter(this); }, listeners: [ { eventName: MultiSelectPopupView.EVENT_CHANGE, action() { self._dataChange = true; self.storeValue = this.getValue(); self._adjust(() => { assertShowValue(); }); self.fireEvent( MultiSelectInsertCombo.EVENT_CLICK_ITEM ); }, }, { eventName: MultiSelectPopupView.EVENT_CLICK_CONFIRM, action() { self._defaultState(); }, }, { eventName: MultiSelectPopupView.EVENT_CLICK_CLEAR, action() { self._dataChange = true; self.setValue(); self._defaultState(); }, } ], itemsCreator: o.itemsCreator, valueFormatter: o.valueFormatter, itemFormatter: o.itemFormatter, itemHeight: o.itemHeight, onLoaded() { nextTick(() => { self.combo.adjustWidth(); self.combo.adjustHeight(); self.numberCounter.adjustView(); self.trigger.getSearcher().adjustView(); }); }, }, value: o.value, hideChecker(e) { return ( triggerBtn.element.find(e.target).length === 0 && self.numberCounter.element.find(e.target).length === 0 ); }, }); this.combo.on(Combo.EVENT_BEFORE_POPUPVIEW, function () { if (!this.isViewVisible()) { self._dataChange = false; // 标记数据是否发生变化 } this.setValue(self.storeValue); nextTick(() => { self._populate(); }); }); // 当退出的时候如果还在处理请求,则等请求结束后再对外发确定事件 this.wants2Quit = false; this.combo.on(Combo.EVENT_AFTER_HIDEVIEW, () => { // important:关闭弹出时又可能没有退出编辑状态 self._stopEditing(); if (self.requesting === true) { self.wants2Quit = true; } else { self._dataChange && self.fireEvent(MultiSelectInsertCombo.EVENT_CONFIRM); } }); triggerBtn.on(TriggerIconButton.EVENT_CHANGE, () => { self.numberCounter.hideView(); if (self.combo.isViewVisible()) { self.combo.hideView(); } else { self.combo.showView(); } }); this.numberCounter = createWidget({ type: MultiSelectCheckSelectedSwitcher.xtype, masker: { offset: { left: 0, top: 0, right: 0, bottom: BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT + 1, }, }, valueFormatter: o.valueFormatter, itemsCreator: bind(this._itemsCreator4Trigger, this), value: o.value, }); this.numberCounter.on( MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE, () => { if (!self.combo.isViewVisible()) { self.combo.showView(); } } ); this.numberCounter.on( MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW, function () { this.updateSelectedValue(self.storeValue); } ); this.numberCounter.on(Events.VIEW, b => { nextTick(() => { // 自动调整宽度 self.trigger.refreshPlaceHolderWidth( b === true ? self.numberCounter.element.outerWidth() + 8 : 0 ); }); }); this.numberCounter.on( MultiSelectCheckSelectedSwitcher.EVENT_AFTER_HIDEVIEW, () => { nextTick(() => { // 收起时自动调整宽度 self.trigger.refreshPlaceHolderWidth(0); }); } ); this.trigger.element.click(e => { if (self.trigger.element.find(e.target).length > 0) { self.numberCounter.hideView(); } }); createWidget({ type: AbsoluteLayout.xtype, element: this, items: [ { el: this.combo, left: 0, right: 0, top: 0, bottom: 0, }, { el: triggerBtn, right: 0, top: 0, bottom: 0, }, { el: { type: VerticalAdaptLayout.xtype, items: [this.numberCounter], }, right: o.height, top: 0, height: o.height, } ], }); } _itemsCreator4Trigger(op, callback) { const self = this, o = this.options; o.itemsCreator(op, function (res) { if (op.times === 1 && isNotNull(op.keywords)) { // 预防trigger内部把当前的storeValue改掉 self.trigger.setValue(deepClone(self.getValue())); } callback.apply(self, arguments); }); } _addItem(assertShowValue) { const self = this; const keyword = this.trigger.getSearcher().getKeyword(); this._join( { type: Selection.Multi, value: [keyword], }, () => { // 如果在不选的状态下直接把该值添加进来 if (self.storeValue.type === Selection.Multi) { pushDistinct(self.storeValue.value, keyword); } self.combo.setValue(self.storeValue); self._setStartValue(keyword); assertShowValue(); self.populate(); self._setStartValue(""); self._dataChange = true; } ); } _stopEditing() { this.trigger.stopEditing(); this.numberCounter.hideView(); } _defaultState() { this._stopEditing(); this.combo.hideView(); } _assertValue(val) { val || (val = {}); val.type || (val.type = Selection.Multi); val.value || (val.value = []); } _makeMap(values) { return makeObject(values || []); } _joinKeywords(keywords, callback) { const self = this; this._assertValue(this.storeValue); this.requesting = true; digest(); function digest() { each(keywords, (i, val) => { self.storeValue.type === Selection.Multi ? pushDistinct(self.storeValue.value, val) : remove(self.storeValue.value, val); }); self._adjust(callback); } } _joinAll(res, callback) { const self = this, o = this.options; this._assertValue(res); this.requesting = true; if (this.storeValue.type === res.type) { const result = Func.getSearchResult( map(this.storeValue.value, (_i, v) => { return { text: o.valueFormatter(v) || v, value: v, }; }), this.trigger.getKey() ); let change = false; const tempMap = this._makeMap(this.storeValue.value); each(concat(result.match, result.find), (i, obj) => { const v = obj.value; if (isNotNull(tempMap[v])) { change = true; self.storeValue.assist && self.storeValue.assist.push(tempMap[v]); delete tempMap[v]; } }); change && (this.storeValue.value = values(tempMap)); this._adjust(callback); return; } o.itemsCreator( { type: MultiSelectInsertCombo.REQ_GET_ALL_DATA, keywords: [this.trigger.getKey()], selectedValues: filter(this.storeValue.value, (_i, v) => !contains(res.value, v)), }, ob => { const items = map(ob.items, "value"); const selectedMap = self._makeMap(self.storeValue.value); const notSelectedMap = self._makeMap(res.value); const newItems = []; each(items, (i, item) => { if (isNotNull(selectedMap[items[i]])) { self.storeValue.assist && self.storeValue.assist.push(selectedMap[items[i]]); delete selectedMap[items[i]]; } if (isNull(notSelectedMap[items[i]])) { remove(self.storeValue.assist, item); newItems.push(item); } }); self.storeValue.value = newItems.concat(values(selectedMap)); self._adjust(callback); } ); } _adjust(callback) { const self = this; adjust(); callback(); function adjust() { if (self.wants2Quit === true) { self._dataChange && self.fireEvent(MultiSelectInsertCombo.EVENT_CONFIRM); self.wants2Quit = false; } self.requesting = false; } } _join(res, callback) { const self = this; this._assertValue(res); this._assertValue(this.storeValue); if (this.storeValue.type === res.type) { const map = this._makeMap(this.storeValue.value); each(res.value, (i, v) => { if (!map[v]) { pushDistinct(self.storeValue.value, v); // value更新的时候assist也需要更新 remove(self.storeValue.assist, v); map[v] = v; } }); let change = false; each(res.assist, (i, v) => { if (isNotNull(map[v])) { change = true; self.storeValue.assist && self.storeValue.assist.push(map[v]); delete map[v]; } }); change && (this.storeValue.value = values(map)); self._adjust(callback); return; } this._joinAll(res, callback); } _setStartValue(value) { this._startValue = value; this.popup.setStartValue(value); } _populate() { this.combo.populate(...arguments); } showView() { this.combo.showView(); } hideView() { this.combo.hideView(); } setValue(v) { this.storeValue = v || {}; this._assertValue(this.storeValue); this.combo.setValue(this.storeValue); this.numberCounter.setValue(this.storeValue); } getValue() { return deepClone(this.storeValue); } populate() { this._populate(...arguments); this.numberCounter.populateSwitcher(...arguments); } }