Added modal confirmation dialog

Added comment counter
Added voting indicator
This commit is contained in:
dartcafe 2019-01-13 14:01:06 +01:00
Родитель b0e0e5bc8f
Коммит 9352b93dd7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: CCE73CEF3035D3C8
19 изменённых файлов: 179 добавлений и 78 удалений

Просмотреть файл

@ -23,8 +23,8 @@
return [
'routes' => [
['name' => 'page#list_polls', 'url' => '/', 'verb' => 'GET'],
['name' => 'page#index', 'url' => '/list', 'verb' => 'GET'],
['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
['name' => 'page#index_old', 'url' => '/list', 'verb' => 'GET'],
['name' => 'page#goto_poll', 'url' => '/poll/{hash}', 'verb' => 'GET'],
['name' => 'page#create_poll', 'url' => '/new', 'verb' => 'GET'],

Просмотреть файл

@ -134,7 +134,7 @@ class PageController extends Controller {
* @NoAdminRequired
* @NoCSRFRequired
*/
public function index() {
public function indexOld() {
$polls = $this->eventMapper->findAllForUserWithInfo($this->userId);
$comments = $this->commentMapper->findDistinctByUser($this->userId);
$votes = $this->voteMapper->findDistinctByUser($this->userId);
@ -164,7 +164,7 @@ class PageController extends Controller {
* @NoAdminRequired
* @NoCSRFRequired
*/
public function listPolls() {
public function index() {
return new TemplateResponse('polls', 'polls.tmpl',
['urlGenerator' => $this->urlGenerator]);
}

Просмотреть файл

@ -1,3 +0,0 @@
$color-main-background: #fff;
$color-border: #ebebeb;

Просмотреть файл

@ -1,37 +0,0 @@
#content-wrapper {
padding-top: unset;
}
#content {
box-sizing: border-box;
position: relative;
display: flex;
padding-top: 45px;
min-height: 100%;
height: unset;
width: unset;
}
#app-content {
position: initial;
height: initial;
overflow-y: initial;
flex-basis: 100vw;
}
#content[class*="app-"] * {
box-sizing: border-box;
}
#controls {
position: sticky;
top: 45px;
right: unset;
left: unset;
display: flex;
height: 40px;
padding: 0;
margin: 0;
z-index: 60;
position: webkit-sticky;
}

Просмотреть файл

@ -1,2 +0,0 @@
@import '../css-oc-fixes/oc-container-fix.scss';
@import '../../css/createpoll.scss';

Просмотреть файл

@ -1 +0,0 @@
@import '../../css/flex.scss';

Просмотреть файл

@ -1,3 +0,0 @@
@import '../css-oc-fixes/oc-colors-fix.scss';
@import '../css-oc-fixes/oc-container-fix.scss';
@import '../../css/list.scss';

Просмотреть файл

@ -1 +0,0 @@
@import '../../css/main.scss';

Просмотреть файл

@ -1 +0,0 @@
@import '../../css/public.scss';

Просмотреть файл

@ -1,2 +0,0 @@
@import '../css-oc-fixes/oc-colors-fix.scss';
@import '../../css/sidebar.scss';

Просмотреть файл

@ -1,2 +0,0 @@
@import '../css-oc-fixes/oc-container-fix.scss';
@import '../../css/vote.scss';

Просмотреть файл

@ -24,7 +24,11 @@
<div>
<div class="wrapper group-master">
<div class="wrapper group-1">
<div class="thumbnail" :class="[poll.event.type, {expired : poll.event.expired}] " />
<div v-if="countComments" class="comment-badge">
{{ countComments }}
</div>
<div class="thumbnail" :class="[poll.event.type, {expired : poll.event.expired}] ">
</div>
<a :href="voteUrl" class="wrapper group-1-1">
<div class="flex-column name">
{{ poll.event.title }}
@ -59,8 +63,7 @@
{{ timeSpanExpiration }}
</div>
<div class="flex-column participants">
<div class="symbol alt-tooltip partic_voted icon-voted" />
<div class="symbol alt-tooltip partic_commented icon-comment-yes" />
<div v-if="votedBycurrentUser" class="symbol icon-voted" />
</div>
</div>
</div>
@ -69,7 +72,7 @@
</template>
<script>
import moment from 'moment'
// import moment from 'moment'
export default {
props: {
@ -212,6 +215,23 @@ export default {
&.expired {
background-color: var(--color-error);
}
}
.icon-voted {
background-image: var(--icon-checkmark-49bc49);
}
.comment-badge {
position: absolute;
top: 0px;
width: 26px;
line-height: 26px;
text-align: center;
font-size: 0.7rem;
color: white;
background-image: var(--icon-comment-49bc49);
background-repeat: no-repeat;
background-size: 26px;
z-index: 1;
}
</style>

Просмотреть файл

@ -27,6 +27,7 @@ import axios from 'nextcloud-axios'
import App from './App.vue'
import vClickOutside from 'v-click-outside'
import VueClipboard from 'vue-clipboard2'
import Modal from './plugins/plugin.js'
import { DatetimePicker, PopoverMenu } from 'nextcloud-vue'
@ -48,10 +49,13 @@ Vue.component('ShareDiv', ShareDiv)
Vue.use(vClickOutside)
Vue.use(VueClipboard)
Vue.use(Modal)
Vue.prototype.t = t
Vue.prototype.n = n
Vue.prototype.$http = axios
Vue.prototype.OC = OC
Vue.prototype.OCA = OCA
// CSP config for webpack dynamic chunk loading
// eslint-disable-next-line

Просмотреть файл

@ -0,0 +1,92 @@
<template>
<div class="modal-wrapper" v-if="visible">
<div class="modal-header">
<h2>{{ title }}</h2>
</div>
<div class="modal-text">
<p>{{ text }}</p>
</div>
<div class="modal-buttons">
<button class="button" @click="hide">{{ t('polls','No') }}</button>
<button class="button primary" @click="confirm">{{ t('polls','yes') }}</button>
</div>
</div>
</template>
<script>
// we must import our Modal plugin instance
// because it contains reference to our Eventbus
import Modal from './plugin.js';
export default {
data() {
return {
visible: false,
title: '',
text: '',
onConfirm: {}
}
},
methods: {
hide() {
this.visible = false;
},
confirm() {
// we must check if this.onConfirm is function
if(typeof this.onConfirm === 'function') {
// run passed function and then close the modal
this.onConfirm();
this.hide();
} else {
// we only close the modal
this.hide();
}
},
show(params) {
// making modal visible
this.visible = true;
// setting title and text
this.title = params.title;
this.text = params.text;
// setting callback function
this.onConfirm = params.onConfirm;
}
},
beforeMount() {
// here we need to listen for emited events
// we declared those events inside our plugin
Modal.EventBus.$on('show', (params) => {
this.show(params)
})
}
}
</script>
<style scoped lang="scss">
.modal-wrapper {
display: flex;
flex-direction: column;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-width: 300px;
max-width: 500px;
z-index: 1000;
background-color: var(--color-main-background);
box-shadow: 10px 10px 30px 1px rgba(0, 0, 0, 0.24);
& > * {
padding: 7px;
}
}
.modal-header {
background-color: var(--color-primary);
& > * {
color: var(--color-primary-text);
}
}
</style>

29
src/js/plugins/plugin.js Normal file
Просмотреть файл

@ -0,0 +1,29 @@
// we need our modal component
import ModalDialog from './modalDialog.vue'
const Modal = {
// every plugin for Vue.js needs install method
// this method will run after Vue.use(<your-plugin-here>) is executed
install(Vue, options) {
// We must create new Eventbus
// which is just another Vue instance that will be listening for and emiting events from our main instance
// this EventBus will be available as Modal.EventBus
this.EventBus = new Vue()
// making our modal component global
Vue.component('modal-dialog', ModalDialog)
// exposing global $modal object with method show()
// method show() takes object params as argument
// inside this object we can have modal title, text, styles... and also our callback confirm function
Vue.prototype.$modal = {
show(params) {
// if we use this.$modal.show(params) inside our original Vue instance
// we will emit 'show' event with parameters 'params'
Modal.EventBus.$emit('show', params)
}
}
}
}
export default Modal

Просмотреть файл

@ -1,3 +1,4 @@
/* jshint esversion: 6 */
/**
* @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>

Просмотреть файл

@ -23,7 +23,8 @@
<template>
<div id="app-content">
<controls>
<router-link :to="{ name: 'create'}" class="button symbol icon-add">
<router-link :to="{ name: 'create'}" class="button">
<span class="symbol icon-add"></span>
<span class="hidden-visually">
{{ t('polls', 'New') }}
</span>
@ -57,6 +58,7 @@
@deletePoll="removePoll(index, poll.event)"
/>
</transition-group>
<modal-dialog/>
</div>
</template>
@ -101,22 +103,27 @@ export default {
})
},
removePoll: function (index, event) {
this.loading = true
this.$http.post(OC.generateUrl('apps/polls/remove/poll'), event )
.then((response) => {
OC.Notification.showTemporary(t('polls', 'Poll "%n" deleted', 1, event.title))
this.polls.splice(index, 1)
this.loading = false
console.log(response.data)
removePoll: function(index, event) {
const params = {
title: t('polls','Delete poll'),
text: t('polls', 'Do you want to delete "%n"?', 1, event.title),
onConfirm: () => {
// this.deletePoll(index, event)
this.$http.post(OC.generateUrl('apps/polls/remove/poll'), event)
.then((response) => {
this.polls.splice(index, 1)
OC.Notification.showTemporary(t('polls', 'Poll "%n" deleted', 1, event.title))
}, (error) => {
OC.Notification.showTemporary(t('polls', 'Error while deleting Poll "%n"', 1, event.title))
/* eslint-disable-next-line no-console */
console.log(error.response)
}
)
}
}
this.$modal.show(params)
},
}, (error) => {
/* eslint-disable-next-line no-console */
OC.Notification.showTemporary(t('polls', 'Error while deleting Poll "%n"', 1, event.title))
console.log(error.response)
this.loading = false
})
}
}
}
</script>

Просмотреть файл

@ -49,7 +49,7 @@
</div>
</div>
<div class="actions creatable" style="">
<a href="<?php p($urlGenerator->linkToRoute('polls.page.polls_app')); ?>" class="button new">
<a href="<?php p($urlGenerator->linkToRoute('polls.page.create_poll')); ?>" class="button new">
<span class="symbol icon-add"></span><span class="hidden-visually">Neu</span>
</a>
<input class="stop icon-close" style="display:none" value="" type="button">

Просмотреть файл

@ -116,7 +116,7 @@
<?php if (User::isLoggedIn()) : ?>
<div class="crumb svg crumbhome">
<a class="icon-home" href="<?php p($urlGenerator->linkToRoute('polls.page.list_polls')); ?>"> Home </a>
<a class="icon-home" href="<?php p($urlGenerator->linkToRoute('polls.page.index')); ?>"> Home </a>
</div>
<?php endif; ?>