UNPKG

amis

Version:

一种MIS页面生成工具

528 lines (527 loc) 28.2 kB
"use strict"; /** * @file Tree * @description 树形组件 * @author fex */ Object.defineProperty(exports, "__esModule", { value: true }); exports.TreeSelector = void 0; var tslib_1 = require("tslib"); var react_1 = tslib_1.__importDefault(require("react")); var helper_1 = require("../utils/helper"); var Select_1 = require("./Select"); var theme_1 = require("../theme"); var Options_1 = require("../renderers/Form/Options"); var icons_1 = require("./icons"); var Checkbox_1 = tslib_1.__importDefault(require("./Checkbox")); var locale_1 = require("../locale"); var Spinner_1 = tslib_1.__importDefault(require("./Spinner")); var TreeSelector = /** @class */ (function (_super) { tslib_1.__extends(TreeSelector, _super); function TreeSelector(props) { var _this = _super.call(this, props) || this; _this.unfolded = new WeakMap(); _this.state = { value: Select_1.value2array(props.value, { multiple: props.multiple, delimiter: props.delimiter, valueField: props.valueField, options: props.options }), inputValue: '', addingParent: null, isAdding: false, isEditing: false, editingItem: null }; _this.syncUnFolded(props); return _this; } TreeSelector.prototype.componentDidUpdate = function (prevProps) { var props = this.props; if (prevProps.options !== props.options) { this.syncUnFolded(props); } if (prevProps.value !== props.value || prevProps.options !== props.options) { this.setState({ value: Select_1.value2array(props.value, { multiple: props.multiple, delimiter: props.delimiter, valueField: props.valueField, options: props.options }) }); } }; TreeSelector.prototype.syncUnFolded = function (props) { // 初始化树节点的展开状态 var unfolded = this.unfolded; var _a = this.props, foldedField = _a.foldedField, unfoldedField = _a.unfoldedField; helper_1.eachTree(props.options, function (node, index, level) { if (unfolded.has(node)) { return; } if (node.children && node.children.length) { var ret = true; if (node.defer && node.loaded) { ret = true; } else if (unfoldedField && typeof node[unfoldedField] !== 'undefined') { ret = !!node[unfoldedField]; } else if (foldedField && typeof node[foldedField] !== 'undefined') { ret = !node[foldedField]; } else { ret = !!props.initiallyOpen; if (!ret && level <= props.unfoldedLevel) { ret = true; } } unfolded.set(node, ret); } }); return unfolded; }; TreeSelector.prototype.toggleUnfolded = function (node) { var unfolded = this.unfolded; var onDeferLoad = this.props.onDeferLoad; if (node.defer && !node.loaded) { onDeferLoad === null || onDeferLoad === void 0 ? void 0 : onDeferLoad(node); return; } unfolded.set(node, !unfolded.get(node)); this.forceUpdate(); }; TreeSelector.prototype.isUnfolded = function (node) { var unfolded = this.unfolded; return unfolded.get(node); }; TreeSelector.prototype.clearSelect = function () { var _this = this; this.setState({ value: [] }, function () { var _a = _this.props, joinValues = _a.joinValues, rootValue = _a.rootValue, onChange = _a.onChange; onChange(joinValues ? rootValue : []); }); }; TreeSelector.prototype.handleSelect = function (node, value) { var _a = this.props, joinValues = _a.joinValues, valueField = _a.valueField, onChange = _a.onChange; if (node[valueField] === undefined) { if (node.defer && !node.loaded) { this.toggleUnfolded(node); } return; } this.setState({ value: [node] }, function () { onChange(joinValues ? node[valueField] : node); }); }; TreeSelector.prototype.handleCheck = function (item, checked) { var props = this.props; var value = this.state.value.concat(); var idx = value.indexOf(item); var onlyChildren = props.onlyChildren; if (checked) { ~idx || value.push(item); // cascade 为 true 表示父节点跟子节点没有级联关系。 if (!props.cascade) { var children = item.children ? item.children.concat([]) : []; if (onlyChildren) { // 父级选中的时候,子节点也都选中,但是自己不选中 !~idx && children.length && value.pop(); while (children.length) { var child = children.shift(); var index = value.indexOf(child); if (child.children) { children.push.apply(children, child.children); } else if (!~index && child.value !== 'undefined') { value.push(child); } } } else { // 只要父节点选择了,子节点就不需要了,全部去掉勾选. withChildren时相反 while (children.length) { var child = children.shift(); var index = value.indexOf(child); if (~index) { value.splice(index, 1); } if (props.withChildren) { value.push(child); } if (child.children && child.children.length) { children.push.apply(children, child.children); } } var toCheck = item; while (true) { var parent = helper_1.getTreeParent(props.options, toCheck); if (parent === null || parent === void 0 ? void 0 : parent.value) { // 如果所有孩子节点都勾选了,应该自动勾选父级。 if (parent.children.every(function (child) { return ~value.indexOf(child); })) { if (!props.withChildren) { parent.children.forEach(function (child) { var index = value.indexOf(child); if (~index) { value.splice(index, 1); } }); } value.push(parent); toCheck = parent; continue; } } break; } } } } else { ~idx && value.splice(idx, 1); if (!props.cascade && (props.withChildren || onlyChildren)) { var children = item.children ? item.children.concat([]) : []; while (children.length) { var child = children.shift(); var index = value.indexOf(child); if (~index) { value.splice(index, 1); } if (child.children && child.children.length) { children.push.apply(children, child.children); } } } } this.setState({ value: value }, function () { var joinValues = props.joinValues, extractValue = props.extractValue, valueField = props.valueField, delimiter = props.delimiter, onChange = props.onChange; onChange(joinValues ? value.map(function (item) { return item[valueField]; }).join(delimiter) : extractValue ? value.map(function (item) { return item[valueField]; }) : value); }); }; TreeSelector.prototype.handleAdd = function (parent) { if (parent === void 0) { parent = null; } var _a = this.props, bultinCUD = _a.bultinCUD, onAdd = _a.onAdd, options = _a.options; if (!bultinCUD) { var idxes = helper_1.findTreeIndex(options, function (item) { return item === parent; }) || []; return onAdd && onAdd(idxes.concat(0)); } else { this.setState({ isEditing: false, isAdding: true, addingParent: parent }); } }; TreeSelector.prototype.handleEdit = function (item) { var _a = this.props, bultinCUD = _a.bultinCUD, onEdit = _a.onEdit, labelField = _a.labelField, options = _a.options; if (!bultinCUD) { onEdit === null || onEdit === void 0 ? void 0 : onEdit(item); } else { this.setState({ isEditing: true, isAdding: false, editingItem: item, inputValue: item[labelField] }); } }; TreeSelector.prototype.handleRemove = function (item) { var onDelete = this.props.onDelete; onDelete && onDelete(item); }; TreeSelector.prototype.handleInputChange = function (e) { this.setState({ inputValue: e.currentTarget.value }); }; TreeSelector.prototype.handleConfirm = function () { var _a = this.state, value = _a.inputValue, isAdding = _a.isAdding, addingParent = _a.addingParent, editingItem = _a.editingItem, isEditing = _a.isEditing; if (!value) { return; } var _b = this.props, labelField = _b.labelField, onAdd = _b.onAdd, options = _b.options, onEdit = _b.onEdit; this.setState({ inputValue: '', isAdding: false, isEditing: false }, function () { var _a, _b; if (isAdding && onAdd) { var idxes = (addingParent && helper_1.findTreeIndex(options, function (item) { return item === addingParent; })) || []; onAdd(idxes.concat(0), (_a = {}, _a[labelField] = value, _a), true); } else if (isEditing && onEdit) { onEdit(tslib_1.__assign(tslib_1.__assign({}, editingItem), (_b = {}, _b[labelField] = value, _b)), editingItem, true); } }); }; TreeSelector.prototype.handleCancel = function () { this.setState({ inputValue: '', isAdding: false, isEditing: false }); }; TreeSelector.prototype.renderInput = function (prfix) { if (prfix === void 0) { prfix = null; } var _a = this.props, cx = _a.classnames, __ = _a.translate; var inputValue = this.state.inputValue; return (react_1.default.createElement("div", { className: cx('Tree-itemLabel') }, react_1.default.createElement("div", { className: cx('Tree-itemInput') }, prfix, react_1.default.createElement("input", { onChange: this.handleInputChange, value: inputValue, placeholder: __('placeholder.enter') }), react_1.default.createElement("a", { "data-tooltip": __('cancel'), onClick: this.handleCancel }, react_1.default.createElement(icons_1.Icon, { icon: "close", className: "icon" })), react_1.default.createElement("a", { "data-tooltip": __('confirm'), onClick: this.handleConfirm }, react_1.default.createElement(icons_1.Icon, { icon: "check", className: "icon" }))))); }; TreeSelector.prototype.renderList = function (list, value, uncheckable) { var _this = this; var _a = this.props, itemClassName = _a.itemClassName, showIcon = _a.showIcon, showRadio = _a.showRadio, multiple = _a.multiple, disabled = _a.disabled, labelField = _a.labelField, valueField = _a.valueField, iconField = _a.iconField, disabledField = _a.disabledField, cascade = _a.cascade, selfDisabledAffectChildren = _a.selfDisabledAffectChildren, onlyChildren = _a.onlyChildren, cx = _a.classnames, highlightTxt = _a.highlightTxt, options = _a.options, maxLength = _a.maxLength, minLength = _a.minLength, creatable = _a.creatable, editable = _a.editable, removable = _a.removable, createTip = _a.createTip, editTip = _a.editTip, removeTip = _a.removeTip, __ = _a.translate; var _b = this.state, stateValue = _b.value, isAdding = _b.isAdding, addingParent = _b.addingParent, editingItem = _b.editingItem, isEditing = _b.isEditing; var childrenChecked = 0; var ret = list.map(function (item, key) { if (!helper_1.isVisible(item, options)) { return null; } var checked = !!~value.indexOf(item); var selfDisabled = item[disabledField]; var selfChecked = !!uncheckable || checked; var childrenItems = null; var selfChildrenChecked = false; if (item.children && item.children.length) { childrenItems = _this.renderList(item.children, value, cascade ? false : uncheckable || (selfDisabledAffectChildren ? selfDisabled : false) || (multiple && checked)); selfChildrenChecked = !!childrenItems.childrenChecked; if (!selfChecked && onlyChildren && item.children.length === childrenItems.childrenChecked) { selfChecked = true; } childrenItems = childrenItems.dom; } if ((onlyChildren ? selfChecked : selfChildrenChecked) || checked) { childrenChecked++; } var nodeDisabled = !!uncheckable || !!disabled || selfDisabled; if (!nodeDisabled && ((maxLength && !selfChecked && stateValue.length >= maxLength) || (minLength && selfChecked && stateValue.length <= minLength))) { nodeDisabled = true; } var checkbox = multiple ? (react_1.default.createElement(Checkbox_1.default, { size: "sm", disabled: nodeDisabled, checked: selfChecked || (!cascade && selfChildrenChecked), partial: !selfChecked, onChange: _this.handleCheck.bind(_this, item, !selfChecked) })) : showRadio ? (react_1.default.createElement(Checkbox_1.default, { size: "sm", disabled: nodeDisabled, checked: checked, onChange: _this.handleSelect.bind(_this, item) })) : null; var isLeaf = (!item.children || !item.children.length) && !item.placeholder; return (react_1.default.createElement("li", { key: key, className: cx("Tree-item " + (itemClassName || ''), { 'Tree-item--isLeaf': isLeaf }) }, isEditing && editingItem === item ? (_this.renderInput(checkbox)) : (react_1.default.createElement("div", { className: cx('Tree-itemLabel', { 'is-children-checked': multiple && !cascade && selfChildrenChecked && !nodeDisabled, 'is-checked': checked, 'is-disabled': nodeDisabled }) }, item.loading ? (react_1.default.createElement(Spinner_1.default, { size: "sm", show: true, icon: "reload", spinnerClassName: cx('Tree-spinner') })) : !isLeaf || (item.defer && !item.loaded) ? (react_1.default.createElement("div", { onClick: function () { return _this.toggleUnfolded(item); }, className: cx('Tree-itemArrow', { 'is-folded': !_this.isUnfolded(item) }) }, react_1.default.createElement(icons_1.Icon, { icon: "right-arrow-bold", className: "icon" }))) : (react_1.default.createElement("span", { className: cx('Tree-itemArrowPlaceholder') })), checkbox, showIcon ? (react_1.default.createElement("i", { className: cx("Tree-itemIcon " + (item[iconField] || (childrenItems ? 'Tree-folderIcon' : 'Tree-leafIcon'))), onClick: function () { return !nodeDisabled && (multiple ? _this.handleCheck(item, !selfChecked) : _this.handleSelect(item)); } }, react_1.default.createElement(icons_1.Icon, { icon: childrenItems ? 'folder' : 'file', className: "icon" }))) : null, react_1.default.createElement("span", { className: cx('Tree-itemText'), onClick: function () { return !nodeDisabled && (multiple ? _this.handleCheck(item, !selfChecked) : _this.handleSelect(item)); } }, highlightTxt ? Options_1.highlight("" + item[labelField], highlightTxt) : "" + item[labelField]), !nodeDisabled && !isAdding && !isEditing && !(item.defer && !item.loaded) ? (react_1.default.createElement("div", { className: cx('Tree-item-icons') }, creatable && helper_1.hasAbility(item, 'creatable') ? (react_1.default.createElement("a", { onClick: _this.handleAdd.bind(_this, item), "data-tooltip": __(createTip), "data-position": "left" }, react_1.default.createElement(icons_1.Icon, { icon: "plus", className: "icon" }))) : null, removable && helper_1.hasAbility(item, 'removable') ? (react_1.default.createElement("a", { onClick: _this.handleRemove.bind(_this, item), "data-tooltip": __(removeTip), "data-position": "left" }, react_1.default.createElement(icons_1.Icon, { icon: "minus", className: "icon" }))) : null, editable && helper_1.hasAbility(item, 'editable') ? (react_1.default.createElement("a", { onClick: _this.handleEdit.bind(_this, item), "data-tooltip": __(editTip), "data-position": "left" }, react_1.default.createElement(icons_1.Icon, { icon: "pencil", className: "icon" }))) : null)) : null)), (childrenItems && _this.isUnfolded(item)) || (isAdding && addingParent === item) ? (react_1.default.createElement("ul", { className: cx('Tree-sublist') }, isAdding && addingParent === item ? (react_1.default.createElement("li", { className: cx('Tree-item') }, _this.renderInput(checkbox ? react_1.default.cloneElement(checkbox, { checked: false, disabled: true }) : null))) : null, childrenItems)) : !childrenItems && item.placeholder && _this.isUnfolded(item) ? (react_1.default.createElement("ul", { className: cx('Tree-sublist') }, react_1.default.createElement("li", { className: cx('Tree-item') }, react_1.default.createElement("div", { className: cx('Tree-placeholder') }, item.placeholder)))) : null)); }); return { dom: ret, childrenChecked: childrenChecked }; }; TreeSelector.prototype.render = function () { var _a = this.props, className = _a.className, placeholder = _a.placeholder, hideRoot = _a.hideRoot, rootLabel = _a.rootLabel, showOutline = _a.showOutline, showIcon = _a.showIcon, cx = _a.classnames, creatable = _a.creatable, rootCreatable = _a.rootCreatable, rootCreateTip = _a.rootCreateTip, disabled = _a.disabled, __ = _a.translate; var options = this.props.options; var _b = this.state, value = _b.value, isAdding = _b.isAdding, addingParent = _b.addingParent, isEditing = _b.isEditing, inputValue = _b.inputValue; var addBtn = null; if (creatable && rootCreatable !== false && hideRoot) { addBtn = (react_1.default.createElement("a", { className: cx('Tree-addTopBtn', { 'is-disabled': isAdding || isEditing }), onClick: this.handleAdd.bind(this, null) }, react_1.default.createElement(icons_1.Icon, { icon: "plus", className: "icon" }), react_1.default.createElement("span", null, __(rootCreateTip)))); } return (react_1.default.createElement("div", { className: cx("Tree " + (className || ''), { 'Tree--outline': showOutline, 'is-disabled': disabled }) }, (options && options.length) || addBtn || hideRoot === false ? (react_1.default.createElement("ul", { className: cx('Tree-list') }, hideRoot ? (react_1.default.createElement(react_1.default.Fragment, null, addBtn, isAdding && !addingParent ? (react_1.default.createElement("li", { className: cx('Tree-item') }, this.renderInput())) : null, this.renderList(options, value, false).dom)) : (react_1.default.createElement("li", { className: cx('Tree-rootItem', { 'is-checked': !value || !value.length }) }, react_1.default.createElement("div", { className: cx('Tree-itemLabel') }, react_1.default.createElement("span", { className: cx('Tree-itemText'), onClick: this.clearSelect }, showIcon ? (react_1.default.createElement("i", { className: cx('Tree-itemIcon Tree-rootIcon') }, react_1.default.createElement(icons_1.Icon, { icon: "home", className: "icon" }))) : null, rootLabel), !disabled && creatable && rootCreatable !== false && !isAdding && !isEditing ? (react_1.default.createElement("div", { className: cx('Tree-item-icons') }, creatable ? (react_1.default.createElement("a", { onClick: this.handleAdd.bind(this, null), "data-tooltip": rootCreateTip, "data-position": "left" }, react_1.default.createElement(icons_1.Icon, { icon: "plus", className: "icon" }))) : null)) : null), react_1.default.createElement("ul", { className: cx('Tree-sublist') }, isAdding && !addingParent ? (react_1.default.createElement("li", { className: cx('Tree-item') }, this.renderInput())) : null, this.renderList(options, value, false).dom))))) : (react_1.default.createElement("div", { className: cx('Tree-placeholder') }, placeholder)))); }; var _a, _b, _c, _d, _e; TreeSelector.defaultProps = { showIcon: true, showOutline: false, initiallyOpen: true, unfoldedLevel: 0, showRadio: false, multiple: false, disabled: false, withChildren: false, onlyChildren: false, labelField: 'label', valueField: 'value', iconField: 'icon', unfoldedField: 'unfolded', foldedField: 'foled', disabledField: 'disabled', joinValues: true, extractValue: false, delimiter: ',', hideRoot: true, rootLabel: 'Tree.root', rootValue: 0, cascade: false, selfDisabledAffectChildren: true, rootCreateTip: 'Tree.addRoot', createTip: 'Tree.addChild', editTip: 'Tree.editNode', removeTip: 'Tree.removeNode' }; tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object]), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "toggleUnfolded", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", []), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "clearSelect", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object, Object]), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "handleSelect", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object, Boolean]), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "handleCheck", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [typeof (_a = typeof Select_1.Option !== "undefined" && Select_1.Option) === "function" ? _a : Object]), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "handleAdd", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [typeof (_b = typeof Select_1.Option !== "undefined" && Select_1.Option) === "function" ? _b : Object]), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "handleEdit", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [typeof (_c = typeof Select_1.Option !== "undefined" && Select_1.Option) === "function" ? _c : Object]), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "handleRemove", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [typeof (_d = typeof react_1.default !== "undefined" && react_1.default.ChangeEvent) === "function" ? _d : Object]), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "handleInputChange", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", []), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "handleConfirm", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", []), tslib_1.__metadata("design:returntype", void 0) ], TreeSelector.prototype, "handleCancel", null); tslib_1.__decorate([ helper_1.autobind, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [typeof (_e = typeof Select_1.Options !== "undefined" && Select_1.Options) === "function" ? _e : Object, Array, Boolean]), tslib_1.__metadata("design:returntype", Object) ], TreeSelector.prototype, "renderList", null); return TreeSelector; }(react_1.default.Component)); exports.TreeSelector = TreeSelector; exports.default = theme_1.themeable(locale_1.localeable(TreeSelector)); //# sourceMappingURL=./components/Tree.js.map