blob: 9fef50a117540830833eddd7c47a9fdfe8864bbc [file] [log] [blame]
/**
* @file Tree list (forest)
* @author sushuang(sushuang@baidu.com)
*/
define(function (require) {
var $ = require('jquery');
var lib = require('../lib');
var Component = require('./Component');
var encodeHTML = lib.encodeHTML;
// Constant
var SLIDE_INTERVAL = 200;
var UNDEFINED;
var DATASOURCE_ID = 'id-0';
/**
* @class
* @extends dt/ui/Component
*/
var TreeSelect = Component.extend({
_define: {
css: 'dtui-treelist',
viewModel: function () {
return {
/**
* 如果是lib.ob则表示单选,其值对应于datasource中的value,表示选中的项。
* 如果是lib.obArray则表示多选,其中:obArray中每项是value
* 可在valueInfo中设置参数:{
* noAnimation: boolean 关闭动画,默认false
* scrollToTarget: 滚屏到第一个目标。默认undefined(不滚屏)。
* {Object} 表示滚屏到第一个目标在浏览器窗口中所处的位置,
* Object内容为:{clientX: number}。
* collapseLevel: number 用于达到“先折叠再展开”的效果。
* 默认null即不collapse。
* 传入collapse level,即最高折叠到树的这层,最高是0层。
* always: Function 动画结束的回调。即使关闭动画,这个函数也会总会被异步触发。
* }
* 可以对此ob进行监听:
* treeList.viewModel('selected').subscribe(function (nextValue, ob) {
* // 这里nextValue 就是树节点上的value字段
* // 如果要获取整个树节点的信息(dataItem),使用:
* var dataItemArray = ob.getTreeDataItem();
* var dataItem = ob.getTreeDataItem(true);
* // 如果enhanceSelected设为了false,则没有此功能,只能手动使用findDataItemByOb来完成此功能。
* // 如果一个ob会被多个组件共享,为避免冲突,enhanceSelected可以关掉。
* });
*/
selected: lib.ob(),
enhanceSelected: true,
/**
* hovered
* 可在valueInfo中设置参数以及监听:同viewModel.selected
*/
hovered: lib.ob(),
enhanceHovered: true,
/**
* highlighted
* 可在valueInfo中设置参数:同viewModel.selected
*/
highlighted: lib.obArray(),
enhanceHighlighted: true,
/**
* @type {Array.<Object>}
*
* 每项为:
* {
* value: ..., // 不禁止value重复。如果重复,同value的项会同时被选中。不可为undefined。
* text: ...,
* itemEncodeHTML: // 每项的文字是否encodeHTML,默认为true。
* tooltip: ..., // 鼠标hover提示文字,如果需要的话,string。
* tooltipEncodeHTML: ... // 文字是否要encdeHTML,默认为true。
* children: [ {同构子项}, {}, ... ]
* childrenPre: // children前文字,如 ": {"
* childrenPost: // children后文字,如 "}"
* childrenBrief: // chilren折叠时显示的文字,如 "..."
* expanded: {boolean} 初始状态是展开还是折叠。默认折叠(false)
* }
* 不能有空项。value可为任意基本类型。
*/
datasource: [],
/**
* 大小改变事件。展开折叠时触发。
*/
resizeEvent: lib.ob()
};
},
viewModelPublic: ['selected', 'hovered', 'highlighted', 'resizeEvent']
},
/**
* @override
*/
_init: function () {
var viewModel = this._viewModel();
lib.assert(lib.obTypeOf(viewModel.selected));
lib.assert(lib.obTypeOf(viewModel.highlighted) === 'obArray');
this._enhanceOb();
this._prepareDatasource();
this._initContent();
// this._initTooltip();
this._initChange();
this._initMouse();
// this._initExpand();
},
/**
* 向ob添加方法,便于外界使用
*
* @private
*/
_enhanceOb: function () {
var viewModel = this._viewModel();
if (viewModel.enhanceSelected) {
var selectedOb = viewModel.selected;
selectedOb.getTreeDataItem = $.proxy(this.findDataItemByOb, this, selectedOb);
}
if (viewModel.enhanceHighlighted) {
var highlightedOb = viewModel.highlighted;
highlightedOb.getTreeDataItem = $.proxy(this.findDataItemByOb, this, highlightedOb);
}
if (viewModel.enhanceHovered) {
var hoveredOb = viewModel.hovered;
hoveredOb.getTreeDataItem = $.proxy(this.findDataItemByOb, this, hoveredOb);
}
},
/**
* @private
*/
_getCss: function (type) {
var suffix = ({
item: '-i',
thumb: '-thumb',
text: '-text',
textActive: '-text-active',
textHover: '-text-hover',
textHighlight: '-text-highlight',
list: '-list',
parent: '-parent',
collapsed: '-collapsed',
expanded: '-expanded',
post: '-post'
})[type || ''];
return this.css() + suffix;
},
/**
* @private
*/
_prepareDatasource: function () {
var datasource = this._viewModel().datasource;
this._containerMap = lib.createLiteHashMap();
var dataItemMap = this._dataItemMap = lib.createLiteHashMap();
var levelMap = this._levelMap = lib.createLiteHashMap();
this._travelData(datasource, function (dataItem, level) {
var id = dataItem.value;
dataItemMap.set(id, dataItem);
levelMap.set(id, level);
});
},
/**
* @private
*/
_initContent: function () {
var datasource = this._viewModel().datasource;
if (datasource && datasource.length) {
var initValues = [datasource[0].value];
var children = datasource[0].children;
if (children && children.length) {
initValues.push(children[0].value);
}
this._build(datasource, null, lib.createLiteHashMap(initValues), true);
}
},
// /**
// * @private
// */
// _initContent: function () {
// var itemCss = this._getCss('item');
// var parentCss = this._getCss('parent');
// var thumbCss = this._getCss('thumb');
// var collapsedCss = this._getCss('collapsed');
// var textCss = this._getCss('text');
// var listCss = this._getCss('list');
// var postCss = this._getCss('post');
// var html = [];
// this._travelData(
// this._viewModel().datasource,
// {
// preList: function (treeList, thisPath, parent) {
// // 第一层(树林的根)展开,其他默认收缩。
// var isRoot = thisPath === '';
// var display = isRoot ? '' : 'display:none';
// var notRendered = isRoot ? '' : 'data-not-rendered';
// html.push('<ul class="', listCss, '" style="', display, '" ', notRendered, '>');
// // return !isRoot;
// },
// postList: function () {
// html.push('</ul>');
// },
// preChildren: function (dataItem, thisPath, parent, isLast, level) {
// var otherCss = (dataItem.children && dataItem.children.length)
// ? (parentCss + ' ' + collapsedCss)
// : '';
// var dataPath = ' ' + PATH_ATTR + '="' + thisPath + '" ';
// var dataLevel = ' ' + LEVEL_ATTR + '="' + level + '" ';
// var dataEncodeHTML = ' ' + ENCODE_HTML_ATTR + '="'
// + (dataItem.itemEncodeHTML !== false ? '1' : '0') + '" ';
// var anchor = dataItem.anchor ? ' name="' + dataItem.anchor + '" ' : ' ';
// var encode = dataItem.itemEncodeHTML !== false ? encodeHTML : returnInput;
// var textHTML = encode(toText(dataItem.text));
// var childrenPreHTML = encode(toText(dataItem.childrenPre));
// var childrenPostHTML = encode(toText(dataItem.childrenPost));
// var childrenBriefHTML = encode(toText(dataItem.childrenBrief));
// html.push(
// '<li class="', itemCss, ' ', otherCss, '" ',
// dataPath, dataLevel, dataEncodeHTML, '>',
// '<i class="', thumbCss, '"></i>', // 展开收起的控制器。
// anchor,
// '<span ',
// ' class="', textCss, '" ', dataPath, '>',
// textHTML, childrenPreHTML, childrenBriefHTML, childrenPostHTML,
// '</span>'
// );
// },
// postChildren: function (dataItem, thisPath, parent, isLast) {
// html.push('</li>');
// var encode = dataItem.itemEncodeHTML !== false ? encodeHTML : returnInput;
// if (isLast && parent && parent.childrenPost) {
// html.push('<li class="' , postCss, '">', encode(parent.childrenPost), '</li>');
// }
// }
// }
// );
// this.el().innerHTML = html.join('');
// },
// /**
// * @private
// */
// _initTooltip: function () {
// var datasource = this._viewModel().datasource;
// var loc = {
// x: 0,
// y: -15,
// xAnchor: 'center',
// yAnchor: 'bottom'
// };
// var that = this;
// this._disposable(lib.bindTooltip({
// bindEl: this.el(),
// followMouse: true,
// selector: '.' + this._getCss('text'),
// location: loc,
// text: getText,
// encodeHTML: false // 在getText中处理encodeHTML
// }));
// function getText(itemEl) {
// if (that.isFrozen()) {
// return;
// }
// var dataItem = that._findDataItemByPath(
// datasource, $(itemEl).attr(PATH_ATTR)
// );
// var tooltipText = (dataItem || {}).tooltip;
// if (tooltipText != null) {
// return dataItem.tooltipEncodeHTML !== false
// ? encodeHTML(tooltipText) : tooltipText;
// }
// // tooltipText为空则不显示tooltip
// }
// },
/**
* @private
*/
_initChange: function () {
var viewModel = this._viewModel();
var selOb = viewModel.selected;
this._disposable(selOb.subscribe(this._updateSelectedByModel, this));
this._updateSelectedByModel(selOb(), selOb); // 设初始值
var highlightedOb = viewModel.highlighted;
this._disposable(highlightedOb.subscribe(this._updateHighlightedByModel, this));
this._updateHighlightedByModel(highlightedOb(), highlightedOb); // 设初始值
},
/**
* @private
*/
_initMouse: function () {
var $el = this.$el();
var viewModel = this._viewModel();
var itemCss = this._getCss('item');
var textHoverCss = this._getCss('textHover');
var textCss = this._getCss('text');
var thumbCss = this._getCss('thumb');
var that = this;
// 鼠标事件
$el.on(this._event('mouseenter'), '.' + textCss, '.' + itemCss, onItemTextEnter);
$el.on(this._event('mouseleave'), '.' + textCss, '.' + itemCss, onItemTextLeave);
$el.on(this._event('click'), '.' + textCss, onItemTextClick);
$el.on(this._event('click'), '.' + thumbCss, onThumbClick);
function onItemTextEnter(e) {
if (that.isFrozen()) {
return;
}
var $item = $(this);
$item.addClass(textHoverCss);
var dataItem = that._findDataItemByEl(this);
viewModel.hovered(dataItem.value, {dataItem: dataItem});
}
function onItemTextLeave(e) {
if (that.isFrozen()) {
return;
}
$(this).removeClass(textHoverCss);
viewModel.hovered(UNDEFINED);
}
function onItemTextClick(e) {
if (that.isFrozen()) {
return;
}
var obType = lib.obTypeOf(viewModel.selected);
var dataItem = that._findDataItemByEl(this);
var value = dataItem.value;
if (obType === 'obArray') { // 多选
var selected = viewModel.selected();
var index = lib.arrayIndexOf(selected, value);
if (index >= 0) {
selected.splice(index, 1);
}
else {
selected.push(value);
}
value = selected;
}
// else 单选
viewModel.selected(value, {preventExpand: true, dataItem: dataItem});
}
function onThumbClick() {
if (that.isFrozen()) {
return;
}
that._toggleSingleItem(that._findItemEl($(this)));
}
},
// /**
// * @protectd
// */
// _initExpand: function () {
// var that = this;
// var datasource = this._viewModel().datasource;
// var $itemEls = this.$el().find('.' + this._getCss('item')).filter(function () {
// return !!that._findDataItemByEl(this).expanded;
// });
// this._expandOrCollapse($itemEls, 'expand', {noAnimation: true});
// },
/**
* Do not build util needed, to enhance performance.
*
* @private
*/
_build: function (treeList, hostDataItem, targetValueMap, isInit) {
var listCss = this._getCss('list');
var itemCss = this._getCss('item');
var parentCss = this._getCss('parent');
var thumbCss = this._getCss('thumb');
var collapsedCss = this._getCss('collapsed');
var textCss = this._getCss('text');
var listCss = this._getCss('list');
var postCss = this._getCss('post');
var containerMap = this._containerMap;
if (containerMap.get(DATASOURCE_ID) == null) {
var thisEl = this.$el()[0];
thisEl.innerHTML = '<ul class="' + listCss
+ '" data-id="' + DATASOURCE_ID + '"></ul>';
containerMap.set(DATASOURCE_ID, thisEl.getElementsByTagName('ul')[0]);
}
buildAndCollect(treeList, hostDataItem);
function buildAndCollect(thisList, hostDataItem) {
if (!thisList || !thisList.length) {
return;
}
var needRenderList;
for (var i = 0, len = thisList.length; i < len; i++) {
var dataItem = thisList[i];
needRenderList |= (
dataItem.__needRenderChildren = buildAndCollect(dataItem.children, dataItem)
);
if (targetValueMap.get(dataItem.value) != null) {
needRenderList = true;
}
}
// If container found, indicate that is has rolluped to a render point.
var container = containerMap.get(hostDataItem ? hostDataItem.value : DATASOURCE_ID);
if (needRenderList && container && !thisList.__rendered) {
var htmlCollector = [];
build(thisList, hostDataItem, htmlCollector);
container.innerHTML = htmlCollector.join('');
// Cache containers for search.
var subContainers = container.getElementsByTagName('ul');
for (var i = 0; i < subContainers.length; i++) {
var subContainer = subContainers[i];
containerMap.set(subContainer.getAttribute('data-id'), subContainer);
}
needRenderList = false;
}
return needRenderList;
}
function build(thisList, hostDataItem, htmlCollector) {
if (!thisList || !thisList.length) {
return;
}
for (var i = 0; i < thisList.length; i++) {
var dataItem = thisList[i];
var encode = dataItem.itemEncodeHTML !== false ? encodeHTML : returnInput;
var otherCss = (dataItem.children && dataItem.children.length)
? (parentCss + ' ' + collapsedCss)
: '';
var anchor = dataItem.anchor ? ' name="' + dataItem.anchor + '" ' : ' ';
var textHTML = encode(toText(dataItem.text));
var childrenPreHTML = encode(toText(dataItem.childrenPre));
var childrenPostHTML = encode(toText(dataItem.childrenPost));
var childrenBriefHTML = encode(toText(dataItem.childrenBrief));
var idString = ' data-id="' + dataItem.value + '" ';
htmlCollector.push(
'<li class="', itemCss, ' ', otherCss, '" ', idString, '>',
'<i class="', thumbCss, '"></i>', // 展开收起的控制器。
anchor,
'<span class="', textCss, '" ', idString, '>',
textHTML, childrenPreHTML, childrenBriefHTML, childrenPostHTML,
'</span>'
);
if (dataItem.children && dataItem.children.length) {
var styleStr = isInit ? '' : ' style="display:none" ';
htmlCollector.push(
'<ul class="', listCss, '" ', idString, styleStr, '>'
);
if (dataItem.__needRenderChildren) {
build(dataItem.children, dataItem, htmlCollector);
}
htmlCollector.push('</ul>');
dataItem.__needRenderChildren = null;
}
htmlCollector.push('</li>');
if (i === thisList.length - 1 && hostDataItem && hostDataItem.childrenPost) {
htmlCollector.push('<li class="' , postCss, '">', encode(parent.childrenPost), '</li>');
}
}
thisList.__rendered = true;
}
},
/**
* @private
*/
_updateSelectedByModel: function (nextValue, ob) {
var viewModel = this._viewModel();
var obType = lib.obTypeOf(viewModel.selected);
var activeCss = this._getCss('textActive');
var expandList = [];
var that = this;
lib.assert(obType !== 'obArray' || $.isArray(nextValue));
var nextValueMap = lib.createLiteHashMap(
obType === 'obArray' ? nextValue : nextValue ? [nextValue] : []
);
this._build(viewModel.datasource, null, nextValueMap);
this._travelItemText(function ($text, thisValue) {
if (nextValueMap.hasOwnProperty(thisValue)) {
$text.addClass(activeCss);
if (!ob.peekValueInfo('preventExpand')) {
expandList.push(that._findItemEl($text));
}
}
else {
$text.removeClass(activeCss);
}
});
this._showItems(
$(expandList),
{
noAnimation: ob.peekValueInfo('noAnimation'),
collapseLevel: ob.peekValueInfo('collapseLevel'),
always: ob.peekValueInfo('always'),
scrollToTarget: ob.peekValueInfo('scrollToTarget')
}
);
},
/**
* @private
*/
_updateHighlightedByModel: function (nextValue, ob) {
var highlightedCss = this._getCss('textHighlight');
var highlightList = [];
var that = this;
var nextValueMap = lib.createLiteHashMap(nextValue);
this._build(this._viewModel().datasource, null, nextValueMap);
this._travelItemText(function ($text, thisValue) {
if (nextValueMap.hasOwnProperty(thisValue)) {
$text.addClass(highlightedCss);
if (!ob.peekValueInfo('preventExpand')) {
highlightList.push(that._findItemEl($text));
}
}
else {
$text.removeClass(highlightedCss);
}
});
this._showItems(
$(highlightList),
{
noAnimation: ob.peekValueInfo('noAnimation'),
collapseLevel: ob.peekValueInfo('collapseLevel'),
always: ob.peekValueInfo('always'),
scrollToTarget: ob.peekValueInfo('scrollToTarget')
}
);
},
/**
* @private
* @param {jQuery} $itemEls
* @param {Object=} options
* @param {number=} [options.collapseLevel]
* @param {boolean=} [options.noAnimation]
* @param {Function=} [options.always]
* @param {boolean=} [options.scrollToTarget]
*/
_showItems: function ($itemEls, options) {
options = options || {};
var $ancestors = this._getAncestorItems($itemEls);
this._collapseAll({
collapseLevel: options.collapseLevel,
noAnimation: options.noAnimation,
always: $.proxy(doExpand, this)
});
function doExpand() {
if (this.isDisposed()) {
return;
}
this._expandOrCollapse(
$ancestors, 'expand',
{noAnimation: options.noAnimation, always: $.proxy(doFinal, this)}
);
}
function doFinal() {
if (this.isDisposed()) {
return;
}
var scrollTarget = $($itemEls[0]);
var scrollToTarget = options.scrollToTarget;
if (scrollToTarget && scrollTarget.length) {
(scrollToTarget.container || $('html,body')).animate({
scrollTop: scrollTarget.offset().top - (scrollToTarget.clientX || 30)
});
}
options.always && options.always();
}
},
/**
* Do not include items itselves.
*
* @protected
* @param {jQuery} $itemEls
* @return {jQuery}
*/
_getAncestorItems: function ($itemEls) {
var that = this;
var ancestors = [];
$itemEls.each(function () {
var $itemEl = $(this);
var baseCss = that.css();
var itemCss = that._getCss('item');
var $el = $itemEl.parent();
while ($el && $el.length && !$el.hasClass(baseCss)) {
if ($el.hasClass(itemCss)) {
ancestors.push($el[0]);
}
$el = $el.parent();
}
});
return $(ancestors);
},
/**
* @protected
*/
_getParentItem: function ($itemEl) {
return $itemEl.parent().closest('.' + this._getCss('item'));
},
/**
* @protected
*
* @param {Function} callback
*/
_travelItemText: function (callback) {
var $o = this.$el().find('.' + this._getCss('text'));
var that = this;
$o.each(function () {
var $this = $(this);
var thisValue = that._findDataItemByEl(this).value;
callback.call(that, $this, thisValue);
});
},
/**
* @protected
* @param {number} collapseLevel
* @param {Object} options
* @param {boolean} [options.collapseLevel]
* @param {boolean=} [options.noAnimation]
* @param {Function=} [options.always]
*/
_collapseAll: function (options) {
var collapseLevel = options.collapseLevel;
var levelMap = this._levelMap;
var that = this;
if (collapseLevel == null || collapseLevel < 0) {
setTimeout(doFinal, 0);
}
else {
var itemSelector = '.' + this._getCss('item');
var $changeItems = this.$el().find(itemSelector).filter(function () {
return levelMap.get(this.getAttribute('data-id')) >= collapseLevel;
});
this._expandOrCollapse(
$changeItems, 'collapse',
{noAnimation: options.noAnimation, always: doFinal}
);
}
function doFinal() {
!that.isDisposed() && options.always && options.always();
}
},
/**
* 展开和收起单层。所有展开收起的最终逻辑都走这里。
*
* @protected
* @param {jQuery} $itemEls 可能是多个element
* @param {string} type 'expand' or 'collapse'
* @param {Object} options
* @param {boolean=} [options.noAnimation] default false
* @param {Function=} [options.always]
*/
_expandOrCollapse: function ($itemEls, type, options) {
options = options || {};
var collapsedCss = this._getCss('collapsed');
var expandedCss = this._getCss('expanded');
var viewModel = this._viewModel();
var that = this;
var cssToRemove;
var cssToAdd;
var animateFn;
if (type === 'expand') {
cssToRemove = collapsedCss;
cssToAdd = expandedCss;
animateFn = 'slideDown';
}
else { // type === 'collapse'
cssToRemove = expandedCss;
cssToAdd = collapsedCss;
animateFn = 'slideUp';
}
var $toBeChangedItemEls = $itemEls.filter('.' + cssToRemove);
// 只有顶层的才实施动画,其他没有动画。
var changeItems = {
withAnimation: [],
withoutAnimation: []
};
$toBeChangedItemEls.each(function () {
if (that._getParentItem($(this)).hasClass(expandedCss)) {
changeItems.withAnimation.push(this);
}
else {
changeItems.withoutAnimation.push(this);
}
});
// 开始变化视图
$toBeChangedItemEls
.removeClass(cssToRemove)
.addClass(cssToAdd);
if (type === 'expand') {
this._resetItemText($toBeChangedItemEls);
}
if (type === 'expand') {
doWithoutAnimation($.proxy(doWithAnimation, this, doFinal));
}
else { // type === 'collapse'
doWithAnimation($.proxy(doWithoutAnimation, this, doFinal));
}
function doWithAnimation(then) {
if (that.isDisposed()) {
return;
}
that._findElInItem($(changeItems.withAnimation), 'list')
[animateFn](options.noAnimation ? 0 : SLIDE_INTERVAL) // 动画
.promise().always(then);
}
function doWithoutAnimation(then) {
if (that.isDisposed()) {
return;
}
that._findElInItem($(changeItems.withoutAnimation), 'list')
[animateFn](0)
.promise().always(then);
}
function doFinal() {
if (that.isDisposed()) {
return;
}
if (type === 'collapse') {
that._resetItemText($toBeChangedItemEls);
}
viewModel.resizeEvent({});
options.always && options.always();
}
},
/**
* @protected
* @param {jQuery} $itemEl 一个element
*/
_toggleSingleItem: function ($itemEl) {
var collapsedCss = this._getCss('collapsed');
var expandedCss = this._getCss('expanded');
var viewModel = this._viewModel();
var dataItem = this._findDataItemByEl($itemEl[0]);
if (dataItem.children && dataItem.children.length && !dataItem.children.__rendered) {
this._build(dataItem.children, dataItem, lib.createLiteHashMap([dataItem.children[0].value]));
}
var $listEl = this._findElInItem($itemEl, 'list');
if ($itemEl.hasClass(collapsedCss)) {
$itemEl.removeClass(collapsedCss).addClass(expandedCss);
$listEl.slideDown(SLIDE_INTERVAL, $.proxy(handleSlideEnd, this, false));
this._resetItemText($itemEl);
}
else if ($itemEl.hasClass(expandedCss)) {
$itemEl.removeClass(expandedCss).addClass(collapsedCss);
$listEl.slideUp(SLIDE_INTERVAL, $.proxy(handleSlideEnd, this, true));
}
function handleSlideEnd(resetText) {
if (this.isDisposed()) {
return;
}
resetText && this._resetItemText($itemEl);
viewModel.resizeEvent({});
}
},
/**
* 判断是否datasource中有某value
*
* @public
* @param {*} value 给定的value
* @return {Boolean} 是否有value
*/
hasValue: function (value) {
var has = false;
this._travelData(this._viewModel().datasource, function (dataItem) {
if (dataItem.value === value) {
has = true;
}
});
return has;
},
/**
* @public
* @param {Object} ob
* @param {boolean} single 如果为true,返回第一个结果。如果为false,返回数组。
* 默认为false。
* @return {(Array.<Object>|Object)}
*/
findDataItemByOb: function (ob, single) {
var values = lib.obTypeOf(ob) === 'obArray' ? ob() : [ob()];
return this.findDataItemByValues(values, single);
},
/**
* @public
* @param {Array.<*>} values
* @param {boolean} single 如果为true,返回第一个结果。如果为false,返回数组。
* 默认为false。
* @return {(Array.<Object>|Object)}
*/
findDataItemByValues: function (values, single) {
var result = [];
this._travelData(this._viewModel().datasource, function (dataItem) {
if (lib.arrayIndexOf(values, dataItem.value) >= 0) {
result.push(dataItem);
}
});
return single ? result[0] : result;
},
_travelData: function (treeList, callback, level) {
level = level || 0;
if (treeList && treeList.length) {
for (var i = 0, len = treeList.length; i < len; i++) {
if (treeList[i]) {
callback(treeList[i], level);
this._travelData(treeList[i].children, callback, level + 1);
}
}
}
},
// /**
// * 深度优先遍历treeListData。
// *
// * @private
// * @param {Array.<Object>} treeList 被遍历的对象。
// * @param {Array.<Function>} callbacks 遍历过程中的回调处理函数。
// * @param {Function} callbacks.preList 访问本list前的处理函数,参数:
// * {Array.<Object>} 本list。
// * {string} path 当前节点的位置信息, 形如'4,1,5'
// * 返回 true 则 skipChildren。
// * @param {Function} callbacks.postList 访问子孙前的处理,参数同preList。
// * @param {Function} callbacks.preChildren 访问子孙前的处理,参数:
// * {Object} item 当前节点,
// * {string} path 当前节点的位置信息, 形如'4,1,5'
// * {boolean} isLast
// * @param {Function} callbacks.postChildren 访问子孙后的处理,参数同callbacks.preChildren
// * @param {string=} parentPath 父节点的位置信息, 形如'4,1,5',递归内部使用。
// * @param {Object=} parent 若没有则可以不传
// */
// _travelData: function (treeList, callbacks, parentPath, parent, level) {
// parentPath = (parentPath == null || parentPath === '')
// ? '' : (parentPath + ',');
// level == null && (level = 0);
// if (treeList && treeList.length) {
// var skipChildren = callbacks.preList && callbacks.preList(treeList, parentPath, parent);
// if (!skipChildren) {
// for (var i = 0, len = treeList.length; i < len; i++) {
// var dataItem = treeList[i];
// var thisPath = parentPath + i;
// var isLast = i === len - 1;
// callbacks.preChildren
// && callbacks.preChildren(dataItem, thisPath, parent, isLast, level);
// this._travelData(dataItem.children, callbacks, thisPath, dataItem, level + 1); // 递归
// callbacks.postChildren
// && callbacks.postChildren(dataItem, thisPath, parent, isLast, level);
// }
// }
// callbacks.postList && callbacks.postList(treeList, parentPath, parent);
// }
// },
_findDataItemByEl: function (itemEl) {
return itemEl && this._dataItemMap.get(itemEl.getAttribute('data-id'));
},
// /**
// * @private
// * @param {Array.<Object>} treeList 在这里面find。
// * @param {string} path 节点的位置信息, 形如'4,1,5'。
// * @return {Object=} 找到的节点对象,没找到返回空。
// */
// _findDataItemByPath: function (treeList, path) {
// path = path.split(',');
// treeList = treeList || [];
// var dataItem;
// for (var i = 0, len = path.length; i < len && treeList; i++) {
// dataItem = treeList[path[i]];
// treeList = (dataItem || {}).children;
// }
// return dataItem;
// },
/**
* 从item中某个el找到itemEl
*
* @private
*/
_findItemEl: function ($subEl) {
var baseCss = this.css();
var itemCss = this._getCss('item');
while (!$subEl.hasClass(itemCss)) {
if ($subEl.hasClass(baseCss)) {
return null;
}
$subEl = $subEl.parent();
}
return $subEl;
},
/**
* @inner
* @this {Object} TreeSelect实例
*/
_findElInItem: function ($itemEls, cssName) {
return $itemEls.find('> .' + this._getCss(cssName));
},
/**
* @private
*/
_resetItemText: function ($itemEls) {
var that = this;
$itemEls.each(function () {
var $itemEl = $(this);
var dataItem = that._findDataItemByEl(this);
var encode = dataItem.itemEncodeHTML !== false ? encodeHTML : returnInput;
var $textEl = that._findElInItem($itemEl, 'text');
if ($itemEl.hasClass(that._getCss('collapsed'))) {
$textEl[0].innerHTML = encode([
toText(dataItem.text),
toText(dataItem.childrenPre),
toText(dataItem.childrenBrief),
toText(dataItem.childrenPost)
].join(''));
}
else if ($itemEl.hasClass(that._getCss('expanded'))) {
$textEl[0].innerHTML = encode([
toText(dataItem.text),
toText(dataItem.childrenPre)
].join(''));
}
});
}
});
function returnInput(v) {
return v;
}
function toText(val) {
return val != null ? val : '';
}
return TreeSelect;
});