add row actions
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -1,7 +1,7 @@
|
||||
@import "mixins";
|
||||
|
||||
@iconfont_path: "~/assets/fonts/";
|
||||
@iconfont_version: 3;
|
||||
@iconfont_version: 4;
|
||||
|
||||
|
||||
@font-face {
|
||||
@@ -19,6 +19,13 @@
|
||||
.icon-search:before { content: '\e800'; } /* '' */
|
||||
.icon-user:before { content: '\e801'; } /* '' */
|
||||
.icon-key:before { content: '\e802'; } /* '' */
|
||||
.icon-cog:before { content: '\e803'; } /* '' */
|
||||
.icon-pencil:before { content: '\e804'; } /* '' */
|
||||
.icon-eye-off:before { content: '\e805'; } /* '' */
|
||||
.icon-cancel:before { content: '\e806'; } /* '' */
|
||||
.icon-ok:before { content: '\e807'; } /* '' */
|
||||
.icon-trash-empty:before { content: '\e808'; } /* '' */
|
||||
.icon-docs:before { content: '\f0c5'; } /* '' */
|
||||
.icon-menu:before { content: '\f0c9'; } /* '' */
|
||||
.icon-angle-left:before { content: '\f104'; } /* '' */
|
||||
.icon-angle-right:before { content: '\f105'; } /* '' */
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
@screen-md: 1024px;
|
||||
@screen-lg: 1200px;
|
||||
|
||||
@text_color: black;
|
||||
|
||||
@cms_bg_lighter: #e0e0e0;
|
||||
@cms_bg_light: #1a2e3b;
|
||||
@cms_dark_border: #152129;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="Userlist">
|
||||
<h1>Userlist</h1>
|
||||
<scroll-table :columns="columns" :new-rows="newRows" :has-more="hasMore" :loading="loading" :handler="more" orderBy="id" :orderDesc="true" limit="50"></scroll-table>
|
||||
<scroll-table :actions="actions" :columns="columns" :new-rows="newRows" :has-more="hasMore" :loading="loading" :handler="more" orderBy="username" :orderDesc="false" limit="50"></scroll-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -15,51 +15,63 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
heading: 'ID',
|
||||
prop: 'ID',
|
||||
orderBy: 'id'
|
||||
},
|
||||
{
|
||||
heading: 'Benutzername',
|
||||
prop: 'Username',
|
||||
orderBy: 'username'
|
||||
},
|
||||
{
|
||||
heading: 'Firma',
|
||||
prop: 'Company',
|
||||
orderBy: 'company'
|
||||
},
|
||||
{
|
||||
heading: 'Nachname',
|
||||
prop: 'Lastname',
|
||||
orderBy: 'lastname'
|
||||
},
|
||||
{
|
||||
heading: 'Vorname',
|
||||
prop: 'Firstname',
|
||||
orderBy: 'firstname'
|
||||
},
|
||||
{
|
||||
heading: 'Email',
|
||||
prop: 'Email',
|
||||
orderBy: 'email'
|
||||
},
|
||||
{
|
||||
heading: 'Reseller',
|
||||
prop: 'Reseller.Username'
|
||||
},
|
||||
{
|
||||
heading: 'Render',
|
||||
render(row) {
|
||||
return 'ID:' + row.ID;
|
||||
}
|
||||
}
|
||||
],
|
||||
newRows: [ ],
|
||||
hasMore: true,
|
||||
loading: false
|
||||
actions: [{
|
||||
title: 'Edit',
|
||||
icon: 'icon-pencil',
|
||||
action(row) {
|
||||
console.log("yay edit", row);
|
||||
}
|
||||
}, {
|
||||
title: 'Duplicate',
|
||||
icon: 'icon-docs',
|
||||
action(row) {
|
||||
console.log("yay duplicate", row);
|
||||
}
|
||||
}, {
|
||||
title: 'Hide',
|
||||
icon: 'icon-eye-off',
|
||||
action(row) {
|
||||
console.log("yay hide", row);
|
||||
}
|
||||
}],
|
||||
columns: [{
|
||||
heading: 'ID',
|
||||
prop: 'ID',
|
||||
orderBy: 'id',
|
||||
align: 'left'
|
||||
}, {
|
||||
heading: 'Benutzername',
|
||||
prop: 'Username',
|
||||
orderBy: 'username',
|
||||
align: 'center'
|
||||
}, {
|
||||
heading: 'Firma',
|
||||
prop: 'Company',
|
||||
orderBy: 'company'
|
||||
}, {
|
||||
heading: 'Nachname',
|
||||
prop: 'Lastname',
|
||||
orderBy: 'lastname'
|
||||
}, {
|
||||
heading: 'Vorname',
|
||||
prop: 'Firstname',
|
||||
orderBy: 'firstname'
|
||||
}, {
|
||||
heading: 'Email',
|
||||
prop: 'Email',
|
||||
orderBy: 'email'
|
||||
}, {
|
||||
heading: 'Reseller',
|
||||
prop: 'Reseller.Username'
|
||||
}, {
|
||||
heading: 'Render',
|
||||
render(row) {
|
||||
return 'ID:' + row.ID;
|
||||
}
|
||||
}],
|
||||
newRows: [ ],
|
||||
hasMore: true,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
Reference in New Issue
Block a user