2
0
mirror of https://github.com/frappe/books.git synced 2024-09-20 11:29:00 +00:00

Added keyboard navigation and delete checked rows features in table (#97)

* Added keyboard navigation and delete checked rows in invoice-table

* cleanup
This commit is contained in:
sahil28297 2018-10-01 20:22:45 +05:30 committed by Faris Ansari
parent d1d1410db7
commit 1827d62464

View File

@ -4,7 +4,7 @@
<thead>
<tr>
<th scope="col" width="60">
<input class="mr-2" type="checkbox">
<input class="mr-2" type="checkbox" @change="toggleCheckAll">
<span>#</span>
</th>
<th scope="col" v-for="column in columns" :key="column.fieldname">
@ -15,35 +15,51 @@
<tbody v-if="rows.length">
<tr v-for="(row, i) in rows" :key="i">
<th scope="row">
<input class="mr-2" type="checkbox" @change="e => onCheck(e, i)">
<input
class="mr-2"
type="checkbox"
:checked="checkedRows.includes(i)"
@change="e => onCheck(e, i)"
>
<span>{{ i + 1 }}</span>
</th>
<td v-for="column in columns" :key="column.fieldname"
tabindex="1"
:ref="column.fieldname + i"
@click="activateFocus(i, column.fieldname)"
@dblclick="activateEditing(i, column.fieldname)"
@click="deactivateEditing(i, column.fieldname)"
@keydown.shift.tab="shiftTabPressOnCell(i, column.fieldname)"
@keydown.tab="tabPressOnCell(i, column.fieldname)"
@keydown.enter="enterPressOnCell(i, column.fieldname)"
@keydown.shift.tab="focusPreviousCell(i, column.fieldname)"
@keydown.tab="focusNextCell(i, column.fieldname)"
@keydown.left="focusPreviousCell(i, column.fieldname)"
@keydown.right="focusNextCell(i, column.fieldname)"
@keydown.up="focusAboveCell(i, column.fieldname)"
@keydown.down="focusBelowCell(i, column.fieldname)"
@keydown.esc="escOnCell(i, column.fieldname)"
>
<frappe-control
v-if="isEditing(i, column.fieldname)"
:docfield="getDocfield(column.fieldname)"
:value="row[column.fieldname]"
:onlyInput="true"
:doc="row"
:autofocus="true"
@change="onCellChange(i, column.fieldname, $event)"
/>
<span v-else>
{{ row[column.fieldname] }}
</span>
<div class="table-cell" :class="{'active': isFocused(i, column.fieldname)}">
<frappe-control
v-if="isEditing(i, column.fieldname)"
:docfield="getDocfield(column.fieldname)"
:value="row[column.fieldname]"
:onlyInput="true"
:doc="row"
:autofocus="true"
@change="onCellChange(i, column.fieldname, $event)"
/>
<span v-else>
{{ row[column.fieldname] || '&nbsp;' }}
</span>
</div>
</td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td :colspan="columns.length + 1" class="text-center">
No Data
<div class="table-cell">
No Data
</div>
</td>
</tr>
</tbody>
@ -56,7 +72,6 @@
</template>
<script>
// import ModelTable from '../ModelTable';
import Base from './Base';
import Observable from 'frappejs/utils/observable';
@ -66,30 +81,79 @@ export default {
return {
columns: [],
checkedRows: [],
currentlyEditing: {}
}
currentlyEditing: {},
currentlyFocused: {}
};
},
mounted() {
this.columns = this.getColumns();
},
methods: {
enterPressOnCell(i, fieldname) {
escOnCell(i, fieldname) {
this.deactivateEditing();
this.activateFocus(i, fieldname);
},
shiftTabPressOnCell(i, fieldname) {
enterPressOnCell(i, fieldname) {
if (this.isEditing(i, fieldname)) {
let pos = this.columns.map(c => c.fieldname).indexOf(fieldname);
this.deactivateEditing();
this.activateFocus(i, fieldname);
} else {
this.activateEditing(i, fieldname);
}
},
focusPreviousCell(i, fieldname) {
if (this.isFocused(i, fieldname) && !this.isEditing(i, fieldname)) {
let pos = this._getColumnIndex(fieldname);
pos = pos - 1;
this.activateEditing(i, this.columns[pos].fieldname);
if (pos < 0) {
i -= 1;
pos = this.columns.length - 1;
}
if (i < 0) {
i = 0;
pos = 0;
}
this.activateFocus(i, this.columns[pos].fieldname);
}
},
tabPressOnCell(i, fieldname) {
if (this.isEditing(i, fieldname)) {
let pos = this.columns.map(c => c.fieldname).indexOf(fieldname);
focusNextCell(i, fieldname) {
if (this.isFocused(i, fieldname) && !this.isEditing(i, fieldname)) {
let pos = this._getColumnIndex(fieldname);
pos = pos + 1;
this.activateEditing(i, this.columns[pos].fieldname);
if (pos > this.columns.length - 1) {
i += 1;
pos = 0;
}
if (i > this.rows.length - 1) {
i = this.rows.length - 1;
pos = this.columns.length - 1;
}
this.activateFocus(i, this.columns[pos].fieldname);
}
},
focusAboveCell(i, fieldname) {
if (this.isFocused(i, fieldname) && !this.isEditing(i, fieldname)) {
let pos = this._getColumnIndex(fieldname);
i -= 1;
if (i < 0) {
i = 0;
}
this.activateFocus(i, this.columns[pos].fieldname);
}
},
focusBelowCell(i, fieldname) {
if (this.isFocused(i, fieldname) && !this.isEditing(i, fieldname)) {
let pos = this._getColumnIndex(fieldname);
i += 1;
if (i > this.rows.length - 1) {
i = this.rows.length - 1;
}
this.activateFocus(i, this.columns[pos].fieldname);
}
},
_getColumnIndex(fieldname) {
return this.columns.map(c => c.fieldname).indexOf(fieldname);
},
onOutsideClick(e) {
this.deactivateEditing();
},
@ -100,6 +164,13 @@ export default {
this.checkedRows = this.checkedRows.filter(i => i !== idx);
}
},
toggleCheckAll() {
if (this.checkedRows.length === this.rows.length) {
this.checkedRows = [];
} else {
this.checkedRows = this.rows.map((row, i) => i);
}
},
getDocfield(fieldname) {
return this.meta.getField(fieldname);
},
@ -107,8 +178,16 @@ export default {
if (this.disabled) {
return false;
}
return this.currentlyEditing.index === i &&
this.currentlyEditing.fieldname === fieldname;
return (
this.currentlyEditing.index === i &&
this.currentlyEditing.fieldname === fieldname
);
},
isFocused(i, fieldname) {
return (
this.currentlyFocused.index === i &&
this.currentlyFocused.fieldname === fieldname
);
},
activateEditing(i, fieldname) {
const docfield = this.columns.find(c => c.fieldname === fieldname);
@ -120,12 +199,27 @@ export default {
fieldname
};
},
activateFocus(i, fieldname) {
this.deactivateEditing();
const docfield = this.columns.find(c => c.fieldname === fieldname);
this.currentlyFocused = {
index: i,
fieldname
};
this.$refs[fieldname + i][0].focus();
},
deactivateEditing(i, _fieldname) {
const { index, fieldname } = this.currentlyEditing;
if (!(index === i && fieldname === _fieldname)) {
this.currentlyEditing = {};
}
},
deactivateFocus(i, _fieldname) {
const { index, fieldname } = this.currentlyFocused;
if (!(index === i && fieldname === _fieldname)) {
this.currentlyFocused = {};
}
},
addRow() {
const rows = this.rows.slice();
const newRow = {
@ -154,7 +248,7 @@ export default {
// make a copy
let rows = this.rows.slice();
rows = rows.filter((row, i) => {
return !indices.includes(i)
return !indices.includes(i);
});
this.emitChange(rows);
@ -190,17 +284,34 @@ export default {
return this.value;
}
}
}
};
</script>
<style>
.table .form-control {
.table-cell .form-control {
padding: 0;
border: none;
box-shadow: none;
outline: none;
}
.table [data-fieldtype="Link"] .input-group-append {
.table td {
padding: 0;
}
.table-cell {
padding: 0.75rem;
border: 1px solid transparent;
}
.table [data-fieldtype='Link'] .input-group-append {
display: none;
}
td {
outline: none;
}
.table-cell.active {
border: 1px solid var(--blue);
}
</style>