diff --git a/Gruntfile.js b/Gruntfile.js index e81af8caa..9f5ff5a10 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -49,6 +49,9 @@ module.exports = function (grunt) { "src/base/tree/ztree/treeview.js", "src/base/tree/ztree/asynctree.js", "src/base/tree/ztree/parttree.js", + "src/base/tree/ztree/list/listtreeview.js", + "src/base/tree/ztree/list/listasynctree.js", + "src/base/tree/ztree/list/listparttree.js", "src/base/**/*.js" ], dest: "dist/base.js" diff --git a/demo/js/component/demo.treevaluechoosercombo.js b/demo/js/component/demo.treevaluechoosercombo.js index 8fa557ee1..1d5075e13 100644 --- a/demo/js/component/demo.treevaluechoosercombo.js +++ b/demo/js/component/demo.treevaluechoosercombo.js @@ -5,18 +5,28 @@ Demo.TreeValueChooser = BI.inherit(BI.Widget, { render: function () { var widget = BI.createWidget({ - type: "bi.tree_value_chooser_combo", + type: "bi.tree_value_chooser_insert_combo", width: 300, // items: BI.deepClone(Demo.CONSTANTS.TREEITEMS), itemsCreator: function (op, callback) { callback(BI.deepClone(Demo.CONSTANTS.TREEITEMS)); } }); + var widget1 = BI.createWidget({ + type: "bi.list_tree_value_chooser_insert_combo", + itemsCreator: function (op, callback) { + callback(BI.deepClone(Demo.CONSTANTS.TREEITEMS)); + } + }); return { type: "bi.vertical", - hgap: 200, - vgap: 10, - items: [widget] + items: [{ + type: "bi.vertical_adapt", + hgap: 200, + vgap: 10, + items: [widget, widget1] + }] + }; } }); diff --git a/dist/2.0/fineui.css b/dist/2.0/fineui.css index 214c1b104..40180856d 100644 --- a/dist/2.0/fineui.css +++ b/dist/2.0/fineui.css @@ -2228,8 +2228,8 @@ textarea { _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/half_selected.png'); + background: url('images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -2274,8 +2274,8 @@ textarea { _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/half_selected.png'); + background: url('images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { @@ -3579,7 +3579,7 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, opacity: 0; } .bi-checkbox.disabled.active .checkbox-content { - border-color: #e8eaed; + border-color: #d0d4da; } .bi-checkbox.disabled.active .checkbox-content:after { opacity: 1; @@ -3587,6 +3587,16 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, .bi-theme-dark .bi-checkbox .checkbox-content { border-color: #9EA6B2; } +.bi-theme-dark .bi-checkbox.active .checkbox-content, +.bi-theme-dark .bi-checkbox:active .checkbox-content { + border-color: #3685f2; +} +.bi-theme-dark .bi-checkbox.disabled .checkbox-content { + background-color: #606479; +} +.bi-theme-dark .bi-checkbox.disabled.active .checkbox-content { + border-color: #606479; +} .bi-file { opacity: 0; filter: alpha(opacity=0); @@ -3765,6 +3775,21 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, opacity: 1; filter: alpha(opacity=100); } + +.bi-list-display-tree .ztree li a, +.bi-list-display-tree .ztree li span { + cursor: default !important; +} +.bi-list-display-tree .ztree li a:hover { + text-decoration: none; +} +.bi-list-display-tree .ztree li a.curSelectedNode { + padding-top: 1px; + border: none; + background-color: inherit; + opacity: 1; + filter: alpha(opacity=100); +} .ztree * { padding: 0; margin: 0; @@ -4548,8 +4573,8 @@ textarea::-webkit-scrollbar-thumb:hover { _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/half_selected.png'); + background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -4594,8 +4619,8 @@ textarea::-webkit-scrollbar-thumb:hover { _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/half_selected.png'); + background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { diff --git a/dist/2.0/fineui.ie.js b/dist/2.0/fineui.ie.js index ac0b998ae..5f146657d 100644 --- a/dist/2.0/fineui.ie.js +++ b/dist/2.0/fineui.ie.js @@ -37190,8 +37190,8 @@ BI.TreeView = BI.inherit(BI.Pane, { async: { enable: true, url: getUrl, - autoParam: ["id", "name"], - otherParam: BI.cjkEncodeDO(paras) + autoParam: ["id", "name"], // 节点展开异步请求自动提交id和name + otherParam: BI.cjkEncodeDO(paras) // 静态参数 }, check: { enable: true @@ -37199,16 +37199,16 @@ BI.TreeView = BI.inherit(BI.Pane, { data: { key: { title: "title", - name: "text" + name: "text" // 节点的name属性替换成text }, simpleData: { - enable: true + enable: true // 可以穿id,pid属性的对象数组 } }, view: { showIcon: false, expandSpeed: "", - nameIsHTML: true, + nameIsHTML: true, // 节点可以用html标签代替 dblClickExpand: false }, callback: { @@ -37231,6 +37231,7 @@ BI.TreeView = BI.inherit(BI.Pane, { if(status.half === true && status.checked === true) { checked = false; } + // 更新此node的check状态, 影响父子关联,并调用beforeCheck和onCheck回调 self.nodes.checkNode(treeNode, !checked, true, true); } @@ -37253,7 +37254,7 @@ BI.TreeView = BI.inherit(BI.Pane, { } return true; } - BI.Msg.toast("Please Wait。", "warning"); + BI.Msg.toast("Please Wait。", "warning"); // 不展开节点,也不触发onExpand事件 return false; } @@ -37291,9 +37292,9 @@ BI.TreeView = BI.inherit(BI.Pane, { function ajaxGetNodes (treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { - zTree.updateNode(treeNode); + zTree.updateNode(treeNode); // 刷新一下当前节点,如果treeNode.xxx被改了的话 } - zTree.reAsyncChildNodes(treeNode, reloadType, true); + zTree.reAsyncChildNodes(treeNode, reloadType, true); // 强制加载子节点,reloadType === refresh为先清空再加载,否则为追加到现有子节点之后 } function beforeCheck (treeId, treeNode) { @@ -37371,15 +37372,18 @@ BI.TreeView = BI.inherit(BI.Pane, { } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); + // 当前节点是全选的,因为上面的判断已经排除了不选和半选 if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } + // 剩下的就是半选不展开的节点,因为不知道里面是什么情况,所以借助selectedValues(这个是完整的选中情况) var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, + // 获取的是以values最后一个节点为根的子树 _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { @@ -37391,6 +37395,7 @@ BI.TreeView = BI.inherit(BI.Pane, { return cur; }, + // 以values为path一路向里补充map, 并在末尾节点添加key: value节点 _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { @@ -37418,7 +37423,7 @@ BI.TreeView = BI.inherit(BI.Pane, { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); - track(rootNoots); + track(rootNoots); // 可以看到这个方法没有递归调用,所以在_getHalfSelectedValues中需要关心全选的节点 function track (nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); @@ -37666,7 +37671,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { var self = this; var setting = { async: { - enable: false, + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: BI.cjkEncodeDO(paras) }, check: { @@ -37756,6 +37761,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { return setting; }, + // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); @@ -37801,7 +37807,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { function callback (nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); - + // 展开节点是没有分页的 if (hasNext === true) { BI.delay(function () { times++; @@ -37818,6 +37824,9 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { } }, + // a,b 两棵树 + // a->b b->a 做两次校验, 构造一个校验后的map + // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join: function (valueA, valueB) { var self = this; var map = {}; @@ -37909,9 +37918,17 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { - BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + this._buildTree(self.options.paras.selectedValues, BI.concat(parentValues, name)); + o.itemsCreator({ + type: BI.TreeView.REQ_TYPE_ADJUST_DATA, + selectedValues: self.options.paras.selectedValues + }, function (res) { + self.options.paras.selectedValues = res; + BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + }); } else { // 如果选中的值中不存在该值不处理 + // 因为反正是不选中,没必要管 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { @@ -37919,6 +37936,7 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { if (t == null) { return; } + // 选中中国-江苏, 搜索南京,取消勾选 if (BI.isEmpty(t)) { break; } @@ -37982,9 +38000,8 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; - if (nodes.length > 0) { - callback(self._dealWidthNodes(nodes)); - } + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { @@ -38010,12 +38027,6 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); - o.itemsCreator({ - type: BI.TreeView.REQ_TYPE_ADJUST_DATA, - selectedValues: result - }, function (res) { - result = res; - }); return result; }, @@ -38030,7 +38041,333 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } }); -BI.shortcut("bi.part_tree", BI.PartTree);BI.prepares.push(function () { +BI.shortcut("bi.part_tree", BI.PartTree);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为[["A"], ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListTreeView + * @extends BI.TreeView + */ +BI.ListTreeView = BI.inherit(BI.TreeView, { + + _constants: { + SPLIT: "<|>" + }, + + _defaultConfig: function () { + return BI.extend(BI.ListTreeView.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListTreeView.superclass._init.apply(this, arguments); + var o = this.options; + this.storeValue = o.value || {}; + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + onClick: onClick + } + }; + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + _selectTreeNode: function (treeId, treeNode) { + this._checkValue(treeNode, treeNode.checked); + BI.ListTreeView.superclass._selectTreeNode.apply(this, arguments); + }, + + _transArrayToMap: function (treeArrays) { + var self = this; + var map = {}; + BI.each(treeArrays, function (idx, array) { + var key = array.join(self._constants.SPLIT); + map[key] = true; + }); + return map; + }, + + _transMapToArray: function (treeMap) { + var self = this; + var array = []; + BI.each(treeMap, function (key) { + var item = key.split(self._constants.SPLIT); + array.push(item); + }); + return array; + }, + + _checkValue: function (treeNode, checked) { + var key = BI.concat(this._getParentValues(treeNode), this._getNodeValue(treeNode)).join(this._constants.SPLIT); + if(checked) { + this.storeValue[key] = true; + } else { + delete this.storeValue[key]; + } + }, + + setSelectedValue: function (value) { + this.options.paras.selectedValues = value || []; + this.storeValue = this._transArrayToMap(value); + }, + + getValue: function () { + return this._transMapToArray(this.storeValue); + } +}); + +BI.shortcut("bi.list_tree_view", BI.ListTreeView);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为["A", ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListListAsyncTree + * @extends BI.TreeView + */ +BI.ListAsyncTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListAsyncTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListAsyncTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 + otherParam: BI.cjkEncodeDO(paras) + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + beforeExpand: beforeExpand, + beforeCheck: beforeCheck, + onClick: onClick + } + }; + + function beforeCheck (treeId, treeNode) { + treeNode.half = false; + } + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function beforeExpand (treeId, treeNode) { + self._beforeExpandNode(treeId, treeNode); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + // 展开节点 + _beforeExpandNode: function (treeId, treeNode) { + var self = this, o = this.options; + var parentValues = treeNode.parentValues || self._getParentValues(treeNode); + var op = BI.extend({}, o.paras, { + id: treeNode.id, + times: 1, + parentValues: parentValues.concat(this._getNodeValue(treeNode)) + }); + var complete = function (d) { + var nodes = d.items || []; + if (nodes.length > 0) { + callback(self._dealWidthNodes(nodes), !!d.hasNext); + } + }; + var times = 1; + + function callback (nodes, hasNext) { + self.nodes.addNodes(treeNode, nodes); + // 展开节点是没有分页的 + if (hasNext === true) { + BI.delay(function () { + times++; + op.times = times; + o.itemsCreator(op, complete); + }, 100); + } + } + + if (!treeNode.children) { + setTimeout(function () { + o.itemsCreator(op, complete); + }, 17); + } + }, + + hasChecked: function () { + return !BI.isEmpty(this.options.paras.selectedValues) || BI.ListAsyncTree.superclass.hasChecked.apply(this, arguments); + }, + + // 生成树方法 + stroke: function (config) { + delete this.options.keyword; + BI.extend(this.options.paras, config); + var setting = this._configSetting(); + this._initTree(setting); + } +}); + +BI.shortcut("bi.list_async_tree", BI.ListAsyncTree);/** + * guy + * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 + * @class BI.ListPartTree + * @extends BI.AsyncTree + */ +BI.ListPartTree = BI.inherit(BI.ListAsyncTree, { + _defaultConfig: function () { + return BI.extend(BI.ListPartTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + + _init: function () { + BI.ListPartTree.superclass._init.apply(this, arguments); + }, + + _loadMore: function () { + var self = this, o = this.options; + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: ++this.times + }); + this.tip.setLoading(); + o.itemsCreator(op, function (d) { + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + if (self._stop === true) { + return; + } + if (!hasNext) { + self.tip.setEnd(); + } else { + self.tip.setLoaded(); + } + if (nodes.length > 0) { + self.nodes.addNodes(null, self._dealWidthNodes(nodes)); + } + }); + }, + + _initTree: function (setting, keyword) { + var self = this, o = this.options; + this.times = 1; + var tree = this.tree; + tree.empty(); + self.tip.setVisible(false); + this.loading(); + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: this.times + }); + var complete = function (d) { + if (self._stop === true || keyword != o.paras.keyword) { + return; + } + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); + self.setTipVisible(nodes.length <= 0); + self.loaded(); + if (!hasNext) { + self.tip.invisible(); + } else { + self.tip.setLoaded(); + } + self.fireEvent(BI.Events.AFTERINIT); + }; + + function callback (nodes) { + if (self._stop === true) { + return; + } + self.nodes = $.fn.zTree.init(tree.element, setting, nodes); + } + + BI.delay(function () { + o.itemsCreator(op, complete); + }, 100); + }, + + // 生成树方法 + stroke: function (config) { + var o = this.options; + delete o.paras.keyword; + BI.extend(o.paras, config); + delete o.paras.lastSearchValue; + var setting = this._configSetting(); + this._initTree(setting, o.paras.keyword); + } +}); + +BI.shortcut("bi.list_part_tree", BI.ListPartTree);BI.prepares.push(function () { BI.Resizers = new BI.ResizeController(); BI.Layers = new BI.LayerController(); BI.Maskers = new BI.MaskersController(); @@ -49533,6 +49870,8 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, + checkboxType = setting.check.chkboxType; + var notEffectByOtherNode = (checkboxType.Y === "" && checkboxType.N === ""); fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; @@ -49541,7 +49880,7 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { - fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); + fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) || notEffectByOtherNode ? c.FULL:c.PART) : ((node.check_Child_State < 1 || notEffectByOtherNode)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; @@ -58890,6 +59229,86 @@ BI.DisplayTree = BI.inherit(BI.TreeView, { BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.display_tree", BI.DisplayTree);/** + * guy + * 异步树 + * @class BI.ListListDisplayTree + * @extends BI.TreeView + */ +BI.ListDisplayTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListDisplayTree.superclass._defaultConfig.apply(this, arguments), { + extraCls: "bi-list-display-tree" + }); + }, + _init: function () { + BI.ListDisplayTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var setting = { + view: { + selectedMulti: false, + dblClickExpand: false, + showIcon: false, + nameIsHTML: true, + showTitle: false, + fontCss: getFont + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + callback: { + beforeCollapse: beforeCollapse + } + }; + + function beforeCollapse(treeId, treeNode) { + return false; + } + + function getFont(treeId, node) { + return node.font ? node.font : {color: "#999999"}; + } + + return setting; + }, + + _dealWidthNodes: function (nodes) { + nodes = BI.ListDisplayTree.superclass._dealWidthNodes.apply(this, arguments); + var self = this, o = this.options; + BI.each(nodes, function (i, node) { + node.isParent = node.isParent || node.parent; + if (node.text == null) { + if (node.count > 0) { + node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; + } + } + if(node.isLeaf === true) { + node.font = {color: "#3d4d66"}; + } + }); + return nodes; + }, + + initTree: function (nodes, setting) { + var setting = setting || this._configSetting(); + this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); + }, + + destroy: function () { + BI.ListDisplayTree.superclass.destroy.apply(this, arguments); + } +}); +BI.ListDisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.shortcut("bi.list_display_tree", BI.ListDisplayTree);/** * 简单的多选树 * * Created by GUY on 2016/2/16. @@ -72122,7 +72541,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -72164,7 +72586,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { @@ -72489,6 +72911,585 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut("bi.multi_tree_combo", BI.MultiTreeCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single + */ + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo + * @extends BI.Single + */ + +BI.MultiTreeListCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo);/** * 带加载的多选下拉面板 * @class BI.MultiTreePopup * @extends BI.Pane @@ -72501,24 +73502,27 @@ BI.MultiTreePopup = BI.inherit(BI.Pane, { maxWidth: "auto", minWidth: 100, maxHeight: 400, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } }); }, _init: function () { BI.MultiTreePopup.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, opts = this.options, v = opts.value; this.selectedValues = {}; - this.tree = BI.createWidget({ + this.tree = BI.createWidget(opts.el, { type: "bi.async_tree", height: 400, cls: "popup-view-tree", itemsCreator: opts.itemsCreator, onLoaded: opts.onLoaded, - value: opts.value || {} + value: v.value || {} }); this.popupView = BI.createWidget({ @@ -72586,6 +73590,190 @@ BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** + * 查看已选按钮 + * Created by guy on 15/11/3. + * @class BI.MultiTreeCheckSelectedButton + * @extends BI.Single + */ +BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-check-selected-button", + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); + var self = this; + this.indicator = BI.createWidget({ + type: "bi.icon_button", + cls: "check-font trigger-check-selected icon-size-12", + width: 15, + height: 15, + stopPropagation: true + }); + + this.checkSelected = BI.createWidget({ + type: "bi.text_button", + cls: "trigger-check-selected", + invisible: true, + hgap: 4, + text: BI.i18nText("BI-Check_Selected"), + textAlign: "center", + textHeight: 15 + }); + this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + }); + + BI.createWidget({ + type: "bi.horizontal", + element: this, + items: [this.indicator, this.checkSelected] + }); + + this.element.hover(function () { + self.indicator.setVisible(false); + self.checkSelected.setVisible(true); + }, function () { + self.indicator.setVisible(true); + self.checkSelected.setVisible(false); + }); + this.setVisible(false); + }, + + setValue: function (v) { + v || (v = {}); + this.setVisible(BI.size(v.value) > 0); + } +}); + +BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane);/** * * 在搜索框中输入文本弹出的面板 * @class BI.MultiTreeSearchPane @@ -72659,72 +73847,163 @@ BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** - * 查看已选按钮 + * searcher * Created by guy on 15/11/3. - * @class BI.MultiTreeCheckSelectedButton - * @extends BI.Single + * @class BI.MultiListTreeSearcher + * @extends Widget */ -BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { - return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-check-selected-button", - itemsCreator: BI.emptyFn + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} }); }, _init: function () { - BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); - var self = this; - this.indicator = BI.createWidget({ - type: "bi.icon_button", - cls: "check-font trigger-check-selected icon-size-12", - width: 15, - height: 15, - stopPropagation: true + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } }); - this.checkSelected = BI.createWidget({ - type: "bi.text_button", - cls: "trigger-check-selected", - invisible: true, - hgap: 4, - text: BI.i18nText("BI-Check_Selected"), - textAlign: "center", - textHeight: 15 + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker }); - this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { - this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); }); - - BI.createWidget({ - type: "bi.horizontal", - element: this, - items: [this.indicator, this.checkSelected] + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); }); - - this.element.hover(function () { - self.indicator.setVisible(false); - self.checkSelected.setVisible(true); - }, function () { - self.indicator.setVisible(true); - self.checkSelected.setVisible(false); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); }); - this.setVisible(false); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } }, - setValue: function (v) { - v || (v = {}); - this.setVisible(BI.size(v.value) > 0); + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); } }); -BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher);/** * searcher * Created by guy on 15/11/3. * @class BI.MultiTreeSearcher @@ -82601,10 +83880,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -82864,7 +84152,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -82901,6 +84189,15 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } @@ -83030,6 +84327,10 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { halfCheck: state[1] }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -83096,6 +84397,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }, + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + _getNode: function (selectedValues, parentValues) { var pNode = selectedValues; for (var i = 0, len = parentValues.length; i < len; i++) { @@ -83181,7 +84498,373 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { _getChildCount: function (parentValues) { return this._getChildren(parentValues).length; } +});BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { + + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); + }); + } + + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; + } + }, + + _reqInitTreeNode: function (op, callback) { + var self = this; + var result = []; + var keyword = op.keyword || ""; + var selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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, result); + } else if (output.length === self._const.perPage) { + var find = nodeSearch(1, [], children[i].value, []); + } + if (find[0] === true) { + output.push(children[i].value); + } + if (output.length > self._const.perPage) { + break; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + BI.each(children, function (i, child) { + var state = nodeSearch(deep + 1, newParents, child.value, result); + if (state[1] === true) { + checked = true; + } + if (state[0] === true) { + can = true; + } + }); + if (can === true) { + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: false, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; + } + BI.every(parentValues, 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 parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var checked = BI.has(valueMap, nodes[i].value); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: checked, + halfCheck: false + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); + + function dealWidthSelectedValue(selectedValues) { + var valueMap = {}; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; + }); + return valueMap; + } + }, + + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } });/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.ListTreeValueChooserInsertCombo.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_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo);/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.TreeValueChooserInsertCombo.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_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. diff --git a/dist/2.0/fineui.js b/dist/2.0/fineui.js index e480ccce0..298fefd4a 100644 --- a/dist/2.0/fineui.js +++ b/dist/2.0/fineui.js @@ -37594,8 +37594,8 @@ BI.TreeView = BI.inherit(BI.Pane, { async: { enable: true, url: getUrl, - autoParam: ["id", "name"], - otherParam: BI.cjkEncodeDO(paras) + autoParam: ["id", "name"], // 节点展开异步请求自动提交id和name + otherParam: BI.cjkEncodeDO(paras) // 静态参数 }, check: { enable: true @@ -37603,16 +37603,16 @@ BI.TreeView = BI.inherit(BI.Pane, { data: { key: { title: "title", - name: "text" + name: "text" // 节点的name属性替换成text }, simpleData: { - enable: true + enable: true // 可以穿id,pid属性的对象数组 } }, view: { showIcon: false, expandSpeed: "", - nameIsHTML: true, + nameIsHTML: true, // 节点可以用html标签代替 dblClickExpand: false }, callback: { @@ -37635,6 +37635,7 @@ BI.TreeView = BI.inherit(BI.Pane, { if(status.half === true && status.checked === true) { checked = false; } + // 更新此node的check状态, 影响父子关联,并调用beforeCheck和onCheck回调 self.nodes.checkNode(treeNode, !checked, true, true); } @@ -37657,7 +37658,7 @@ BI.TreeView = BI.inherit(BI.Pane, { } return true; } - BI.Msg.toast("Please Wait。", "warning"); + BI.Msg.toast("Please Wait。", "warning"); // 不展开节点,也不触发onExpand事件 return false; } @@ -37695,9 +37696,9 @@ BI.TreeView = BI.inherit(BI.Pane, { function ajaxGetNodes (treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { - zTree.updateNode(treeNode); + zTree.updateNode(treeNode); // 刷新一下当前节点,如果treeNode.xxx被改了的话 } - zTree.reAsyncChildNodes(treeNode, reloadType, true); + zTree.reAsyncChildNodes(treeNode, reloadType, true); // 强制加载子节点,reloadType === refresh为先清空再加载,否则为追加到现有子节点之后 } function beforeCheck (treeId, treeNode) { @@ -37775,15 +37776,18 @@ BI.TreeView = BI.inherit(BI.Pane, { } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); + // 当前节点是全选的,因为上面的判断已经排除了不选和半选 if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } + // 剩下的就是半选不展开的节点,因为不知道里面是什么情况,所以借助selectedValues(这个是完整的选中情况) var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, + // 获取的是以values最后一个节点为根的子树 _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { @@ -37795,6 +37799,7 @@ BI.TreeView = BI.inherit(BI.Pane, { return cur; }, + // 以values为path一路向里补充map, 并在末尾节点添加key: value节点 _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { @@ -37822,7 +37827,7 @@ BI.TreeView = BI.inherit(BI.Pane, { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); - track(rootNoots); + track(rootNoots); // 可以看到这个方法没有递归调用,所以在_getHalfSelectedValues中需要关心全选的节点 function track (nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); @@ -38070,7 +38075,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { var self = this; var setting = { async: { - enable: false, + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: BI.cjkEncodeDO(paras) }, check: { @@ -38160,6 +38165,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { return setting; }, + // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); @@ -38205,7 +38211,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { function callback (nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); - + // 展开节点是没有分页的 if (hasNext === true) { BI.delay(function () { times++; @@ -38222,6 +38228,9 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { } }, + // a,b 两棵树 + // a->b b->a 做两次校验, 构造一个校验后的map + // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join: function (valueA, valueB) { var self = this; var map = {}; @@ -38313,9 +38322,17 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { - BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + this._buildTree(self.options.paras.selectedValues, BI.concat(parentValues, name)); + o.itemsCreator({ + type: BI.TreeView.REQ_TYPE_ADJUST_DATA, + selectedValues: self.options.paras.selectedValues + }, function (res) { + self.options.paras.selectedValues = res; + BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + }); } else { // 如果选中的值中不存在该值不处理 + // 因为反正是不选中,没必要管 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { @@ -38323,6 +38340,7 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { if (t == null) { return; } + // 选中中国-江苏, 搜索南京,取消勾选 if (BI.isEmpty(t)) { break; } @@ -38386,9 +38404,8 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; - if (nodes.length > 0) { - callback(self._dealWidthNodes(nodes)); - } + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { @@ -38414,12 +38431,6 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); - o.itemsCreator({ - type: BI.TreeView.REQ_TYPE_ADJUST_DATA, - selectedValues: result - }, function (res) { - result = res; - }); return result; }, @@ -38434,7 +38445,333 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } }); -BI.shortcut("bi.part_tree", BI.PartTree);BI.prepares.push(function () { +BI.shortcut("bi.part_tree", BI.PartTree);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为[["A"], ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListTreeView + * @extends BI.TreeView + */ +BI.ListTreeView = BI.inherit(BI.TreeView, { + + _constants: { + SPLIT: "<|>" + }, + + _defaultConfig: function () { + return BI.extend(BI.ListTreeView.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListTreeView.superclass._init.apply(this, arguments); + var o = this.options; + this.storeValue = o.value || {}; + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + onClick: onClick + } + }; + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + _selectTreeNode: function (treeId, treeNode) { + this._checkValue(treeNode, treeNode.checked); + BI.ListTreeView.superclass._selectTreeNode.apply(this, arguments); + }, + + _transArrayToMap: function (treeArrays) { + var self = this; + var map = {}; + BI.each(treeArrays, function (idx, array) { + var key = array.join(self._constants.SPLIT); + map[key] = true; + }); + return map; + }, + + _transMapToArray: function (treeMap) { + var self = this; + var array = []; + BI.each(treeMap, function (key) { + var item = key.split(self._constants.SPLIT); + array.push(item); + }); + return array; + }, + + _checkValue: function (treeNode, checked) { + var key = BI.concat(this._getParentValues(treeNode), this._getNodeValue(treeNode)).join(this._constants.SPLIT); + if(checked) { + this.storeValue[key] = true; + } else { + delete this.storeValue[key]; + } + }, + + setSelectedValue: function (value) { + this.options.paras.selectedValues = value || []; + this.storeValue = this._transArrayToMap(value); + }, + + getValue: function () { + return this._transMapToArray(this.storeValue); + } +}); + +BI.shortcut("bi.list_tree_view", BI.ListTreeView);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为["A", ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListListAsyncTree + * @extends BI.TreeView + */ +BI.ListAsyncTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListAsyncTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListAsyncTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 + otherParam: BI.cjkEncodeDO(paras) + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + beforeExpand: beforeExpand, + beforeCheck: beforeCheck, + onClick: onClick + } + }; + + function beforeCheck (treeId, treeNode) { + treeNode.half = false; + } + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function beforeExpand (treeId, treeNode) { + self._beforeExpandNode(treeId, treeNode); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + // 展开节点 + _beforeExpandNode: function (treeId, treeNode) { + var self = this, o = this.options; + var parentValues = treeNode.parentValues || self._getParentValues(treeNode); + var op = BI.extend({}, o.paras, { + id: treeNode.id, + times: 1, + parentValues: parentValues.concat(this._getNodeValue(treeNode)) + }); + var complete = function (d) { + var nodes = d.items || []; + if (nodes.length > 0) { + callback(self._dealWidthNodes(nodes), !!d.hasNext); + } + }; + var times = 1; + + function callback (nodes, hasNext) { + self.nodes.addNodes(treeNode, nodes); + // 展开节点是没有分页的 + if (hasNext === true) { + BI.delay(function () { + times++; + op.times = times; + o.itemsCreator(op, complete); + }, 100); + } + } + + if (!treeNode.children) { + setTimeout(function () { + o.itemsCreator(op, complete); + }, 17); + } + }, + + hasChecked: function () { + return !BI.isEmpty(this.options.paras.selectedValues) || BI.ListAsyncTree.superclass.hasChecked.apply(this, arguments); + }, + + // 生成树方法 + stroke: function (config) { + delete this.options.keyword; + BI.extend(this.options.paras, config); + var setting = this._configSetting(); + this._initTree(setting); + } +}); + +BI.shortcut("bi.list_async_tree", BI.ListAsyncTree);/** + * guy + * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 + * @class BI.ListPartTree + * @extends BI.AsyncTree + */ +BI.ListPartTree = BI.inherit(BI.ListAsyncTree, { + _defaultConfig: function () { + return BI.extend(BI.ListPartTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + + _init: function () { + BI.ListPartTree.superclass._init.apply(this, arguments); + }, + + _loadMore: function () { + var self = this, o = this.options; + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: ++this.times + }); + this.tip.setLoading(); + o.itemsCreator(op, function (d) { + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + if (self._stop === true) { + return; + } + if (!hasNext) { + self.tip.setEnd(); + } else { + self.tip.setLoaded(); + } + if (nodes.length > 0) { + self.nodes.addNodes(null, self._dealWidthNodes(nodes)); + } + }); + }, + + _initTree: function (setting, keyword) { + var self = this, o = this.options; + this.times = 1; + var tree = this.tree; + tree.empty(); + self.tip.setVisible(false); + this.loading(); + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: this.times + }); + var complete = function (d) { + if (self._stop === true || keyword != o.paras.keyword) { + return; + } + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); + self.setTipVisible(nodes.length <= 0); + self.loaded(); + if (!hasNext) { + self.tip.invisible(); + } else { + self.tip.setLoaded(); + } + self.fireEvent(BI.Events.AFTERINIT); + }; + + function callback (nodes) { + if (self._stop === true) { + return; + } + self.nodes = $.fn.zTree.init(tree.element, setting, nodes); + } + + BI.delay(function () { + o.itemsCreator(op, complete); + }, 100); + }, + + // 生成树方法 + stroke: function (config) { + var o = this.options; + delete o.paras.keyword; + BI.extend(o.paras, config); + delete o.paras.lastSearchValue; + var setting = this._configSetting(); + this._initTree(setting, o.paras.keyword); + } +}); + +BI.shortcut("bi.list_part_tree", BI.ListPartTree);BI.prepares.push(function () { BI.Resizers = new BI.ResizeController(); BI.Layers = new BI.LayerController(); BI.Maskers = new BI.MaskersController(); @@ -49937,6 +50274,8 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, + checkboxType = setting.check.chkboxType; + var notEffectByOtherNode = (checkboxType.Y === "" && checkboxType.N === ""); fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; @@ -49945,7 +50284,7 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { - fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); + fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) || notEffectByOtherNode ? c.FULL:c.PART) : ((node.check_Child_State < 1 || notEffectByOtherNode)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; @@ -59294,6 +59633,86 @@ BI.DisplayTree = BI.inherit(BI.TreeView, { BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.display_tree", BI.DisplayTree);/** + * guy + * 异步树 + * @class BI.ListListDisplayTree + * @extends BI.TreeView + */ +BI.ListDisplayTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListDisplayTree.superclass._defaultConfig.apply(this, arguments), { + extraCls: "bi-list-display-tree" + }); + }, + _init: function () { + BI.ListDisplayTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var setting = { + view: { + selectedMulti: false, + dblClickExpand: false, + showIcon: false, + nameIsHTML: true, + showTitle: false, + fontCss: getFont + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + callback: { + beforeCollapse: beforeCollapse + } + }; + + function beforeCollapse(treeId, treeNode) { + return false; + } + + function getFont(treeId, node) { + return node.font ? node.font : {color: "#999999"}; + } + + return setting; + }, + + _dealWidthNodes: function (nodes) { + nodes = BI.ListDisplayTree.superclass._dealWidthNodes.apply(this, arguments); + var self = this, o = this.options; + BI.each(nodes, function (i, node) { + node.isParent = node.isParent || node.parent; + if (node.text == null) { + if (node.count > 0) { + node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; + } + } + if(node.isLeaf === true) { + node.font = {color: "#3d4d66"}; + } + }); + return nodes; + }, + + initTree: function (nodes, setting) { + var setting = setting || this._configSetting(); + this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); + }, + + destroy: function () { + BI.ListDisplayTree.superclass.destroy.apply(this, arguments); + } +}); +BI.ListDisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.shortcut("bi.list_display_tree", BI.ListDisplayTree);/** * 简单的多选树 * * Created by GUY on 2016/2/16. @@ -72526,7 +72945,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -72568,7 +72990,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { @@ -72893,6 +73315,585 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut("bi.multi_tree_combo", BI.MultiTreeCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single + */ + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo + * @extends BI.Single + */ + +BI.MultiTreeListCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo);/** * 带加载的多选下拉面板 * @class BI.MultiTreePopup * @extends BI.Pane @@ -72905,24 +73906,27 @@ BI.MultiTreePopup = BI.inherit(BI.Pane, { maxWidth: "auto", minWidth: 100, maxHeight: 400, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } }); }, _init: function () { BI.MultiTreePopup.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, opts = this.options, v = opts.value; this.selectedValues = {}; - this.tree = BI.createWidget({ + this.tree = BI.createWidget(opts.el, { type: "bi.async_tree", height: 400, cls: "popup-view-tree", itemsCreator: opts.itemsCreator, onLoaded: opts.onLoaded, - value: opts.value || {} + value: v.value || {} }); this.popupView = BI.createWidget({ @@ -72990,6 +73994,190 @@ BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** + * 查看已选按钮 + * Created by guy on 15/11/3. + * @class BI.MultiTreeCheckSelectedButton + * @extends BI.Single + */ +BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-check-selected-button", + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); + var self = this; + this.indicator = BI.createWidget({ + type: "bi.icon_button", + cls: "check-font trigger-check-selected icon-size-12", + width: 15, + height: 15, + stopPropagation: true + }); + + this.checkSelected = BI.createWidget({ + type: "bi.text_button", + cls: "trigger-check-selected", + invisible: true, + hgap: 4, + text: BI.i18nText("BI-Check_Selected"), + textAlign: "center", + textHeight: 15 + }); + this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + }); + + BI.createWidget({ + type: "bi.horizontal", + element: this, + items: [this.indicator, this.checkSelected] + }); + + this.element.hover(function () { + self.indicator.setVisible(false); + self.checkSelected.setVisible(true); + }, function () { + self.indicator.setVisible(true); + self.checkSelected.setVisible(false); + }); + this.setVisible(false); + }, + + setValue: function (v) { + v || (v = {}); + this.setVisible(BI.size(v.value) > 0); + } +}); + +BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane);/** * * 在搜索框中输入文本弹出的面板 * @class BI.MultiTreeSearchPane @@ -73063,72 +74251,163 @@ BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** - * 查看已选按钮 + * searcher * Created by guy on 15/11/3. - * @class BI.MultiTreeCheckSelectedButton - * @extends BI.Single + * @class BI.MultiListTreeSearcher + * @extends Widget */ -BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { - return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-check-selected-button", - itemsCreator: BI.emptyFn + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} }); }, _init: function () { - BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); - var self = this; - this.indicator = BI.createWidget({ - type: "bi.icon_button", - cls: "check-font trigger-check-selected icon-size-12", - width: 15, - height: 15, - stopPropagation: true + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } }); - this.checkSelected = BI.createWidget({ - type: "bi.text_button", - cls: "trigger-check-selected", - invisible: true, - hgap: 4, - text: BI.i18nText("BI-Check_Selected"), - textAlign: "center", - textHeight: 15 + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker }); - this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { - this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); }); - - BI.createWidget({ - type: "bi.horizontal", - element: this, - items: [this.indicator, this.checkSelected] + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); }); - - this.element.hover(function () { - self.indicator.setVisible(false); - self.checkSelected.setVisible(true); - }, function () { - self.indicator.setVisible(true); - self.checkSelected.setVisible(false); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); }); - this.setVisible(false); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } }, - setValue: function (v) { - v || (v = {}); - this.setVisible(BI.size(v.value) > 0); + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); } }); -BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher);/** * searcher * Created by guy on 15/11/3. * @class BI.MultiTreeSearcher @@ -83005,10 +84284,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -83268,7 +84556,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -83305,6 +84593,15 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } @@ -83434,6 +84731,10 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { halfCheck: state[1] }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -83500,6 +84801,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }, + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + _getNode: function (selectedValues, parentValues) { var pNode = selectedValues; for (var i = 0, len = parentValues.length; i < len; i++) { @@ -83585,7 +84902,373 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { _getChildCount: function (parentValues) { return this._getChildren(parentValues).length; } +});BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { + + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); + }); + } + + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; + } + }, + + _reqInitTreeNode: function (op, callback) { + var self = this; + var result = []; + var keyword = op.keyword || ""; + var selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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, result); + } else if (output.length === self._const.perPage) { + var find = nodeSearch(1, [], children[i].value, []); + } + if (find[0] === true) { + output.push(children[i].value); + } + if (output.length > self._const.perPage) { + break; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + BI.each(children, function (i, child) { + var state = nodeSearch(deep + 1, newParents, child.value, result); + if (state[1] === true) { + checked = true; + } + if (state[0] === true) { + can = true; + } + }); + if (can === true) { + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: false, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; + } + BI.every(parentValues, 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 parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var checked = BI.has(valueMap, nodes[i].value); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: checked, + halfCheck: false + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); + + function dealWidthSelectedValue(selectedValues) { + var valueMap = {}; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; + }); + return valueMap; + } + }, + + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } });/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.ListTreeValueChooserInsertCombo.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_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo);/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.TreeValueChooserInsertCombo.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_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. diff --git a/dist/base.css b/dist/base.css index 5091d3fc2..885f7082f 100644 --- a/dist/base.css +++ b/dist/base.css @@ -72,8 +72,8 @@ _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/half_selected.png'); + background: url('images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -118,8 +118,8 @@ _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/half_selected.png'); + background: url('images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { @@ -1423,7 +1423,7 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, opacity: 0; } .bi-checkbox.disabled.active .checkbox-content { - border-color: #e8eaed; + border-color: #d0d4da; } .bi-checkbox.disabled.active .checkbox-content:after { opacity: 1; @@ -1431,6 +1431,16 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, .bi-theme-dark .bi-checkbox .checkbox-content { border-color: #9EA6B2; } +.bi-theme-dark .bi-checkbox.active .checkbox-content, +.bi-theme-dark .bi-checkbox:active .checkbox-content { + border-color: #3685f2; +} +.bi-theme-dark .bi-checkbox.disabled .checkbox-content { + background-color: #606479; +} +.bi-theme-dark .bi-checkbox.disabled.active .checkbox-content { + border-color: #606479; +} .bi-file { opacity: 0; filter: alpha(opacity=0); @@ -1609,6 +1619,21 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, opacity: 1; filter: alpha(opacity=100); } + +.bi-list-display-tree .ztree li a, +.bi-list-display-tree .ztree li span { + cursor: default !important; +} +.bi-list-display-tree .ztree li a:hover { + text-decoration: none; +} +.bi-list-display-tree .ztree li a.curSelectedNode { + padding-top: 1px; + border: none; + background-color: inherit; + opacity: 1; + filter: alpha(opacity=100); +} .ztree * { padding: 0; margin: 0; diff --git a/dist/base.js b/dist/base.js index 290d8647f..4f2350b06 100644 --- a/dist/base.js +++ b/dist/base.js @@ -1727,8 +1727,8 @@ BI.TreeView = BI.inherit(BI.Pane, { async: { enable: true, url: getUrl, - autoParam: ["id", "name"], - otherParam: BI.cjkEncodeDO(paras) + autoParam: ["id", "name"], // 节点展开异步请求自动提交id和name + otherParam: BI.cjkEncodeDO(paras) // 静态参数 }, check: { enable: true @@ -1736,16 +1736,16 @@ BI.TreeView = BI.inherit(BI.Pane, { data: { key: { title: "title", - name: "text" + name: "text" // 节点的name属性替换成text }, simpleData: { - enable: true + enable: true // 可以穿id,pid属性的对象数组 } }, view: { showIcon: false, expandSpeed: "", - nameIsHTML: true, + nameIsHTML: true, // 节点可以用html标签代替 dblClickExpand: false }, callback: { @@ -1768,6 +1768,7 @@ BI.TreeView = BI.inherit(BI.Pane, { if(status.half === true && status.checked === true) { checked = false; } + // 更新此node的check状态, 影响父子关联,并调用beforeCheck和onCheck回调 self.nodes.checkNode(treeNode, !checked, true, true); } @@ -1790,7 +1791,7 @@ BI.TreeView = BI.inherit(BI.Pane, { } return true; } - BI.Msg.toast("Please Wait。", "warning"); + BI.Msg.toast("Please Wait。", "warning"); // 不展开节点,也不触发onExpand事件 return false; } @@ -1828,9 +1829,9 @@ BI.TreeView = BI.inherit(BI.Pane, { function ajaxGetNodes (treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { - zTree.updateNode(treeNode); + zTree.updateNode(treeNode); // 刷新一下当前节点,如果treeNode.xxx被改了的话 } - zTree.reAsyncChildNodes(treeNode, reloadType, true); + zTree.reAsyncChildNodes(treeNode, reloadType, true); // 强制加载子节点,reloadType === refresh为先清空再加载,否则为追加到现有子节点之后 } function beforeCheck (treeId, treeNode) { @@ -1908,15 +1909,18 @@ BI.TreeView = BI.inherit(BI.Pane, { } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); + // 当前节点是全选的,因为上面的判断已经排除了不选和半选 if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } + // 剩下的就是半选不展开的节点,因为不知道里面是什么情况,所以借助selectedValues(这个是完整的选中情况) var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, + // 获取的是以values最后一个节点为根的子树 _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { @@ -1928,6 +1932,7 @@ BI.TreeView = BI.inherit(BI.Pane, { return cur; }, + // 以values为path一路向里补充map, 并在末尾节点添加key: value节点 _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { @@ -1955,7 +1960,7 @@ BI.TreeView = BI.inherit(BI.Pane, { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); - track(rootNoots); + track(rootNoots); // 可以看到这个方法没有递归调用,所以在_getHalfSelectedValues中需要关心全选的节点 function track (nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); @@ -2203,7 +2208,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { var self = this; var setting = { async: { - enable: false, + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: BI.cjkEncodeDO(paras) }, check: { @@ -2293,6 +2298,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { return setting; }, + // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); @@ -2338,7 +2344,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { function callback (nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); - + // 展开节点是没有分页的 if (hasNext === true) { BI.delay(function () { times++; @@ -2355,6 +2361,9 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { } }, + // a,b 两棵树 + // a->b b->a 做两次校验, 构造一个校验后的map + // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join: function (valueA, valueB) { var self = this; var map = {}; @@ -2446,9 +2455,17 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { - BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + this._buildTree(self.options.paras.selectedValues, BI.concat(parentValues, name)); + o.itemsCreator({ + type: BI.TreeView.REQ_TYPE_ADJUST_DATA, + selectedValues: self.options.paras.selectedValues + }, function (res) { + self.options.paras.selectedValues = res; + BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + }); } else { // 如果选中的值中不存在该值不处理 + // 因为反正是不选中,没必要管 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { @@ -2456,6 +2473,7 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { if (t == null) { return; } + // 选中中国-江苏, 搜索南京,取消勾选 if (BI.isEmpty(t)) { break; } @@ -2519,9 +2537,8 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; - if (nodes.length > 0) { - callback(self._dealWidthNodes(nodes)); - } + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { @@ -2547,12 +2564,6 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); - o.itemsCreator({ - type: BI.TreeView.REQ_TYPE_ADJUST_DATA, - selectedValues: result - }, function (res) { - result = res; - }); return result; }, @@ -2567,7 +2578,333 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } }); -BI.shortcut("bi.part_tree", BI.PartTree);BI.prepares.push(function () { +BI.shortcut("bi.part_tree", BI.PartTree);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为[["A"], ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListTreeView + * @extends BI.TreeView + */ +BI.ListTreeView = BI.inherit(BI.TreeView, { + + _constants: { + SPLIT: "<|>" + }, + + _defaultConfig: function () { + return BI.extend(BI.ListTreeView.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListTreeView.superclass._init.apply(this, arguments); + var o = this.options; + this.storeValue = o.value || {}; + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + onClick: onClick + } + }; + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + _selectTreeNode: function (treeId, treeNode) { + this._checkValue(treeNode, treeNode.checked); + BI.ListTreeView.superclass._selectTreeNode.apply(this, arguments); + }, + + _transArrayToMap: function (treeArrays) { + var self = this; + var map = {}; + BI.each(treeArrays, function (idx, array) { + var key = array.join(self._constants.SPLIT); + map[key] = true; + }); + return map; + }, + + _transMapToArray: function (treeMap) { + var self = this; + var array = []; + BI.each(treeMap, function (key) { + var item = key.split(self._constants.SPLIT); + array.push(item); + }); + return array; + }, + + _checkValue: function (treeNode, checked) { + var key = BI.concat(this._getParentValues(treeNode), this._getNodeValue(treeNode)).join(this._constants.SPLIT); + if(checked) { + this.storeValue[key] = true; + } else { + delete this.storeValue[key]; + } + }, + + setSelectedValue: function (value) { + this.options.paras.selectedValues = value || []; + this.storeValue = this._transArrayToMap(value); + }, + + getValue: function () { + return this._transMapToArray(this.storeValue); + } +}); + +BI.shortcut("bi.list_tree_view", BI.ListTreeView);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为["A", ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListListAsyncTree + * @extends BI.TreeView + */ +BI.ListAsyncTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListAsyncTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListAsyncTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 + otherParam: BI.cjkEncodeDO(paras) + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + beforeExpand: beforeExpand, + beforeCheck: beforeCheck, + onClick: onClick + } + }; + + function beforeCheck (treeId, treeNode) { + treeNode.half = false; + } + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function beforeExpand (treeId, treeNode) { + self._beforeExpandNode(treeId, treeNode); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + // 展开节点 + _beforeExpandNode: function (treeId, treeNode) { + var self = this, o = this.options; + var parentValues = treeNode.parentValues || self._getParentValues(treeNode); + var op = BI.extend({}, o.paras, { + id: treeNode.id, + times: 1, + parentValues: parentValues.concat(this._getNodeValue(treeNode)) + }); + var complete = function (d) { + var nodes = d.items || []; + if (nodes.length > 0) { + callback(self._dealWidthNodes(nodes), !!d.hasNext); + } + }; + var times = 1; + + function callback (nodes, hasNext) { + self.nodes.addNodes(treeNode, nodes); + // 展开节点是没有分页的 + if (hasNext === true) { + BI.delay(function () { + times++; + op.times = times; + o.itemsCreator(op, complete); + }, 100); + } + } + + if (!treeNode.children) { + setTimeout(function () { + o.itemsCreator(op, complete); + }, 17); + } + }, + + hasChecked: function () { + return !BI.isEmpty(this.options.paras.selectedValues) || BI.ListAsyncTree.superclass.hasChecked.apply(this, arguments); + }, + + // 生成树方法 + stroke: function (config) { + delete this.options.keyword; + BI.extend(this.options.paras, config); + var setting = this._configSetting(); + this._initTree(setting); + } +}); + +BI.shortcut("bi.list_async_tree", BI.ListAsyncTree);/** + * guy + * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 + * @class BI.ListPartTree + * @extends BI.AsyncTree + */ +BI.ListPartTree = BI.inherit(BI.ListAsyncTree, { + _defaultConfig: function () { + return BI.extend(BI.ListPartTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + + _init: function () { + BI.ListPartTree.superclass._init.apply(this, arguments); + }, + + _loadMore: function () { + var self = this, o = this.options; + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: ++this.times + }); + this.tip.setLoading(); + o.itemsCreator(op, function (d) { + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + if (self._stop === true) { + return; + } + if (!hasNext) { + self.tip.setEnd(); + } else { + self.tip.setLoaded(); + } + if (nodes.length > 0) { + self.nodes.addNodes(null, self._dealWidthNodes(nodes)); + } + }); + }, + + _initTree: function (setting, keyword) { + var self = this, o = this.options; + this.times = 1; + var tree = this.tree; + tree.empty(); + self.tip.setVisible(false); + this.loading(); + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: this.times + }); + var complete = function (d) { + if (self._stop === true || keyword != o.paras.keyword) { + return; + } + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); + self.setTipVisible(nodes.length <= 0); + self.loaded(); + if (!hasNext) { + self.tip.invisible(); + } else { + self.tip.setLoaded(); + } + self.fireEvent(BI.Events.AFTERINIT); + }; + + function callback (nodes) { + if (self._stop === true) { + return; + } + self.nodes = $.fn.zTree.init(tree.element, setting, nodes); + } + + BI.delay(function () { + o.itemsCreator(op, complete); + }, 100); + }, + + // 生成树方法 + stroke: function (config) { + var o = this.options; + delete o.paras.keyword; + BI.extend(o.paras, config); + delete o.paras.lastSearchValue; + var setting = this._configSetting(); + this._initTree(setting, o.paras.keyword); + } +}); + +BI.shortcut("bi.list_part_tree", BI.ListPartTree);BI.prepares.push(function () { BI.Resizers = new BI.ResizeController(); BI.Layers = new BI.LayerController(); BI.Maskers = new BI.MaskersController(); @@ -14070,6 +14407,8 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, + checkboxType = setting.check.chkboxType; + var notEffectByOtherNode = (checkboxType.Y === "" && checkboxType.N === ""); fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; @@ -14078,7 +14417,7 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { - fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); + fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) || notEffectByOtherNode ? c.FULL:c.PART) : ((node.check_Child_State < 1 || notEffectByOtherNode)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; diff --git a/dist/bundle.css b/dist/bundle.css index 214c1b104..40180856d 100644 --- a/dist/bundle.css +++ b/dist/bundle.css @@ -2228,8 +2228,8 @@ textarea { _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/half_selected.png'); + background: url('images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -2274,8 +2274,8 @@ textarea { _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/half_selected.png'); + background: url('images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { @@ -3579,7 +3579,7 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, opacity: 0; } .bi-checkbox.disabled.active .checkbox-content { - border-color: #e8eaed; + border-color: #d0d4da; } .bi-checkbox.disabled.active .checkbox-content:after { opacity: 1; @@ -3587,6 +3587,16 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, .bi-theme-dark .bi-checkbox .checkbox-content { border-color: #9EA6B2; } +.bi-theme-dark .bi-checkbox.active .checkbox-content, +.bi-theme-dark .bi-checkbox:active .checkbox-content { + border-color: #3685f2; +} +.bi-theme-dark .bi-checkbox.disabled .checkbox-content { + background-color: #606479; +} +.bi-theme-dark .bi-checkbox.disabled.active .checkbox-content { + border-color: #606479; +} .bi-file { opacity: 0; filter: alpha(opacity=0); @@ -3765,6 +3775,21 @@ body .bi-button.button-ignore.disabled.ghost .b-font:before, opacity: 1; filter: alpha(opacity=100); } + +.bi-list-display-tree .ztree li a, +.bi-list-display-tree .ztree li span { + cursor: default !important; +} +.bi-list-display-tree .ztree li a:hover { + text-decoration: none; +} +.bi-list-display-tree .ztree li a.curSelectedNode { + padding-top: 1px; + border: none; + background-color: inherit; + opacity: 1; + filter: alpha(opacity=100); +} .ztree * { padding: 0; margin: 0; @@ -4548,8 +4573,8 @@ textarea::-webkit-scrollbar-thumb:hover { _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/half_selected.png'); + background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -4594,8 +4619,8 @@ textarea::-webkit-scrollbar-thumb:hover { _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/half_selected.png'); + background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { diff --git a/dist/bundle.ie.js b/dist/bundle.ie.js index ac0b998ae..5f146657d 100644 --- a/dist/bundle.ie.js +++ b/dist/bundle.ie.js @@ -37190,8 +37190,8 @@ BI.TreeView = BI.inherit(BI.Pane, { async: { enable: true, url: getUrl, - autoParam: ["id", "name"], - otherParam: BI.cjkEncodeDO(paras) + autoParam: ["id", "name"], // 节点展开异步请求自动提交id和name + otherParam: BI.cjkEncodeDO(paras) // 静态参数 }, check: { enable: true @@ -37199,16 +37199,16 @@ BI.TreeView = BI.inherit(BI.Pane, { data: { key: { title: "title", - name: "text" + name: "text" // 节点的name属性替换成text }, simpleData: { - enable: true + enable: true // 可以穿id,pid属性的对象数组 } }, view: { showIcon: false, expandSpeed: "", - nameIsHTML: true, + nameIsHTML: true, // 节点可以用html标签代替 dblClickExpand: false }, callback: { @@ -37231,6 +37231,7 @@ BI.TreeView = BI.inherit(BI.Pane, { if(status.half === true && status.checked === true) { checked = false; } + // 更新此node的check状态, 影响父子关联,并调用beforeCheck和onCheck回调 self.nodes.checkNode(treeNode, !checked, true, true); } @@ -37253,7 +37254,7 @@ BI.TreeView = BI.inherit(BI.Pane, { } return true; } - BI.Msg.toast("Please Wait。", "warning"); + BI.Msg.toast("Please Wait。", "warning"); // 不展开节点,也不触发onExpand事件 return false; } @@ -37291,9 +37292,9 @@ BI.TreeView = BI.inherit(BI.Pane, { function ajaxGetNodes (treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { - zTree.updateNode(treeNode); + zTree.updateNode(treeNode); // 刷新一下当前节点,如果treeNode.xxx被改了的话 } - zTree.reAsyncChildNodes(treeNode, reloadType, true); + zTree.reAsyncChildNodes(treeNode, reloadType, true); // 强制加载子节点,reloadType === refresh为先清空再加载,否则为追加到现有子节点之后 } function beforeCheck (treeId, treeNode) { @@ -37371,15 +37372,18 @@ BI.TreeView = BI.inherit(BI.Pane, { } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); + // 当前节点是全选的,因为上面的判断已经排除了不选和半选 if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } + // 剩下的就是半选不展开的节点,因为不知道里面是什么情况,所以借助selectedValues(这个是完整的选中情况) var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, + // 获取的是以values最后一个节点为根的子树 _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { @@ -37391,6 +37395,7 @@ BI.TreeView = BI.inherit(BI.Pane, { return cur; }, + // 以values为path一路向里补充map, 并在末尾节点添加key: value节点 _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { @@ -37418,7 +37423,7 @@ BI.TreeView = BI.inherit(BI.Pane, { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); - track(rootNoots); + track(rootNoots); // 可以看到这个方法没有递归调用,所以在_getHalfSelectedValues中需要关心全选的节点 function track (nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); @@ -37666,7 +37671,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { var self = this; var setting = { async: { - enable: false, + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: BI.cjkEncodeDO(paras) }, check: { @@ -37756,6 +37761,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { return setting; }, + // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); @@ -37801,7 +37807,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { function callback (nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); - + // 展开节点是没有分页的 if (hasNext === true) { BI.delay(function () { times++; @@ -37818,6 +37824,9 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { } }, + // a,b 两棵树 + // a->b b->a 做两次校验, 构造一个校验后的map + // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join: function (valueA, valueB) { var self = this; var map = {}; @@ -37909,9 +37918,17 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { - BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + this._buildTree(self.options.paras.selectedValues, BI.concat(parentValues, name)); + o.itemsCreator({ + type: BI.TreeView.REQ_TYPE_ADJUST_DATA, + selectedValues: self.options.paras.selectedValues + }, function (res) { + self.options.paras.selectedValues = res; + BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + }); } else { // 如果选中的值中不存在该值不处理 + // 因为反正是不选中,没必要管 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { @@ -37919,6 +37936,7 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { if (t == null) { return; } + // 选中中国-江苏, 搜索南京,取消勾选 if (BI.isEmpty(t)) { break; } @@ -37982,9 +38000,8 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; - if (nodes.length > 0) { - callback(self._dealWidthNodes(nodes)); - } + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { @@ -38010,12 +38027,6 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); - o.itemsCreator({ - type: BI.TreeView.REQ_TYPE_ADJUST_DATA, - selectedValues: result - }, function (res) { - result = res; - }); return result; }, @@ -38030,7 +38041,333 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } }); -BI.shortcut("bi.part_tree", BI.PartTree);BI.prepares.push(function () { +BI.shortcut("bi.part_tree", BI.PartTree);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为[["A"], ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListTreeView + * @extends BI.TreeView + */ +BI.ListTreeView = BI.inherit(BI.TreeView, { + + _constants: { + SPLIT: "<|>" + }, + + _defaultConfig: function () { + return BI.extend(BI.ListTreeView.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListTreeView.superclass._init.apply(this, arguments); + var o = this.options; + this.storeValue = o.value || {}; + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + onClick: onClick + } + }; + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + _selectTreeNode: function (treeId, treeNode) { + this._checkValue(treeNode, treeNode.checked); + BI.ListTreeView.superclass._selectTreeNode.apply(this, arguments); + }, + + _transArrayToMap: function (treeArrays) { + var self = this; + var map = {}; + BI.each(treeArrays, function (idx, array) { + var key = array.join(self._constants.SPLIT); + map[key] = true; + }); + return map; + }, + + _transMapToArray: function (treeMap) { + var self = this; + var array = []; + BI.each(treeMap, function (key) { + var item = key.split(self._constants.SPLIT); + array.push(item); + }); + return array; + }, + + _checkValue: function (treeNode, checked) { + var key = BI.concat(this._getParentValues(treeNode), this._getNodeValue(treeNode)).join(this._constants.SPLIT); + if(checked) { + this.storeValue[key] = true; + } else { + delete this.storeValue[key]; + } + }, + + setSelectedValue: function (value) { + this.options.paras.selectedValues = value || []; + this.storeValue = this._transArrayToMap(value); + }, + + getValue: function () { + return this._transMapToArray(this.storeValue); + } +}); + +BI.shortcut("bi.list_tree_view", BI.ListTreeView);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为["A", ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListListAsyncTree + * @extends BI.TreeView + */ +BI.ListAsyncTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListAsyncTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListAsyncTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 + otherParam: BI.cjkEncodeDO(paras) + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + beforeExpand: beforeExpand, + beforeCheck: beforeCheck, + onClick: onClick + } + }; + + function beforeCheck (treeId, treeNode) { + treeNode.half = false; + } + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function beforeExpand (treeId, treeNode) { + self._beforeExpandNode(treeId, treeNode); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + // 展开节点 + _beforeExpandNode: function (treeId, treeNode) { + var self = this, o = this.options; + var parentValues = treeNode.parentValues || self._getParentValues(treeNode); + var op = BI.extend({}, o.paras, { + id: treeNode.id, + times: 1, + parentValues: parentValues.concat(this._getNodeValue(treeNode)) + }); + var complete = function (d) { + var nodes = d.items || []; + if (nodes.length > 0) { + callback(self._dealWidthNodes(nodes), !!d.hasNext); + } + }; + var times = 1; + + function callback (nodes, hasNext) { + self.nodes.addNodes(treeNode, nodes); + // 展开节点是没有分页的 + if (hasNext === true) { + BI.delay(function () { + times++; + op.times = times; + o.itemsCreator(op, complete); + }, 100); + } + } + + if (!treeNode.children) { + setTimeout(function () { + o.itemsCreator(op, complete); + }, 17); + } + }, + + hasChecked: function () { + return !BI.isEmpty(this.options.paras.selectedValues) || BI.ListAsyncTree.superclass.hasChecked.apply(this, arguments); + }, + + // 生成树方法 + stroke: function (config) { + delete this.options.keyword; + BI.extend(this.options.paras, config); + var setting = this._configSetting(); + this._initTree(setting); + } +}); + +BI.shortcut("bi.list_async_tree", BI.ListAsyncTree);/** + * guy + * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 + * @class BI.ListPartTree + * @extends BI.AsyncTree + */ +BI.ListPartTree = BI.inherit(BI.ListAsyncTree, { + _defaultConfig: function () { + return BI.extend(BI.ListPartTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + + _init: function () { + BI.ListPartTree.superclass._init.apply(this, arguments); + }, + + _loadMore: function () { + var self = this, o = this.options; + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: ++this.times + }); + this.tip.setLoading(); + o.itemsCreator(op, function (d) { + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + if (self._stop === true) { + return; + } + if (!hasNext) { + self.tip.setEnd(); + } else { + self.tip.setLoaded(); + } + if (nodes.length > 0) { + self.nodes.addNodes(null, self._dealWidthNodes(nodes)); + } + }); + }, + + _initTree: function (setting, keyword) { + var self = this, o = this.options; + this.times = 1; + var tree = this.tree; + tree.empty(); + self.tip.setVisible(false); + this.loading(); + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: this.times + }); + var complete = function (d) { + if (self._stop === true || keyword != o.paras.keyword) { + return; + } + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); + self.setTipVisible(nodes.length <= 0); + self.loaded(); + if (!hasNext) { + self.tip.invisible(); + } else { + self.tip.setLoaded(); + } + self.fireEvent(BI.Events.AFTERINIT); + }; + + function callback (nodes) { + if (self._stop === true) { + return; + } + self.nodes = $.fn.zTree.init(tree.element, setting, nodes); + } + + BI.delay(function () { + o.itemsCreator(op, complete); + }, 100); + }, + + // 生成树方法 + stroke: function (config) { + var o = this.options; + delete o.paras.keyword; + BI.extend(o.paras, config); + delete o.paras.lastSearchValue; + var setting = this._configSetting(); + this._initTree(setting, o.paras.keyword); + } +}); + +BI.shortcut("bi.list_part_tree", BI.ListPartTree);BI.prepares.push(function () { BI.Resizers = new BI.ResizeController(); BI.Layers = new BI.LayerController(); BI.Maskers = new BI.MaskersController(); @@ -49533,6 +49870,8 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, + checkboxType = setting.check.chkboxType; + var notEffectByOtherNode = (checkboxType.Y === "" && checkboxType.N === ""); fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; @@ -49541,7 +49880,7 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { - fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); + fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) || notEffectByOtherNode ? c.FULL:c.PART) : ((node.check_Child_State < 1 || notEffectByOtherNode)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; @@ -58890,6 +59229,86 @@ BI.DisplayTree = BI.inherit(BI.TreeView, { BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.display_tree", BI.DisplayTree);/** + * guy + * 异步树 + * @class BI.ListListDisplayTree + * @extends BI.TreeView + */ +BI.ListDisplayTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListDisplayTree.superclass._defaultConfig.apply(this, arguments), { + extraCls: "bi-list-display-tree" + }); + }, + _init: function () { + BI.ListDisplayTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var setting = { + view: { + selectedMulti: false, + dblClickExpand: false, + showIcon: false, + nameIsHTML: true, + showTitle: false, + fontCss: getFont + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + callback: { + beforeCollapse: beforeCollapse + } + }; + + function beforeCollapse(treeId, treeNode) { + return false; + } + + function getFont(treeId, node) { + return node.font ? node.font : {color: "#999999"}; + } + + return setting; + }, + + _dealWidthNodes: function (nodes) { + nodes = BI.ListDisplayTree.superclass._dealWidthNodes.apply(this, arguments); + var self = this, o = this.options; + BI.each(nodes, function (i, node) { + node.isParent = node.isParent || node.parent; + if (node.text == null) { + if (node.count > 0) { + node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; + } + } + if(node.isLeaf === true) { + node.font = {color: "#3d4d66"}; + } + }); + return nodes; + }, + + initTree: function (nodes, setting) { + var setting = setting || this._configSetting(); + this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); + }, + + destroy: function () { + BI.ListDisplayTree.superclass.destroy.apply(this, arguments); + } +}); +BI.ListDisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.shortcut("bi.list_display_tree", BI.ListDisplayTree);/** * 简单的多选树 * * Created by GUY on 2016/2/16. @@ -72122,7 +72541,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -72164,7 +72586,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { @@ -72489,6 +72911,585 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut("bi.multi_tree_combo", BI.MultiTreeCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single + */ + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo + * @extends BI.Single + */ + +BI.MultiTreeListCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo);/** * 带加载的多选下拉面板 * @class BI.MultiTreePopup * @extends BI.Pane @@ -72501,24 +73502,27 @@ BI.MultiTreePopup = BI.inherit(BI.Pane, { maxWidth: "auto", minWidth: 100, maxHeight: 400, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } }); }, _init: function () { BI.MultiTreePopup.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, opts = this.options, v = opts.value; this.selectedValues = {}; - this.tree = BI.createWidget({ + this.tree = BI.createWidget(opts.el, { type: "bi.async_tree", height: 400, cls: "popup-view-tree", itemsCreator: opts.itemsCreator, onLoaded: opts.onLoaded, - value: opts.value || {} + value: v.value || {} }); this.popupView = BI.createWidget({ @@ -72586,6 +73590,190 @@ BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** + * 查看已选按钮 + * Created by guy on 15/11/3. + * @class BI.MultiTreeCheckSelectedButton + * @extends BI.Single + */ +BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-check-selected-button", + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); + var self = this; + this.indicator = BI.createWidget({ + type: "bi.icon_button", + cls: "check-font trigger-check-selected icon-size-12", + width: 15, + height: 15, + stopPropagation: true + }); + + this.checkSelected = BI.createWidget({ + type: "bi.text_button", + cls: "trigger-check-selected", + invisible: true, + hgap: 4, + text: BI.i18nText("BI-Check_Selected"), + textAlign: "center", + textHeight: 15 + }); + this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + }); + + BI.createWidget({ + type: "bi.horizontal", + element: this, + items: [this.indicator, this.checkSelected] + }); + + this.element.hover(function () { + self.indicator.setVisible(false); + self.checkSelected.setVisible(true); + }, function () { + self.indicator.setVisible(true); + self.checkSelected.setVisible(false); + }); + this.setVisible(false); + }, + + setValue: function (v) { + v || (v = {}); + this.setVisible(BI.size(v.value) > 0); + } +}); + +BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane);/** * * 在搜索框中输入文本弹出的面板 * @class BI.MultiTreeSearchPane @@ -72659,72 +73847,163 @@ BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** - * 查看已选按钮 + * searcher * Created by guy on 15/11/3. - * @class BI.MultiTreeCheckSelectedButton - * @extends BI.Single + * @class BI.MultiListTreeSearcher + * @extends Widget */ -BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { - return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-check-selected-button", - itemsCreator: BI.emptyFn + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} }); }, _init: function () { - BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); - var self = this; - this.indicator = BI.createWidget({ - type: "bi.icon_button", - cls: "check-font trigger-check-selected icon-size-12", - width: 15, - height: 15, - stopPropagation: true + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } }); - this.checkSelected = BI.createWidget({ - type: "bi.text_button", - cls: "trigger-check-selected", - invisible: true, - hgap: 4, - text: BI.i18nText("BI-Check_Selected"), - textAlign: "center", - textHeight: 15 + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker }); - this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { - this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); }); - - BI.createWidget({ - type: "bi.horizontal", - element: this, - items: [this.indicator, this.checkSelected] + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); }); - - this.element.hover(function () { - self.indicator.setVisible(false); - self.checkSelected.setVisible(true); - }, function () { - self.indicator.setVisible(true); - self.checkSelected.setVisible(false); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); }); - this.setVisible(false); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } }, - setValue: function (v) { - v || (v = {}); - this.setVisible(BI.size(v.value) > 0); + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); } }); -BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher);/** * searcher * Created by guy on 15/11/3. * @class BI.MultiTreeSearcher @@ -82601,10 +83880,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -82864,7 +84152,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -82901,6 +84189,15 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } @@ -83030,6 +84327,10 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { halfCheck: state[1] }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -83096,6 +84397,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }, + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + _getNode: function (selectedValues, parentValues) { var pNode = selectedValues; for (var i = 0, len = parentValues.length; i < len; i++) { @@ -83181,7 +84498,373 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { _getChildCount: function (parentValues) { return this._getChildren(parentValues).length; } +});BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { + + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); + }); + } + + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; + } + }, + + _reqInitTreeNode: function (op, callback) { + var self = this; + var result = []; + var keyword = op.keyword || ""; + var selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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, result); + } else if (output.length === self._const.perPage) { + var find = nodeSearch(1, [], children[i].value, []); + } + if (find[0] === true) { + output.push(children[i].value); + } + if (output.length > self._const.perPage) { + break; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + BI.each(children, function (i, child) { + var state = nodeSearch(deep + 1, newParents, child.value, result); + if (state[1] === true) { + checked = true; + } + if (state[0] === true) { + can = true; + } + }); + if (can === true) { + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: false, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; + } + BI.every(parentValues, 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 parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var checked = BI.has(valueMap, nodes[i].value); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: checked, + halfCheck: false + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); + + function dealWidthSelectedValue(selectedValues) { + var valueMap = {}; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; + }); + return valueMap; + } + }, + + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } });/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.ListTreeValueChooserInsertCombo.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_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo);/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.TreeValueChooserInsertCombo.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_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. diff --git a/dist/bundle.js b/dist/bundle.js index e480ccce0..298fefd4a 100644 --- a/dist/bundle.js +++ b/dist/bundle.js @@ -37594,8 +37594,8 @@ BI.TreeView = BI.inherit(BI.Pane, { async: { enable: true, url: getUrl, - autoParam: ["id", "name"], - otherParam: BI.cjkEncodeDO(paras) + autoParam: ["id", "name"], // 节点展开异步请求自动提交id和name + otherParam: BI.cjkEncodeDO(paras) // 静态参数 }, check: { enable: true @@ -37603,16 +37603,16 @@ BI.TreeView = BI.inherit(BI.Pane, { data: { key: { title: "title", - name: "text" + name: "text" // 节点的name属性替换成text }, simpleData: { - enable: true + enable: true // 可以穿id,pid属性的对象数组 } }, view: { showIcon: false, expandSpeed: "", - nameIsHTML: true, + nameIsHTML: true, // 节点可以用html标签代替 dblClickExpand: false }, callback: { @@ -37635,6 +37635,7 @@ BI.TreeView = BI.inherit(BI.Pane, { if(status.half === true && status.checked === true) { checked = false; } + // 更新此node的check状态, 影响父子关联,并调用beforeCheck和onCheck回调 self.nodes.checkNode(treeNode, !checked, true, true); } @@ -37657,7 +37658,7 @@ BI.TreeView = BI.inherit(BI.Pane, { } return true; } - BI.Msg.toast("Please Wait。", "warning"); + BI.Msg.toast("Please Wait。", "warning"); // 不展开节点,也不触发onExpand事件 return false; } @@ -37695,9 +37696,9 @@ BI.TreeView = BI.inherit(BI.Pane, { function ajaxGetNodes (treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { - zTree.updateNode(treeNode); + zTree.updateNode(treeNode); // 刷新一下当前节点,如果treeNode.xxx被改了的话 } - zTree.reAsyncChildNodes(treeNode, reloadType, true); + zTree.reAsyncChildNodes(treeNode, reloadType, true); // 强制加载子节点,reloadType === refresh为先清空再加载,否则为追加到现有子节点之后 } function beforeCheck (treeId, treeNode) { @@ -37775,15 +37776,18 @@ BI.TreeView = BI.inherit(BI.Pane, { } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); + // 当前节点是全选的,因为上面的判断已经排除了不选和半选 if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } + // 剩下的就是半选不展开的节点,因为不知道里面是什么情况,所以借助selectedValues(这个是完整的选中情况) var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, + // 获取的是以values最后一个节点为根的子树 _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { @@ -37795,6 +37799,7 @@ BI.TreeView = BI.inherit(BI.Pane, { return cur; }, + // 以values为path一路向里补充map, 并在末尾节点添加key: value节点 _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { @@ -37822,7 +37827,7 @@ BI.TreeView = BI.inherit(BI.Pane, { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); - track(rootNoots); + track(rootNoots); // 可以看到这个方法没有递归调用,所以在_getHalfSelectedValues中需要关心全选的节点 function track (nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); @@ -38070,7 +38075,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { var self = this; var setting = { async: { - enable: false, + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: BI.cjkEncodeDO(paras) }, check: { @@ -38160,6 +38165,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { return setting; }, + // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); @@ -38205,7 +38211,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { function callback (nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); - + // 展开节点是没有分页的 if (hasNext === true) { BI.delay(function () { times++; @@ -38222,6 +38228,9 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { } }, + // a,b 两棵树 + // a->b b->a 做两次校验, 构造一个校验后的map + // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join: function (valueA, valueB) { var self = this; var map = {}; @@ -38313,9 +38322,17 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { - BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + this._buildTree(self.options.paras.selectedValues, BI.concat(parentValues, name)); + o.itemsCreator({ + type: BI.TreeView.REQ_TYPE_ADJUST_DATA, + selectedValues: self.options.paras.selectedValues + }, function (res) { + self.options.paras.selectedValues = res; + BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + }); } else { // 如果选中的值中不存在该值不处理 + // 因为反正是不选中,没必要管 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { @@ -38323,6 +38340,7 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { if (t == null) { return; } + // 选中中国-江苏, 搜索南京,取消勾选 if (BI.isEmpty(t)) { break; } @@ -38386,9 +38404,8 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; - if (nodes.length > 0) { - callback(self._dealWidthNodes(nodes)); - } + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { @@ -38414,12 +38431,6 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); - o.itemsCreator({ - type: BI.TreeView.REQ_TYPE_ADJUST_DATA, - selectedValues: result - }, function (res) { - result = res; - }); return result; }, @@ -38434,7 +38445,333 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } }); -BI.shortcut("bi.part_tree", BI.PartTree);BI.prepares.push(function () { +BI.shortcut("bi.part_tree", BI.PartTree);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为[["A"], ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListTreeView + * @extends BI.TreeView + */ +BI.ListTreeView = BI.inherit(BI.TreeView, { + + _constants: { + SPLIT: "<|>" + }, + + _defaultConfig: function () { + return BI.extend(BI.ListTreeView.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListTreeView.superclass._init.apply(this, arguments); + var o = this.options; + this.storeValue = o.value || {}; + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + onClick: onClick + } + }; + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + _selectTreeNode: function (treeId, treeNode) { + this._checkValue(treeNode, treeNode.checked); + BI.ListTreeView.superclass._selectTreeNode.apply(this, arguments); + }, + + _transArrayToMap: function (treeArrays) { + var self = this; + var map = {}; + BI.each(treeArrays, function (idx, array) { + var key = array.join(self._constants.SPLIT); + map[key] = true; + }); + return map; + }, + + _transMapToArray: function (treeMap) { + var self = this; + var array = []; + BI.each(treeMap, function (key) { + var item = key.split(self._constants.SPLIT); + array.push(item); + }); + return array; + }, + + _checkValue: function (treeNode, checked) { + var key = BI.concat(this._getParentValues(treeNode), this._getNodeValue(treeNode)).join(this._constants.SPLIT); + if(checked) { + this.storeValue[key] = true; + } else { + delete this.storeValue[key]; + } + }, + + setSelectedValue: function (value) { + this.options.paras.selectedValues = value || []; + this.storeValue = this._transArrayToMap(value); + }, + + getValue: function () { + return this._transMapToArray(this.storeValue); + } +}); + +BI.shortcut("bi.list_tree_view", BI.ListTreeView);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为["A", ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListListAsyncTree + * @extends BI.TreeView + */ +BI.ListAsyncTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListAsyncTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListAsyncTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 + otherParam: BI.cjkEncodeDO(paras) + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + beforeExpand: beforeExpand, + beforeCheck: beforeCheck, + onClick: onClick + } + }; + + function beforeCheck (treeId, treeNode) { + treeNode.half = false; + } + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function beforeExpand (treeId, treeNode) { + self._beforeExpandNode(treeId, treeNode); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + // 展开节点 + _beforeExpandNode: function (treeId, treeNode) { + var self = this, o = this.options; + var parentValues = treeNode.parentValues || self._getParentValues(treeNode); + var op = BI.extend({}, o.paras, { + id: treeNode.id, + times: 1, + parentValues: parentValues.concat(this._getNodeValue(treeNode)) + }); + var complete = function (d) { + var nodes = d.items || []; + if (nodes.length > 0) { + callback(self._dealWidthNodes(nodes), !!d.hasNext); + } + }; + var times = 1; + + function callback (nodes, hasNext) { + self.nodes.addNodes(treeNode, nodes); + // 展开节点是没有分页的 + if (hasNext === true) { + BI.delay(function () { + times++; + op.times = times; + o.itemsCreator(op, complete); + }, 100); + } + } + + if (!treeNode.children) { + setTimeout(function () { + o.itemsCreator(op, complete); + }, 17); + } + }, + + hasChecked: function () { + return !BI.isEmpty(this.options.paras.selectedValues) || BI.ListAsyncTree.superclass.hasChecked.apply(this, arguments); + }, + + // 生成树方法 + stroke: function (config) { + delete this.options.keyword; + BI.extend(this.options.paras, config); + var setting = this._configSetting(); + this._initTree(setting); + } +}); + +BI.shortcut("bi.list_async_tree", BI.ListAsyncTree);/** + * guy + * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 + * @class BI.ListPartTree + * @extends BI.AsyncTree + */ +BI.ListPartTree = BI.inherit(BI.ListAsyncTree, { + _defaultConfig: function () { + return BI.extend(BI.ListPartTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + + _init: function () { + BI.ListPartTree.superclass._init.apply(this, arguments); + }, + + _loadMore: function () { + var self = this, o = this.options; + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: ++this.times + }); + this.tip.setLoading(); + o.itemsCreator(op, function (d) { + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + if (self._stop === true) { + return; + } + if (!hasNext) { + self.tip.setEnd(); + } else { + self.tip.setLoaded(); + } + if (nodes.length > 0) { + self.nodes.addNodes(null, self._dealWidthNodes(nodes)); + } + }); + }, + + _initTree: function (setting, keyword) { + var self = this, o = this.options; + this.times = 1; + var tree = this.tree; + tree.empty(); + self.tip.setVisible(false); + this.loading(); + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: this.times + }); + var complete = function (d) { + if (self._stop === true || keyword != o.paras.keyword) { + return; + } + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); + self.setTipVisible(nodes.length <= 0); + self.loaded(); + if (!hasNext) { + self.tip.invisible(); + } else { + self.tip.setLoaded(); + } + self.fireEvent(BI.Events.AFTERINIT); + }; + + function callback (nodes) { + if (self._stop === true) { + return; + } + self.nodes = $.fn.zTree.init(tree.element, setting, nodes); + } + + BI.delay(function () { + o.itemsCreator(op, complete); + }, 100); + }, + + // 生成树方法 + stroke: function (config) { + var o = this.options; + delete o.paras.keyword; + BI.extend(o.paras, config); + delete o.paras.lastSearchValue; + var setting = this._configSetting(); + this._initTree(setting, o.paras.keyword); + } +}); + +BI.shortcut("bi.list_part_tree", BI.ListPartTree);BI.prepares.push(function () { BI.Resizers = new BI.ResizeController(); BI.Layers = new BI.LayerController(); BI.Maskers = new BI.MaskersController(); @@ -49937,6 +50274,8 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, + checkboxType = setting.check.chkboxType; + var notEffectByOtherNode = (checkboxType.Y === "" && checkboxType.N === ""); fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; @@ -49945,7 +50284,7 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { - fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); + fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) || notEffectByOtherNode ? c.FULL:c.PART) : ((node.check_Child_State < 1 || notEffectByOtherNode)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; @@ -59294,6 +59633,86 @@ BI.DisplayTree = BI.inherit(BI.TreeView, { BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.display_tree", BI.DisplayTree);/** + * guy + * 异步树 + * @class BI.ListListDisplayTree + * @extends BI.TreeView + */ +BI.ListDisplayTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListDisplayTree.superclass._defaultConfig.apply(this, arguments), { + extraCls: "bi-list-display-tree" + }); + }, + _init: function () { + BI.ListDisplayTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var setting = { + view: { + selectedMulti: false, + dblClickExpand: false, + showIcon: false, + nameIsHTML: true, + showTitle: false, + fontCss: getFont + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + callback: { + beforeCollapse: beforeCollapse + } + }; + + function beforeCollapse(treeId, treeNode) { + return false; + } + + function getFont(treeId, node) { + return node.font ? node.font : {color: "#999999"}; + } + + return setting; + }, + + _dealWidthNodes: function (nodes) { + nodes = BI.ListDisplayTree.superclass._dealWidthNodes.apply(this, arguments); + var self = this, o = this.options; + BI.each(nodes, function (i, node) { + node.isParent = node.isParent || node.parent; + if (node.text == null) { + if (node.count > 0) { + node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; + } + } + if(node.isLeaf === true) { + node.font = {color: "#3d4d66"}; + } + }); + return nodes; + }, + + initTree: function (nodes, setting) { + var setting = setting || this._configSetting(); + this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); + }, + + destroy: function () { + BI.ListDisplayTree.superclass.destroy.apply(this, arguments); + } +}); +BI.ListDisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.shortcut("bi.list_display_tree", BI.ListDisplayTree);/** * 简单的多选树 * * Created by GUY on 2016/2/16. @@ -72526,7 +72945,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -72568,7 +72990,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { @@ -72893,6 +73315,585 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut("bi.multi_tree_combo", BI.MultiTreeCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single + */ + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo + * @extends BI.Single + */ + +BI.MultiTreeListCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo);/** * 带加载的多选下拉面板 * @class BI.MultiTreePopup * @extends BI.Pane @@ -72905,24 +73906,27 @@ BI.MultiTreePopup = BI.inherit(BI.Pane, { maxWidth: "auto", minWidth: 100, maxHeight: 400, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } }); }, _init: function () { BI.MultiTreePopup.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, opts = this.options, v = opts.value; this.selectedValues = {}; - this.tree = BI.createWidget({ + this.tree = BI.createWidget(opts.el, { type: "bi.async_tree", height: 400, cls: "popup-view-tree", itemsCreator: opts.itemsCreator, onLoaded: opts.onLoaded, - value: opts.value || {} + value: v.value || {} }); this.popupView = BI.createWidget({ @@ -72990,6 +73994,190 @@ BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** + * 查看已选按钮 + * Created by guy on 15/11/3. + * @class BI.MultiTreeCheckSelectedButton + * @extends BI.Single + */ +BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-check-selected-button", + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); + var self = this; + this.indicator = BI.createWidget({ + type: "bi.icon_button", + cls: "check-font trigger-check-selected icon-size-12", + width: 15, + height: 15, + stopPropagation: true + }); + + this.checkSelected = BI.createWidget({ + type: "bi.text_button", + cls: "trigger-check-selected", + invisible: true, + hgap: 4, + text: BI.i18nText("BI-Check_Selected"), + textAlign: "center", + textHeight: 15 + }); + this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + }); + + BI.createWidget({ + type: "bi.horizontal", + element: this, + items: [this.indicator, this.checkSelected] + }); + + this.element.hover(function () { + self.indicator.setVisible(false); + self.checkSelected.setVisible(true); + }, function () { + self.indicator.setVisible(true); + self.checkSelected.setVisible(false); + }); + this.setVisible(false); + }, + + setValue: function (v) { + v || (v = {}); + this.setVisible(BI.size(v.value) > 0); + } +}); + +BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane);/** * * 在搜索框中输入文本弹出的面板 * @class BI.MultiTreeSearchPane @@ -73063,72 +74251,163 @@ BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** - * 查看已选按钮 + * searcher * Created by guy on 15/11/3. - * @class BI.MultiTreeCheckSelectedButton - * @extends BI.Single + * @class BI.MultiListTreeSearcher + * @extends Widget */ -BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { - return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-check-selected-button", - itemsCreator: BI.emptyFn + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} }); }, _init: function () { - BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); - var self = this; - this.indicator = BI.createWidget({ - type: "bi.icon_button", - cls: "check-font trigger-check-selected icon-size-12", - width: 15, - height: 15, - stopPropagation: true + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } }); - this.checkSelected = BI.createWidget({ - type: "bi.text_button", - cls: "trigger-check-selected", - invisible: true, - hgap: 4, - text: BI.i18nText("BI-Check_Selected"), - textAlign: "center", - textHeight: 15 + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker }); - this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { - this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); }); - - BI.createWidget({ - type: "bi.horizontal", - element: this, - items: [this.indicator, this.checkSelected] + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); }); - - this.element.hover(function () { - self.indicator.setVisible(false); - self.checkSelected.setVisible(true); - }, function () { - self.indicator.setVisible(true); - self.checkSelected.setVisible(false); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); }); - this.setVisible(false); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } }, - setValue: function (v) { - v || (v = {}); - this.setVisible(BI.size(v.value) > 0); + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); } }); -BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher);/** * searcher * Created by guy on 15/11/3. * @class BI.MultiTreeSearcher @@ -83005,10 +84284,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -83268,7 +84556,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -83305,6 +84593,15 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } @@ -83434,6 +84731,10 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { halfCheck: state[1] }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -83500,6 +84801,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }, + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + _getNode: function (selectedValues, parentValues) { var pNode = selectedValues; for (var i = 0, len = parentValues.length; i < len; i++) { @@ -83585,7 +84902,373 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { _getChildCount: function (parentValues) { return this._getChildren(parentValues).length; } +});BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { + + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); + }); + } + + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; + } + }, + + _reqInitTreeNode: function (op, callback) { + var self = this; + var result = []; + var keyword = op.keyword || ""; + var selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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, result); + } else if (output.length === self._const.perPage) { + var find = nodeSearch(1, [], children[i].value, []); + } + if (find[0] === true) { + output.push(children[i].value); + } + if (output.length > self._const.perPage) { + break; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + BI.each(children, function (i, child) { + var state = nodeSearch(deep + 1, newParents, child.value, result); + if (state[1] === true) { + checked = true; + } + if (state[0] === true) { + can = true; + } + }); + if (can === true) { + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: false, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; + } + BI.every(parentValues, 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 parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var checked = BI.has(valueMap, nodes[i].value); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: checked, + halfCheck: false + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); + + function dealWidthSelectedValue(selectedValues) { + var valueMap = {}; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; + }); + return valueMap; + } + }, + + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } });/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.ListTreeValueChooserInsertCombo.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_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo);/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.TreeValueChooserInsertCombo.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_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. diff --git a/dist/case.js b/dist/case.js index bcc925ec0..73989d8e5 100644 --- a/dist/case.js +++ b/dist/case.js @@ -9155,6 +9155,86 @@ BI.DisplayTree = BI.inherit(BI.TreeView, { BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.display_tree", BI.DisplayTree);/** + * guy + * 异步树 + * @class BI.ListListDisplayTree + * @extends BI.TreeView + */ +BI.ListDisplayTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListDisplayTree.superclass._defaultConfig.apply(this, arguments), { + extraCls: "bi-list-display-tree" + }); + }, + _init: function () { + BI.ListDisplayTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var setting = { + view: { + selectedMulti: false, + dblClickExpand: false, + showIcon: false, + nameIsHTML: true, + showTitle: false, + fontCss: getFont + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + callback: { + beforeCollapse: beforeCollapse + } + }; + + function beforeCollapse(treeId, treeNode) { + return false; + } + + function getFont(treeId, node) { + return node.font ? node.font : {color: "#999999"}; + } + + return setting; + }, + + _dealWidthNodes: function (nodes) { + nodes = BI.ListDisplayTree.superclass._dealWidthNodes.apply(this, arguments); + var self = this, o = this.options; + BI.each(nodes, function (i, node) { + node.isParent = node.isParent || node.parent; + if (node.text == null) { + if (node.count > 0) { + node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; + } + } + if(node.isLeaf === true) { + node.font = {color: "#3d4d66"}; + } + }); + return nodes; + }, + + initTree: function (nodes, setting) { + var setting = setting || this._configSetting(); + this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); + }, + + destroy: function () { + BI.ListDisplayTree.superclass.destroy.apply(this, arguments); + } +}); +BI.ListDisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.shortcut("bi.list_display_tree", BI.ListDisplayTree);/** * 简单的多选树 * * Created by GUY on 2016/2/16. diff --git a/dist/demo.js b/dist/demo.js index 3e07f8eac..9831888e1 100644 --- a/dist/demo.js +++ b/dist/demo.js @@ -2700,18 +2700,28 @@ BI.shortcut("demo.center", Demo.Center);Demo.TreeValueChooser = BI.inherit(BI.Wi render: function () { var widget = BI.createWidget({ - type: "bi.tree_value_chooser_combo", + type: "bi.tree_value_chooser_insert_combo", width: 300, // items: BI.deepClone(Demo.CONSTANTS.TREEITEMS), itemsCreator: function (op, callback) { callback(BI.deepClone(Demo.CONSTANTS.TREEITEMS)); } }); + var widget1 = BI.createWidget({ + type: "bi.list_tree_value_chooser_insert_combo", + itemsCreator: function (op, callback) { + callback(BI.deepClone(Demo.CONSTANTS.TREEITEMS)); + } + }); return { type: "bi.vertical", - hgap: 200, - vgap: 10, - items: [widget] + items: [{ + type: "bi.vertical_adapt", + hgap: 200, + vgap: 10, + items: [widget, widget1] + }] + }; } }); diff --git a/dist/fineui.ie.js b/dist/fineui.ie.js index e1a0bcdf4..5b6fef10d 100644 --- a/dist/fineui.ie.js +++ b/dist/fineui.ie.js @@ -37435,8 +37435,8 @@ BI.TreeView = BI.inherit(BI.Pane, { async: { enable: true, url: getUrl, - autoParam: ["id", "name"], - otherParam: BI.cjkEncodeDO(paras) + autoParam: ["id", "name"], // 节点展开异步请求自动提交id和name + otherParam: BI.cjkEncodeDO(paras) // 静态参数 }, check: { enable: true @@ -37444,16 +37444,16 @@ BI.TreeView = BI.inherit(BI.Pane, { data: { key: { title: "title", - name: "text" + name: "text" // 节点的name属性替换成text }, simpleData: { - enable: true + enable: true // 可以穿id,pid属性的对象数组 } }, view: { showIcon: false, expandSpeed: "", - nameIsHTML: true, + nameIsHTML: true, // 节点可以用html标签代替 dblClickExpand: false }, callback: { @@ -37476,6 +37476,7 @@ BI.TreeView = BI.inherit(BI.Pane, { if(status.half === true && status.checked === true) { checked = false; } + // 更新此node的check状态, 影响父子关联,并调用beforeCheck和onCheck回调 self.nodes.checkNode(treeNode, !checked, true, true); } @@ -37498,7 +37499,7 @@ BI.TreeView = BI.inherit(BI.Pane, { } return true; } - BI.Msg.toast("Please Wait。", "warning"); + BI.Msg.toast("Please Wait。", "warning"); // 不展开节点,也不触发onExpand事件 return false; } @@ -37536,9 +37537,9 @@ BI.TreeView = BI.inherit(BI.Pane, { function ajaxGetNodes (treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { - zTree.updateNode(treeNode); + zTree.updateNode(treeNode); // 刷新一下当前节点,如果treeNode.xxx被改了的话 } - zTree.reAsyncChildNodes(treeNode, reloadType, true); + zTree.reAsyncChildNodes(treeNode, reloadType, true); // 强制加载子节点,reloadType === refresh为先清空再加载,否则为追加到现有子节点之后 } function beforeCheck (treeId, treeNode) { @@ -37616,15 +37617,18 @@ BI.TreeView = BI.inherit(BI.Pane, { } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); + // 当前节点是全选的,因为上面的判断已经排除了不选和半选 if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } + // 剩下的就是半选不展开的节点,因为不知道里面是什么情况,所以借助selectedValues(这个是完整的选中情况) var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, + // 获取的是以values最后一个节点为根的子树 _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { @@ -37636,6 +37640,7 @@ BI.TreeView = BI.inherit(BI.Pane, { return cur; }, + // 以values为path一路向里补充map, 并在末尾节点添加key: value节点 _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { @@ -37663,7 +37668,7 @@ BI.TreeView = BI.inherit(BI.Pane, { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); - track(rootNoots); + track(rootNoots); // 可以看到这个方法没有递归调用,所以在_getHalfSelectedValues中需要关心全选的节点 function track (nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); @@ -37911,7 +37916,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { var self = this; var setting = { async: { - enable: false, + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: BI.cjkEncodeDO(paras) }, check: { @@ -38001,6 +38006,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { return setting; }, + // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); @@ -38046,7 +38052,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { function callback (nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); - + // 展开节点是没有分页的 if (hasNext === true) { BI.delay(function () { times++; @@ -38063,6 +38069,9 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { } }, + // a,b 两棵树 + // a->b b->a 做两次校验, 构造一个校验后的map + // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join: function (valueA, valueB) { var self = this; var map = {}; @@ -38154,9 +38163,17 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { - BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + this._buildTree(self.options.paras.selectedValues, BI.concat(parentValues, name)); + o.itemsCreator({ + type: BI.TreeView.REQ_TYPE_ADJUST_DATA, + selectedValues: self.options.paras.selectedValues + }, function (res) { + self.options.paras.selectedValues = res; + BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + }); } else { // 如果选中的值中不存在该值不处理 + // 因为反正是不选中,没必要管 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { @@ -38164,6 +38181,7 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { if (t == null) { return; } + // 选中中国-江苏, 搜索南京,取消勾选 if (BI.isEmpty(t)) { break; } @@ -38227,9 +38245,8 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; - if (nodes.length > 0) { - callback(self._dealWidthNodes(nodes)); - } + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { @@ -38255,12 +38272,6 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); - o.itemsCreator({ - type: BI.TreeView.REQ_TYPE_ADJUST_DATA, - selectedValues: result - }, function (res) { - result = res; - }); return result; }, @@ -38275,7 +38286,333 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } }); -BI.shortcut("bi.part_tree", BI.PartTree);BI.prepares.push(function () { +BI.shortcut("bi.part_tree", BI.PartTree);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为[["A"], ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListTreeView + * @extends BI.TreeView + */ +BI.ListTreeView = BI.inherit(BI.TreeView, { + + _constants: { + SPLIT: "<|>" + }, + + _defaultConfig: function () { + return BI.extend(BI.ListTreeView.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListTreeView.superclass._init.apply(this, arguments); + var o = this.options; + this.storeValue = o.value || {}; + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + onClick: onClick + } + }; + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + _selectTreeNode: function (treeId, treeNode) { + this._checkValue(treeNode, treeNode.checked); + BI.ListTreeView.superclass._selectTreeNode.apply(this, arguments); + }, + + _transArrayToMap: function (treeArrays) { + var self = this; + var map = {}; + BI.each(treeArrays, function (idx, array) { + var key = array.join(self._constants.SPLIT); + map[key] = true; + }); + return map; + }, + + _transMapToArray: function (treeMap) { + var self = this; + var array = []; + BI.each(treeMap, function (key) { + var item = key.split(self._constants.SPLIT); + array.push(item); + }); + return array; + }, + + _checkValue: function (treeNode, checked) { + var key = BI.concat(this._getParentValues(treeNode), this._getNodeValue(treeNode)).join(this._constants.SPLIT); + if(checked) { + this.storeValue[key] = true; + } else { + delete this.storeValue[key]; + } + }, + + setSelectedValue: function (value) { + this.options.paras.selectedValues = value || []; + this.storeValue = this._transArrayToMap(value); + }, + + getValue: function () { + return this._transMapToArray(this.storeValue); + } +}); + +BI.shortcut("bi.list_tree_view", BI.ListTreeView);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为["A", ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListListAsyncTree + * @extends BI.TreeView + */ +BI.ListAsyncTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListAsyncTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListAsyncTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 + otherParam: BI.cjkEncodeDO(paras) + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + beforeExpand: beforeExpand, + beforeCheck: beforeCheck, + onClick: onClick + } + }; + + function beforeCheck (treeId, treeNode) { + treeNode.half = false; + } + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function beforeExpand (treeId, treeNode) { + self._beforeExpandNode(treeId, treeNode); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + // 展开节点 + _beforeExpandNode: function (treeId, treeNode) { + var self = this, o = this.options; + var parentValues = treeNode.parentValues || self._getParentValues(treeNode); + var op = BI.extend({}, o.paras, { + id: treeNode.id, + times: 1, + parentValues: parentValues.concat(this._getNodeValue(treeNode)) + }); + var complete = function (d) { + var nodes = d.items || []; + if (nodes.length > 0) { + callback(self._dealWidthNodes(nodes), !!d.hasNext); + } + }; + var times = 1; + + function callback (nodes, hasNext) { + self.nodes.addNodes(treeNode, nodes); + // 展开节点是没有分页的 + if (hasNext === true) { + BI.delay(function () { + times++; + op.times = times; + o.itemsCreator(op, complete); + }, 100); + } + } + + if (!treeNode.children) { + setTimeout(function () { + o.itemsCreator(op, complete); + }, 17); + } + }, + + hasChecked: function () { + return !BI.isEmpty(this.options.paras.selectedValues) || BI.ListAsyncTree.superclass.hasChecked.apply(this, arguments); + }, + + // 生成树方法 + stroke: function (config) { + delete this.options.keyword; + BI.extend(this.options.paras, config); + var setting = this._configSetting(); + this._initTree(setting); + } +}); + +BI.shortcut("bi.list_async_tree", BI.ListAsyncTree);/** + * guy + * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 + * @class BI.ListPartTree + * @extends BI.AsyncTree + */ +BI.ListPartTree = BI.inherit(BI.ListAsyncTree, { + _defaultConfig: function () { + return BI.extend(BI.ListPartTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + + _init: function () { + BI.ListPartTree.superclass._init.apply(this, arguments); + }, + + _loadMore: function () { + var self = this, o = this.options; + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: ++this.times + }); + this.tip.setLoading(); + o.itemsCreator(op, function (d) { + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + if (self._stop === true) { + return; + } + if (!hasNext) { + self.tip.setEnd(); + } else { + self.tip.setLoaded(); + } + if (nodes.length > 0) { + self.nodes.addNodes(null, self._dealWidthNodes(nodes)); + } + }); + }, + + _initTree: function (setting, keyword) { + var self = this, o = this.options; + this.times = 1; + var tree = this.tree; + tree.empty(); + self.tip.setVisible(false); + this.loading(); + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: this.times + }); + var complete = function (d) { + if (self._stop === true || keyword != o.paras.keyword) { + return; + } + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); + self.setTipVisible(nodes.length <= 0); + self.loaded(); + if (!hasNext) { + self.tip.invisible(); + } else { + self.tip.setLoaded(); + } + self.fireEvent(BI.Events.AFTERINIT); + }; + + function callback (nodes) { + if (self._stop === true) { + return; + } + self.nodes = $.fn.zTree.init(tree.element, setting, nodes); + } + + BI.delay(function () { + o.itemsCreator(op, complete); + }, 100); + }, + + // 生成树方法 + stroke: function (config) { + var o = this.options; + delete o.paras.keyword; + BI.extend(o.paras, config); + delete o.paras.lastSearchValue; + var setting = this._configSetting(); + this._initTree(setting, o.paras.keyword); + } +}); + +BI.shortcut("bi.list_part_tree", BI.ListPartTree);BI.prepares.push(function () { BI.Resizers = new BI.ResizeController(); BI.Layers = new BI.LayerController(); BI.Maskers = new BI.MaskersController(); @@ -49778,6 +50115,8 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, + checkboxType = setting.check.chkboxType; + var notEffectByOtherNode = (checkboxType.Y === "" && checkboxType.N === ""); fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; @@ -49786,7 +50125,7 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { - fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); + fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) || notEffectByOtherNode ? c.FULL:c.PART) : ((node.check_Child_State < 1 || notEffectByOtherNode)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; @@ -59135,6 +59474,86 @@ BI.DisplayTree = BI.inherit(BI.TreeView, { BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.display_tree", BI.DisplayTree);/** + * guy + * 异步树 + * @class BI.ListListDisplayTree + * @extends BI.TreeView + */ +BI.ListDisplayTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListDisplayTree.superclass._defaultConfig.apply(this, arguments), { + extraCls: "bi-list-display-tree" + }); + }, + _init: function () { + BI.ListDisplayTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var setting = { + view: { + selectedMulti: false, + dblClickExpand: false, + showIcon: false, + nameIsHTML: true, + showTitle: false, + fontCss: getFont + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + callback: { + beforeCollapse: beforeCollapse + } + }; + + function beforeCollapse(treeId, treeNode) { + return false; + } + + function getFont(treeId, node) { + return node.font ? node.font : {color: "#999999"}; + } + + return setting; + }, + + _dealWidthNodes: function (nodes) { + nodes = BI.ListDisplayTree.superclass._dealWidthNodes.apply(this, arguments); + var self = this, o = this.options; + BI.each(nodes, function (i, node) { + node.isParent = node.isParent || node.parent; + if (node.text == null) { + if (node.count > 0) { + node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; + } + } + if(node.isLeaf === true) { + node.font = {color: "#3d4d66"}; + } + }); + return nodes; + }, + + initTree: function (nodes, setting) { + var setting = setting || this._configSetting(); + this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); + }, + + destroy: function () { + BI.ListDisplayTree.superclass.destroy.apply(this, arguments); + } +}); +BI.ListDisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.shortcut("bi.list_display_tree", BI.ListDisplayTree);/** * 简单的多选树 * * Created by GUY on 2016/2/16. @@ -72367,7 +72786,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -72409,7 +72831,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { @@ -72734,6 +73156,585 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut("bi.multi_tree_combo", BI.MultiTreeCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single + */ + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo + * @extends BI.Single + */ + +BI.MultiTreeListCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo);/** * 带加载的多选下拉面板 * @class BI.MultiTreePopup * @extends BI.Pane @@ -72746,24 +73747,27 @@ BI.MultiTreePopup = BI.inherit(BI.Pane, { maxWidth: "auto", minWidth: 100, maxHeight: 400, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } }); }, _init: function () { BI.MultiTreePopup.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, opts = this.options, v = opts.value; this.selectedValues = {}; - this.tree = BI.createWidget({ + this.tree = BI.createWidget(opts.el, { type: "bi.async_tree", height: 400, cls: "popup-view-tree", itemsCreator: opts.itemsCreator, onLoaded: opts.onLoaded, - value: opts.value || {} + value: v.value || {} }); this.popupView = BI.createWidget({ @@ -72831,6 +73835,190 @@ BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** + * 查看已选按钮 + * Created by guy on 15/11/3. + * @class BI.MultiTreeCheckSelectedButton + * @extends BI.Single + */ +BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-check-selected-button", + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); + var self = this; + this.indicator = BI.createWidget({ + type: "bi.icon_button", + cls: "check-font trigger-check-selected icon-size-12", + width: 15, + height: 15, + stopPropagation: true + }); + + this.checkSelected = BI.createWidget({ + type: "bi.text_button", + cls: "trigger-check-selected", + invisible: true, + hgap: 4, + text: BI.i18nText("BI-Check_Selected"), + textAlign: "center", + textHeight: 15 + }); + this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + }); + + BI.createWidget({ + type: "bi.horizontal", + element: this, + items: [this.indicator, this.checkSelected] + }); + + this.element.hover(function () { + self.indicator.setVisible(false); + self.checkSelected.setVisible(true); + }, function () { + self.indicator.setVisible(true); + self.checkSelected.setVisible(false); + }); + this.setVisible(false); + }, + + setValue: function (v) { + v || (v = {}); + this.setVisible(BI.size(v.value) > 0); + } +}); + +BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane);/** * * 在搜索框中输入文本弹出的面板 * @class BI.MultiTreeSearchPane @@ -72904,72 +74092,163 @@ BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** - * 查看已选按钮 + * searcher * Created by guy on 15/11/3. - * @class BI.MultiTreeCheckSelectedButton - * @extends BI.Single + * @class BI.MultiListTreeSearcher + * @extends Widget */ -BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { - return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-check-selected-button", - itemsCreator: BI.emptyFn + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} }); }, _init: function () { - BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); - var self = this; - this.indicator = BI.createWidget({ - type: "bi.icon_button", - cls: "check-font trigger-check-selected icon-size-12", - width: 15, - height: 15, - stopPropagation: true + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } }); - this.checkSelected = BI.createWidget({ - type: "bi.text_button", - cls: "trigger-check-selected", - invisible: true, - hgap: 4, - text: BI.i18nText("BI-Check_Selected"), - textAlign: "center", - textHeight: 15 + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker }); - this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { - this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); }); - - BI.createWidget({ - type: "bi.horizontal", - element: this, - items: [this.indicator, this.checkSelected] + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); }); - - this.element.hover(function () { - self.indicator.setVisible(false); - self.checkSelected.setVisible(true); - }, function () { - self.indicator.setVisible(true); - self.checkSelected.setVisible(false); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); }); - this.setVisible(false); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } }, - setValue: function (v) { - v || (v = {}); - this.setVisible(BI.size(v.value) > 0); + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); } }); -BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher);/** * searcher * Created by guy on 15/11/3. * @class BI.MultiTreeSearcher @@ -82846,10 +84125,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -83109,7 +84397,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -83146,6 +84434,15 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } @@ -83275,6 +84572,10 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { halfCheck: state[1] }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -83341,6 +84642,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }, + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + _getNode: function (selectedValues, parentValues) { var pNode = selectedValues; for (var i = 0, len = parentValues.length; i < len; i++) { @@ -83426,7 +84743,373 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { _getChildCount: function (parentValues) { return this._getChildren(parentValues).length; } +});BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { + + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); + }); + } + + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; + } + }, + + _reqInitTreeNode: function (op, callback) { + var self = this; + var result = []; + var keyword = op.keyword || ""; + var selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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, result); + } else if (output.length === self._const.perPage) { + var find = nodeSearch(1, [], children[i].value, []); + } + if (find[0] === true) { + output.push(children[i].value); + } + if (output.length > self._const.perPage) { + break; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + BI.each(children, function (i, child) { + var state = nodeSearch(deep + 1, newParents, child.value, result); + if (state[1] === true) { + checked = true; + } + if (state[0] === true) { + can = true; + } + }); + if (can === true) { + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: false, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; + } + BI.every(parentValues, 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 parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var checked = BI.has(valueMap, nodes[i].value); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: checked, + halfCheck: false + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); + + function dealWidthSelectedValue(selectedValues) { + var valueMap = {}; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; + }); + return valueMap; + } + }, + + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } });/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.ListTreeValueChooserInsertCombo.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_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo);/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.TreeValueChooserInsertCombo.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_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. diff --git a/dist/fineui.js b/dist/fineui.js index 38b84b17d..1c0b4dd1d 100644 --- a/dist/fineui.js +++ b/dist/fineui.js @@ -37839,8 +37839,8 @@ BI.TreeView = BI.inherit(BI.Pane, { async: { enable: true, url: getUrl, - autoParam: ["id", "name"], - otherParam: BI.cjkEncodeDO(paras) + autoParam: ["id", "name"], // 节点展开异步请求自动提交id和name + otherParam: BI.cjkEncodeDO(paras) // 静态参数 }, check: { enable: true @@ -37848,16 +37848,16 @@ BI.TreeView = BI.inherit(BI.Pane, { data: { key: { title: "title", - name: "text" + name: "text" // 节点的name属性替换成text }, simpleData: { - enable: true + enable: true // 可以穿id,pid属性的对象数组 } }, view: { showIcon: false, expandSpeed: "", - nameIsHTML: true, + nameIsHTML: true, // 节点可以用html标签代替 dblClickExpand: false }, callback: { @@ -37880,6 +37880,7 @@ BI.TreeView = BI.inherit(BI.Pane, { if(status.half === true && status.checked === true) { checked = false; } + // 更新此node的check状态, 影响父子关联,并调用beforeCheck和onCheck回调 self.nodes.checkNode(treeNode, !checked, true, true); } @@ -37902,7 +37903,7 @@ BI.TreeView = BI.inherit(BI.Pane, { } return true; } - BI.Msg.toast("Please Wait。", "warning"); + BI.Msg.toast("Please Wait。", "warning"); // 不展开节点,也不触发onExpand事件 return false; } @@ -37940,9 +37941,9 @@ BI.TreeView = BI.inherit(BI.Pane, { function ajaxGetNodes (treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { - zTree.updateNode(treeNode); + zTree.updateNode(treeNode); // 刷新一下当前节点,如果treeNode.xxx被改了的话 } - zTree.reAsyncChildNodes(treeNode, reloadType, true); + zTree.reAsyncChildNodes(treeNode, reloadType, true); // 强制加载子节点,reloadType === refresh为先清空再加载,否则为追加到现有子节点之后 } function beforeCheck (treeId, treeNode) { @@ -38020,15 +38021,18 @@ BI.TreeView = BI.inherit(BI.Pane, { } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); + // 当前节点是全选的,因为上面的判断已经排除了不选和半选 if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } + // 剩下的就是半选不展开的节点,因为不知道里面是什么情况,所以借助selectedValues(这个是完整的选中情况) var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, + // 获取的是以values最后一个节点为根的子树 _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { @@ -38040,6 +38044,7 @@ BI.TreeView = BI.inherit(BI.Pane, { return cur; }, + // 以values为path一路向里补充map, 并在末尾节点添加key: value节点 _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { @@ -38067,7 +38072,7 @@ BI.TreeView = BI.inherit(BI.Pane, { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); - track(rootNoots); + track(rootNoots); // 可以看到这个方法没有递归调用,所以在_getHalfSelectedValues中需要关心全选的节点 function track (nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); @@ -38315,7 +38320,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { var self = this; var setting = { async: { - enable: false, + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: BI.cjkEncodeDO(paras) }, check: { @@ -38405,6 +38410,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { return setting; }, + // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); @@ -38450,7 +38456,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { function callback (nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); - + // 展开节点是没有分页的 if (hasNext === true) { BI.delay(function () { times++; @@ -38467,6 +38473,9 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { } }, + // a,b 两棵树 + // a->b b->a 做两次校验, 构造一个校验后的map + // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join: function (valueA, valueB) { var self = this; var map = {}; @@ -38558,9 +38567,17 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { - BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + this._buildTree(self.options.paras.selectedValues, BI.concat(parentValues, name)); + o.itemsCreator({ + type: BI.TreeView.REQ_TYPE_ADJUST_DATA, + selectedValues: self.options.paras.selectedValues + }, function (res) { + self.options.paras.selectedValues = res; + BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + }); } else { // 如果选中的值中不存在该值不处理 + // 因为反正是不选中,没必要管 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { @@ -38568,6 +38585,7 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { if (t == null) { return; } + // 选中中国-江苏, 搜索南京,取消勾选 if (BI.isEmpty(t)) { break; } @@ -38631,9 +38649,8 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; - if (nodes.length > 0) { - callback(self._dealWidthNodes(nodes)); - } + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { @@ -38659,12 +38676,6 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); - o.itemsCreator({ - type: BI.TreeView.REQ_TYPE_ADJUST_DATA, - selectedValues: result - }, function (res) { - result = res; - }); return result; }, @@ -38679,7 +38690,333 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } }); -BI.shortcut("bi.part_tree", BI.PartTree);BI.prepares.push(function () { +BI.shortcut("bi.part_tree", BI.PartTree);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为[["A"], ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListTreeView + * @extends BI.TreeView + */ +BI.ListTreeView = BI.inherit(BI.TreeView, { + + _constants: { + SPLIT: "<|>" + }, + + _defaultConfig: function () { + return BI.extend(BI.ListTreeView.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListTreeView.superclass._init.apply(this, arguments); + var o = this.options; + this.storeValue = o.value || {}; + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + onClick: onClick + } + }; + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + _selectTreeNode: function (treeId, treeNode) { + this._checkValue(treeNode, treeNode.checked); + BI.ListTreeView.superclass._selectTreeNode.apply(this, arguments); + }, + + _transArrayToMap: function (treeArrays) { + var self = this; + var map = {}; + BI.each(treeArrays, function (idx, array) { + var key = array.join(self._constants.SPLIT); + map[key] = true; + }); + return map; + }, + + _transMapToArray: function (treeMap) { + var self = this; + var array = []; + BI.each(treeMap, function (key) { + var item = key.split(self._constants.SPLIT); + array.push(item); + }); + return array; + }, + + _checkValue: function (treeNode, checked) { + var key = BI.concat(this._getParentValues(treeNode), this._getNodeValue(treeNode)).join(this._constants.SPLIT); + if(checked) { + this.storeValue[key] = true; + } else { + delete this.storeValue[key]; + } + }, + + setSelectedValue: function (value) { + this.options.paras.selectedValues = value || []; + this.storeValue = this._transArrayToMap(value); + }, + + getValue: function () { + return this._transMapToArray(this.storeValue); + } +}); + +BI.shortcut("bi.list_tree_view", BI.ListTreeView);/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为["A", ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListListAsyncTree + * @extends BI.TreeView + */ +BI.ListAsyncTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListAsyncTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListAsyncTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 + otherParam: BI.cjkEncodeDO(paras) + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + beforeExpand: beforeExpand, + beforeCheck: beforeCheck, + onClick: onClick + } + }; + + function beforeCheck (treeId, treeNode) { + treeNode.half = false; + } + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function beforeExpand (treeId, treeNode) { + self._beforeExpandNode(treeId, treeNode); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + // 展开节点 + _beforeExpandNode: function (treeId, treeNode) { + var self = this, o = this.options; + var parentValues = treeNode.parentValues || self._getParentValues(treeNode); + var op = BI.extend({}, o.paras, { + id: treeNode.id, + times: 1, + parentValues: parentValues.concat(this._getNodeValue(treeNode)) + }); + var complete = function (d) { + var nodes = d.items || []; + if (nodes.length > 0) { + callback(self._dealWidthNodes(nodes), !!d.hasNext); + } + }; + var times = 1; + + function callback (nodes, hasNext) { + self.nodes.addNodes(treeNode, nodes); + // 展开节点是没有分页的 + if (hasNext === true) { + BI.delay(function () { + times++; + op.times = times; + o.itemsCreator(op, complete); + }, 100); + } + } + + if (!treeNode.children) { + setTimeout(function () { + o.itemsCreator(op, complete); + }, 17); + } + }, + + hasChecked: function () { + return !BI.isEmpty(this.options.paras.selectedValues) || BI.ListAsyncTree.superclass.hasChecked.apply(this, arguments); + }, + + // 生成树方法 + stroke: function (config) { + delete this.options.keyword; + BI.extend(this.options.paras, config); + var setting = this._configSetting(); + this._initTree(setting); + } +}); + +BI.shortcut("bi.list_async_tree", BI.ListAsyncTree);/** + * guy + * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 + * @class BI.ListPartTree + * @extends BI.AsyncTree + */ +BI.ListPartTree = BI.inherit(BI.ListAsyncTree, { + _defaultConfig: function () { + return BI.extend(BI.ListPartTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + + _init: function () { + BI.ListPartTree.superclass._init.apply(this, arguments); + }, + + _loadMore: function () { + var self = this, o = this.options; + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: ++this.times + }); + this.tip.setLoading(); + o.itemsCreator(op, function (d) { + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + if (self._stop === true) { + return; + } + if (!hasNext) { + self.tip.setEnd(); + } else { + self.tip.setLoaded(); + } + if (nodes.length > 0) { + self.nodes.addNodes(null, self._dealWidthNodes(nodes)); + } + }); + }, + + _initTree: function (setting, keyword) { + var self = this, o = this.options; + this.times = 1; + var tree = this.tree; + tree.empty(); + self.tip.setVisible(false); + this.loading(); + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: this.times + }); + var complete = function (d) { + if (self._stop === true || keyword != o.paras.keyword) { + return; + } + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); + self.setTipVisible(nodes.length <= 0); + self.loaded(); + if (!hasNext) { + self.tip.invisible(); + } else { + self.tip.setLoaded(); + } + self.fireEvent(BI.Events.AFTERINIT); + }; + + function callback (nodes) { + if (self._stop === true) { + return; + } + self.nodes = $.fn.zTree.init(tree.element, setting, nodes); + } + + BI.delay(function () { + o.itemsCreator(op, complete); + }, 100); + }, + + // 生成树方法 + stroke: function (config) { + var o = this.options; + delete o.paras.keyword; + BI.extend(o.paras, config); + delete o.paras.lastSearchValue; + var setting = this._configSetting(); + this._initTree(setting, o.paras.keyword); + } +}); + +BI.shortcut("bi.list_part_tree", BI.ListPartTree);BI.prepares.push(function () { BI.Resizers = new BI.ResizeController(); BI.Layers = new BI.LayerController(); BI.Maskers = new BI.MaskersController(); @@ -50182,6 +50519,8 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, + checkboxType = setting.check.chkboxType; + var notEffectByOtherNode = (checkboxType.Y === "" && checkboxType.N === ""); fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; @@ -50190,7 +50529,7 @@ BI.shortcut("bi.custom_tree", BI.CustomTree);/* } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { - fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); + fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) || notEffectByOtherNode ? c.FULL:c.PART) : ((node.check_Child_State < 1 || notEffectByOtherNode)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; @@ -59539,6 +59878,86 @@ BI.DisplayTree = BI.inherit(BI.TreeView, { BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.display_tree", BI.DisplayTree);/** + * guy + * 异步树 + * @class BI.ListListDisplayTree + * @extends BI.TreeView + */ +BI.ListDisplayTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListDisplayTree.superclass._defaultConfig.apply(this, arguments), { + extraCls: "bi-list-display-tree" + }); + }, + _init: function () { + BI.ListDisplayTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var setting = { + view: { + selectedMulti: false, + dblClickExpand: false, + showIcon: false, + nameIsHTML: true, + showTitle: false, + fontCss: getFont + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + callback: { + beforeCollapse: beforeCollapse + } + }; + + function beforeCollapse(treeId, treeNode) { + return false; + } + + function getFont(treeId, node) { + return node.font ? node.font : {color: "#999999"}; + } + + return setting; + }, + + _dealWidthNodes: function (nodes) { + nodes = BI.ListDisplayTree.superclass._dealWidthNodes.apply(this, arguments); + var self = this, o = this.options; + BI.each(nodes, function (i, node) { + node.isParent = node.isParent || node.parent; + if (node.text == null) { + if (node.count > 0) { + node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; + } + } + if(node.isLeaf === true) { + node.font = {color: "#3d4d66"}; + } + }); + return nodes; + }, + + initTree: function (nodes, setting) { + var setting = setting || this._configSetting(); + this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); + }, + + destroy: function () { + BI.ListDisplayTree.superclass.destroy.apply(this, arguments); + } +}); +BI.ListDisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.shortcut("bi.list_display_tree", BI.ListDisplayTree);/** * 简单的多选树 * * Created by GUY on 2016/2/16. @@ -72771,7 +73190,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -72813,7 +73235,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { @@ -73138,6 +73560,585 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut("bi.multi_tree_combo", BI.MultiTreeCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single + */ + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo + * @extends BI.Single + */ + +BI.MultiTreeListCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo);/** * 带加载的多选下拉面板 * @class BI.MultiTreePopup * @extends BI.Pane @@ -73150,24 +74151,27 @@ BI.MultiTreePopup = BI.inherit(BI.Pane, { maxWidth: "auto", minWidth: 100, maxHeight: 400, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } }); }, _init: function () { BI.MultiTreePopup.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, opts = this.options, v = opts.value; this.selectedValues = {}; - this.tree = BI.createWidget({ + this.tree = BI.createWidget(opts.el, { type: "bi.async_tree", height: 400, cls: "popup-view-tree", itemsCreator: opts.itemsCreator, onLoaded: opts.onLoaded, - value: opts.value || {} + value: v.value || {} }); this.popupView = BI.createWidget({ @@ -73235,6 +74239,190 @@ BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** + * 查看已选按钮 + * Created by guy on 15/11/3. + * @class BI.MultiTreeCheckSelectedButton + * @extends BI.Single + */ +BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-check-selected-button", + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); + var self = this; + this.indicator = BI.createWidget({ + type: "bi.icon_button", + cls: "check-font trigger-check-selected icon-size-12", + width: 15, + height: 15, + stopPropagation: true + }); + + this.checkSelected = BI.createWidget({ + type: "bi.text_button", + cls: "trigger-check-selected", + invisible: true, + hgap: 4, + text: BI.i18nText("BI-Check_Selected"), + textAlign: "center", + textHeight: 15 + }); + this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + }); + + BI.createWidget({ + type: "bi.horizontal", + element: this, + items: [this.indicator, this.checkSelected] + }); + + this.element.hover(function () { + self.indicator.setVisible(false); + self.checkSelected.setVisible(true); + }, function () { + self.indicator.setVisible(true); + self.checkSelected.setVisible(false); + }); + this.setVisible(false); + }, + + setValue: function (v) { + v || (v = {}); + this.setVisible(BI.size(v.value) > 0); + } +}); + +BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane);/** * * 在搜索框中输入文本弹出的面板 * @class BI.MultiTreeSearchPane @@ -73308,72 +74496,163 @@ BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** - * 查看已选按钮 + * searcher * Created by guy on 15/11/3. - * @class BI.MultiTreeCheckSelectedButton - * @extends BI.Single + * @class BI.MultiListTreeSearcher + * @extends Widget */ -BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { - return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-check-selected-button", - itemsCreator: BI.emptyFn + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} }); }, _init: function () { - BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); - var self = this; - this.indicator = BI.createWidget({ - type: "bi.icon_button", - cls: "check-font trigger-check-selected icon-size-12", - width: 15, - height: 15, - stopPropagation: true + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } }); - this.checkSelected = BI.createWidget({ - type: "bi.text_button", - cls: "trigger-check-selected", - invisible: true, - hgap: 4, - text: BI.i18nText("BI-Check_Selected"), - textAlign: "center", - textHeight: 15 + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker }); - this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { - this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); }); - - BI.createWidget({ - type: "bi.horizontal", - element: this, - items: [this.indicator, this.checkSelected] + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); }); - - this.element.hover(function () { - self.indicator.setVisible(false); - self.checkSelected.setVisible(true); - }, function () { - self.indicator.setVisible(true); - self.checkSelected.setVisible(false); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); }); - this.setVisible(false); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } }, - setValue: function (v) { - v || (v = {}); - this.setVisible(BI.size(v.value) > 0); + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); } }); -BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher);/** * searcher * Created by guy on 15/11/3. * @class BI.MultiTreeSearcher @@ -83250,10 +84529,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -83513,7 +84801,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -83550,6 +84838,15 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } @@ -83679,6 +84976,10 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { halfCheck: state[1] }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -83745,6 +85046,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }, + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + _getNode: function (selectedValues, parentValues) { var pNode = selectedValues; for (var i = 0, len = parentValues.length; i < len; i++) { @@ -83830,7 +85147,373 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { _getChildCount: function (parentValues) { return this._getChildren(parentValues).length; } +});BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { + + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); + }); + } + + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; + } + }, + + _reqInitTreeNode: function (op, callback) { + var self = this; + var result = []; + var keyword = op.keyword || ""; + var selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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, result); + } else if (output.length === self._const.perPage) { + var find = nodeSearch(1, [], children[i].value, []); + } + if (find[0] === true) { + output.push(children[i].value); + } + if (output.length > self._const.perPage) { + break; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + BI.each(children, function (i, child) { + var state = nodeSearch(deep + 1, newParents, child.value, result); + if (state[1] === true) { + checked = true; + } + if (state[0] === true) { + can = true; + } + }); + if (can === true) { + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: false, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; + } + BI.every(parentValues, 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 parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var checked = BI.has(valueMap, nodes[i].value); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: checked, + halfCheck: false + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); + + function dealWidthSelectedValue(selectedValues) { + var valueMap = {}; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; + }); + return valueMap; + } + }, + + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } });/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.ListTreeValueChooserInsertCombo.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_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo);/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.TreeValueChooserInsertCombo.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_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. diff --git a/dist/fineui_without_jquery_polyfill.js b/dist/fineui_without_jquery_polyfill.js index b289ef70f..66b47d71c 100644 --- a/dist/fineui_without_jquery_polyfill.js +++ b/dist/fineui_without_jquery_polyfill.js @@ -55581,7 +55581,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -55623,7 +55626,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { @@ -55948,310 +55951,1167 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut("bi.multi_tree_combo", BI.MultiTreeCombo);/** - * 带加载的多选下拉面板 - * @class BI.MultiTreePopup - * @extends BI.Pane + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single */ -BI.MultiTreePopup = BI.inherit(BI.Pane, { + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, _defaultConfig: function () { - return BI.extend(BI.MultiTreePopup.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-popup", - maxWidth: "auto", - minWidth: 100, - maxHeight: 400, - onLoaded: BI.emptyFn + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 }); }, _init: function () { - BI.MultiTreePopup.superclass._init.apply(this, arguments); + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, o = this.options; - this.selectedValues = {}; + var isInit = false; + var want2showCounter = false; - this.tree = BI.createWidget({ - type: "bi.async_tree", - height: 400, - cls: "popup-view-tree", - itemsCreator: opts.itemsCreator, - onLoaded: opts.onLoaded, - value: opts.value || {} - }); + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} - this.popupView = BI.createWidget({ - type: "bi.multi_popup_view", - element: this, - stopPropagation: false, - maxWidth: opts.maxWidth, - minWidth: opts.minWidth, - maxHeight: opts.maxHeight, - buttons: [BI.i18nText("BI-Basic_Clears"), BI.i18nText("BI-Basic_Sure")], - el: this.tree }); - this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) { - switch (index) { - case 0: - self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CLEAR); - break; - case 1: - self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CONFIRM); - break; + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; } }); - this.tree.on(BI.TreeView.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiTreePopup.EVENT_CHANGE); - }); + var change = false; + var clear = false; // 标识当前是否点击了清空 - this.tree.on(BI.TreeView.EVENT_AFTERINIT, function () { - self.fireEvent(BI.MultiTreePopup.EVENT_AFTERINIT); - }); + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; - }, + var isPopupView = function () { + return self.combo.isViewVisible(); + }; - getValue: function () { - return this.tree.getValue(); - }, + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); - setValue: function (v) { - v || (v = {}); - this.tree.setSelectedValue(v.value); - }, + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } - populate: function (config) { - this.tree.stroke(config); - }, + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); - hasChecked: function () { - return this.tree.hasChecked(); - }, + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); - resetHeight: function (h) { - this.popupView.resetHeight(h); - }, + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); - resetWidth: function (w) { - this.popupView.resetWidth(w); - } -}); + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); -BI.MultiTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; -BI.MultiTreePopup.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; -BI.MultiTreePopup.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; -BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; - - -BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** - * - * 在搜索框中输入文本弹出的面板 - * @class BI.MultiTreeSearchPane - * @extends BI.Pane - */ - -BI.MultiTreeSearchPane = BI.inherit(BI.Pane, { - - _defaultConfig: function () { - return BI.extend(BI.MultiTreeSearchPane.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-search-pane bi-card", - itemsCreator: BI.emptyFn, - keywordGetter: BI.emptyFn - }); - }, - - _init: function () { - BI.MultiTreeSearchPane.superclass._init.apply(this, arguments); - - var self = this, opts = this.options; - - this.partTree = BI.createWidget({ - type: "bi.part_tree", - element: this, - tipText: BI.i18nText("BI-No_Select"), - itemsCreator: function (op, callback) { - op.keyword = opts.keywordGetter(); - opts.itemsCreator(op, callback); - }, - value: opts.value + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" }); - - this.partTree.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } }); - - this.partTree.on(BI.TreeView.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiTreeSearchPane.EVENT_CHANGE); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] }); }, - hasChecked: function () { - return this.partTree.hasChecked(); + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); }, - setValue: function (v) { - this.setSelectedValue(v.value); + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); }, - setSelectedValue: function (v) { - v || (v = {}); - this.partTree.setSelectedValue(v); + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); }, getValue: function () { - return this.partTree.getValue(); - }, - - empty: function () { - this.partTree.empty(); + return this.storeValue.value; }, - populate: function (op) { - this.partTree.stroke.apply(this.partTree, arguments); + populate: function () { + this.combo.populate.apply(this.combo, arguments); } }); -BI.MultiTreeSearchPane.EVENT_CHANGE = "EVENT_CHANGE"; - -BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; -BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; -BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** - * 查看已选按钮 - * Created by guy on 15/11/3. - * @class BI.MultiTreeCheckSelectedButton +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo * @extends BI.Single */ -BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { - - _defaultConfig: function () { - return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-check-selected-button", - itemsCreator: BI.emptyFn - }); - }, - - _init: function () { - BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); - var self = this; - this.indicator = BI.createWidget({ - type: "bi.icon_button", - cls: "check-font trigger-check-selected icon-size-12", - width: 15, - height: 15, - stopPropagation: true - }); - - this.checkSelected = BI.createWidget({ - type: "bi.text_button", - cls: "trigger-check-selected", - invisible: true, - hgap: 4, - text: BI.i18nText("BI-Check_Selected"), - textAlign: "center", - textHeight: 15 - }); - this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); - }); - - this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); - }); - BI.createWidget({ - type: "bi.horizontal", - element: this, - items: [this.indicator, this.checkSelected] - }); +BI.MultiTreeListCombo = BI.inherit(BI.Single, { - this.element.hover(function () { - self.indicator.setVisible(false); - self.checkSelected.setVisible(true); - }, function () { - self.indicator.setVisible(true); - self.checkSelected.setVisible(false); - }); - this.setVisible(false); + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } }, - setValue: function (v) { - v || (v = {}); - this.setVisible(BI.size(v.value) > 0); - } -}); - -BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** - * searcher - * Created by guy on 15/11/3. - * @class BI.MultiTreeSearcher - * @extends Widget - */ -BI.MultiTreeSearcher = BI.inherit(BI.Widget, { - _defaultConfig: function () { - return BI.extend(BI.MultiTreeSearcher.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-searcher", + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", itemsCreator: BI.emptyFn, - valueFormatter: function (v) { - return v; - }, - popup: {}, - - adapter: null, - masker: {} + valueFormatter: BI.emptyFn, + height: 24 }); }, _init: function () { - BI.MultiTreeSearcher.superclass._init.apply(this, arguments); + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + var self = this, o = this.options; - this.editor = BI.createWidget({ - type: "bi.multi_select_editor", - height: o.height, - el: { - type: "bi.simple_state_editor", - height: o.height - } - }); - this.searcher = BI.createWidget({ - type: "bi.searcher", - element: this, - isAutoSearch: false, - isAutoSync: false, - onSearch: function (op, callback) { - callback({ - keyword: self.editor.getValue() - }); - }, - el: this.editor, + var isInit = false; + var want2showCounter = false; - popup: BI.extend({ - type: "bi.multi_tree_search_pane", - keywordGetter: function () { - return self.editor.getValue(); - }, - itemsCreator: function (op, callback) { - op.keyword = self.editor.getValue(); - o.itemsCreator(op, callback); + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" }, - value: o.value - }, o.popup), + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} - adapter: o.adapter, - masker: o.masker - }); - this.searcher.on(BI.Searcher.EVENT_START, function () { - self.fireEvent(BI.MultiTreeSearcher.EVENT_START); }); - this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { - if (this.hasMatched()) { - } - self.fireEvent(BI.MultiTreeSearcher.EVENT_PAUSE); + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo);/** + * 带加载的多选下拉面板 + * @class BI.MultiTreePopup + * @extends BI.Pane + */ +BI.MultiTreePopup = BI.inherit(BI.Pane, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreePopup.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-popup", + maxWidth: "auto", + minWidth: 100, + maxHeight: 400, + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } + }); + }, + + _init: function () { + BI.MultiTreePopup.superclass._init.apply(this, arguments); + + var self = this, opts = this.options, v = opts.value; + + this.selectedValues = {}; + + this.tree = BI.createWidget(opts.el, { + type: "bi.async_tree", + height: 400, + cls: "popup-view-tree", + itemsCreator: opts.itemsCreator, + onLoaded: opts.onLoaded, + value: v.value || {} + }); + + this.popupView = BI.createWidget({ + type: "bi.multi_popup_view", + element: this, + stopPropagation: false, + maxWidth: opts.maxWidth, + minWidth: opts.minWidth, + maxHeight: opts.maxHeight, + buttons: [BI.i18nText("BI-Basic_Clears"), BI.i18nText("BI-Basic_Sure")], + el: this.tree + }); + + this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) { + switch (index) { + case 0: + self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CLEAR); + break; + case 1: + self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CONFIRM); + break; + } + }); + + this.tree.on(BI.TreeView.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiTreePopup.EVENT_CHANGE); + }); + + this.tree.on(BI.TreeView.EVENT_AFTERINIT, function () { + self.fireEvent(BI.MultiTreePopup.EVENT_AFTERINIT); + }); + + }, + + getValue: function () { + return this.tree.getValue(); + }, + + setValue: function (v) { + v || (v = {}); + this.tree.setSelectedValue(v.value); + }, + + populate: function (config) { + this.tree.stroke(config); + }, + + hasChecked: function () { + return this.tree.hasChecked(); + }, + + resetHeight: function (h) { + this.popupView.resetHeight(h); + }, + + resetWidth: function (w) { + this.popupView.resetWidth(w); + } +}); + +BI.MultiTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiTreePopup.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreePopup.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; + + +BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** + * 查看已选按钮 + * Created by guy on 15/11/3. + * @class BI.MultiTreeCheckSelectedButton + * @extends BI.Single + */ +BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-check-selected-button", + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); + var self = this; + this.indicator = BI.createWidget({ + type: "bi.icon_button", + cls: "check-font trigger-check-selected icon-size-12", + width: 15, + height: 15, + stopPropagation: true + }); + + this.checkSelected = BI.createWidget({ + type: "bi.text_button", + cls: "trigger-check-selected", + invisible: true, + hgap: 4, + text: BI.i18nText("BI-Check_Selected"), + textAlign: "center", + textHeight: 15 + }); + this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + }); + + BI.createWidget({ + type: "bi.horizontal", + element: this, + items: [this.indicator, this.checkSelected] + }); + + this.element.hover(function () { + self.indicator.setVisible(false); + self.checkSelected.setVisible(true); + }, function () { + self.indicator.setVisible(true); + self.checkSelected.setVisible(false); + }); + this.setVisible(false); + }, + + setValue: function (v) { + v || (v = {}); + this.setVisible(BI.size(v.value) > 0); + } +}); + +BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchPane = BI.inherit(BI.Pane, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeSearchPane.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-search-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeSearchPane.superclass._init.apply(this, arguments); + + var self = this, opts = this.options; + + this.partTree = BI.createWidget({ + type: "bi.part_tree", + element: this, + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, callback); + }, + value: opts.value + }); + + this.partTree.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.partTree.on(BI.TreeView.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiTreeSearchPane.EVENT_CHANGE); + }); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; + +BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** + * searcher + * Created by guy on 15/11/3. + * @class BI.MultiListTreeSearcher + * @extends Widget + */ +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { + + _defaultConfig: function () { + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} + }); + }, + + _init: function () { + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } + }); + + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker + }); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); + }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { + + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); + }); + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); + }); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); + }); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } + }, + + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); + } +}); + +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher);/** + * searcher + * Created by guy on 15/11/3. + * @class BI.MultiTreeSearcher + * @extends Widget + */ +BI.MultiTreeSearcher = BI.inherit(BI.Widget, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} + }); + }, + + _init: function () { + BI.MultiTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } + }); + + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker + }); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiTreeSearcher.EVENT_START); + }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { + + } + self.fireEvent(BI.MultiTreeSearcher.EVENT_PAUSE); }); this.searcher.on(BI.Searcher.EVENT_STOP, function () { self.fireEvent(BI.MultiTreeSearcher.EVENT_STOP); @@ -66060,10 +66920,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -66206,115 +67075,519 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { }); } - function search(parents, current, result, searched) { - var newParents = BI.clone(parents); - newParents.push(current); - if (self._isMatch(parents, current, keyword)) { - searched && searched.push(newParents); - return true; - } - - var children = self._getChildren(newParents); + function search(parents, current, result, searched) { + var newParents = BI.clone(parents); + newParents.push(current); + if (self._isMatch(parents, current, keyword)) { + searched && searched.push(newParents); + return true; + } + + var children = self._getChildren(newParents); + + var notSearch = []; + var can = false; + + BI.each(children, function (i, child) { + if (search(newParents, child.value, result, searched)) { + 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 isSearchValueInParent(parentValues) { + for (var i = 0, len = parentValues.length; i < len; i++) { + if (self._isMatch(parentValues.slice(0, i), parentValues[i], keyword)) { + return true; + } + } + return false; + } + + function canFindKey(selectedValues, parents) { + var t = selectedValues; + for (var i = 0; i < parents.length; i++) { + var v = parents[i]; + t = t[v]; + if (t == null) { + return false; + } + } + return true; + } + + function isChild(selectedValues, parents) { + var t = selectedValues; + for (var i = 0; i < parents.length; i++) { + var v = parents[i]; + if (!BI.has(t, v)) { + return false; + } + t = t[v]; + if (BI.isEmpty(t)) { + return true; + } + } + return false; + } + }, + + _reqAdjustTreeNode: function (op, callback) { + var self = this; + var result = []; + var selectedValues = op.selectedValues; + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + BI.each(selectedValues, function (k, v) { + result.push([k]); + }); + + dealWithSelectedValues(selectedValues, []); + + 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 selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, isAllSelect, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isAllSelect || isSelected(parentValues, current); + createOneJson(parentValues, current, false, checked, !isAllSelect && isHalf(parentValues, current), true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + var isCurAllSelected = isAllSelect || isAllSelected(parentValues, 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(parentValues, current) && checked); + createOneJson(parentValues, current, true, checked, false, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, half, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: half, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + if (find == null) { + return false; + } + return BI.any(find, function (v) { + if (v === value) { + return true; + } + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; + } + BI.every(parentValues, 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 checkState = op.checkState || {}; + var parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || {}; + var valueMap = {}; + // if (judgeState(parentValues, selectedValues, checkState)) { + valueMap = dealWidthSelectedValue(parentValues, selectedValues); + // } + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var state = getCheckState(nodes[i].value, parentValues, valueMap, checkState); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: state[0], + halfCheck: state[1] + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); - var notSearch = []; - var can = false; + function judgeState(parentValues, selected_value, checkState) { + var checked = checkState.checked, half = checkState.half; + if (parentValues.length > 0 && !checked) { + return false; + } + return (parentValues.length === 0 || (checked && half) && !BI.isEmpty(selected_value)); + } - BI.each(children, function (i, child) { - if (search(newParents, child.value, result, searched)) { - can = true; - } else { - notSearch.push(child.value); - } + function dealWidthSelectedValue(parentValues, selectedValues) { + var valueMap = {}; + BI.each(parentValues, function (i, v) { + selectedValues = selectedValues[v] || {}; }); - if (can === true) { - BI.each(notSearch, function (i, v) { - var next = BI.clone(newParents); - next.push(v); - result.push(next); + BI.each(selectedValues, 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; + } }); - } - return can; + valueMap[value] = [1, BI.size(nextNames)]; + }); + return valueMap; } - function isSearchValueInParent(parentValues) { - for (var i = 0, len = parentValues.length; i < len; i++) { - if (self._isMatch(parentValues.slice(0, i), parentValues[i], keyword)) { - return true; + function getCheckState(current, parentValues, valueMap, checkState) { + var checked = checkState.checked, half = checkState.half; + var tempCheck = false, halfCheck = false; + if (BI.has(valueMap, current)) { + // 可能是半选 + if (valueMap[current][0] === 1) { + var values = BI.clone(parentValues); + values.push(current); + var childCount = self._getChildCount(values); + if (childCount > 0 && childCount !== valueMap[current][1]) { + halfCheck = true; + } + } else if (valueMap[current][0] === 2) { + tempCheck = true; } } - return false; + var check; + if (!checked && !halfCheck && !tempCheck) { + check = BI.has(valueMap, current); + } else { + check = ((tempCheck || checked) && !half) || BI.has(valueMap, current); + } + return [check, halfCheck]; } + }, - function canFindKey(selectedValues, parents) { - var t = selectedValues; - for (var i = 0; i < parents.length; i++) { - var v = parents[i]; - t = t[v]; - if (t == null) { - return false; - } + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + + _getNode: function (selectedValues, parentValues) { + var pNode = selectedValues; + for (var i = 0, len = parentValues.length; i < len; i++) { + if (pNode == null) { + return null; } - return true; + pNode = pNode[parentValues[i]]; } + return pNode; + }, - function isChild(selectedValues, parents) { - var t = selectedValues; - for (var i = 0; i < parents.length; i++) { - var v = parents[i]; - if (!BI.has(t, v)) { - return false; - } - t = t[v]; - if (BI.isEmpty(t)) { - return true; + _deleteNode: function (selectedValues, values) { + var name = values[values.length - 1]; + var p = values.slice(0, values.length - 1); + var pNode = this._getNode(selectedValues, p); + if (pNode != null && pNode[name]) { + delete pNode[name]; + // 递归删掉空父节点 + while (p.length > 0 && BI.isEmpty(pNode)) { + name = p[p.length - 1]; + p = p.slice(0, p.length - 1); + pNode = this._getNode(selectedValues, p); + if (pNode != null) { + delete pNode[name]; } } + } + }, + + _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 (parentValues, value, keyword) { + var node = this._getTreeNode(parentValues, value); + if (!node) { return false; } + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; }, - _reqAdjustTreeNode: function (op, callback) { + _getTreeNode: function (parentValues, v) { var self = this; - var result = []; - var selectedValues = op.selectedValues; - if (selectedValues == null || BI.isEmpty(selectedValues)) { - callback({}); - return; - } - BI.each(selectedValues, function (k, v) { - result.push([k]); + var findParentNode; + var index = 0; + this.tree.traverse(function (node) { + if (self.tree.isRoot(node)) { + return; + } + if (index > parentValues.length) { + return false; + } + if (index === parentValues.length && node.value === v) { + findParentNode = node; + return false; + } + if (node.value === parentValues[index]) { + index++; + return; + } + return true; }); + return findParentNode; + }, - dealWithSelectedValues(selectedValues, []); + _getChildren: function (parentValues) { + if (parentValues.length > 0) { + var value = BI.last(parentValues); + var parent = this._getTreeNode(parentValues.slice(0, parentValues.length - 1), value); + } else { + var parent = this.tree.getRoot(); + } + return parent.getChildren(); + }, - var jo = {}; - BI.each(result, function (i, strs) { - self._buildTree(jo, strs); - }); - callback(jo); + _getChildCount: function (parentValues) { + return this._getChildren(parentValues).length; + } +});BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { - 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; - } + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); }); - return can && isAllSelected(selected, parents); } - function isAllSelected(selected, parents) { - return BI.isEmpty(selected) || self._getChildCount(parents) === BI.size(selected); + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; } }, @@ -66323,7 +67596,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -66349,9 +67622,9 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { 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); + var find = nodeSearch(1, [], children[i].value, result); } else if (output.length === self._const.perPage) { - var find = nodeSearch(1, [], children[i].value, false, []); + var find = nodeSearch(1, [], children[i].value, []); } if (find[0] === true) { output.push(children[i].value); @@ -66360,13 +67633,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } - function nodeSearch(deep, parentValues, current, isAllSelect, result) { + function nodeSearch(deep, parentValues, current, result) { if (self._isMatch(parentValues, current, keyword)) { - var checked = isAllSelect || isSelected(parentValues, current); - createOneJson(parentValues, current, false, checked, !isAllSelect && isHalf(parentValues, current), true, result); + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); return [true, checked]; } var newParents = BI.clone(parentValues); @@ -66375,9 +67657,8 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var can = false, checked = false; - var isCurAllSelected = isAllSelect || isAllSelected(parentValues, current); BI.each(children, function (i, child) { - var state = nodeSearch(deep + 1, newParents, child.value, isCurAllSelected, result); + var state = nodeSearch(deep + 1, newParents, child.value, result); if (state[1] === true) { checked = true; } @@ -66386,13 +67667,13 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }); if (can === true) { - checked = isCurAllSelected || (isSelected(parentValues, current) && checked); - createOneJson(parentValues, current, true, checked, false, false, result); + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); } return [can, checked]; } - function createOneJson(parentValues, value, isOpen, checked, half, flag, result) { + function createOneJson(parentValues, value, isOpen, checked, flag, result) { var node = self._getTreeNode(parentValues, value); result.push({ id: node.id, @@ -66403,7 +67684,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { isParent: node.getChildrenLength() > 0, open: isOpen, checked: checked, - halfCheck: half, + halfCheck: false, flag: flag }); } @@ -66436,15 +67717,9 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { }); } - function isSelected(parentValues, value) { - var find = findSelectedObj(parentValues); - if (find == null) { - return false; - } - return BI.any(find, function (v) { - if (v === value) { - return true; - } + function isSelected(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; }); } @@ -66468,16 +67743,12 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var self = this; var result = []; var times = op.times; - var checkState = op.checkState || {}; var parentValues = op.parentValues || []; - var selectedValues = op.selectedValues || {}; - var valueMap = {}; - // if (judgeState(parentValues, selectedValues, checkState)) { - valueMap = dealWidthSelectedValue(parentValues, selectedValues); - // } + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); var nodes = this._getChildren(parentValues); for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { - var state = getCheckState(nodes[i].value, parentValues, valueMap, checkState); + var checked = BI.has(valueMap, nodes[i].value); result.push({ id: nodes[i].id, pId: nodes[i].pId, @@ -66485,10 +67756,14 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { text: nodes[i].text, times: 1, isParent: nodes[i].getChildrenLength() > 0, - checked: state[0], - halfCheck: state[1] + checked: checked, + halfCheck: false }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -66496,151 +67771,140 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { }); }); - function judgeState(parentValues, selected_value, checkState) { - var checked = checkState.checked, half = checkState.half; - if (parentValues.length > 0 && !checked) { - return false; - } - return (parentValues.length === 0 || (checked && half) && !BI.isEmpty(selected_value)); - } - - function dealWidthSelectedValue(parentValues, selectedValues) { + function dealWidthSelectedValue(selectedValues) { var valueMap = {}; - BI.each(parentValues, function (i, v) { - selectedValues = selectedValues[v] || {}; - }); - BI.each(selectedValues, 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)]; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; }); return valueMap; } + }, - function getCheckState(current, parentValues, valueMap, checkState) { - var checked = checkState.checked, half = checkState.half; - var tempCheck = false, halfCheck = false; - if (BI.has(valueMap, current)) { - // 可能是半选 - if (valueMap[current][0] === 1) { - var values = BI.clone(parentValues); - values.push(current); - var childCount = self._getChildCount(values); - if (childCount > 0 && childCount !== 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]; - } + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } +});/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); }, - _getNode: function (selectedValues, parentValues) { - var pNode = selectedValues; - for (var i = 0, len = parentValues.length; i < len; i++) { - if (pNode == null) { - return null; - } - pNode = pNode[parentValues[i]]; + _init: function () { + BI.ListTreeValueChooserInsertCombo.superclass._init.apply(this, arguments); + var self = this, o = this.options; + if (BI.isNotNull(o.items)) { + this._initData(o.items); } - return pNode; + this.combo = BI.createWidget({ + type: "bi.multi_tree_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); }, - _deleteNode: function (selectedValues, values) { - var name = values[values.length - 1]; - var p = values.slice(0, values.length - 1); - var pNode = this._getNode(selectedValues, p); - if (pNode != null && pNode[name]) { - delete pNode[name]; - // 递归删掉空父节点 - while (p.length > 0 && BI.isEmpty(pNode)) { - name = p[p.length - 1]; - p = p.slice(0, p.length - 1); - pNode = this._getNode(selectedValues, p); - if (pNode != null) { - delete pNode[name]; - } - } - } + setValue: function (v) { + this.combo.setValue(v); }, - _buildTree: function (jo, values) { - var t = jo; - BI.each(values, function (i, v) { - if (!BI.has(t, v)) { - t[v] = {}; - } - t = t[v]; + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo);/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn }); }, - _isMatch: function (parentValues, value, keyword) { - var node = this._getTreeNode(parentValues, value); - if (!node) { - return false; + _init: function () { + BI.TreeValueChooserInsertCombo.superclass._init.apply(this, arguments); + var self = this, o = this.options; + if (BI.isNotNull(o.items)) { + this._initData(o.items); } - var find = BI.Func.getSearchResult([node.text || node.value], keyword); - return find.find.length > 0 || find.match.length > 0; - }, + this.combo = BI.createWidget({ + type: "bi.multi_tree_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); - _getTreeNode: function (parentValues, v) { - var self = this; - var findParentNode; - var index = 0; - this.tree.traverse(function (node) { - if (self.tree.isRoot(node)) { - return; - } - if (index > parentValues.length) { - return false; - } - if (index === parentValues.length && node.value === v) { - findParentNode = node; - return false; - } - if (node.value === parentValues[index]) { - index++; - return; - } - return true; + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); }); - return findParentNode; }, - _getChildren: function (parentValues) { - if (parentValues.length > 0) { - var value = BI.last(parentValues); - var parent = this._getTreeNode(parentValues.slice(0, parentValues.length - 1), value); - } else { - var parent = this.tree.getRoot(); - } - return parent.getChildren(); + setValue: function (v) { + this.combo.setValue(v); }, - _getChildCount: function (parentValues) { - return this._getChildren(parentValues).length; + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); } -});/** +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. diff --git a/dist/resource.css b/dist/resource.css index cad505e88..fe83a374a 100644 --- a/dist/resource.css +++ b/dist/resource.css @@ -122,8 +122,8 @@ textarea::-webkit-scrollbar-thumb:hover { _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/half_selected.png'); + background: url('images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -168,8 +168,8 @@ textarea::-webkit-scrollbar-thumb:hover { _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/half_selected.png'); + background: url('images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { diff --git a/dist/widget.js b/dist/widget.js index 0b623837d..0a3250a50 100644 --- a/dist/widget.js +++ b/dist/widget.js @@ -12585,7 +12585,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -12627,7 +12630,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { @@ -12952,312 +12955,1169 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut("bi.multi_tree_combo", BI.MultiTreeCombo);/** - * 带加载的多选下拉面板 - * @class BI.MultiTreePopup - * @extends BI.Pane + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single */ -BI.MultiTreePopup = BI.inherit(BI.Pane, { + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, _defaultConfig: function () { - return BI.extend(BI.MultiTreePopup.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-popup", - maxWidth: "auto", - minWidth: 100, - maxHeight: 400, - onLoaded: BI.emptyFn + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 }); }, _init: function () { - BI.MultiTreePopup.superclass._init.apply(this, arguments); + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, o = this.options; - this.selectedValues = {}; + var isInit = false; + var want2showCounter = false; - this.tree = BI.createWidget({ - type: "bi.async_tree", - height: 400, - cls: "popup-view-tree", - itemsCreator: opts.itemsCreator, - onLoaded: opts.onLoaded, - value: opts.value || {} - }); + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} - this.popupView = BI.createWidget({ - type: "bi.multi_popup_view", - element: this, - stopPropagation: false, - maxWidth: opts.maxWidth, - minWidth: opts.minWidth, - maxHeight: opts.maxHeight, - buttons: [BI.i18nText("BI-Basic_Clears"), BI.i18nText("BI-Basic_Sure")], - el: this.tree }); - this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) { - switch (index) { - case 0: - self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CLEAR); - break; - case 1: - self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CONFIRM); - break; + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; } }); - this.tree.on(BI.TreeView.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiTreePopup.EVENT_CHANGE); - }); + var change = false; + var clear = false; // 标识当前是否点击了清空 - this.tree.on(BI.TreeView.EVENT_AFTERINIT, function () { - self.fireEvent(BI.MultiTreePopup.EVENT_AFTERINIT); - }); + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; - }, + var isPopupView = function () { + return self.combo.isViewVisible(); + }; - getValue: function () { - return this.tree.getValue(); - }, + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); - setValue: function (v) { - v || (v = {}); - this.tree.setSelectedValue(v.value); - }, + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } - populate: function (config) { - this.tree.stroke(config); - }, + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); - hasChecked: function () { - return this.tree.hasChecked(); - }, + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); - resetHeight: function (h) { - this.popupView.resetHeight(h); - }, + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); - resetWidth: function (w) { - this.popupView.resetWidth(w); - } -}); + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); -BI.MultiTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; -BI.MultiTreePopup.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; -BI.MultiTreePopup.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; -BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; - - -BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** - * - * 在搜索框中输入文本弹出的面板 - * @class BI.MultiTreeSearchPane - * @extends BI.Pane - */ - -BI.MultiTreeSearchPane = BI.inherit(BI.Pane, { - - _defaultConfig: function () { - return BI.extend(BI.MultiTreeSearchPane.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-search-pane bi-card", - itemsCreator: BI.emptyFn, - keywordGetter: BI.emptyFn - }); - }, - - _init: function () { - BI.MultiTreeSearchPane.superclass._init.apply(this, arguments); - - var self = this, opts = this.options; - - this.partTree = BI.createWidget({ - type: "bi.part_tree", - element: this, - tipText: BI.i18nText("BI-No_Select"), - itemsCreator: function (op, callback) { - op.keyword = opts.keywordGetter(); - opts.itemsCreator(op, callback); - }, - value: opts.value + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" }); - - this.partTree.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } }); - - this.partTree.on(BI.TreeView.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiTreeSearchPane.EVENT_CHANGE); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] }); }, - hasChecked: function () { - return this.partTree.hasChecked(); + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); }, - setValue: function (v) { - this.setSelectedValue(v.value); + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); }, - setSelectedValue: function (v) { - v || (v = {}); - this.partTree.setSelectedValue(v); + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); }, getValue: function () { - return this.partTree.getValue(); - }, - - empty: function () { - this.partTree.empty(); + return this.storeValue.value; }, - populate: function (op) { - this.partTree.stroke.apply(this.partTree, arguments); + populate: function () { + this.combo.populate.apply(this.combo, arguments); } }); -BI.MultiTreeSearchPane.EVENT_CHANGE = "EVENT_CHANGE"; - -BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; -BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; -BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** - * 查看已选按钮 - * Created by guy on 15/11/3. - * @class BI.MultiTreeCheckSelectedButton +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo);/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo * @extends BI.Single */ -BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { - - _defaultConfig: function () { - return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-check-selected-button", - itemsCreator: BI.emptyFn - }); - }, - - _init: function () { - BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); - var self = this; - this.indicator = BI.createWidget({ - type: "bi.icon_button", - cls: "check-font trigger-check-selected icon-size-12", - width: 15, - height: 15, - stopPropagation: true - }); - - this.checkSelected = BI.createWidget({ - type: "bi.text_button", - cls: "trigger-check-selected", - invisible: true, - hgap: 4, - text: BI.i18nText("BI-Check_Selected"), - textAlign: "center", - textHeight: 15 - }); - this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); - }); - - this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { - self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); - }); - BI.createWidget({ - type: "bi.horizontal", - element: this, - items: [this.indicator, this.checkSelected] - }); +BI.MultiTreeListCombo = BI.inherit(BI.Single, { - this.element.hover(function () { - self.indicator.setVisible(false); - self.checkSelected.setVisible(true); - }, function () { - self.indicator.setVisible(true); - self.checkSelected.setVisible(false); - }); - this.setVisible(false); + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } }, - setValue: function (v) { - v || (v = {}); - this.setVisible(BI.size(v.value) > 0); - } -}); - -BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** - * searcher - * Created by guy on 15/11/3. - * @class BI.MultiTreeSearcher - * @extends Widget - */ -BI.MultiTreeSearcher = BI.inherit(BI.Widget, { - _defaultConfig: function () { - return BI.extend(BI.MultiTreeSearcher.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-searcher", + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", itemsCreator: BI.emptyFn, - valueFormatter: function (v) { - return v; - }, - popup: {}, - - adapter: null, - masker: {} + valueFormatter: BI.emptyFn, + height: 24 }); }, _init: function () { - BI.MultiTreeSearcher.superclass._init.apply(this, arguments); + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + var self = this, o = this.options; - this.editor = BI.createWidget({ - type: "bi.multi_select_editor", - height: o.height, - el: { - type: "bi.simple_state_editor", - height: o.height - } - }); - this.searcher = BI.createWidget({ - type: "bi.searcher", - element: this, - isAutoSearch: false, - isAutoSync: false, - onSearch: function (op, callback) { - callback({ - keyword: self.editor.getValue() - }); - }, - el: this.editor, + var isInit = false; + var want2showCounter = false; - popup: BI.extend({ - type: "bi.multi_tree_search_pane", - keywordGetter: function () { - return self.editor.getValue(); - }, - itemsCreator: function (op, callback) { - op.keyword = self.editor.getValue(); - o.itemsCreator(op, callback); + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" }, - value: o.value - }, o.popup), + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} - adapter: o.adapter, - masker: o.masker - }); - this.searcher.on(BI.Searcher.EVENT_START, function () { - self.fireEvent(BI.MultiTreeSearcher.EVENT_START); }); - this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { - if (this.hasMatched()) { - } - self.fireEvent(BI.MultiTreeSearcher.EVENT_PAUSE); - }); - this.searcher.on(BI.Searcher.EVENT_STOP, function () { + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo);/** + * 带加载的多选下拉面板 + * @class BI.MultiTreePopup + * @extends BI.Pane + */ +BI.MultiTreePopup = BI.inherit(BI.Pane, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreePopup.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-popup", + maxWidth: "auto", + minWidth: 100, + maxHeight: 400, + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } + }); + }, + + _init: function () { + BI.MultiTreePopup.superclass._init.apply(this, arguments); + + var self = this, opts = this.options, v = opts.value; + + this.selectedValues = {}; + + this.tree = BI.createWidget(opts.el, { + type: "bi.async_tree", + height: 400, + cls: "popup-view-tree", + itemsCreator: opts.itemsCreator, + onLoaded: opts.onLoaded, + value: v.value || {} + }); + + this.popupView = BI.createWidget({ + type: "bi.multi_popup_view", + element: this, + stopPropagation: false, + maxWidth: opts.maxWidth, + minWidth: opts.minWidth, + maxHeight: opts.maxHeight, + buttons: [BI.i18nText("BI-Basic_Clears"), BI.i18nText("BI-Basic_Sure")], + el: this.tree + }); + + this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) { + switch (index) { + case 0: + self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CLEAR); + break; + case 1: + self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CONFIRM); + break; + } + }); + + this.tree.on(BI.TreeView.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiTreePopup.EVENT_CHANGE); + }); + + this.tree.on(BI.TreeView.EVENT_AFTERINIT, function () { + self.fireEvent(BI.MultiTreePopup.EVENT_AFTERINIT); + }); + + }, + + getValue: function () { + return this.tree.getValue(); + }, + + setValue: function (v) { + v || (v = {}); + this.tree.setSelectedValue(v.value); + }, + + populate: function (config) { + this.tree.stroke(config); + }, + + hasChecked: function () { + return this.tree.hasChecked(); + }, + + resetHeight: function (h) { + this.popupView.resetHeight(h); + }, + + resetWidth: function (w) { + this.popupView.resetWidth(w); + } +}); + +BI.MultiTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiTreePopup.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreePopup.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; + + +BI.shortcut("bi.multi_tree_popup_view", BI.MultiTreePopup);/** + * 查看已选按钮 + * Created by guy on 15/11/3. + * @class BI.MultiTreeCheckSelectedButton + * @extends BI.Single + */ +BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-check-selected-button", + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); + var self = this; + this.indicator = BI.createWidget({ + type: "bi.icon_button", + cls: "check-font trigger-check-selected icon-size-12", + width: 15, + height: 15, + stopPropagation: true + }); + + this.checkSelected = BI.createWidget({ + type: "bi.text_button", + cls: "trigger-check-selected", + invisible: true, + hgap: 4, + text: BI.i18nText("BI-Check_Selected"), + textAlign: "center", + textHeight: 15 + }); + this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); + }); + + BI.createWidget({ + type: "bi.horizontal", + element: this, + items: [this.indicator, this.checkSelected] + }); + + this.element.hover(function () { + self.indicator.setVisible(false); + self.checkSelected.setVisible(true); + }, function () { + self.indicator.setVisible(true); + self.checkSelected.setVisible(false); + }); + this.setVisible(false); + }, + + setValue: function (v) { + v || (v = {}); + this.setVisible(BI.size(v.value) > 0); + } +}); + +BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.multi_tree_check_selected_button", BI.MultiTreeCheckSelectedButton);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane);/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchPane = BI.inherit(BI.Pane, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeSearchPane.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-search-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn + }); + }, + + _init: function () { + BI.MultiTreeSearchPane.superclass._init.apply(this, arguments); + + var self = this, opts = this.options; + + this.partTree = BI.createWidget({ + type: "bi.part_tree", + element: this, + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, callback); + }, + value: opts.value + }); + + this.partTree.on(BI.Controller.EVENT_CHANGE, function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + }); + + this.partTree.on(BI.TreeView.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiTreeSearchPane.EVENT_CHANGE); + }); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; + +BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** + * searcher + * Created by guy on 15/11/3. + * @class BI.MultiListTreeSearcher + * @extends Widget + */ +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { + + _defaultConfig: function () { + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} + }); + }, + + _init: function () { + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } + }); + + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker + }); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); + }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { + + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); + }); + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); + }); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); + }); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } + }, + + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); + } +}); + +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher);/** + * searcher + * Created by guy on 15/11/3. + * @class BI.MultiTreeSearcher + * @extends Widget + */ +BI.MultiTreeSearcher = BI.inherit(BI.Widget, { + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} + }); + }, + + _init: function () { + BI.MultiTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } + }); + + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker + }); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiTreeSearcher.EVENT_START); + }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { + + } + self.fireEvent(BI.MultiTreeSearcher.EVENT_PAUSE); + }); + this.searcher.on(BI.Searcher.EVENT_STOP, function () { self.fireEvent(BI.MultiTreeSearcher.EVENT_STOP); }); this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { @@ -23064,10 +23924,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -23210,115 +24079,519 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { }); } - function search(parents, current, result, searched) { - var newParents = BI.clone(parents); - newParents.push(current); - if (self._isMatch(parents, current, keyword)) { - searched && searched.push(newParents); - return true; + function search(parents, current, result, searched) { + var newParents = BI.clone(parents); + newParents.push(current); + if (self._isMatch(parents, current, keyword)) { + searched && searched.push(newParents); + return true; + } + + var children = self._getChildren(newParents); + + var notSearch = []; + var can = false; + + BI.each(children, function (i, child) { + if (search(newParents, child.value, result, searched)) { + 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 isSearchValueInParent(parentValues) { + for (var i = 0, len = parentValues.length; i < len; i++) { + if (self._isMatch(parentValues.slice(0, i), parentValues[i], keyword)) { + return true; + } + } + return false; + } + + function canFindKey(selectedValues, parents) { + var t = selectedValues; + for (var i = 0; i < parents.length; i++) { + var v = parents[i]; + t = t[v]; + if (t == null) { + return false; + } + } + return true; + } + + function isChild(selectedValues, parents) { + var t = selectedValues; + for (var i = 0; i < parents.length; i++) { + var v = parents[i]; + if (!BI.has(t, v)) { + return false; + } + t = t[v]; + if (BI.isEmpty(t)) { + return true; + } + } + return false; + } + }, + + _reqAdjustTreeNode: function (op, callback) { + var self = this; + var result = []; + var selectedValues = op.selectedValues; + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + BI.each(selectedValues, function (k, v) { + result.push([k]); + }); + + dealWithSelectedValues(selectedValues, []); + + 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 selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, isAllSelect, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isAllSelect || isSelected(parentValues, current); + createOneJson(parentValues, current, false, checked, !isAllSelect && isHalf(parentValues, current), true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + var isCurAllSelected = isAllSelect || isAllSelected(parentValues, 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(parentValues, current) && checked); + createOneJson(parentValues, current, true, checked, false, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, half, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: half, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + if (find == null) { + return false; + } + return BI.any(find, function (v) { + if (v === value) { + return true; + } + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; } + BI.every(parentValues, function (i, v) { + find = find[v]; + if (find == null) { + return false; + } + return true; + }); + return find; + } + }, - var children = self._getChildren(newParents); + _reqTreeNode: function (op, callback) { + var self = this; + var result = []; + var times = op.times; + var checkState = op.checkState || {}; + var parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || {}; + var valueMap = {}; + // if (judgeState(parentValues, selectedValues, checkState)) { + valueMap = dealWidthSelectedValue(parentValues, selectedValues); + // } + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var state = getCheckState(nodes[i].value, parentValues, valueMap, checkState); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: state[0], + halfCheck: state[1] + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); - var notSearch = []; - var can = false; + function judgeState(parentValues, selected_value, checkState) { + var checked = checkState.checked, half = checkState.half; + if (parentValues.length > 0 && !checked) { + return false; + } + return (parentValues.length === 0 || (checked && half) && !BI.isEmpty(selected_value)); + } - BI.each(children, function (i, child) { - if (search(newParents, child.value, result, searched)) { - can = true; - } else { - notSearch.push(child.value); - } + function dealWidthSelectedValue(parentValues, selectedValues) { + var valueMap = {}; + BI.each(parentValues, function (i, v) { + selectedValues = selectedValues[v] || {}; }); - if (can === true) { - BI.each(notSearch, function (i, v) { - var next = BI.clone(newParents); - next.push(v); - result.push(next); + BI.each(selectedValues, 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; + } }); - } - return can; + valueMap[value] = [1, BI.size(nextNames)]; + }); + return valueMap; } - function isSearchValueInParent(parentValues) { - for (var i = 0, len = parentValues.length; i < len; i++) { - if (self._isMatch(parentValues.slice(0, i), parentValues[i], keyword)) { - return true; + function getCheckState(current, parentValues, valueMap, checkState) { + var checked = checkState.checked, half = checkState.half; + var tempCheck = false, halfCheck = false; + if (BI.has(valueMap, current)) { + // 可能是半选 + if (valueMap[current][0] === 1) { + var values = BI.clone(parentValues); + values.push(current); + var childCount = self._getChildCount(values); + if (childCount > 0 && childCount !== valueMap[current][1]) { + halfCheck = true; + } + } else if (valueMap[current][0] === 2) { + tempCheck = true; } } - return false; + var check; + if (!checked && !halfCheck && !tempCheck) { + check = BI.has(valueMap, current); + } else { + check = ((tempCheck || checked) && !half) || BI.has(valueMap, current); + } + return [check, halfCheck]; } + }, - function canFindKey(selectedValues, parents) { - var t = selectedValues; - for (var i = 0; i < parents.length; i++) { - var v = parents[i]; - t = t[v]; - if (t == null) { - return false; - } + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + + _getNode: function (selectedValues, parentValues) { + var pNode = selectedValues; + for (var i = 0, len = parentValues.length; i < len; i++) { + if (pNode == null) { + return null; } - return true; + pNode = pNode[parentValues[i]]; } + return pNode; + }, - function isChild(selectedValues, parents) { - var t = selectedValues; - for (var i = 0; i < parents.length; i++) { - var v = parents[i]; - if (!BI.has(t, v)) { - return false; - } - t = t[v]; - if (BI.isEmpty(t)) { - return true; + _deleteNode: function (selectedValues, values) { + var name = values[values.length - 1]; + var p = values.slice(0, values.length - 1); + var pNode = this._getNode(selectedValues, p); + if (pNode != null && pNode[name]) { + delete pNode[name]; + // 递归删掉空父节点 + while (p.length > 0 && BI.isEmpty(pNode)) { + name = p[p.length - 1]; + p = p.slice(0, p.length - 1); + pNode = this._getNode(selectedValues, p); + if (pNode != null) { + delete pNode[name]; } } + } + }, + + _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 (parentValues, value, keyword) { + var node = this._getTreeNode(parentValues, value); + if (!node) { return false; } + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; }, - _reqAdjustTreeNode: function (op, callback) { + _getTreeNode: function (parentValues, v) { var self = this; - var result = []; - var selectedValues = op.selectedValues; - if (selectedValues == null || BI.isEmpty(selectedValues)) { - callback({}); - return; - } - BI.each(selectedValues, function (k, v) { - result.push([k]); + var findParentNode; + var index = 0; + this.tree.traverse(function (node) { + if (self.tree.isRoot(node)) { + return; + } + if (index > parentValues.length) { + return false; + } + if (index === parentValues.length && node.value === v) { + findParentNode = node; + return false; + } + if (node.value === parentValues[index]) { + index++; + return; + } + return true; }); + return findParentNode; + }, - dealWithSelectedValues(selectedValues, []); + _getChildren: function (parentValues) { + if (parentValues.length > 0) { + var value = BI.last(parentValues); + var parent = this._getTreeNode(parentValues.slice(0, parentValues.length - 1), value); + } else { + var parent = this.tree.getRoot(); + } + return parent.getChildren(); + }, - var jo = {}; - BI.each(result, function (i, strs) { - self._buildTree(jo, strs); - }); - callback(jo); + _getChildCount: function (parentValues) { + return this._getChildren(parentValues).length; + } +});BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { - 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; - } + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); }); - return can && isAllSelected(selected, parents); } - function isAllSelected(selected, parents) { - return BI.isEmpty(selected) || self._getChildCount(parents) === BI.size(selected); + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; } }, @@ -23327,7 +24600,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -23353,9 +24626,9 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { 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); + var find = nodeSearch(1, [], children[i].value, result); } else if (output.length === self._const.perPage) { - var find = nodeSearch(1, [], children[i].value, false, []); + var find = nodeSearch(1, [], children[i].value, []); } if (find[0] === true) { output.push(children[i].value); @@ -23364,13 +24637,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } - function nodeSearch(deep, parentValues, current, isAllSelect, result) { + function nodeSearch(deep, parentValues, current, result) { if (self._isMatch(parentValues, current, keyword)) { - var checked = isAllSelect || isSelected(parentValues, current); - createOneJson(parentValues, current, false, checked, !isAllSelect && isHalf(parentValues, current), true, result); + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); return [true, checked]; } var newParents = BI.clone(parentValues); @@ -23379,9 +24661,8 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var can = false, checked = false; - var isCurAllSelected = isAllSelect || isAllSelected(parentValues, current); BI.each(children, function (i, child) { - var state = nodeSearch(deep + 1, newParents, child.value, isCurAllSelected, result); + var state = nodeSearch(deep + 1, newParents, child.value, result); if (state[1] === true) { checked = true; } @@ -23390,13 +24671,13 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }); if (can === true) { - checked = isCurAllSelected || (isSelected(parentValues, current) && checked); - createOneJson(parentValues, current, true, checked, false, false, result); + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); } return [can, checked]; } - function createOneJson(parentValues, value, isOpen, checked, half, flag, result) { + function createOneJson(parentValues, value, isOpen, checked, flag, result) { var node = self._getTreeNode(parentValues, value); result.push({ id: node.id, @@ -23407,7 +24688,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { isParent: node.getChildrenLength() > 0, open: isOpen, checked: checked, - halfCheck: half, + halfCheck: false, flag: flag }); } @@ -23440,15 +24721,9 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { }); } - function isSelected(parentValues, value) { - var find = findSelectedObj(parentValues); - if (find == null) { - return false; - } - return BI.any(find, function (v) { - if (v === value) { - return true; - } + function isSelected(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; }); } @@ -23472,16 +24747,12 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var self = this; var result = []; var times = op.times; - var checkState = op.checkState || {}; var parentValues = op.parentValues || []; - var selectedValues = op.selectedValues || {}; - var valueMap = {}; - // if (judgeState(parentValues, selectedValues, checkState)) { - valueMap = dealWidthSelectedValue(parentValues, selectedValues); - // } + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); var nodes = this._getChildren(parentValues); for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { - var state = getCheckState(nodes[i].value, parentValues, valueMap, checkState); + var checked = BI.has(valueMap, nodes[i].value); result.push({ id: nodes[i].id, pId: nodes[i].pId, @@ -23489,10 +24760,14 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { text: nodes[i].text, times: 1, isParent: nodes[i].getChildrenLength() > 0, - checked: state[0], - halfCheck: state[1] + checked: checked, + halfCheck: false }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -23500,151 +24775,140 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { }); }); - function judgeState(parentValues, selected_value, checkState) { - var checked = checkState.checked, half = checkState.half; - if (parentValues.length > 0 && !checked) { - return false; - } - return (parentValues.length === 0 || (checked && half) && !BI.isEmpty(selected_value)); - } - - function dealWidthSelectedValue(parentValues, selectedValues) { + function dealWidthSelectedValue(selectedValues) { var valueMap = {}; - BI.each(parentValues, function (i, v) { - selectedValues = selectedValues[v] || {}; - }); - BI.each(selectedValues, 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)]; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; }); return valueMap; } + }, - function getCheckState(current, parentValues, valueMap, checkState) { - var checked = checkState.checked, half = checkState.half; - var tempCheck = false, halfCheck = false; - if (BI.has(valueMap, current)) { - // 可能是半选 - if (valueMap[current][0] === 1) { - var values = BI.clone(parentValues); - values.push(current); - var childCount = self._getChildCount(values); - if (childCount > 0 && childCount !== 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]; - } + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } +});/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); }, - _getNode: function (selectedValues, parentValues) { - var pNode = selectedValues; - for (var i = 0, len = parentValues.length; i < len; i++) { - if (pNode == null) { - return null; - } - pNode = pNode[parentValues[i]]; + _init: function () { + BI.ListTreeValueChooserInsertCombo.superclass._init.apply(this, arguments); + var self = this, o = this.options; + if (BI.isNotNull(o.items)) { + this._initData(o.items); } - return pNode; + this.combo = BI.createWidget({ + type: "bi.multi_tree_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); }, - _deleteNode: function (selectedValues, values) { - var name = values[values.length - 1]; - var p = values.slice(0, values.length - 1); - var pNode = this._getNode(selectedValues, p); - if (pNode != null && pNode[name]) { - delete pNode[name]; - // 递归删掉空父节点 - while (p.length > 0 && BI.isEmpty(pNode)) { - name = p[p.length - 1]; - p = p.slice(0, p.length - 1); - pNode = this._getNode(selectedValues, p); - if (pNode != null) { - delete pNode[name]; - } - } - } + setValue: function (v) { + this.combo.setValue(v); }, - _buildTree: function (jo, values) { - var t = jo; - BI.each(values, function (i, v) { - if (!BI.has(t, v)) { - t[v] = {}; - } - t = t[v]; + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo);/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn }); }, - _isMatch: function (parentValues, value, keyword) { - var node = this._getTreeNode(parentValues, value); - if (!node) { - return false; + _init: function () { + BI.TreeValueChooserInsertCombo.superclass._init.apply(this, arguments); + var self = this, o = this.options; + if (BI.isNotNull(o.items)) { + this._initData(o.items); } - var find = BI.Func.getSearchResult([node.text || node.value], keyword); - return find.find.length > 0 || find.match.length > 0; - }, + this.combo = BI.createWidget({ + type: "bi.multi_tree_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); - _getTreeNode: function (parentValues, v) { - var self = this; - var findParentNode; - var index = 0; - this.tree.traverse(function (node) { - if (self.tree.isRoot(node)) { - return; - } - if (index > parentValues.length) { - return false; - } - if (index === parentValues.length && node.value === v) { - findParentNode = node; - return false; - } - if (node.value === parentValues[index]) { - index++; - return; - } - return true; + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); }); - return findParentNode; }, - _getChildren: function (parentValues) { - if (parentValues.length > 0) { - var value = BI.last(parentValues); - var parent = this._getTreeNode(parentValues.slice(0, parentValues.length - 1), value); - } else { - var parent = this.tree.getRoot(); - } - return parent.getChildren(); + setValue: function (v) { + this.combo.setValue(v); }, - _getChildCount: function (parentValues) { - return this._getChildren(parentValues).length; + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); } -});/** +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. diff --git a/public/css/background.css b/public/css/background.css index 06d0a8e7f..4a8e7653f 100644 --- a/public/css/background.css +++ b/public/css/background.css @@ -51,8 +51,8 @@ _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/half_selected.png'); + background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -97,8 +97,8 @@ _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/half_selected.png'); + background: url('http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://fine-design-storage.oss-cn-shanghai.aliyuncs.com/fineui/2.0/images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { diff --git a/src/base/tree/ztree/asynctree.js b/src/base/tree/ztree/asynctree.js index 23eb2123a..2273209d9 100644 --- a/src/base/tree/ztree/asynctree.js +++ b/src/base/tree/ztree/asynctree.js @@ -18,7 +18,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { var self = this; var setting = { async: { - enable: false, + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 otherParam: BI.cjkEncodeDO(paras) }, check: { @@ -108,6 +108,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { return setting; }, + // 用来更新this.options.paras.selectedValues, 和ztree内部无关 _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); @@ -153,7 +154,7 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { function callback (nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); - + // 展开节点是没有分页的 if (hasNext === true) { BI.delay(function () { times++; @@ -170,6 +171,9 @@ BI.AsyncTree = BI.inherit(BI.TreeView, { } }, + // a,b 两棵树 + // a->b b->a 做两次校验, 构造一个校验后的map + // e.g. 以a为基准,如果b没有此节点,则在map中添加。 如b有,且是全选的, 则在map中构造全选(为什么不添加a的值呢? 因为这次是取并集), 如果b中也有和a一样的存值,就递归 _join: function (valueA, valueB) { var self = this; var map = {}; diff --git a/src/base/tree/ztree/jquery.ztree.excheck-3.5.js b/src/base/tree/ztree/jquery.ztree.excheck-3.5.js index 1a2774bca..fb0a5b8e8 100644 --- a/src/base/tree/ztree/jquery.ztree.excheck-3.5.js +++ b/src/base/tree/ztree/jquery.ztree.excheck-3.5.js @@ -425,6 +425,8 @@ makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, + checkboxType = setting.check.chkboxType; + var notEffectByOtherNode = (checkboxType.Y === "" && checkboxType.N === ""); fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; @@ -433,7 +435,7 @@ } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { - fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); + fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) || notEffectByOtherNode ? c.FULL:c.PART) : ((node.check_Child_State < 1 || notEffectByOtherNode)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; diff --git a/src/base/tree/ztree/list/listasynctree.js b/src/base/tree/ztree/list/listasynctree.js new file mode 100644 index 000000000..a15c73993 --- /dev/null +++ b/src/base/tree/ztree/list/listasynctree.js @@ -0,0 +1,123 @@ +/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为["A", ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListListAsyncTree + * @extends BI.TreeView + */ +BI.ListAsyncTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListAsyncTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListAsyncTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false, // 很明显这棵树把异步请求关掉了,所有的异步请求都是手动控制的 + otherParam: BI.cjkEncodeDO(paras) + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + beforeExpand: beforeExpand, + beforeCheck: beforeCheck, + onClick: onClick + } + }; + + function beforeCheck (treeId, treeNode) { + treeNode.half = false; + } + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function beforeExpand (treeId, treeNode) { + self._beforeExpandNode(treeId, treeNode); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + // 展开节点 + _beforeExpandNode: function (treeId, treeNode) { + var self = this, o = this.options; + var parentValues = treeNode.parentValues || self._getParentValues(treeNode); + var op = BI.extend({}, o.paras, { + id: treeNode.id, + times: 1, + parentValues: parentValues.concat(this._getNodeValue(treeNode)) + }); + var complete = function (d) { + var nodes = d.items || []; + if (nodes.length > 0) { + callback(self._dealWidthNodes(nodes), !!d.hasNext); + } + }; + var times = 1; + + function callback (nodes, hasNext) { + self.nodes.addNodes(treeNode, nodes); + // 展开节点是没有分页的 + if (hasNext === true) { + BI.delay(function () { + times++; + op.times = times; + o.itemsCreator(op, complete); + }, 100); + } + } + + if (!treeNode.children) { + setTimeout(function () { + o.itemsCreator(op, complete); + }, 17); + } + }, + + hasChecked: function () { + return !BI.isEmpty(this.options.paras.selectedValues) || BI.ListAsyncTree.superclass.hasChecked.apply(this, arguments); + }, + + // 生成树方法 + stroke: function (config) { + delete this.options.keyword; + BI.extend(this.options.paras, config); + var setting = this._configSetting(); + this._initTree(setting); + } +}); + +BI.shortcut("bi.list_async_tree", BI.ListAsyncTree); \ No newline at end of file diff --git a/src/base/tree/ztree/list/listparttree.js b/src/base/tree/ztree/list/listparttree.js new file mode 100644 index 000000000..8a1fda13b --- /dev/null +++ b/src/base/tree/ztree/list/listparttree.js @@ -0,0 +1,92 @@ +/** + * guy + * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 + * @class BI.ListPartTree + * @extends BI.AsyncTree + */ +BI.ListPartTree = BI.inherit(BI.ListAsyncTree, { + _defaultConfig: function () { + return BI.extend(BI.ListPartTree.superclass._defaultConfig.apply(this, arguments), {}); + }, + + _init: function () { + BI.ListPartTree.superclass._init.apply(this, arguments); + }, + + _loadMore: function () { + var self = this, o = this.options; + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: ++this.times + }); + this.tip.setLoading(); + o.itemsCreator(op, function (d) { + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + if (self._stop === true) { + return; + } + if (!hasNext) { + self.tip.setEnd(); + } else { + self.tip.setLoaded(); + } + if (nodes.length > 0) { + self.nodes.addNodes(null, self._dealWidthNodes(nodes)); + } + }); + }, + + _initTree: function (setting, keyword) { + var self = this, o = this.options; + this.times = 1; + var tree = this.tree; + tree.empty(); + self.tip.setVisible(false); + this.loading(); + var op = BI.extend({}, o.paras, { + type: BI.TreeView.REQ_TYPE_INIT_DATA, + times: this.times + }); + var complete = function (d) { + if (self._stop === true || keyword != o.paras.keyword) { + return; + } + var hasNext = !!d.hasNext, nodes = d.items || []; + o.paras.lastSearchValue = d.lastSearchValue; + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); + self.setTipVisible(nodes.length <= 0); + self.loaded(); + if (!hasNext) { + self.tip.invisible(); + } else { + self.tip.setLoaded(); + } + self.fireEvent(BI.Events.AFTERINIT); + }; + + function callback (nodes) { + if (self._stop === true) { + return; + } + self.nodes = $.fn.zTree.init(tree.element, setting, nodes); + } + + BI.delay(function () { + o.itemsCreator(op, complete); + }, 100); + }, + + // 生成树方法 + stroke: function (config) { + var o = this.options; + delete o.paras.keyword; + BI.extend(o.paras, config); + delete o.paras.lastSearchValue; + var setting = this._configSetting(); + this._initTree(setting, o.paras.keyword); + } +}); + +BI.shortcut("bi.list_part_tree", BI.ListPartTree); \ No newline at end of file diff --git a/src/base/tree/ztree/list/listtreeview.js b/src/base/tree/ztree/list/listtreeview.js new file mode 100644 index 000000000..854267028 --- /dev/null +++ b/src/base/tree/ztree/list/listtreeview.js @@ -0,0 +1,114 @@ +/** + * author: windy + * 继承自treeView, 此树的父子节点的勾选状态互不影响, 此树不会有半选节点 + * 返回value格式为[["A"], ["A", "a"]]表示勾选了A且勾选了a + * @class BI.ListTreeView + * @extends BI.TreeView + */ +BI.ListTreeView = BI.inherit(BI.TreeView, { + + _constants: { + SPLIT: "<|>" + }, + + _defaultConfig: function () { + return BI.extend(BI.ListTreeView.superclass._defaultConfig.apply(this, arguments), {}); + }, + _init: function () { + BI.ListTreeView.superclass._init.apply(this, arguments); + var o = this.options; + this.storeValue = o.value || {}; + }, + + // 配置属性 + _configSetting: function () { + var paras = this.options.paras; + var self = this; + var setting = { + async: { + enable: false + }, + check: { + enable: true, + chkboxType: {Y: "", N: ""} + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + view: { + showIcon: false, + expandSpeed: "", + nameIsHTML: true, + dblClickExpand: false + }, + callback: { + onCheck: onCheck, + onClick: onClick + } + }; + + function onClick (event, treeId, treeNode) { + var zTree = $.fn.zTree.getZTreeObj(treeId); + var checked = treeNode.checked; + self._checkValue(treeNode, !checked); + zTree.checkNode(treeNode, !checked, true, true); + } + + function onCheck (event, treeId, treeNode) { + self._selectTreeNode(treeId, treeNode); + } + + return setting; + }, + + _selectTreeNode: function (treeId, treeNode) { + this._checkValue(treeNode, treeNode.checked); + BI.ListTreeView.superclass._selectTreeNode.apply(this, arguments); + }, + + _transArrayToMap: function (treeArrays) { + var self = this; + var map = {}; + BI.each(treeArrays, function (idx, array) { + var key = array.join(self._constants.SPLIT); + map[key] = true; + }); + return map; + }, + + _transMapToArray: function (treeMap) { + var self = this; + var array = []; + BI.each(treeMap, function (key) { + var item = key.split(self._constants.SPLIT); + array.push(item); + }); + return array; + }, + + _checkValue: function (treeNode, checked) { + var key = BI.concat(this._getParentValues(treeNode), this._getNodeValue(treeNode)).join(this._constants.SPLIT); + if(checked) { + this.storeValue[key] = true; + } else { + delete this.storeValue[key]; + } + }, + + setSelectedValue: function (value) { + this.options.paras.selectedValues = value || []; + this.storeValue = this._transArrayToMap(value); + }, + + getValue: function () { + return this._transMapToArray(this.storeValue); + } +}); + +BI.shortcut("bi.list_tree_view", BI.ListTreeView); \ No newline at end of file diff --git a/src/base/tree/ztree/parttree.js b/src/base/tree/ztree/parttree.js index 8718b5efa..fbd806d14 100644 --- a/src/base/tree/ztree/parttree.js +++ b/src/base/tree/ztree/parttree.js @@ -42,9 +42,17 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { - BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + this._buildTree(self.options.paras.selectedValues, BI.concat(parentValues, name)); + o.itemsCreator({ + type: BI.TreeView.REQ_TYPE_ADJUST_DATA, + selectedValues: self.options.paras.selectedValues + }, function (res) { + self.options.paras.selectedValues = res; + BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); + }); } else { // 如果选中的值中不存在该值不处理 + // 因为反正是不选中,没必要管 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { @@ -52,6 +60,7 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { if (t == null) { return; } + // 选中中国-江苏, 搜索南京,取消勾选 if (BI.isEmpty(t)) { break; } @@ -115,9 +124,8 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; - if (nodes.length > 0) { - callback(self._dealWidthNodes(nodes)); - } + // 没有请求到数据也要初始化空树, 如果不初始化, 树就是上一次构造的树, 节点信息都是过期的 + callback(nodes.length > 0 ? self._dealWidthNodes(nodes) : []); self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { @@ -143,12 +151,6 @@ BI.PartTree = BI.inherit(BI.AsyncTree, { getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); - o.itemsCreator({ - type: BI.TreeView.REQ_TYPE_ADJUST_DATA, - selectedValues: result - }, function (res) { - result = res; - }); return result; }, diff --git a/src/base/tree/ztree/treeview.js b/src/base/tree/ztree/treeview.js index e7de3bbd5..bd87b215e 100644 --- a/src/base/tree/ztree/treeview.js +++ b/src/base/tree/ztree/treeview.js @@ -71,8 +71,8 @@ BI.TreeView = BI.inherit(BI.Pane, { async: { enable: true, url: getUrl, - autoParam: ["id", "name"], - otherParam: BI.cjkEncodeDO(paras) + autoParam: ["id", "name"], // 节点展开异步请求自动提交id和name + otherParam: BI.cjkEncodeDO(paras) // 静态参数 }, check: { enable: true @@ -80,16 +80,16 @@ BI.TreeView = BI.inherit(BI.Pane, { data: { key: { title: "title", - name: "text" + name: "text" // 节点的name属性替换成text }, simpleData: { - enable: true + enable: true // 可以穿id,pid属性的对象数组 } }, view: { showIcon: false, expandSpeed: "", - nameIsHTML: true, + nameIsHTML: true, // 节点可以用html标签代替 dblClickExpand: false }, callback: { @@ -112,6 +112,7 @@ BI.TreeView = BI.inherit(BI.Pane, { if(status.half === true && status.checked === true) { checked = false; } + // 更新此node的check状态, 影响父子关联,并调用beforeCheck和onCheck回调 self.nodes.checkNode(treeNode, !checked, true, true); } @@ -134,7 +135,7 @@ BI.TreeView = BI.inherit(BI.Pane, { } return true; } - BI.Msg.toast("Please Wait。", "warning"); + BI.Msg.toast("Please Wait。", "warning"); // 不展开节点,也不触发onExpand事件 return false; } @@ -172,9 +173,9 @@ BI.TreeView = BI.inherit(BI.Pane, { function ajaxGetNodes (treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { - zTree.updateNode(treeNode); + zTree.updateNode(treeNode); // 刷新一下当前节点,如果treeNode.xxx被改了的话 } - zTree.reAsyncChildNodes(treeNode, reloadType, true); + zTree.reAsyncChildNodes(treeNode, reloadType, true); // 强制加载子节点,reloadType === refresh为先清空再加载,否则为追加到现有子节点之后 } function beforeCheck (treeId, treeNode) { @@ -252,15 +253,18 @@ BI.TreeView = BI.inherit(BI.Pane, { } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); + // 当前节点是全选的,因为上面的判断已经排除了不选和半选 if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } + // 剩下的就是半选不展开的节点,因为不知道里面是什么情况,所以借助selectedValues(这个是完整的选中情况) var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, + // 获取的是以values最后一个节点为根的子树 _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { @@ -272,6 +276,7 @@ BI.TreeView = BI.inherit(BI.Pane, { return cur; }, + // 以values为path一路向里补充map, 并在末尾节点添加key: value节点 _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { @@ -299,7 +304,7 @@ BI.TreeView = BI.inherit(BI.Pane, { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); - track(rootNoots); + track(rootNoots); // 可以看到这个方法没有递归调用,所以在_getHalfSelectedValues中需要关心全选的节点 function track (nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); diff --git a/src/case/tree/ztree/tree.list.display.js b/src/case/tree/ztree/tree.list.display.js new file mode 100644 index 000000000..3be529e13 --- /dev/null +++ b/src/case/tree/ztree/tree.list.display.js @@ -0,0 +1,81 @@ +/** + * guy + * 异步树 + * @class BI.ListListDisplayTree + * @extends BI.TreeView + */ +BI.ListDisplayTree = BI.inherit(BI.ListTreeView, { + _defaultConfig: function () { + return BI.extend(BI.ListDisplayTree.superclass._defaultConfig.apply(this, arguments), { + extraCls: "bi-list-display-tree" + }); + }, + _init: function () { + BI.ListDisplayTree.superclass._init.apply(this, arguments); + }, + + // 配置属性 + _configSetting: function () { + var setting = { + view: { + selectedMulti: false, + dblClickExpand: false, + showIcon: false, + nameIsHTML: true, + showTitle: false, + fontCss: getFont + }, + data: { + key: { + title: "title", + name: "text" + }, + simpleData: { + enable: true + } + }, + callback: { + beforeCollapse: beforeCollapse + } + }; + + function beforeCollapse(treeId, treeNode) { + return false; + } + + function getFont(treeId, node) { + return node.font ? node.font : {color: "#999999"}; + } + + return setting; + }, + + _dealWidthNodes: function (nodes) { + nodes = BI.ListDisplayTree.superclass._dealWidthNodes.apply(this, arguments); + var self = this, o = this.options; + BI.each(nodes, function (i, node) { + node.isParent = node.isParent || node.parent; + if (node.text == null) { + if (node.count > 0) { + node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; + } + } + if(node.isLeaf === true) { + node.font = {color: "#3d4d66"}; + } + }); + return nodes; + }, + + initTree: function (nodes, setting) { + var setting = setting || this._configSetting(); + this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); + }, + + destroy: function () { + BI.ListDisplayTree.superclass.destroy.apply(this, arguments); + } +}); +BI.ListDisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.shortcut("bi.list_display_tree", BI.ListDisplayTree); \ No newline at end of file diff --git a/src/component/treevaluechooser/abstract.treevaluechooser.js b/src/component/treevaluechooser/abstract.treevaluechooser.js index b0821bda1..5bd5b7875 100644 --- a/src/component/treevaluechooser/abstract.treevaluechooser.js +++ b/src/component/treevaluechooser/abstract.treevaluechooser.js @@ -92,10 +92,19 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); - var newParents = BI.clone(parentValues); - newParents.push(node.value); - createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); - doCheck(newParents, node, selected[k]); + // 找不到就是新增值 + if(BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: k, + value: k + }, BI.UUID(), 0); + } else { + var newParents = BI.clone(parentValues); + newParents.push(node.value); + createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); + doCheck(newParents, node, selected[k]); + } }); } @@ -355,7 +364,7 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; - var lastSearchValue = op.lastSearchValue || ""; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 var output = search(); BI.nextTick(function () { callback({ @@ -392,6 +401,15 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { break; } } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } return output; } @@ -521,6 +539,10 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { halfCheck: state[1] }); } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } BI.nextTick(function () { callback({ items: result, @@ -587,6 +609,22 @@ BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { } }, + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + return BI.map(BI.difference(BI.keys(selectedValues), BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + }, + _getNode: function (selectedValues, parentValues) { var pNode = selectedValues; for (var i = 0, len = parentValues.length; i < len; i++) { diff --git a/src/component/treevaluechooser/abstract.treevaluechooser.list.js b/src/component/treevaluechooser/abstract.treevaluechooser.list.js new file mode 100644 index 000000000..2d43295dd --- /dev/null +++ b/src/component/treevaluechooser/abstract.treevaluechooser.list.js @@ -0,0 +1,261 @@ +BI.AbstractListTreeValueChooser = BI.inherit(BI.AbstractTreeValueChooser, { + + _reqDisplayTreeNode: function (op, callback) { + var self = this; + var result = {}; + var selectedValues = op.selectedValues; + + if (selectedValues == null || BI.isEmpty(selectedValues)) { + callback({}); + return; + } + + doCheck([], this.tree.getRoot(), selectedValues); + + callback({ + items: BI.values(result) + }); + + function doCheck(parentValues, node, selected) { + BI.each(selected, function (idx, path) { + BI.each(path, function (id, value) { + var nodeValue = value; + var node = self._getTreeNode(path.slice(0, id), nodeValue); + // 找不到就是新增值 + if (BI.isNull(node)) { + createOneJson({ + id: BI.UUID(), + text: nodeValue, + value: nodeValue, + isLeaf: true + }, BI.UUID()); + } else { + if(!BI.has(result, node.id)) { + createOneJson(node, node.parent && node.parent.id); + } + result[node.id].isLeaf = id === path.length - 1; + } + }); + }); + } + + function createOneJson(node, pId, leaf) { + result[node.id] = { + id: node.id, + pId: pId, + text: node.text, + value: node.value, + open: true, + isLeaf: leaf + }; + } + }, + + _reqInitTreeNode: function (op, callback) { + var self = this; + var result = []; + var keyword = op.keyword || ""; + var selectedValues = op.selectedValues; + var lastSearchValue = op.lastSearchValue || ""; // 一次请求100个,但是搜索是拿全部的,lastSearchValue是上一次遍历到的节点索引 + var output = search(); + BI.nextTick(function () { + callback({ + hasNext: output.length > self._const.perPage, + items: result, + lastSearchValue: BI.last(output) + }); + }); + + function search() { + var children = self._getChildren([]); + var start = children.length; + if (lastSearchValue !== "") { + for (var j = 0, len = start; j < len; j++) { + if (children[j].value === lastSearchValue) { + 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, result); + } else if (output.length === self._const.perPage) { + var find = nodeSearch(1, [], children[i].value, []); + } + if (find[0] === true) { + output.push(children[i].value); + } + if (output.length > self._const.perPage) { + break; + } + } + + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (op.times === 1) { + var nodes = self._getAddedValueNode([], selectedValues); + result = BI.concat(BI.filter(nodes, function (idx, node) { + var find = BI.Func.getSearchResult([node.text || node.value], keyword); + return find.find.length > 0 || find.match.length > 0; + }), result); + } + return output; + } + + function nodeSearch(deep, parentValues, current, result) { + if (self._isMatch(parentValues, current, keyword)) { + var checked = isSelected(current); + createOneJson(parentValues, current, false, checked, true, result); + return [true, checked]; + } + var newParents = BI.clone(parentValues); + newParents.push(current); + var children = self._getChildren(newParents); + + var can = false, checked = false; + + BI.each(children, function (i, child) { + var state = nodeSearch(deep + 1, newParents, child.value, result); + if (state[1] === true) { + checked = true; + } + if (state[0] === true) { + can = true; + } + }); + if (can === true) { + checked = isSelected(current); + createOneJson(parentValues, current, true, checked, false, result); + } + return [can, checked]; + } + + function createOneJson(parentValues, value, isOpen, checked, flag, result) { + var node = self._getTreeNode(parentValues, value); + result.push({ + id: node.id, + pId: node.pId, + text: node.text, + value: node.value, + title: node.title, + isParent: node.getChildrenLength() > 0, + open: isOpen, + checked: checked, + halfCheck: false, + flag: flag + }); + } + + function isHalf(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(parentValues, value) { + var find = findSelectedObj(parentValues); + 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(value) { + return BI.any(selectedValues, function (idx, array) { + return BI.last(array) === value; + }); + } + + function findSelectedObj(parentValues) { + var find = selectedValues; + if (find == null) { + return null; + } + BI.every(parentValues, 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 parentValues = op.parentValues || []; + var selectedValues = op.selectedValues || []; + var valueMap = dealWidthSelectedValue(selectedValues); + var nodes = this._getChildren(parentValues); + for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { + var checked = BI.has(valueMap, nodes[i].value); + result.push({ + id: nodes[i].id, + pId: nodes[i].pId, + value: nodes[i].value, + text: nodes[i].text, + times: 1, + isParent: nodes[i].getChildrenLength() > 0, + checked: checked, + halfCheck: false + }); + } + // 深层嵌套的比较麻烦,这边先实现的是在根节点添加 + if (parentValues.length === 0 && times === 1) { + result = BI.concat(self._getAddedValueNode(parentValues, selectedValues), result); + } + BI.nextTick(function () { + callback({ + items: result, + hasNext: nodes.length > times * self._const.perPage + }); + }); + + function dealWidthSelectedValue(selectedValues) { + var valueMap = {}; + BI.each(selectedValues, function (idx, v) { + valueMap[BI.last(v)] = [2, 0]; + }); + return valueMap; + } + }, + + _getAddedValueNode: function (parentValues, selectedValues) { + var nodes = this._getChildren(parentValues); + var values = BI.flatten(BI.filter(selectedValues, function (idx, array) { + return array.length === 1; + })); + return BI.map(BI.difference(values, BI.map(nodes, "value")), function (idx, v) { + return { + id: BI.UUID(), + pId: nodes.length > 0 ? nodes[0].pId : BI.UUID(), + value: v, + text: v, + times: 1, + isParent: false, + checked: true, + halfCheck: false + }; + }); + } +}); \ No newline at end of file diff --git a/src/component/treevaluechooser/combo.listtreevaluechooser.js b/src/component/treevaluechooser/combo.listtreevaluechooser.js new file mode 100644 index 000000000..0a1d327e4 --- /dev/null +++ b/src/component/treevaluechooser/combo.listtreevaluechooser.js @@ -0,0 +1,54 @@ +/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.ListTreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.ListTreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-list-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.ListTreeValueChooserInsertCombo.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_list_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.ListTreeValueChooserInsertCombo.EVENT_CONFIRM = "ListTreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.list_tree_value_chooser_insert_combo", BI.ListTreeValueChooserInsertCombo); \ No newline at end of file diff --git a/src/component/treevaluechooser/combo.treevaluechooser.insert.js b/src/component/treevaluechooser/combo.treevaluechooser.insert.js new file mode 100644 index 000000000..530c13f54 --- /dev/null +++ b/src/component/treevaluechooser/combo.treevaluechooser.insert.js @@ -0,0 +1,54 @@ +/** + * 简单的复选下拉树控件, 适用于数据量少的情况, 可以自增值 + * + * Created by GUY on 2015/10/29. + * @class BI.TreeValueChooserInsertCombo + * @extends BI.Widget + */ +BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { + + _defaultConfig: function () { + return BI.extend(BI.TreeValueChooserInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-value-chooser-insert-combo", + width: 200, + height: 24, + items: null, + itemsCreator: BI.emptyFn + }); + }, + + _init: function () { + BI.TreeValueChooserInsertCombo.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_insert_combo", + element: this, + itemsCreator: BI.bind(this._itemsCreator, this), + valueFormatter: BI.bind(this._valueFormatter, this), + width: o.width, + height: o.height + }); + + this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { + self.fireEvent(BI.TreeValueChooserInsertCombo.EVENT_CONFIRM); + }); + }, + + setValue: function (v) { + this.combo.setValue(v); + }, + + getValue: function () { + return this.combo.getValue(); + }, + + populate: function (items) { + this._initData(items); + this.combo.populate.apply(this.combo, arguments); + } +}); +BI.TreeValueChooserInsertCombo.EVENT_CONFIRM = "TreeValueChooserInsertCombo.EVENT_CONFIRM"; +BI.shortcut("bi.tree_value_chooser_insert_combo", BI.TreeValueChooserInsertCombo); \ No newline at end of file diff --git a/src/css/base/colorchooser/colorpicker/editor.css b/src/css/base/colorchooser/colorpicker/editor.css index 1d04d58c3..493b54450 100644 --- a/src/css/base/colorchooser/colorpicker/editor.css +++ b/src/css/base/colorchooser/colorpicker/editor.css @@ -51,8 +51,8 @@ _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/half_selected.png'); + background: url('images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -97,8 +97,8 @@ _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/half_selected.png'); + background: url('images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { diff --git a/src/css/base/tree/tree.css b/src/css/base/tree/tree.css index 9ae37a8a1..4ba2ec450 100644 --- a/src/css/base/tree/tree.css +++ b/src/css/base/tree/tree.css @@ -19,3 +19,18 @@ opacity: 1; filter: alpha(opacity=100); } + +.bi-list-display-tree .ztree li a, +.bi-list-display-tree .ztree li span { + cursor: default !important; +} +.bi-list-display-tree .ztree li a:hover { + text-decoration: none; +} +.bi-list-display-tree .ztree li a.curSelectedNode { + padding-top: 1px; + border: none; + background-color: inherit; + opacity: 1; + filter: alpha(opacity=100); +} diff --git a/src/css/resource/background.css b/src/css/resource/background.css index 128ccf2ab..788094caa 100644 --- a/src/css/resource/background.css +++ b/src/css/resource/background.css @@ -51,8 +51,8 @@ _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/half_selected.png'); + background: url('images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -97,8 +97,8 @@ _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/half_selected.png'); + background: url('images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus { diff --git a/src/less/base/tree/tree.list.display.less b/src/less/base/tree/tree.list.display.less new file mode 100644 index 000000000..e58d3a5dd --- /dev/null +++ b/src/less/base/tree/tree.list.display.less @@ -0,0 +1,17 @@ +@import "../../index"; + +.bi-list-display-tree{ + + & .ztree li a, & .ztree li span{ + cursor: default !important; + } + & .ztree li a:hover{ + text-decoration: none; + } + & .ztree li a.curSelectedNode{ + padding-top: 1px; + border: none; + background-color: inherit; + .opacity(1); + } +} \ No newline at end of file diff --git a/src/less/resource/background.less b/src/less/resource/background.less index c6036b3ff..e1eb69d35 100644 --- a/src/less/resource/background.less +++ b/src/less/resource/background.less @@ -47,7 +47,7 @@ } .ztree li span.button.chk.checkbox_false_part { - .image2xPath(@icon-half-select); + .image2xPath(@icon-checkbox-normal); } .ztree li span.button.chk.checkbox_false_part_focus { @@ -79,7 +79,7 @@ } .ztree.hack li span.button.chk.checkbox_false_part { - .imagePath(@icon-half-select); + .imagePath(@icon-checkbox-normal); } .ztree.hack li span.button.chk.checkbox_false_part_focus { diff --git a/src/widget/multitree/check/multi.tree.check.pane.js b/src/widget/multitree/check/multi.tree.check.pane.js index b33b77daf..b73f8d1ec 100644 --- a/src/widget/multitree/check/multi.tree.check.pane.js +++ b/src/widget/multitree/check/multi.tree.check.pane.js @@ -14,7 +14,10 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", - onClickContinueSelect: BI.emptyFn + onClickContinueSelect: BI.emptyFn, + el: { + type: "bi.display_tree" + } }); }, @@ -56,7 +59,7 @@ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { }] }); - this.display = BI.createWidget({ + this.display = BI.createWidget(opts.el, { type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { diff --git a/src/widget/multitree/multi.tree.insert.combo.js b/src/widget/multitree/multi.tree.insert.combo.js new file mode 100644 index 000000000..6133cf92f --- /dev/null +++ b/src/widget/multitree/multi.tree.insert.combo.js @@ -0,0 +1,286 @@ +/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeInsertCombo + * @extends BI.Single + */ + +BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeInsertCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-insert-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeInsertCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || {}}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value[self.trigger.getSearcher().getKeyword()] = {}; + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : {} + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: {}}; + } + self.fireEvent(BI.MultiTreeInsertCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || {}; + this.combo.setValue({ + value: v || {} + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeInsertCombo.EVENT_CONFIRM = "MultiTreeInsertCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_insert_combo", BI.MultiTreeInsertCombo); \ No newline at end of file diff --git a/src/widget/multitree/multi.tree.list.combo.js b/src/widget/multitree/multi.tree.list.combo.js new file mode 100644 index 000000000..8d7f2e9f0 --- /dev/null +++ b/src/widget/multitree/multi.tree.list.combo.js @@ -0,0 +1,295 @@ +/** + * 可以往当前选中节点下添加新值的下拉树 + * @class BI.MultiTreeListCombo + * @extends BI.Single + */ + +BI.MultiTreeListCombo = BI.inherit(BI.Single, { + + constants: { + offset: { + top: 0, + left: 0, + right: 0, + bottom: 25 + } + }, + + _defaultConfig: function () { + return BI.extend(BI.MultiTreeListCombo.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-list-combo", + itemsCreator: BI.emptyFn, + valueFormatter: BI.emptyFn, + height: 24 + }); + }, + + _init: function () { + BI.MultiTreeListCombo.superclass._init.apply(this, arguments); + + var self = this, o = this.options; + + var isInit = false; + var want2showCounter = false; + + this.storeValue = {value: o.value || []}; + + this.trigger = BI.createWidget({ + type: "bi.multi_select_trigger", + height: o.height, + valueFormatter: o.valueFormatter, + // adapter: this.popup, + masker: { + offset: this.constants.offset + }, + searcher: { + type: "bi.multi_list_tree_searcher", + itemsCreator: o.itemsCreator, + popup: { + type: "bi.multi_tree_search_insert_pane", + el: { + type: "bi.list_part_tree" + }, + listeners: [{ + eventName: BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, + action: function () { + self.storeValue.value.unshift([self.trigger.getSearcher().getKeyword()]); + self._assertShowValue(); + // setValue以更新paras.value, 之后从search popup中拿到的就能有add的值了 + self.combo.setValue(self.storeValue); + self.trigger.stopEditing(); + } + }] + } + }, + switcher: { + el: { + type: "bi.multi_tree_check_selected_button" + }, + popup: { + type: "bi.multi_tree_check_pane", + el: { + type: "bi.list_display_tree" + }, + itemsCreator: o.itemsCreator + } + }, + value: {value: o.value || {}} + + }); + + this.combo = BI.createWidget({ + type: "bi.combo", + toggle: false, + container: o.container, + el: this.trigger, + adjustLength: 1, + popup: { + type: "bi.multi_tree_popup_view", + ref: function () { + self.popup = this; + self.trigger.setAdapter(this); + }, + el: { + type: "bi.list_async_tree" + }, + listeners: [{ + eventName: BI.MultiTreePopup.EVENT_AFTERINIT, + action: function () { + self.trigger.getCounter().adjustView(); + isInit = true; + if (want2showCounter === true) { + showCounter(); + } + } + }, { + eventName: BI.MultiTreePopup.EVENT_CHANGE, + action: function () { + change = true; + var val = { + type: BI.Selection.Multi, + value: this.hasChecked() ? this.getValue() : [] + }; + self.trigger.getSearcher().setState(val); + self.trigger.getCounter().setButtonChecked(val); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, + action: function () { + self.combo.hideView(); + } + }, { + eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, + action: function () { + clear = true; + self.setValue(); + self._defaultState(); + } + }], + itemsCreator: o.itemsCreator, + onLoaded: function () { + BI.nextTick(function () { + self.trigger.getCounter().adjustView(); + self.trigger.getSearcher().adjustView(); + }); + } + }, + value: {value: o.value || {}}, + hideChecker: function (e) { + return triggerBtn.element.find(e.target).length === 0; + } + }); + + var change = false; + var clear = false; // 标识当前是否点击了清空 + + var isSearching = function () { + return self.trigger.getSearcher().isSearching(); + }; + + var isPopupView = function () { + return self.combo.isViewVisible(); + }; + + this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { + self.storeValue = {value: self.combo.getValue()}; + this.setValue(self.storeValue); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { + self.storeValue = {value: this.getValue()}; + self.combo.setValue(self.storeValue); + BI.nextTick(function () { + if (isPopupView()) { + self.combo.populate(); + } + }); + }); + + function showCounter () { + if (isSearching()) { + self.storeValue = {value: self.trigger.getValue()}; + } else if (isPopupView()) { + self.storeValue = {value: self.combo.getValue()}; + } + self.trigger.setValue(self.storeValue); + } + + this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { + if (want2showCounter === false) { + want2showCounter = true; + } + if (isInit === true) { + want2showCounter = null; + showCounter(); + } + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { + self.combo.toggle(); + }); + this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { + if (!self.combo.isViewVisible()) { + self.combo.showView(); + } + }); + + this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { + var checked = this.getSearcher().hasChecked(); + var val = { + type: BI.Selection.Multi, + value: checked ? {1: 1} : {} + }; + this.getSearcher().setState(checked ? BI.Selection.Multi : BI.Selection.None); + this.getCounter().setButtonChecked(val); + }); + + this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { + if (isSearching()) { + return; + } + if (change === true) { + self.storeValue = {value: self.combo.getValue()}; + change = false; + } + self.combo.setValue(self.storeValue); + self.populate(); + + }); + this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { + if (isSearching()) { + self.trigger.stopEditing(); + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } else { + if (isPopupView()) { + self.trigger.stopEditing(); + self.storeValue = {value: self.combo.getValue()}; + if (clear === true) { + self.storeValue = {value: []}; + } + self.fireEvent(BI.MultiTreeListCombo.EVENT_CONFIRM); + } + } + clear = false; + change = false; + }); + + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.trigger.getCounter().hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: this.combo, + left: 0, + right: 0, + top: 0, + bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 + }] + }); + }, + + _assertShowValue: function () { + this.trigger.getSearcher().setState(this.storeValue); + this.trigger.getCounter().setButtonChecked(this.storeValue); + }, + + _defaultState: function () { + this.trigger.stopEditing(); + this.combo.hideView(); + }, + + setValue: function (v) { + this.storeValue.value = v || []; + this.combo.setValue({ + value: v || [] + }); + }, + + getValue: function () { + return this.storeValue.value; + }, + + populate: function () { + this.combo.populate.apply(this.combo, arguments); + } +}); + +BI.MultiTreeListCombo.EVENT_CONFIRM = "MultiTreeListCombo.EVENT_CONFIRM"; + +BI.shortcut("bi.multi_tree_list_combo", BI.MultiTreeListCombo); \ No newline at end of file diff --git a/src/widget/multitree/multi.tree.popup.js b/src/widget/multitree/multi.tree.popup.js index 7a38c7beb..64d54d66b 100644 --- a/src/widget/multitree/multi.tree.popup.js +++ b/src/widget/multitree/multi.tree.popup.js @@ -11,24 +11,27 @@ BI.MultiTreePopup = BI.inherit(BI.Pane, { maxWidth: "auto", minWidth: 100, maxHeight: 400, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, + el: { + type: "bi.async_tree" + } }); }, _init: function () { BI.MultiTreePopup.superclass._init.apply(this, arguments); - var self = this, opts = this.options; + var self = this, opts = this.options, v = opts.value; this.selectedValues = {}; - this.tree = BI.createWidget({ + this.tree = BI.createWidget(opts.el, { type: "bi.async_tree", height: 400, cls: "popup-view-tree", itemsCreator: opts.itemsCreator, onLoaded: opts.onLoaded, - value: opts.value || {} + value: v.value || {} }); this.popupView = BI.createWidget({ diff --git a/src/widget/multitree/trigger/multi.tree.search.insert.pane.js b/src/widget/multitree/trigger/multi.tree.search.insert.pane.js new file mode 100644 index 000000000..cc5bff3c9 --- /dev/null +++ b/src/widget/multitree/trigger/multi.tree.search.insert.pane.js @@ -0,0 +1,119 @@ +/** + * + * 在搜索框中输入文本弹出的面板 + * @class BI.MultiTreeSearchInsertPane + * @extends BI.Pane + */ + +BI.MultiTreeSearchInsertPane = BI.inherit(BI.Widget, { + + constants: { + height: 24, + }, + + props: { + baseCls: "bi-multi-tree-search-insert-pane bi-card", + itemsCreator: BI.emptyFn, + keywordGetter: BI.emptyFn, + el: { + type: "bi.part_tree" + } + }, + + render: function () { + var self = this, opts = this.options; + + return { + type: "bi.absolute", + items: [{ + el: { + type: "bi.text_button", + invisible: true, + ref: function (_ref) { + self.addTip = _ref; + }, + text: BI.i18nText("BI-Basic_Click_To_Add_Text", ""), + height: this.constants.height, + cls: "bi-high-light", + handler: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM, opts.keywordGetter()); + } + }, + top: 5, + left: 0, + right: 0 + }, { + el: BI.extend({ + type: "bi.part_tree", + tipText: BI.i18nText("BI-No_Select"), + itemsCreator: function (op, callback) { + op.keyword = opts.keywordGetter(); + opts.itemsCreator(op, function (res) { + callback(res); + self.setKeyword(opts.keywordGetter(), res.items); + }); + }, + ref: function (_ref) { + self.partTree = _ref; + }, + value: opts.value, + listeners: [{ + eventName: BI.Controller.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); + } + }, { + eventName: BI.TreeView.EVENT_CHANGE, + action: function () { + self.fireEvent(BI.MultiTreeSearchInsertPane.EVENT_CHANGE); + } + }] + }, opts.el), + left: 0, + top: 0, + bottom: 0, + right: 0 + }] + }; + }, + + setKeyword: function (keyword, nodes) { + var isAddTipVisible = BI.isEmptyArray(nodes); + this.addTip.setVisible(isAddTipVisible); + this.partTree.setVisible(!isAddTipVisible); + isAddTipVisible && this.addTip.setText(BI.i18nText("BI-Basic_Click_To_Add_Text", keyword)); + }, + + hasChecked: function () { + return this.partTree.hasChecked(); + }, + + setValue: function (v) { + this.setSelectedValue(v.value); + }, + + setSelectedValue: function (v) { + v || (v = {}); + this.partTree.setSelectedValue(v); + }, + + getValue: function () { + return this.partTree.getValue(); + }, + + empty: function () { + this.partTree.empty(); + }, + + populate: function (op) { + this.partTree.stroke.apply(this.partTree, arguments); + } +}); + +BI.MultiTreeSearchInsertPane.EVENT_CHANGE = "EVENT_CHANGE"; + +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; +BI.MultiTreeSearchInsertPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; +BI.MultiTreeSearchInsertPane.EVENT_ADD_ITEM = "EVENT_ADD_ITEM"; + +BI.shortcut("bi.multi_tree_search_insert_pane", BI.MultiTreeSearchInsertPane); \ No newline at end of file diff --git a/src/widget/multitree/multi.tree.search.pane.js b/src/widget/multitree/trigger/multi.tree.search.pane.js similarity index 100% rename from src/widget/multitree/multi.tree.search.pane.js rename to src/widget/multitree/trigger/multi.tree.search.pane.js diff --git a/src/widget/multitree/trigger/searcher.list.multi.tree.js b/src/widget/multitree/trigger/searcher.list.multi.tree.js new file mode 100644 index 000000000..acfe1cf45 --- /dev/null +++ b/src/widget/multitree/trigger/searcher.list.multi.tree.js @@ -0,0 +1,158 @@ +/** + * searcher + * Created by guy on 15/11/3. + * @class BI.MultiListTreeSearcher + * @extends Widget + */ +BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { + + _defaultConfig: function () { + return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-multi-tree-searcher", + itemsCreator: BI.emptyFn, + valueFormatter: function (v) { + return v; + }, + popup: {}, + + adapter: null, + masker: {} + }); + }, + + _init: function () { + BI.MultiListTreeSearcher.superclass._init.apply(this, arguments); + var self = this, o = this.options; + this.editor = BI.createWidget({ + type: "bi.multi_select_editor", + height: o.height, + el: { + type: "bi.simple_state_editor", + height: o.height + } + }); + + this.searcher = BI.createWidget({ + type: "bi.searcher", + element: this, + isAutoSearch: false, + isAutoSync: false, + onSearch: function (op, callback) { + callback({ + keyword: self.editor.getValue() + }); + }, + el: this.editor, + + popup: BI.extend({ + type: "bi.multi_tree_search_pane", + keywordGetter: function () { + return self.editor.getValue(); + }, + itemsCreator: function (op, callback) { + op.keyword = self.editor.getValue(); + o.itemsCreator(op, callback); + }, + value: o.value + }, o.popup), + + adapter: o.adapter, + masker: o.masker + }); + this.searcher.on(BI.Searcher.EVENT_START, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_START); + }); + this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { + if (this.hasMatched()) { + + } + self.fireEvent(BI.MultiListTreeSearcher.EVENT_PAUSE); + }); + this.searcher.on(BI.Searcher.EVENT_STOP, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_STOP); + }); + this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { + self.fireEvent(BI.MultiListTreeSearcher.EVENT_CHANGE, arguments); + }); + if (BI.isNotNull(o.value)) { + this.setState(o.value); + } + }, + + adjustView: function () { + this.searcher.adjustView(); + }, + + setAdapter: function (adapter) { + this.searcher.setAdapter(adapter); + }, + + isSearching: function () { + return this.searcher.isSearching(); + }, + + stopSearch: function () { + this.searcher.stopSearch(); + }, + + getKeyword: function () { + return this.editor.getValue(); + }, + + hasMatched: function () { + return this.searcher.hasMatched(); + }, + + hasChecked: function () { + return this.searcher.getView() && this.searcher.getView().hasChecked(); + }, + + setState: function (ob) { + var o = this.options; + ob || (ob = {}); + ob.value || (ob.value = []); + var count = 0; + if (BI.isNumber(ob)) { + this.editor.setState(ob); + } else if (BI.size(ob.value) === 0) { + this.editor.setState(BI.Selection.None); + } else { + var text = ""; + BI.each(ob.value, function (idx, path) { + var childValue = BI.last(path); + text += (o.valueFormatter(childValue + "") || childValue) + "; "; + count++; + }); + + if (count > 20) { + this.editor.setState(BI.Selection.Multi); + } else { + this.editor.setState(text); + } + } + }, + + setValue: function (ob) { + this.setState(ob); + this.searcher.setValue(ob); + }, + + getKey: function () { + return this.editor.getValue(); + }, + + getValue: function () { + return this.searcher.getValue(); + }, + + populate: function (items) { + this.searcher.populate.apply(this.searcher, arguments); + } +}); + +BI.MultiListTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; +BI.MultiListTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiListTreeSearcher.EVENT_START = "EVENT_START"; +BI.MultiListTreeSearcher.EVENT_STOP = "EVENT_STOP"; +BI.MultiListTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; +BI.shortcut("bi.multi_list_tree_searcher", BI.MultiListTreeSearcher); \ No newline at end of file diff --git a/ui/css/background.css b/ui/css/background.css index c03b30dc3..98501eb71 100644 --- a/ui/css/background.css +++ b/ui/css/background.css @@ -51,8 +51,8 @@ _background: none; } .ztree li span.button.chk.checkbox_false_part { - background: url('resources?path=/com/fr/web/ui/images/2x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='resources?path=/com/fr/web/ui/images/2x/icon/half_selected.png'); + background: url('resources?path=/com/fr/web/ui/images/2x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='resources?path=/com/fr/web/ui/images/2x/icon/check_box_normal.png'); background-size: contain; _background: none; } @@ -97,8 +97,8 @@ _background: none; } .ztree.hack li span.button.chk.checkbox_false_part { - background: url('resources?path=/com/fr/web/ui/images/1x/icon/half_selected.png') no-repeat center center; - _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='resources?path=/com/fr/web/ui/images/1x/icon/half_selected.png'); + background: url('resources?path=/com/fr/web/ui/images/1x/icon/check_box_normal.png') no-repeat center center; + _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='resources?path=/com/fr/web/ui/images/1x/icon/check_box_normal.png'); _background: none; } .ztree.hack li span.button.chk.checkbox_false_part_focus {