2
0
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:
sahil28297 2018-10-01 20:22:45 +05:30 committed by Faris Ansari
parent d1d1410db7
commit 1827d62464

View File

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