primevue-mirror/components/treetable/TreeTableRow.vue

257 lines
9.0 KiB
Vue
Executable File

<template>
<tr :class="containerClass" @click="onClick" @keydown="onKeyDown" @touchend="onTouchEnd" :style="node.style" tabindex="0">
<template v-for="(col,i) of columns" :key="columnProp(col, 'columnKey')||columnProp(col, 'field')||i">
<TTBodyCell v-if="!columnProp(col, 'hidden')" :column="col" :node="node"
:level="level" :leaf="leaf" :indentation="indentation" :expanded="expanded" :selectionMode="selectionMode"
:checked="checked" :partialChecked="partialChecked"
@node-toggle="$emit('node-toggle', $event)" @checkbox-toggle="toggleCheckbox"></TTBodyCell>
</template>
</tr>
<template v-if="expanded && node.children && node.children.length">
<TreeTableRow v-for="childNode of node.children" :key="childNode.key" :columns="columns" :node="childNode" :parentNode="node" :level="level + 1"
:expandedKeys="expandedKeys" :selectionMode="selectionMode" :selectionKeys="selectionKeys" :indentation="indentation"
@node-toggle="$emit('node-toggle', $event)" @node-click="$emit('node-click', $event)" @checkbox-change="onCheckboxChange" />
</template>
</template>
<script>
import {DomHandler, ObjectUtils} from 'primevue/utils';
import BodyCell from './BodyCell.vue';
export default {
name: 'TreeTableRow',
emits: ['node-click', 'node-toggle', 'checkbox-change','nodeClick', 'nodeToggle', 'checkboxChange'],
props: {
node: {
type: null,
default: null
},
parentNode: {
type: null,
default: null
},
columns: {
type: null,
default: null
},
expandedKeys: {
type: null,
default: null
},
selectionKeys: {
type: null,
default: null
},
selectionMode: {
type: String,
default: null
},
level: {
type: Number,
default: 0
},
indentation: {
type: Number,
default: 1
}
},
nodeTouched: false,
methods: {
columnProp(col, prop) {
return ObjectUtils.getVNodeProp(col, prop);
},
toggle() {
this.$emit('node-toggle', this.node);
},
onClick(event) {
if (DomHandler.isClickable(event.target) ||
DomHandler.hasClass(event.target, 'p-treetable-toggler') || DomHandler.hasClass(event.target.parentElement, 'p-treetable-toggler')) {
return;
}
this.$emit('node-click', {
originalEvent: event,
nodeTouched: this.nodeTouched,
node: this.node
});
this.nodeTouched = false;
},
onTouchEnd() {
this.nodeTouched = true;
},
onKeyDown(event) {
if (event.target === this.$el) {
const rowElement = this.$el;
switch (event.which) {
//down arrow
case 40: {
const nextRow = rowElement.nextElementSibling;
if (nextRow) {
nextRow.focus();
}
event.preventDefault();
break;
}
//up arrow
case 38: {
const previousRow = rowElement.previousElementSibling;
if (previousRow) {
previousRow.focus();
}
event.preventDefault();
break;
}
//right-left arrows
case 37:
case 39: {
if (!this.leaf) {
this.$emit('node-toggle', this.node);
event.preventDefault();
}
break;
}
//enter
case 13: {
this.onClick(event);
event.preventDefault();
break;
}
default:
//no op
break;
}
}
},
toggleCheckbox() {
let _selectionKeys = this.selectionKeys ? {...this.selectionKeys} : {};
const _check = !this.checked;
this.propagateDown(this.node, _check, _selectionKeys);
this.$emit('checkbox-change', {
node: this.node,
check: _check,
selectionKeys: _selectionKeys
});
},
propagateDown(node, check, selectionKeys) {
if (check)
selectionKeys[node.key] = {checked: true, partialChecked: false};
else
delete selectionKeys[node.key];
if (node.children && node.children.length) {
for (let child of node.children) {
this.propagateDown(child, check, selectionKeys);
}
}
},
propagateUp(event) {
let check = event.check;
let _selectionKeys = {...event.selectionKeys};
let checkedChildCount = 0;
let childPartialSelected = false;
for(let child of this.node.children) {
if(_selectionKeys[child.key] && _selectionKeys[child.key].checked)
checkedChildCount++;
else if(_selectionKeys[child.key] && _selectionKeys[child.key].partialChecked)
childPartialSelected = true;
}
if(check && checkedChildCount === this.node.children.length) {
_selectionKeys[this.node.key] = {checked: true, partialChecked: false};
}
else {
if (!check) {
delete _selectionKeys[this.node.key];
}
if(childPartialSelected || (checkedChildCount > 0 && checkedChildCount !== this.node.children.length))
_selectionKeys[this.node.key] = {checked: false, partialChecked: true};
else
_selectionKeys[this.node.key] = {checked: false, partialChecked: false};
}
this.$emit('checkbox-change', {
node: event.node,
check: event.check,
selectionKeys: _selectionKeys
});
},
onCheckboxChange(event) {
let check = event.check;
let _selectionKeys = {...event.selectionKeys};
let checkedChildCount = 0;
let childPartialSelected = false;
for(let child of this.node.children) {
if(_selectionKeys[child.key] && _selectionKeys[child.key].checked)
checkedChildCount++;
else if(_selectionKeys[child.key] && _selectionKeys[child.key].partialChecked)
childPartialSelected = true;
}
if(check && checkedChildCount === this.node.children.length) {
_selectionKeys[this.node.key] = {checked: true, partialChecked: false};
}
else {
if (!check) {
delete _selectionKeys[this.node.key];
}
if(childPartialSelected || (checkedChildCount > 0 && checkedChildCount !== this.node.children.length))
_selectionKeys[this.node.key] = {checked: false, partialChecked: true};
else
_selectionKeys[this.node.key] = {checked: false, partialChecked: false};
}
this.$emit('checkbox-change', {
node: event.node,
check: event.check,
selectionKeys: _selectionKeys
});
}
},
computed: {
containerClass() {
return [this.node.styleClass, {
'p-highlight': this.selected
}]
},
hasChildren() {
return this.node.children && this.node.children.length > 0;
},
expanded() {
return this.expandedKeys && this.expandedKeys[this.node.key] === true;
},
leaf() {
return this.node.leaf === false ? false : !(this.node.children && this.node.children.length);
},
selected() {
return (this.selectionMode && this.selectionKeys) ? this.selectionKeys[this.node.key] === true : false;
},
childLevel() {
return this.level + 1;
},
checked() {
return this.selectionKeys ? this.selectionKeys[this.node.key] && this.selectionKeys[this.node.key].checked: false;
},
partialChecked() {
return this.selectionKeys ? this.selectionKeys[this.node.key] && this.selectionKeys[this.node.key].partialChecked: false;
}
},
components: {
'TTBodyCell': BodyCell
}
}
</script>