mirror of
https://github.com/frappe/books.git
synced 2024-11-10 07:40:55 +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:
parent
d1d1410db7
commit
1827d62464
@ -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,16 +15,29 @@
|
||||
<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)"
|
||||
>
|
||||
<div class="table-cell" :class="{'active': isFocused(i, column.fieldname)}">
|
||||
<frappe-control
|
||||
v-if="isEditing(i, column.fieldname)"
|
||||
:docfield="getDocfield(column.fieldname)"
|
||||
@ -35,15 +48,18 @@
|
||||
@change="onCellChange(i, column.fieldname, $event)"
|
||||
/>
|
||||
<span v-else>
|
||||
{{ row[column.fieldname] }}
|
||||
{{ row[column.fieldname] || ' ' }}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-else>
|
||||
<tr>
|
||||
<td :colspan="columns.length + 1" class="text-center">
|
||||
<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,29 +81,78 @@ 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>
|
||||
|
Loading…
Reference in New Issue
Block a user