add row actions

This commit is contained in:
2017-08-29 23:10:03 +02:00
parent 76704b2c82
commit 82569aba22
11 changed files with 331 additions and 185 deletions

View File

@@ -11,6 +11,7 @@
</div>
<div v-else>{{ col.heading }}</div>
</div>
<div class="table_cell cell_settings" v-if="actions.length"></div>
</div>
</div>
<div class="table_content" is="transition-group" name="list">
@@ -19,6 +20,25 @@
<div v-if="col.prop">{{ getProp(row, col.prop) }}</div>
<div v-else-if="col.render">{{ col.render(row) }}</div>
</div>
<div class="table_cell cell_settings" v-if="actions.length" ref="row_actions">
<div title="Open actions" class="actions_btn" @click="openActions">
<i class="icon icon-cog" aria-hidden="true"></i>
</div>
<ul class="actions_container">
<li v-for="(a, i) in actions">
<div :title="a.title" @click="a.action(row)">
<i :class="['icon', a.icon]"></i>
</div>
</li>
<li>
<div title="Close actions" @click="closeActions">
<i class="icon icon-cog"></i>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
@@ -28,11 +48,11 @@
export default {
name: 'My-Table',
props: {
currentOrderBy: {
type: String
},
currentOrderDesc: {
type: Boolean
actions: {
type: Array,
default() {
return [ ];
}
},
columns: {
type: Array,
@@ -45,6 +65,12 @@
default() {
return [ ];
}
},
currentOrderBy: {
type: String
},
currentOrderDesc: {
type: Boolean
}
},
data() {
@@ -68,7 +94,19 @@
}
});
return val;
}
},
openActions(event) {
const parent = event.currentTarget.parentNode;
this.$refs.row_actions.forEach((item) => {
if (item !== parent)
item.classList.remove("open")
});
parent.classList.add("open");
},
closeActions(event) {
const parent = event.currentTarget.parentNode.parentNode.parentNode;
parent.classList.remove("open");
}
}
}
</script>
@@ -150,44 +188,69 @@
*/
/* === Cell settings === */
/*.cell_settings {text-align:right; width:150px; position:relative; right:0px;}
.cell_settings a {color:#000; list-style-type:none;}
.cell_settings .fa-cog {font-size:20px;}
.cell_settings_inner {
position:absolute;
width:205px; height:40px;
top:50%;
right:-3px;
margin-top:-21px;
border-radius:20px;
background:#e0e0e0;
padding:0px 10px;
z-index:-1;
overflow:hidden;
opacity:0;
-webkit-opacity:0;
-moz-opacity:0;
transition:all 0.3s;
}
.cell_settings_inner_container {float:right;}
.cell_settings_inner_section {float:left; border-right:solid 1px #999; padding:0px 10px;}
.cell_settings_inner_section_last {border:none; padding-right:3px;}
.cell_settings_inner_section ul {list-style-type:none;}
.cell_settings_inner_section ul li {float:left; padding-right:7px;}
.cell_settings_inner_section_last ul li {padding:0px;}
.cell_settings_inner_section ul li a {color:#000;}
.cell_settings_inner_section ul li .fa {line-height:40px; font-size:20px;}
.cell_settings {
.clearfix();
position:relative;
width: 40px;
text-align: right;
.cell_settings_click, .cell_settings_close {cursor:pointer;}
.cell_settings a:hover, .cell_settings_click:hover {color:#28b78d!important;}
.actions_btn{
z-index: 20;
&:hover{
cursor: pointer;
color: @cms_brand_primary;
}
}
.cell_settings_inner_open {
opacity:1;
-webkit-opacity:1;
-moz-opacity:1;
width:205px;
z-index:600;
transition:all 0.3s;
}*/
.icon {
font-size: 16px;
}
.actions_container {
position: absolute;
z-index: -1;
top: -5px;
right: 0;
padding: 5px 10px;
opacity: 0;
overflow: hidden;
border-radius: 20px;
background: @cms_bg_lighter;
transition: all 0.3s;
white-space: nowrap;
li {
display: inline-block;
&:last-child{
border-left: 1px solid @text_color;
padding-left: 5px;
.icon:before{
margin-right: 0;
}
}
}
li+li{
margin-left: 5px;
}
.icon {
color: @text_color;
&:hover{
cursor: pointer;
color: @cms_brand_primary;
}
}
}
&.open {
.actions_container{
opacity: 1;
z-index: 1;
transition: all 0.3s;
}
}
}
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<div class="Scroll-Table">
<my-input placeholder="Suche" type="text" @change="searchChanged" v-model="currentSearch"></my-input>
<my-table :columns="columns" :rows="rows"
<my-table :actions="actions" :columns="columns" :rows="rows"
:currentOrderBy="currentOrderBy"
:currentOrderDesc="currentOrderDesc"
@sort="sort">
@@ -20,127 +20,132 @@ import MyInput from './my-input.vue';
import { ObserveVisibility } from 'vue-observe-visibility/dist/vue-observe-visibility';
export default {
name: "ScrollTable",
directives: {
ObserveVisibility
},
components: {
MyTable,
MyInput
},
props: {
columns: {
type: Array,
default() {
name: "ScrollTable",
directives: {
ObserveVisibility
},
components: {
MyTable,
MyInput
},
props: {
actions: {
type: Array,
default() {
return [ ];
}
},
newRows: {
type: Array,
default() {
return [ ];
}
},
offset: {
type: Number,
default: 0
},
limit: {
type: Number,
default: 10
},
orderBy: {
type: String
},
orderDesc: {
type: Boolean,
default: false
},
search: {
type: String
},
loading: {
type: Boolean,
default: false
},
hasMore: {
type: Boolean,
default: true
},
handler: {
type: Function,
default: () => {}
}
},
watch: {
newRows(rows) {
rows.forEach(row => {
this.rowsToPush.push(row);
});
this.currentOffset += rows.length;
}
},
columns: {
type: Array,
default() {
return [ ];
}
},
newRows: {
type: Array,
default() {
return [ ];
}
},
offset: {
type: Number,
default: 0
},
limit: {
type: Number,
default: 10
},
orderBy: {
type: String
},
orderDesc: {
type: Boolean,
default: false
},
search: {
type: String
},
loading: {
type: Boolean,
default: false
},
hasMore: {
type: Boolean,
default: true
},
handler: {
type: Function,
default: () => {}
}
},
watch: {
newRows(rows) {
rows.forEach(row => {
this.rowsToPush.push(row);
});
this.currentOffset += rows.length;
this.pushRows(); // for transition
},
loading(l) {
if (!l) {
if (!l) {
// delay after loading for visibility observer
setTimeout(() => {
this.loadingDelayed = false;
this.loadingDelayed = false;
}, 200);
} else {
this.loadingDelayed = true;
this.loadingDelayed = true;
}
}
},
data() {
return {
rows: [ ],
rowsToPush: [ ],
currentOffset: this.offset,
currentOrderBy: this.orderBy,
currentOrderDesc: this.orderDesc,
currentSearch: this.search,
loadingDelayed: false,
reloadTriggered: false
}
return {
rows: [ ],
rowsToPush: [ ],
currentOffset: this.offset,
currentOrderBy: this.orderBy,
currentOrderDesc: this.orderDesc,
currentSearch: this.search,
loadingDelayed: false,
reloadTriggered: false
}
},
methods: {
visibilityChanged(isVisible, entry) {
if (isVisible) {
visibilityChanged(isVisible, entry) {
if (isVisible) {
// infinite scrolling
this.reloadTriggered = false;
this.handler(this.currentOffset, this.limit, this.currentOrderBy, this.currentOrderDesc, this.currentSearch);
}
},
pushRows() {
let row = this.rowsToPush.shift();
if (row) {
this.rows.push(row);
setTimeout(() => {
this.pushRows();
}, 20);
}
let row = this.rowsToPush.shift();
if (row) {
this.rows.push(row);
setTimeout(() => {
this.pushRows();
}, 20);
}
},
clear() {
this.currentOffset = 0;
this.rows = [];
this.rowsToPush = [];
this.currentOffset = 0;
this.rows = [];
this.rowsToPush = [];
},
sort(e) {
if (e.orderBy == this.currentOrderBy) {
this.currentOrderDesc = !this.currentOrderDesc;
} else {
this.currentOrderDesc = false;
}
this.currentOrderBy = e.orderBy;
this.reloadTriggered = true;
this.clear();
if (e.orderBy == this.currentOrderBy) {
this.currentOrderDesc = !this.currentOrderDesc;
} else {
this.currentOrderDesc = false;
}
this.currentOrderBy = e.orderBy;
this.reloadTriggered = true;
this.clear();
},
searchChanged(e) {
this.currentSearch = e;
this.reloadTriggered = true;
this.clear();
this.currentSearch = e;
this.reloadTriggered = true;
this.clear();
}
}
}
</script>