improve styles and behavior of the col editor, preparing for backend impl
This commit is contained in:
@@ -5,13 +5,13 @@ Complex animated column editor for the table edit page
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<input type="hidden" :name="name" :value="JSON.stringify(columns)" v-if="newTable">
|
<input type="hidden" :name="name" :value="JSON.stringify(columns)" v-if="newTable">
|
||||||
<table class="editor-table">
|
<table :class="[{'table': !newTable},{'new-table': newTable},'table-narrow','table-sm','table-fixed','td-va-middle']">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-if="sortable"></th>
|
<th v-if="sortable"></th>
|
||||||
<th>Name</th>
|
<th :style="tdWidthStyle('name')">Name</th>
|
||||||
<th>Type</th>
|
<th :style="tdWidthStyle('type')">Type</th>
|
||||||
<th>Title</th>
|
<th :style="tdWidthStyle('title')">Title</th>
|
||||||
<th v-if="!newTable"></th>
|
<th v-if="!newTable"></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
@@ -19,65 +19,81 @@ Complex animated column editor for the table edit page
|
|||||||
</thead>
|
</thead>
|
||||||
<transition-group name="col-list" tag="tbody" ref="col-list">
|
<transition-group name="col-list" tag="tbody" ref="col-list">
|
||||||
<tr v-for="(col, i) in columns" :key="col.id" :ref="`col${i}`" :class="{dragging: col._dragging}">
|
<tr v-for="(col, i) in columns" :key="col.id" :ref="`col${i}`" :class="{dragging: col._dragging}">
|
||||||
<td class="btn-group" v-if="sortable">
|
<td v-if="sortable">
|
||||||
<button type="button" class="btn btn-outline-secondary drag-btn"
|
<span class="btn-group">
|
||||||
@keyup.up="move(i, -1)"
|
<button type="button" class="btn btn-outline-secondary drag-btn"
|
||||||
@keyup.down="move(i, 1)"
|
@keyup.up="move(i, -1)"
|
||||||
:ref="`col${i}-sort`"
|
@keyup.down="move(i, 1)"
|
||||||
@mousedown="beginDrag(i, $event)">
|
:ref="`col${i}-sort`"
|
||||||
<v-icon class="fa-bars" alt="Drag" />
|
:style="{visibility: (columns.length > 1) ? 'visible' : 'hidden'}"
|
||||||
</button><!--
|
@mousedown="beginDrag(i, $event)">
|
||||||
--><button type="button" :class="['btn', 'btn-outline-secondary', {disabled: i==0}]" v-if="manualSort"
|
<v-icon class="fa-bars" alt="Drag" />
|
||||||
@click.prevent="move(i, -1)">
|
</button><!--
|
||||||
<v-icon class="fa-chevron-up" alt="Move Up" />
|
--><button type="button" :class="['btn', 'btn-outline-secondary', {disabled: i==0}]" v-if="manualSort"
|
||||||
</button><!--
|
@click.prevent="move(i, -1)">
|
||||||
--><button type="button" :class="['btn', 'btn-outline-secondary', {disabled: i == (columns.length-1)}]" v-if="manualSort"
|
<v-icon class="fa-chevron-up" alt="Move Up" />
|
||||||
@click.prevent="move(i, 1)">
|
</button><!--
|
||||||
<v-icon class="fa-chevron-down" alt="Move Down" />
|
--><button type="button" :class="['btn', 'btn-outline-secondary', {disabled: i == (columns.length-1)}]" v-if="manualSort"
|
||||||
</button>
|
@click.prevent="move(i, 1)">
|
||||||
|
<v-icon class="fa-chevron-down" alt="Move Down" />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<template v-if="col._editing || newTable">
|
||||||
<input v-model="col.name"
|
<!-- Editable cells -->
|
||||||
@input="markColNeedSave(i)"
|
<td :style="tdWidthStyle('name')">
|
||||||
class="form-control"
|
<input v-model="col.name"
|
||||||
type="text"
|
class="form-control"
|
||||||
style="width: 140px">
|
type="text">
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td :style="tdWidthStyle('type')">
|
||||||
<select v-model="col.type"
|
<select v-model="col.type"
|
||||||
@input="markColNeedSave(i)"
|
class="form-control custom-select">
|
||||||
class="form-control custom-select"
|
<option v-for="t in colTypes" :value="t">{{t}}</option>
|
||||||
style="width: 110px">
|
</select>
|
||||||
<option v-for="t in colTypes" :value="t">{{t}}</option>
|
</td>
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
<td :style="tdWidthStyle('title')">
|
||||||
<input v-model="col.title"
|
<input v-model="col.title"
|
||||||
@input="markColNeedSave(i)"
|
class="form-control"
|
||||||
class="form-control"
|
type="text">
|
||||||
type="text"
|
</td>
|
||||||
style="width: 170px">
|
</template>
|
||||||
</td>
|
|
||||||
|
<template v-else>
|
||||||
|
<!-- Value fields -->
|
||||||
|
<td v-for='cell in ["name", "type", "title"]'>
|
||||||
|
<span class="text-danger strike" title="Original value" v-if="isChanged(col, cell)">{{col._orig[cell]}}</span>
|
||||||
|
<span>{{ col[cell] }}</span>
|
||||||
|
<v-icon v-if="isChanged(col, cell)"
|
||||||
|
@click="revertCell(col, cell)"
|
||||||
|
class="fa-undo text-danger pointer"
|
||||||
|
alt="Revert Change" />
|
||||||
|
</td>
|
||||||
|
</template>
|
||||||
|
|
||||||
<td v-if="!newTable">
|
<td v-if="!newTable">
|
||||||
<button type="button" :class="['btn', col._dirty ? 'btn-info' : 'btn-outline-secondary']"
|
<!-- Save button -->
|
||||||
@click.prevent="saveCol(i)">
|
<a href="" :class="['btn','btn-outline-secondary',{'disabled': col._remove}]"
|
||||||
<v-icon class="fa-save" alt="Save" />
|
@click.prevent="toggleColEditing(col)">
|
||||||
</button>
|
<v-icon :class="col._editing ? 'fa-save' : 'fa-pencil'"
|
||||||
|
:alt="col._editing ? 'Save' : 'Edit'" />
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
<!-- Delete button -->
|
||||||
<button type="button" :class="delBtnClass(col)"
|
<button type="button" :class="delBtnClass(col)"
|
||||||
@click.prevent="toggleColDelete(i)">
|
@click.prevent="toggleColDelete(col)">
|
||||||
<v-icon :class="col._remove ? 'fa-undo' : 'fa-trash-o'"
|
<v-icon :class="col._remove ? 'fa-undo' : 'fa-trash-o'"
|
||||||
:alt="col._remove ? 'Undo Remove' : 'Remove'" />
|
:alt="col._remove ? 'Undo Remove' : 'Remove'" />
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
<!-- Add button -->
|
||||||
<button type="button" :class="['btn', 'btn-outline-secondary']"
|
<button type="button" :class="['btn', 'btn-outline-secondary']"
|
||||||
v-if="i === columns.length - 1"
|
v-if="i === columns.length - 1"
|
||||||
@click.prevent="addCol()">
|
@click.prevent="addCol()">
|
||||||
@@ -93,8 +109,10 @@ Complex animated column editor for the table edit page
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "base";
|
@import "base";
|
||||||
|
|
||||||
table {
|
@media screen and (min-width: 625px) {
|
||||||
border-collapse: collapse;
|
table.new-table {
|
||||||
|
margin-left: -53px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td, th {
|
td, th {
|
||||||
@@ -102,15 +120,23 @@ Complex animated column editor for the table edit page
|
|||||||
@include py(1);
|
@include py(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
border-top: 0 none;
|
||||||
|
}
|
||||||
|
|
||||||
tr.dragging {
|
tr.dragging {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background-color: $body-bg;
|
//background-color: $body-bg;
|
||||||
|
}
|
||||||
|
tr.dragging .btn {
|
||||||
|
background-color: $body-bg; // no see-through buttons
|
||||||
}
|
}
|
||||||
tr.dragging .drag-btn {
|
tr.dragging .drag-btn {
|
||||||
// fake hover
|
// fake hover
|
||||||
background-color: $secondary;
|
background-color: $secondary;
|
||||||
color: color-yiq($secondary);
|
color: color-yiq($secondary);
|
||||||
|
box-shadow: $btn-box-shadow, 0 0 0 $btn-focus-width rgba($secondary, .5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.col-list-enter-active {
|
.col-list-enter-active {
|
||||||
@@ -169,6 +195,7 @@ export default {
|
|||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
newColNum: 0,
|
||||||
columns: this.xColumns,
|
columns: this.xColumns,
|
||||||
colTypes: ['string', 'int', 'float', 'bool'],
|
colTypes: ['string', 'int', 'float', 'bool'],
|
||||||
}
|
}
|
||||||
@@ -179,11 +206,35 @@ export default {
|
|||||||
query(this.route, data, sucfn, erfn)
|
query(this.route, data, sucfn, erfn)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
colPos(col) {
|
||||||
|
for (let n = 0; n < this.columns.length; n++) {
|
||||||
|
if (this.columns[n].id == col.id) return n;
|
||||||
|
}
|
||||||
|
throw `Col ${col.id} not found in list`;
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Save a change */
|
||||||
|
submitColChange (col) {
|
||||||
|
if (_.isUndefined(col)) return
|
||||||
|
let n = this.colPos(col)
|
||||||
|
|
||||||
|
this.query({
|
||||||
|
action: 'col.update',
|
||||||
|
data: col
|
||||||
|
}, (resp) => {
|
||||||
|
this.$set(this.columns, n, resp.data)
|
||||||
|
}, (er) => {
|
||||||
|
if (!_.isUndefined(er.errors)) {
|
||||||
|
this.$set(this.columns[n], '_errors', er.errors)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
/** Add a column at the end */
|
/** Add a column at the end */
|
||||||
addCol () {
|
addCol () {
|
||||||
if (this.newTable) {
|
if (this.newTable) {
|
||||||
this.columns.push({
|
this.columns.push({
|
||||||
id: Math.random().toString(),
|
id: '_' + (this.newColNum++),
|
||||||
name: '',
|
name: '',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -218,11 +269,6 @@ export default {
|
|||||||
setTimeout(() => this.$refs[`col${pos2}-sort`][0].focus(), 0)
|
setTimeout(() => this.$refs[`col${pos2}-sort`][0].focus(), 0)
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Indicate a column is dirty and needs saving */
|
|
||||||
markColNeedSave(i) {
|
|
||||||
this.$set(this.columns[i], '_dirty', true)
|
|
||||||
},
|
|
||||||
|
|
||||||
/** User started dragging a column */
|
/** User started dragging a column */
|
||||||
beginDrag (i, evt) {
|
beginDrag (i, evt) {
|
||||||
const column = this.columns[i]
|
const column = this.columns[i]
|
||||||
@@ -274,29 +320,14 @@ export default {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Save a column */
|
|
||||||
saveCol(n) {
|
|
||||||
let col = this.columns[n]
|
|
||||||
if (_.isUndefined(col)) return
|
|
||||||
|
|
||||||
this.query({
|
|
||||||
action: 'col.update',
|
|
||||||
data: col
|
|
||||||
}, (resp) => {
|
|
||||||
this.$set(this.columns, n, resp.data)
|
|
||||||
}, (er) => {
|
|
||||||
if (!_.isUndefined(er.errors)) {
|
|
||||||
this.$set(this.columns[n], '_errors', er.errors)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
/** Delete / undelete a column; New columns vanish. */
|
/** Delete / undelete a column; New columns vanish. */
|
||||||
toggleColDelete(n) {
|
toggleColDelete(col) {
|
||||||
let col = this.columns[n]
|
|
||||||
if (_.isUndefined(col)) return
|
if (_.isUndefined(col)) return
|
||||||
|
let n = this.colPos(col)
|
||||||
|
|
||||||
if (this.newTable) {
|
if (this.newTable) {
|
||||||
|
if (this.columns.length == 1) return; // can't delete the last col
|
||||||
|
|
||||||
// hard delete
|
// hard delete
|
||||||
this.columns.splice(n, 1)
|
this.columns.splice(n, 1)
|
||||||
} else {
|
} else {
|
||||||
@@ -317,6 +348,39 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** Toggle editing state - edit or save */
|
||||||
|
toggleColEditing (col) {
|
||||||
|
if (col._remove) return false // can't edit col marked for removal
|
||||||
|
let editing = !col._editing
|
||||||
|
|
||||||
|
let n = this.colPos(col)
|
||||||
|
|
||||||
|
if (!editing) {
|
||||||
|
this.submitColChange(col)
|
||||||
|
} else {
|
||||||
|
this.$set(this.columns[n], '_editing', true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Test if a value cell is changed */
|
||||||
|
isChanged (col, cell) {
|
||||||
|
return col._changed && col._changed.indexOf(cell) > -1
|
||||||
|
},
|
||||||
|
|
||||||
|
/** Revert a value cell */
|
||||||
|
revertCell (col, cell) {
|
||||||
|
this.submitColChange(_.merge({}, col, {[cell]: col._orig[cell]}))
|
||||||
|
},
|
||||||
|
|
||||||
|
tdWidthStyle(cell) {
|
||||||
|
let w = 100;
|
||||||
|
if (cell == 'name') w = '14'
|
||||||
|
if (cell == 'type') w = '12'
|
||||||
|
if (cell == 'title') w = '14'
|
||||||
|
|
||||||
|
return {width: `${w}rem`};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ Rows are identified by row._id, columns by col.id
|
|||||||
<table class="table table-hover table-sm table-fixed td-va-middle">
|
<table class="table table-hover table-sm table-fixed td-va-middle">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style="width:3rem" class="border-top-0"></th>
|
<th style="width:3rem"></th>
|
||||||
<th style="width:3rem" class="border-top-0"></th>
|
<th style="width:3rem"></th>
|
||||||
<th v-for="col in columns" :class="colClasses(col)" :title="col.name">{{col.title}}</th>
|
<th v-for="col in columns" :class="colClasses(col)" :title="col.name">{{col.title}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -62,6 +62,10 @@ Rows are identified by row._id, columns by col.id
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "base";
|
@import "base";
|
||||||
|
|
||||||
|
th {
|
||||||
|
border-top: 0 none;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -133,14 +137,11 @@ Rows are identified by row._id, columns by col.id
|
|||||||
|
|
||||||
/** Compute classes for a value cell */
|
/** Compute classes for a value cell */
|
||||||
colClasses (col) {
|
colClasses (col) {
|
||||||
return [
|
return {
|
||||||
'border-top-0',
|
'text-danger': col._remove,
|
||||||
{
|
'strike': col._remove,
|
||||||
'text-danger': col._remove,
|
'text-success': col._new
|
||||||
'strike': col._remove,
|
}
|
||||||
'text-success': col._new
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Compute style for a row */
|
/** Compute style for a row */
|
||||||
|
|||||||
@@ -7,3 +7,7 @@
|
|||||||
vertical-align: middle !important;
|
vertical-align: middle !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table.table-narrow {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@
|
|||||||
name: 'columns',
|
name: 'columns',
|
||||||
xColumns: {!! old('columns', toJSON($columns)) !!},
|
xColumns: {!! old('columns', toJSON($columns)) !!},
|
||||||
newTable: true,
|
newTable: true,
|
||||||
|
//sortable: false,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user