fineui是帆软报表和BI产品线所使用的前端框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

521 lines
17 KiB

import {
shortcut,
extend,
isKey,
Selection,
remove,
pushDistinct,
deepClone,
createWidget,
toPix,
isNotNull,
last,
initial,
endWith,
bind,
nextTick,
AbsoluteLayout,
contains,
map,
makeObject,
each,
values,
isNull,
Func,
filter,
isNotEmptyArray,
isArray,
find,
BlankSplitChar
} from "@/core";
import { Single, Combo } from "@/base";
import { MultiSelectTrigger, MultiSelectPopupView, MultiSelectCombo, SearchMultiSelectTrigger, SearchMultiSelectPopupView } from "@/widget";
import { MultiSelectBar, TriggerIconButton } from "@/case";
@shortcut()
export class SearchMultiTextValueCombo extends Single {
static xtype = "bi.search_multi_text_value_combo";
static REQ_GET_DATA_LENGTH = 1;
static REQ_GET_ALL_DATA = -1;
static EVENT_CONFIRM = "EVENT_CONFIRM";
_defaultConfig() {
return extend(super._defaultConfig(...arguments), {
7 years ago
baseCls: "bi-multi-select-combo bi-search-multi-text-value-combo",
height: 24,
items: [],
});
}
_init() {
const o = this.options;
const triggerBtn = createWidget({
type: TriggerIconButton.xtype,
width: o.height,
height: o.height,
cls: "multi-select-trigger-icon-button",
});
super._init(...arguments);
const assertShowValue = () => {
isKey(this._startValue) &&
(this.storeValue.type === Selection.All
? remove(this.storeValue.value, this._startValue)
: pushDistinct(this.storeValue.value, this._startValue));
this._updateAllValue();
this._checkError();
this.trigger.getSearcher().setState(this.storeValue);
this.trigger.getCounter().setButtonChecked(this.storeValue);
};
this.storeValue = deepClone(o.value || {});
this._updateAllValue();
this._assertValue(this.storeValue);
this._checkError();
// 标记正在请求数据
this.requesting = false;
this.trigger = createWidget({
type: SearchMultiSelectTrigger.xtype,
text: o.text,
height: toPix(o.height, o.simple ? 1 : 2),
// adapter: this.popup,
masker: {
offset: {
7 years ago
left: 0,
top: 0,
right: 0,
bottom: BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT + 1,
},
},
allValueGetter: () => this.allValue,
valueFormatter: o.valueFormatter,
itemsCreator: (op, callback) => {
this._itemsCreator(op, (res, ...args) => {
if (op.times === 1 && isNotNull(op.keywords)) {
// 预防trigger内部把当前的storeValue改掉
this.trigger.setValue(deepClone(this.getValue()));
}
callback.apply(this, [res, ...args]);
});
},
value: this.storeValue,
warningTitle: o.warningTitle,
});
this.trigger.on(MultiSelectTrigger.EVENT_START, () => {
this._setStartValue("");
this.trigger.getSearcher().setValue(this.storeValue);
});
this.trigger.on(MultiSelectTrigger.EVENT_STOP, () => {
this._setStartValue("");
});
this.trigger.on(MultiSelectTrigger.EVENT_SEARCHING, keywords => {
const _last = last(keywords);
keywords = initial(keywords || []);
if (keywords.length > 0) {
this._joinKeywords(keywords, () => {
if (endWith(_last, BlankSplitChar)) {
this.combo.setValue(this.storeValue);
assertShowValue();
this.combo.populate();
this._setStartValue("");
} else {
this.combo.setValue(this.storeValue);
assertShowValue();
}
this._dataChange = true;
});
}
});
this.trigger.on(MultiSelectTrigger.EVENT_CHANGE, (value, obj) => {
if (obj instanceof MultiSelectBar) {
this._joinAll(this.getValue(), () => {
assertShowValue();
});
} else {
this._join(this.getValue(), () => {
assertShowValue();
});
}
this._dataChange = true;
});
this.trigger.on(MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, () => {
this.trigger.getCounter().setValue(this.storeValue);
});
this.trigger.on(MultiSelectTrigger.EVENT_COUNTER_CLICK, () => {
if (!this.combo.isViewVisible()) {
this.combo.showView();
}
});
this.combo = createWidget({
type: Combo.xtype,
cls: o.simple ? "bi-border-bottom" : "bi-border bi-border-radius",
toggle: false,
container: o.container,
el: this.trigger,
adjustLength: 1,
popup: {
type: SearchMultiSelectPopupView.xtype,
ref: _ref => {
this.popup = _ref;
this.trigger.setAdapter(_ref);
},
listeners: [
{
eventName: MultiSelectPopupView.EVENT_CHANGE,
action: () => {
this._dataChange = true;
this.storeValue = this.popup.getValue();
this._adjust(() => {
assertShowValue();
});
},
},
{
eventName: MultiSelectPopupView.EVENT_CLICK_CONFIRM,
action: () => {
this._defaultState();
},
},
{
eventName: MultiSelectPopupView.EVENT_CLICK_CLEAR,
action: () => {
this._dataChange = true;
this.setValue();
this._defaultState();
},
}
],
itemsCreator: bind(this._itemsCreator, this),
valueFormatter: o.valueFormatter,
onLoaded: () => {
nextTick(() => {
this.combo.adjustWidth();
this.combo.adjustHeight();
this.trigger.getCounter().adjustView();
this.trigger.getSearcher().adjustView();
});
},
},
value: o.value,
hideChecker: e => triggerBtn.element.find(e.target).length === 0,
});
this.combo.on(Combo.EVENT_BEFORE_POPUPVIEW, () => {
if (!this.combo.isViewVisible()) {
this._dataChange = false; // 标记数据是否发生变化
4 years ago
}
this.setValue(this.storeValue);
nextTick(() => {
this._populate();
});
});
// 当退出的时候如果还在处理请求,则等请求结束后再对外发确定事件
this.wants2Quit = false;
this.combo.on(Combo.EVENT_AFTER_HIDEVIEW, () => {
// important:关闭弹出时又可能没有退出编辑状态
this.trigger.stopEditing();
if (this.requesting === true) {
this.wants2Quit = true;
} else {
7 years ago
/**
* 在存在标红的情况如果popover没有发生改变就确认需要同步trigger的值否则对外value值和trigger样式不统一
*/
assertShowValue();
this._dataChange && this.fireEvent(SearchMultiTextValueCombo.EVENT_CONFIRM);
}
});
triggerBtn.on(TriggerIconButton.EVENT_CHANGE, () => {
this.trigger.getCounter().hideView();
if (this.combo.isViewVisible()) {
this.combo.hideView();
} else {
this.combo.showView();
}
});
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,
}
],
});
this._checkError();
}
_defaultState() {
this.trigger.stopEditing();
this.combo.hideView();
}
_assertValue(val) {
const o = this.options;
val || (val = {});
val.type || (val.type = Selection.Multi);
val.value || (val.value = []);
remove(val.value, (idx, value) => !contains(map(o.items, "value"), value));
}
_makeMap(values) {
return makeObject(values || []);
}
_joinKeywords(keywords, callback) {
const digest = items => {
const selectedMap = this._makeMap(items);
each(keywords, (i, val) => {
if (isNotNull(selectedMap[val])) {
this.storeValue.type === Selection.Multi
? pushDistinct(this.storeValue.value, val)
: remove(this.storeValue.value, val);
}
});
this._adjust(callback);
};
this._assertValue(this.storeValue);
this.requesting = true;
this._itemsCreator(
{
type: SearchMultiTextValueCombo.REQ_GET_ALL_DATA,
keywords,
},
ob => {
const values = map(ob.items, "value");
digest(values);
}
);
}
_joinAll(res, callback) {
this._assertValue(res);
this.requesting = true;
this._itemsCreator(
{
type: SearchMultiTextValueCombo.REQ_GET_ALL_DATA,
keywords: [this.trigger.getKey()],
},
ob => {
const items = map(ob.items, "value");
if (this.storeValue.type === res.type) {
let change = false;
const _map = this._makeMap(this.storeValue.value);
each(items, (i, v) => {
if (isNotNull(_map[v])) {
change = true;
this.storeValue.assist && this.storeValue.assist.push(_map[v]);
delete _map[v];
}
});
change && (this.storeValue.value = values(_map));
this._adjust(callback);
return;
}
const selectedMap = this._makeMap(this.storeValue.value);
const notSelectedMap = this._makeMap(res.value);
const newItems = [];
each(items, (i, item) => {
if (isNotNull(selectedMap[items[i]])) {
this.storeValue.assist && this.storeValue.assist.push(selectedMap[items[i]]);
delete selectedMap[items[i]];
}
if (isNull(notSelectedMap[items[i]])) {
remove(this.storeValue.assist, item);
newItems.push(item);
}
});
this.storeValue.value = newItems.concat(values(selectedMap));
this._adjust(callback);
}
);
}
_adjust(callback) {
const adjust = () => {
if (this.storeValue.type === Selection.All && this.storeValue.value.length >= this._count) {
this.storeValue = {
type: Selection.Multi,
value: [],
};
} else if (this.storeValue.type === Selection.Multi && this.storeValue.value.length >= this._count) {
this.storeValue = {
type: Selection.All,
value: [],
};
}
this._updateAllValue();
this._checkError();
if (this.wants2Quit === true) {
this._dataChange && this.fireEvent(SearchMultiTextValueCombo.EVENT_CONFIRM);
this.wants2Quit = false;
}
this.requesting = false;
};
if (!this._count) {
this._itemsCreator(
{
type: SearchMultiTextValueCombo.REQ_GET_DATA_LENGTH,
},
res => {
this._count = res.count;
adjust();
callback();
}
);
} else {
adjust();
callback();
}
}
_join(res, callback) {
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]) {
this.storeValue.value.push(v);
remove(this.storeValue.assist, v);
map[v] = v;
}
});
let change = false;
each(res.assist, (i, v) => {
if (isNotNull(map[v])) {
change = true;
this.storeValue.assist && this.storeValue.assist.push(map[v]);
delete map[v];
}
});
change && (this.storeValue.value = values(map));
this._adjust(callback);
return;
}
this._joinAll(res, callback);
}
_setStartValue(value) {
this._startValue = value;
this.popup.setStartValue(value);
}
_getItemsByTimes(items, times) {
const res = [];
for (let i = (times - 1) * 100; items[i] && i < times * 100; i++) {
res.push(items[i]);
}
return res;
}
_hasNextByTimes(items, times) {
7 years ago
return times * 100 < items.length;
}
_itemsCreator(options, callback) {
const o = this.options;
let items = o.items;
const keywords = (options.keywords || []).slice();
if (options.keyword) {
keywords.push(options.keyword);
}
each(keywords, (i, kw) => {
const search = Func.getSearchResult(items, kw);
items = search.match.concat(search.find);
});
if (options.selectedValues) {
// 过滤
const _filter = makeObject(options.selectedValues, true);
items = filter(items, (i, ob) => !_filter[ob.value]);
}
if (options.type == MultiSelectCombo.REQ_GET_ALL_DATA) {
callback({
items,
});
return;
}
if (options.type == MultiSelectCombo.REQ_GET_DATA_LENGTH) {
callback({ count: items.length });
return;
}
callback({
items: this._getItemsByTimes(items, options.times),
hasNext: this._hasNextByTimes(items, options.times),
});
}
_checkError() {
let v = this.storeValue.value || [];
if (isNotEmptyArray(v)) {
v = isArray(v) ? v : [v];
const result = find(this.allValue, (idx, value) => !contains(v, value));
if (isNull(result)) {
isNotNull(this.trigger) && this.trigger.setTipType("success");
this.element.removeClass("combo-error");
7 years ago
} else {
isNotNull(this.trigger) && this.trigger.setTipType("warning");
7 years ago
this.element.addClass("combo-error");
}
} else {
if (v.length === this.allValue.length) {
isNotNull(this.trigger) && this.trigger.setTipType("success");
this.element.removeClass("combo-error");
} else {
isNotNull(this.trigger) && this.trigger.setTipType("warning");
this.element.addClass("combo-error");
}
}
}
_updateAllValue() {
this.storeValue = this.storeValue || {};
this.allValue = deepClone(this.storeValue.value || []);
}
setValue(v) {
this.storeValue = deepClone(v || {});
this._updateAllValue();
this._assertValue(this.storeValue);
this.combo.setValue(this.storeValue);
this._checkError();
}
getValue() {
return deepClone(this.storeValue);
}
_populate() {
this._count = null;
this.combo.populate();
}
populate(items) {
this.options.items = items;
this._populate();
}
}