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.

599 lines
20 KiB

8 years ago
/**
* 简单的复选下拉树控件, 适用于数据量少的情况
*
* Created by GUY on 2015/10/29.
* @class BI.TreeValueChooserCombo
* @extends BI.Widget
*/
BI.TreeValueChooserCombo = BI.inherit(BI.Widget, {
_const: {
perPage: 10
},
_defaultConfig: function () {
return BI.extend(BI.TreeValueChooserCombo.superclass._defaultConfig.apply(this, arguments), {
baseCls: "bi-tree-value-chooser-combo",
width: 200,
height: 30,
items: null,
itemsCreator: BI.emptyFn
});
},
_init: function () {
BI.TreeValueChooserCombo.superclass._init.apply(this, arguments);
var self = this, o = this.options;
if (BI.isNotNull(o.items)) {
this._initData(o.items);
}
this.combo = BI.createWidget({
type: 'bi.multi_tree_combo',
element: this.element,
itemsCreator: BI.bind(this._itemsCreator, this),
width: o.width,
height: o.height
});
this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () {
self.fireEvent(BI.TreeValueChooserCombo.EVENT_CONFIRM);
});
},
_initData: function (items) {
this.items = items;
var nodes = BI.Tree.transformToTreeFormat(items);
this.tree = new BI.Tree();
this.tree.initTree(nodes);
this._initMap();
this._initFloors();
},
_initMap: function () {
var map = this.map = {};
BI.each(this.items, function (i, item) {
map[item.value] = item;
});
},
_initFloors: function () {
this.floors = -1;
var root = this.tree.getRoot();
while (root) {
this.floors++;
root = root.getChildren()[0];
}
},
_itemsCreator: function (options, callback) {
var self = this, o = this.options;
if (!this.items) {
o.itemsCreator({}, function (items) {
self._initData(items);
call();
});
} else {
call();
}
function call() {
switch (options.type) {
case BI.TreeView.REQ_TYPE_INIT_DATA:
self._reqInitTreeNode(options, callback);
break;
case BI.TreeView.REQ_TYPE_ADJUST_DATA:
self._reqAdjustTreeNode(options, callback);
break;
case BI.TreeView.REQ_TYPE_CALCULATE_SELECT_DATA:
self._reqSelectedTreeNode(options, callback);
break;
case BI.TreeView.REQ_TYPE_SELECTED_DATA:
self._reqDisplayTreeNode(options, callback);
break;
default :
self._reqTreeNode(options, callback);
break;
}
}
},
_reqDisplayTreeNode: function (op, callback) {
var self = this;
var result = [];
var selected_values = op.selected_values;
if (selected_values == null || BI.isEmpty(selected_values)) {
callback({});
return;
}
doCheck(0, [], selected_values);
callback({
items: result
});
function doCheck(floor, parent_values, selected) {
if (floor >= self.floors) {
return;
}
if (selected == null || BI.isEmpty(selected)) {
var children = self._getChildren(parent_values);
BI.each(children, function (i, child) {
var newParents = BI.clone(parent_values);
newParents.push(child.value);
var llen = self._getChildCount(newParents);
createOneJson(child, llen);
doCheck(floor + 1, newParents, {});
});
return;
}
BI.each(selected, function (k) {
var node = self._getNode(k);
var newParents = BI.clone(parent_values);
newParents.push(node.value);
createOneJson(node, getCount(selected[k], newParents));
doCheck(floor + 1, newParents, selected[k]);
})
}
function getCount(jo, parent_values) {
if (jo == null) {
return 0;
}
if (BI.isEmpty(jo)) {
return self._getChildCount(parent_values);
}
return BI.size(jo);
}
function createOneJson(node, llen) {
result.push({
id: node.id,
pId: node.pId,
text: node.text + (llen > 0 ? ("(" + BI.i18nText("BI-Basic_Altogether") + llen + BI.i18nText("BI-Basic_Count") + ")") : ""),
value: node.value,
open: true
});
}
},
_reqSelectedTreeNode: function (op, callback) {
var self = this;
var selected_values = op.selected_values;
var not_selected_value = op.not_selected_value || {};
var keyword = op.keyword || "";
var parent_values = op.parent_values || [];
if (selected_values == null || BI.isEmpty(selected_values)) {
callback({});
return;
}
dealWithSelectedValues(selected_values);
callback(selected_values);
function dealWithSelectedValues(selected_values) {
var p = BI.clone(parent_values);
p.push(not_selected_value);
if (isChild(selected_values, p)) {
var result = [];
var finded = search(parent_values.length + 1, parent_values, not_selected_value, result);
if (finded === true) {
var next = selected_values;
BI.each(p, function (i, v) {
var t = next[v];
if (t == null) {
if (BI.isEmpty(next)) {
var split = p.slice(0, i);
var expanded = self._getChildren(split);
BI.each(expanded, function (m, child) {
if (i === p.length - 1 && child.value === not_selected_value) {
return true;
}
next[child.value] = {};
});
next = next[v];
} else {
next = {};
next[v] = {};
}
} else {
next = t;
}
});
if (result.length > 0) {
BI.each(result, function (i, strs) {
self._buildTree(selected_values, strs);
})
}
}
}
}
function search(deep, parents, current, result) {
var newParents = BI.clone(parents);
newParents.push(current);
if (self._isMatch(current, keyword)) {
return true;
}
if (deep >= self.floors) {
return false;
}
var children = self._getChildren(newParents);
var notSearch = [];
var can = false;
BI.each(children, function (i, child) {
if (search(deep + 1, newParents, child.value, result)) {
can = true;
} else {
notSearch.push(child.value);
}
});
if (can === true) {
BI.each(notSearch, function (i, v) {
var next = BI.clone(newParents);
next.push(v);
result.push(next);
});
}
return can;
}
function isChild(selected_values, parents) {
var t = selected_values;
for (var i = 0; i < parents.length; i++) {
var v = parents[i];
if (!BI.has(t, v)) {
return false;
}
t = t[v];
if (t == null || BI.isEmpty(t)) {
return true;
}
}
return true;
}
},
_reqAdjustTreeNode: function (op, callback) {
var self = this;
var result = [];
var selected_values = op.selected_values;
if (selected_values == null || BI.isEmpty(selected_values)) {
callback({});
return;
}
BI.each(selected_values, function (k, v) {
result.push([k]);
});
dealWithSelectedValues(selected_values, []);
var jo = {};
BI.each(result, function (i, strs) {
self._buildTree(jo, strs);
});
callback(jo);
function dealWithSelectedValues(selected, parents) {
if (selected == null || BI.isEmpty(selected)) {
return true;
}
var can = true;
BI.each(selected, function (k, v) {
var p = BI.clone(parents);
p.push(k);
if (!dealWithSelectedValues(selected[k], p)) {
BI.each(selected[k], function (nk, nv) {
var t = BI.clone(p);
t.push(nk);
result.push(t);
});
can = false;
}
});
return can && isAllSelected(selected, parents);
}
function isAllSelected(selected, parents) {
return BI.isEmpty(selected) || self._getChildCount(parents) === BI.size(selected);
}
},
_reqInitTreeNode: function (op, callback) {
var self = this;
var result = [];
var keyword = op.keyword || "";
var selected_values = op.selected_values;
var last_search_value = op.last_search_value || "";
var output = search();
BI.nextTick(function () {
callback({
hasNext: output.length > self._const.perPage,
items: result,
last_search_value: BI.last(output)
})
});
function search() {
var children = self._getChildren([]);
var start = children.length;
if (last_search_value !== "") {
for (var j = 0, len = start; j < len; j++) {
if (children[j].value === last_search_value) {
start = j + 1;
break;
}
}
} else {
start = 0;
}
var output = [];
for (var i = start, len = children.length; i < len; i++) {
if (output.length < self._const.perPage) {
var find = nodeSearch(1, [], children[i].value, false, result);
} else if (output.length === self._const.perPage) {
var find = nodeSearch(1, [], children[i].value, false, []);
}
if (find[0] === true) {
output.push(children[i].value);
}
if (output.length > self._const.perPage) {
break;
}
}
return output;
}
function nodeSearch(deep, parent_values, current, isAllSelect, result) {
if (self._isMatch(current, keyword)) {
var checked = isAllSelect || isSelected(parent_values, current);
createOneJson(parent_values, current, false, checked, !isAllSelect && isHalf(parent_values, current), true, result);
return [true, checked];
}
if (deep >= self.floors) {
return [false, false];
}
var newParents = BI.clone(parent_values);
newParents.push(current);
var children = self._getChildren(newParents);
var can = false, checked = false;
var isCurAllSelected = isAllSelect || isAllSelected(parent_values, current);
BI.each(children, function (i, child) {
var state = nodeSearch(deep + 1, newParents, child.value, isCurAllSelected, result);
if (state[1] === true) {
checked = true;
}
if (state[0] === true) {
can = true;
}
});
if (can === true) {
checked = isCurAllSelected || (isSelected(parent_values, current) && checked);
createOneJson(parent_values, current, true, checked, false, false, result);
}
return [can, checked];
}
function createOneJson(parent_values, value, isOpen, checked, half, flag, result) {
var node = self.map[value];
result.push({
id: node.id,
pId: node.pId,
text: node.text,
value: node.value,
title: node.title,
isParent: parent_values.length + 1 < self.floors,
open: isOpen,
checked: checked,
halfCheck: half,
flag: flag
});
}
function isHalf(parent_values, value) {
var find = findSelectedObj(parent_values);
if (find == null) {
return null;
}
return BI.any(find, function (v, ob) {
if (v === value) {
if (ob != null && !BI.isEmpty(ob)) {
return true;
}
}
});
}
function isAllSelected(parent_values, value) {
var find = findSelectedObj(parent_values);
if (find == null) {
return null;
}
return BI.any(find, function (v, ob) {
if (v === value) {
if (ob != null && BI.isEmpty(ob)) {
return true;
}
}
});
}
function isSelected(parent_values, value) {
var find = findSelectedObj(parent_values);
if (find == null) {
return false;
}
return BI.any(find, function (v) {
if (v === value) {
return true;
}
});
}
function findSelectedObj(parent_values) {
var find = selected_values;
if (find == null) {
return null;
}
BI.every(parent_values, function (i, v) {
find = find[v];
if (find == null) {
return false;
}
return true;
});
return find;
}
},
_reqTreeNode: function (op, callback) {
var self = this;
var result = [];
var times = op.times;
var check_state = op.check_state || {};
var parent_values = op.parent_values || [];
var selected_values = op.selected_values;
var valueMap = {};
if (judgeState(parent_values, selected_values, check_state)) {
valueMap = dealWidthSelectedValue(parent_values, selected_values);
}
var nodes = this._getChildren(parent_values);
for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) {
var state = getCheckState(nodes[i].value, parent_values, valueMap, check_state);
result.push({
id: nodes[i].id,
pId: nodes[i].pId,
value: nodes[i].value,
text: nodes[i].text,
times: 1,
isParent: parent_values.length + 1 < this.floors,
checked: state[0],
halfCheck: state[1]
})
}
BI.nextTick(function () {
callback({
items: result,
hasNext: nodes.length > times * self._const.perPage
});
});
function judgeState(parent_values, selected_value, check_state) {
var checked = check_state.checked, half = check_state.half;
if (parent_values.length > 0 && !checked) {
return false;
}
return (parent_values.length === 0 || (checked && half) && !BI.isEmpty(selected_value));
}
function dealWidthSelectedValue(parent_values, selected_values) {
var valueMap = {};
BI.each(parent_values, function (i, v) {
selected_values = selected_values[v];
});
BI.each(selected_values, function (value, obj) {
if (BI.isNull(obj)) {
valueMap[value] = [0, 0];
return;
}
if (BI.isEmpty(obj)) {
valueMap[value] = [2, 0];
return;
}
var nextNames = {};
BI.each(obj, function (t, o) {
if (BI.isNull(o) || BI.isEmpty(o)) {
nextNames[t] = true;
}
});
valueMap[value] = [1, BI.size(nextNames)];
});
return valueMap;
}
function getCheckState(current, parent_values, valueMap, check_state) {
var checked = check_state.checked, half = check_state.half;
var hasChild = parent_values.length + 1 < self.floors;
var tempCheck = false, halfCheck = false;
if (BI.has(valueMap, current)) {
//可能是半选
if (valueMap[current][0] === 1) {
var values = BI.clone(parent_values);
values.push(current);
if (hasChild && self._getChildCount(values) != valueMap[current][1]) {
halfCheck = true;
}
} else if (valueMap[current][0] === 2) {
tempCheck = true;
}
}
var check;
if (!checked && !halfCheck && !tempCheck) {
check = BI.has(valueMap, current);
} else {
check = ((tempCheck || checked) && !half) || BI.has(valueMap, current);
}
return [check, halfCheck];
}
},
_buildTree: function (jo, values) {
var t = jo;
BI.each(values, function (i, v) {
if (!BI.has(t, v)) {
t[v] = {};
}
t = t[v];
});
},
_isMatch: function (value, keyword) {
var finded = BI.Func.getSearchResult([value], keyword);
return finded.finded.length > 0 || finded.matched.length > 0;
},
_getNode: function (v) {
return this.tree.search(v, "value");
},
_getChildren: function (parent_values) {
if (parent_values.length > 0) {
var value = BI.last(parent_values);
var parent = this.tree.search(value, "value");
} else {
var parent = this.tree.getRoot();
}
return parent.getChildren();
},
_getChildCount: function (parent_values) {
return this._getChildren(parent_values).length;
},
setValue: function (v) {
this.combo.setValue(v);
},
getValue: function () {
return this.combo.getValue();
},
populate: function () {
this.combo.populate.apply(this, arguments);
}
});
BI.TreeValueChooserCombo.EVENT_CONFIRM = "TreeValueChooserCombo.EVENT_CONFIRM";
$.shortcut('bi.tree_value_chooser_combo', BI.TreeValueChooserCombo);