diff options
author | dartcafe <github@dartcafe.de> | 2019-12-10 09:32:58 +0300 |
---|---|---|
committer | dartcafe <github@dartcafe.de> | 2019-12-10 09:32:58 +0300 |
commit | 41930996829421bbf5e26aeb25c93d9214d35e9c (patch) | |
tree | 217e7fe3ed394256a324ed7bcbf81c89f0a0c19e /src/js/components/SideBar | |
parent | 7363c382904c6ea909010a4939e4ecd40dfdb5eb (diff) |
- moved src back in right place
Diffstat (limited to 'src/js/components/SideBar')
-rw-r--r-- | src/js/components/SideBar/CommentAdd.vue | 99 | ||||
-rw-r--r-- | src/js/components/SideBar/SideBar.vue | 109 | ||||
-rw-r--r-- | src/js/components/SideBar/SideBarTabComments.vue | 98 | ||||
-rw-r--r-- | src/js/components/SideBar/SideBarTabConfiguration.vue | 344 | ||||
-rw-r--r-- | src/js/components/SideBar/SideBarTabDateOptions.vue | 173 | ||||
-rw-r--r-- | src/js/components/SideBar/SideBarTabInformation.vue | 58 | ||||
-rw-r--r-- | src/js/components/SideBar/SideBarTabShare.vue | 211 | ||||
-rw-r--r-- | src/js/components/SideBar/SideBarTabTextOptions.vue | 164 |
8 files changed, 1256 insertions, 0 deletions
diff --git a/src/js/components/SideBar/CommentAdd.vue b/src/js/components/SideBar/CommentAdd.vue new file mode 100644 index 00000000..2d7f054a --- /dev/null +++ b/src/js/components/SideBar/CommentAdd.vue @@ -0,0 +1,99 @@ +<!-- + - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de> + - + - @author René Gieling <github@dartcafe.de> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template lang="html"> + <div class="newCommentRow comment new-comment"> + <user-div :user-id="currentUser" /> + + <form class="commentAdd" name="send_comment"> + <input v-model="comment" class="message" data-placeholder="New Comment ..."> + <input v-show="!loading" class="submitComment icon-confirm" @click="writeComment"> + <span v-show="loading" class="icon-loading-small" style="float:right;" /> + </form> + </div> +</template> + +<script> +export default { + name: 'AddComment', + data() { + return { + comment: '' + } + }, + + computed: { + currentUser() { + return OC.getCurrentUser().uid + } + }, + + methods: { + writeComment() { + this.$store.dispatch('writeCommentPromise', this.comment) + .then(response => { + OC.Notification.showTemporary(t('polls', 'Your comment was added'), { type: 'success' }) + }) + .catch(error => { + this.writingVote = false + console.error('Error while saving comment - Error: ', error.response) + OC.Notification.showTemporary(t('polls', 'Error while saving comment'), { type: 'error' }) + }) + + } + } +} +</script> + +<style lang="scss" scoped> + .comment { + margin-bottom: 30px; + } + + .commentAdd { + display: flex; + } + + .message { + margin-left: 40px; + flex: 1; + &:empty:before { + content: attr(data-placeholder); + color: grey; + } + } + .submitComment { + align-self: last baseline; + width: 30px; + margin: 0; + padding: 7px 9px; + background-color: transparent; + border: none; + opacity: 0.3; + cursor: pointer; + } + + .icon-loading-small { + float: left; + margin-top: 10px; + } +</style> diff --git a/src/js/components/SideBar/SideBar.vue b/src/js/components/SideBar/SideBar.vue new file mode 100644 index 00000000..30931f01 --- /dev/null +++ b/src/js/components/SideBar/SideBar.vue @@ -0,0 +1,109 @@ +<!-- + - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de> + - + - @author René Gieling <github@dartcafe.de> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <AppSidebar :active="initialTab" :title="t('polls', 'Details')" @close="$emit('closeSideBar')"> + <UserDiv slot="primary-actions" :user-id="event.owner" :description="t('polls', 'Owner')" /> + + <AppSidebarTab :name="t('polls', 'Comments')" icon="icon-comment"> + <SideBarTabComments /> + </AppSidebarTab> + + <AppSidebarTab v-if="acl.allowEdit && event.type === 'datePoll'" :name="t('polls', 'Date options')" icon="icon-calendar"> + <SideBarTabDateOptions /> + </AppSidebarTab> + + <AppSidebarTab v-if="acl.allowEdit && event.type === 'textPoll'" :name="t('polls', 'Text options')" icon="icon-toggle-filelist"> + <SideBarTabTextOptions /> + </AppSidebarTab> + + <AppSidebarTab v-if="acl.allowEdit" :name="t('polls', 'Configuration')" icon="icon-settings"> + <SideBarTabConfiguration @deletePoll="$emit('deletePoll')" /> + </AppSidebarTab> + + <AppSidebarTab v-if="acl.allowEdit" :name="t('polls', 'Shares')" icon="icon-share"> + <SideBarTabShare /> + </AppSidebarTab> + </AppSidebar> +</template> + +<script> +import { AppSidebar, AppSidebarTab } from '@nextcloud/vue' + +import SideBarTabConfiguration from './SideBarTabConfiguration' +import SideBarTabDateOptions from './SideBarTabDateOptions' +import SideBarTabTextOptions from './SideBarTabTextOptions' +import SideBarTabComments from './SideBarTabComments' +import SideBarTabShare from './SideBarTabShare' +import { mapState } from 'vuex' + +export default { + name: 'SideBar', + components: { + SideBarTabConfiguration, + SideBarTabComments, + SideBarTabDateOptions, + SideBarTabTextOptions, + SideBarTabShare, + AppSidebar, + AppSidebarTab + }, + + data() { + return { + initialTab: 'comments' + } + }, + + computed: { + ...mapState({ + event: state => state.event, + acl: state => state.acl + }) + } + +} + +</script> + +<style scoped lang="scss"> + + ul { + & > li { + margin-bottom: 30px; + & > .comment-item { + display: flex; + align-items: center; + + & > .date { + right: 0; + top: 5px; + opacity: 0.5; + } + } + & > .message { + margin-left: 44px; + flex: 1 1; + } + } + } +</style> diff --git a/src/js/components/SideBar/SideBarTabComments.vue b/src/js/components/SideBar/SideBarTabComments.vue new file mode 100644 index 00000000..1d4c9fb4 --- /dev/null +++ b/src/js/components/SideBar/SideBarTabComments.vue @@ -0,0 +1,98 @@ +<!-- + - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de> + - + - @author René Gieling <github@dartcafe.de> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div> + <CommentAdd /> + <transition-group v-if="countComments" name="fade" class="comments" + tag="ul"> + <li v-for="(comment) in sortedComments" :key="comment.id"> + <div class="comment-item"> + <user-div :user-id="comment.userId" /> + <div class="date"> + {{ realtiveDate(comment.date) }} + </div> + </div> + <div class="message wordwrap comment-content"> + {{ comment.comment }} + </div> + </li> + </transition-group> + <div v-else class="emptycontent"> + <div class="icon-comment" /> + <p> {{ t('polls', 'No comments yet. Be the first.') }}</p> + </div> + </div> +</template> + +<script> +import moment from 'moment' +import CommentAdd from './CommentAdd' +import { mapState, mapGetters } from 'vuex' + +export default { + name: 'SideBarTabComments', + components: { + CommentAdd + }, + + computed: { + ...mapState({ + comments: state => state.comments + }), + ...mapGetters([ + 'countComments', + 'sortedComments' + ]) + }, + + methods: { + realtiveDate(date) { + return t('core', moment.utc(date).fromNow()) + } + + } +} +</script> + +<style scoped lang="scss"> + + ul { + & > li { + margin-bottom: 30px; + & > .comment-item { + display: flex; + align-items: center; + + & > .date { + right: 0; + top: 5px; + opacity: 0.5; + } + } + & > .message { + margin-left: 44px; + flex: 1 1; + } + } + } +</style> diff --git a/src/js/components/SideBar/SideBarTabConfiguration.vue b/src/js/components/SideBar/SideBarTabConfiguration.vue new file mode 100644 index 00000000..1e135af1 --- /dev/null +++ b/src/js/components/SideBar/SideBarTabConfiguration.vue @@ -0,0 +1,344 @@ +<!-- + - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de> + - + - @author René Gieling <github@dartcafe.de> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div> + <div class="configBox"> + <label v-if="writingPoll" class="icon-loading-small title"> + {{ t('polls', 'Saving') }} + </label> + <label v-else class="icon-checkmark title"> + {{ t('polls', 'Saved') }} + </label> + </div> + + <div v-if="acl.allowEdit" class="configBox"> + <label class="icon-sound title"> + {{ t('polls', 'Title') }} + </label> + <input v-model="eventTitle" :class="{ error: titleEmpty }" type="text"> + </div> + + <div v-if="acl.allowEdit" class="configBox"> + <label class="icon-edit title"> + {{ t('polls', 'Description') }} + </label> + <textarea v-model="eventDescription" /> + <!-- <textarea v-if="acl.allowEdit" :value="event.description" @input="updateDescription" /> --> + </div> + + <div class="configBox"> + <label class="title icon-category-customization"> + {{ t('polls', 'Poll configurations') }} + </label> + + <input id="allowMaybe" + v-model="eventAllowMaybe" + :disabled="!acl.allowEdit" + type="checkbox" + class="checkbox"> + <label for="allowMaybe" class="title"> + {{ t('polls', 'Allow "maybe" vote') }} + </label> + + <input id="anonymous" v-model="eventIsAnonymous" + :disabled="!acl.allowEdit" + type="checkbox" + class="checkbox"> + <label for="anonymous" class="title"> + {{ t('polls', 'Anonymous poll') }} + </label> + + <input v-show="event.isAnonymous" + id="trueAnonymous" + v-model="eventFullAnonymous" + :disabled="!acl.allowEdit" + type="checkbox" + class="checkbox"> + <label v-show="event.isAnonymous" class="title" for="trueAnonymous"> + {{ t('polls', 'Hide user names for admin') }} + </label> + + <input id="expiration" + v-model="eventExpiration" + :disabled="!acl.allowEdit" + type="checkbox" + class="checkbox"> + <label class="title" for="expirtion"> + {{ t('polls', 'Expires') }} + </label> + + <date-picker v-show="event.expire" + v-model="eventExpiration" + v-bind="expirationDatePicker" + :disabled="!acl.allowEdit" + :time-picker-options="{ start: '00:00', step: '00:05', end: '23:55' }" + style="width:170px" /> + </div> + + <div class="configBox"> + <label class="title icon-category-auth"> + {{ t('polls', 'Access') }} + </label> + + <input id="hidden" + v-model="eventAccess" + :disabled="!acl.allowEdit" + type="radio" + value="hidden" + class="radio"> + <label for="hidden" class="title"> + <div class="title icon-category-security" /> + <span>{{ t('polls', 'Hidden to other users') }}</span> + </label> + + <input id="public" + v-model="eventAccess" + :disabled="!acl.allowEdit" + type="radio" + value="public" + class="radio"> + <label for="public" class="title"> + <div class="title icon-link" /> + <span>{{ t('polls', 'Visible to other users') }}</span> + </label> + </div> + + <button class="button btn primary" @click="$emit('deletePoll')"> + <span>{{ t('polls', 'Delete this poll') }}</span> + </button> + </div> +</template> + +<script> +import debounce from 'lodash/debounce' +import { mapState, mapMutations, mapActions, mapGetters } from 'vuex' + +export default { + name: 'SideBarTab', + + data() { + return { + writingPoll: false, + sidebar: false, + titleEmpty: false + } + }, + + computed: { + ...mapState({ + event: state => state.event, + acl: state => state.acl + }), + + ...mapGetters([ + 'languageCodeShort' + ]), + + // Add bindings + eventDescription: { + get() { + return this.event.description + }, + set(value) { + this.writeValueDebounced({ 'description': value }) + } + }, + + eventTitle: { + get() { + return this.event.title + }, + set(value) { + this.writeValueDebounced({ 'title': value }) + } + }, + + eventAccess: { + get() { + return this.event.access + }, + set(value) { + this.writeValue({ 'access': value }) + } + }, + + eventExpiration: { + get() { + return this.event.expire + }, + set(value) { + this.writeValue({ 'expire': value }) + } + }, + + eventFullAnonymous: { + get() { + return this.event.fullAnonymous + }, + set(value) { + this.writeValue({ 'fullAnonymous': value }) + } + }, + + eventIsAnonymous: { + get() { + return this.event.isAnonymous + }, + set(value) { + this.writeValue({ 'isAnonymous': value }) + } + }, + + eventAllowMaybe: { + get() { + return this.event.allowMaybe + }, + set(value) { + this.writeValue({ 'allowMaybe': value }) + } + }, + + // eventExpiration: { + // get() { + // return this.$store.state.event.expiration + // }, + // set(value) { + // this.writeValue({ 'expiration': value }) + // } + // }, + + expirationDatePicker() { + return { + editable: true, + minuteStep: 1, + type: 'datetime', + format: this.dateTimeFormat, + lang: this.langShort, + placeholder: t('polls', 'Expiration date'), + timePickerOptions: { + start: '00:00', + step: '00:30', + end: '23:30' + } + } + }, + + optionDatePicker() { + return { + editable: false, + minuteStep: 1, + type: 'datetime', + format: this.dateTimeFormat, + lang: this.languageCodeShort, + placeholder: t('polls', 'Click to add a date'), + timePickerOptions: { + start: '00:00', + step: '00:30', + end: '23:30' + } + } + }, + + protect: function() { + return this.poll.mode === 'vote' + }, + + saveButtonTitle: function() { + if (this.writingPoll) { + return t('polls', 'Writing poll') + } else if (this.acl.allowEdit) { + return t('polls', 'Update poll') + } else { + return t('polls', 'Create new poll') + } + } + }, + methods: { + + ...mapMutations([ 'setEventProperty' ]), + ...mapActions([ 'writeEventPromise' ]), + + writeValueDebounced: debounce(function(e) { + this.writeValue(e) + }, 1500), + + writeValue(e) { + this.$store.commit('setEventProperty', e) + this.writingPoll = true + this.writePoll() + }, + + writePoll() { + if (this.titleEmpty) { + OC.Notification.showTemporary(t('polls', 'Title must not be empty!'), { type: 'success' }) + } else { + this.writeEventPromise() + this.writingPoll = false + OC.Notification.showTemporary(t('polls', '%n successfully saved', 1, this.event.title), { type: 'success' }) + } + }, + + write() { + if (this.acl.allowEdit) { + this.writePoll() + } + + } + } +} +</script> + +<style lang="scss"> + .configBox { + display: flex; + flex-direction: column; + padding: 8px; + & > * { + padding-left: 21px; + } + + & > input { + margin-left: 24px; + width: auto; + + } + + & > textarea { + margin-left: 24px; + width: auto; + padding: 7px 6px; + } + + & > .title { + display: flex; + background-position: 0 2px; + padding-left: 24px; + opacity: 0.7; + font-weight: bold; + margin-bottom: 4px; + & > span { + padding-left: 4px; + } + } + } +</style> diff --git a/src/js/components/SideBar/SideBarTabDateOptions.vue b/src/js/components/SideBar/SideBarTabDateOptions.vue new file mode 100644 index 00000000..c99b129b --- /dev/null +++ b/src/js/components/SideBar/SideBarTabDateOptions.vue @@ -0,0 +1,173 @@ +<!-- + - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de> + - + - @author René Gieling <github@dartcafe.de> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div> + <div class="configBox"> + <label class="title icon-calendar"> + {{ t('polls', 'Add a date option') }} + </label> + <DatePicker v-bind="optionDatePicker" style="width:100%" confirm + @change="addOption($event)" /> + </div> + + <div class="configBox"> + <label class="title icon-history"> + {{ t('polls', 'Shift all date options') }} + </label> + <div> + <div class="selectUnit"> + <input v-model="move.step"> + <Multiselect v-model="move.unit" :options="move.units" /> + </div> + </div> + <div> + <button class="button btn primary" @click="shiftDates(move)"> + <span>{{ t('polls', 'Shift') }}</span> + </button> + </div> + </div> + + <ul class="configBox poll-table"> + <label class="title icon-calendar"> + {{ t('polls', 'Available Options') }} + </label> + <DatePollItem v-for="(option) in sortedOptions" + :key="option.id" + :option="option" + @remove="removeOption(option)" /> + </ul> + </div> +</template> + +<script> +import { Multiselect } from '@nextcloud/vue' +import moment from 'moment' +import { mapGetters, mapState } from 'vuex' +import DatePollItem from '../Create/CreateDateItem' + +export default { + name: 'SideBarTabDateOptions', + + components: { + Multiselect, + DatePollItem + + }, + + data() { + return { + move: { + step: 1, + unit: 'week', + units: ['minute', 'hour', 'day', 'week', 'month', 'year'] + } + } + }, + + computed: { + ...mapState({ + options: state => state.options + }), + + ...mapGetters([ 'languageCodeShort', 'sortedOptions' ]), + + optionDatePicker() { + return { + editable: false, + minuteStep: 1, + type: 'datetime', + format: this.dateTimeFormat, + lang: this.languageCodeShort, + placeholder: t('polls', 'Click to add a date'), + timePickerOptions: { + start: '00:00', + step: '00:30', + end: '23:30' + } + } + } + }, + + methods: { + + addOption(pollOptionText) { + this.$store.dispatch('addOptionAsync', { pollOptionText: pollOptionText }) + }, + + shiftDates(payload) { + let store = this.$store + this.options.list.forEach(function(existingOption) { + let option = Object.assign({}, existingOption) + option.pollOptionText = moment(option.pollOptionText).add(payload.step, payload.unit).format('YYYY-MM-DD HH:mm:ss') + option.timestamp = moment.utc(option.pollOptionText).unix() + store.dispatch('updateOptionAsync', { option: option }) + }) + }, + + removeOption(option) { + this.$store.dispatch('removeOptionAsync', { option: option }) + } + + } + +} +</script> + +<style lang="scss"> + .configBox { + display: flex; + flex-direction: column; + padding: 8px; + & > * { + padding-left: 21px; + } + + & > input { + margin-left: 24px; + width: auto; + + } + + & > textarea { + margin-left: 24px; + width: auto; + padding: 7px 6px; + } + + & > .title { + display: flex; + background-position: 0 2px; + padding-left: 24px; + opacity: 0.7; + font-weight: bold; + margin-bottom: 4px; + & > span { + padding-left: 4px; + } + } + &.poll-table > li { + border-bottom-color: rgb(72, 72, 72); + margin-left: 18px; + } + } +</style> diff --git a/src/js/components/SideBar/SideBarTabInformation.vue b/src/js/components/SideBar/SideBarTabInformation.vue new file mode 100644 index 00000000..edffcaaf --- /dev/null +++ b/src/js/components/SideBar/SideBarTabInformation.vue @@ -0,0 +1,58 @@ +<!-- + - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de> + - + - @author René Gieling <github@dartcafe.de> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div> + <user-div :user-id="event.owner" :description="t('polls', 'Owner')" /> + <div>{{ accessType }}</div> + <h3> {{ t('polls', 'Created') }} </h3> + <div>{{ timeSpanCreated }}</div> + <h3> {{ t('polls', 'Expires') }} </h3> + <div>{{ timeSpanExpiration }}</div> + <div>{{ countCommentsHint }}</div> + </div> +</template> + +<script> +import { mapState, mapGetters } from 'vuex' + +export default { + name: 'SideBarTabInformationTab', + computed: { + ...mapState({ + event: state => state.event + }), + + ...mapGetters([ + 'accessType', + 'countComments', + 'timeSpanCreated', + 'timeSpanExpiration' + ]), + + countCommentsHint: function() { + return n('polls', 'There is %n comment', 'There are %n comments', this.countComments) + } + } +} + +</script> diff --git a/src/js/components/SideBar/SideBarTabShare.vue b/src/js/components/SideBar/SideBarTabShare.vue new file mode 100644 index 00000000..080be7db --- /dev/null +++ b/src/js/components/SideBar/SideBarTabShare.vue @@ -0,0 +1,211 @@ +<!-- + - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de> + - + - @author René Gieling <github@dartcafe.de> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div> + <h3>{{ t('polls','Invitations') }}</h3> + <TransitionGroup :css="false" tag="ul" class="shared-list"> + <li v-for="(share) in invitationShares" :key="share.id"> + <UserDiv :user-id="resolveShareUser(share)" :type="share.type" :icon="true" /> + <div class="options"> + <a class="icon icon-clippy" @click="copyLink( { url: OC.generateUrl('apps/polls/s/') + share.token } )" /> + <a class="icon icon-delete svg delete-poll" @click="removeShare(share)" /> + </div> + </li> + </TransitionGroup> + + <Multiselect id="ajax" + :options="users" + :multiple="false" + :user-select="true" + :tag-width="80" + :clear-on-select="false" + :preserve-search="true" + :options-limit="20" + :loading="isLoading" + :internal-search="false" + :searchable="true" + :preselect-first="true" + :placeholder="placeholder" + label="displayName" + track-by="user" + @select="addShare" + @search-change="loadUsersAsync"> + <template slot="selection" slot-scope="{ values, search, isOpen }"> + <span v-if="values.length && !isOpen" class="multiselect__single"> + {{ values.length }} users selected + </span> + </template> + </Multiselect> + + <h3>{{ t('polls','Public shares') }}</h3> + <TransitionGroup :css="false" tag="ul" class="shared-list"> + <li v-for="(share) in publicShares" :key="share.id"> + <div class="user-row user"> + <div class="avatar icon-public" /> + <div class="user-name"> + {{ t('polls', 'Share Link') }} + </div> + </div> + <div class="options"> + <a class="icon icon-clippy" @click="copyLink( { url: OC.generateUrl('apps/polls/s/') + share.token } )" /> + <a class="icon icon-delete" @click="removeShare(share)" /> + </div> + </li> + </TransitionGroup> + <div class="user-row user" @click="addShare({type: 'public', user: ''})"> + <div class="avatar icon-add" /> + <div class="user-name"> + {{ t('polls', 'Add a public link') }} + </div> + </div> + </div> +</template> + +<script> +import { Multiselect } from '@nextcloud/vue' +import { mapGetters } from 'vuex' + +export default { + name: 'SideBarTabShare', + + components: { + Multiselect + }, + + data() { + return { + users: [], + invitations: [], + invitation: {}, + isLoading: false, + siteUsersListOptions: { + getUsers: true, + getGroups: true, + query: '' + } + } + }, + + computed: { + ...mapGetters([ + 'countShares', + 'sortedShares', + 'invitationShares', + 'publicShares' + ]) + }, + + methods: { + loadUsersAsync(query) { + this.isLoading = false + this.siteUsersListOptions.query = query + this.$http.post(OC.generateUrl('apps/polls/get/siteusers'), this.siteUsersListOptions) + .then((response) => { + this.users = response.data.siteusers + this.isLoading = false + }, (error) => { + console.error(error.response) + }) + }, + + copyLink(payload) { + this.$copyText(window.location.origin + payload.url).then( + function(e) { + OC.Notification.showTemporary(t('polls', 'Link copied to clipboard'), { type: 'success' }) + }, + function(e) { + OC.Notification.showTemporary(t('polls', 'Error while copying link to clipboard'), { type: 'error' }) + } + ) + }, + + resolveShareUser(share) { + if (share.userId !== '' && share.userId !== null) { + return share.userId + } else if (share.type === 'mail') { + return share.userEmail + } else { + return t('polls', 'Unknown user') + } + + }, + + removeShare(share) { + this.$store.dispatch('removeShareAsync', { share: share }) + }, + + addShare(payload) { + this.$store.dispatch('writeSharePromise', { + 'share': { + 'type': payload.type, + 'userId': payload.user, + 'pollId': '0', + 'userEmail': '', + 'token': '' + } + }) + // .then(response => { + // OC.Notification.showTemporary(t('polls', 'You added %n.', 1, payload.user), { type: 'success' }) + // }) + .catch(error => { + console.error('Error while adding share comment - Error: ', error) + OC.Notification.showTemporary(t('polls', 'Error while adding share'), { type: 'error' }) + }) + } + } +} +</script> + +<style lang="scss"> + .shared-list { + display: flex; + flex-wrap: wrap; + flex-direction: column; + justify-content: flex-start; + padding-top: 8px; + + > li { + display: flex; + align-items: stretch; + margin: 4px 0; + } + } + + .options { + display: flex; + + .icon:not(.hidden) { + padding: 14px; + height: 44px; + width: 44px; + opacity: .5; + display: block; + cursor: pointer; + } + } + + .multiselect { + width: 100% !important; + max-width: 100% !important; + } +</style> diff --git a/src/js/components/SideBar/SideBarTabTextOptions.vue b/src/js/components/SideBar/SideBarTabTextOptions.vue new file mode 100644 index 00000000..002d5d62 --- /dev/null +++ b/src/js/components/SideBar/SideBarTabTextOptions.vue @@ -0,0 +1,164 @@ +<!-- + - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de> + - + - @author René Gieling <github@dartcafe.de> + - + - @license GNU AGPL version 3 or any later version + - + - This program is free software: you can redistribute it and/or modify + - it under the terms of the GNU Affero General Public License as + - published by the Free Software Foundation, either version 3 of the + - License, or (at your option) any later version. + - + - This program is distributed in the hope that it will be useful, + - but WITHOUT ANY WARRANTY; without even the implied warranty of + - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + - GNU Affero General Public License for more details. + - + - You should have received a copy of the GNU Affero General Public License + - along with this program. If not, see <http://www.gnu.org/licenses/>. + - + --> + +<template> + <div> + <div class="configBox"> + <label class="title icon-toggle-filelist"> + {{ t('polls', 'Add a new text option') }} + </label> + <input v-model="newPollText" :placeholder=" t('polls', 'Enter option text and press Enter') " @keyup.enter="addOption(newPollText)"> + </div> + + <ul class="configBox poll-table"> + <label class="title icon-calendar"> + {{ t('polls', 'Available Options') }} + </label> + <TextPollItem v-for="(option) in sortedOptions" :key="option.id" :option="option" + @remove="removeOption(option)" /> + </ul> + </div> +</template> + +<script> +import { mapGetters, mapState } from 'vuex' +import TextPollItem from '../Create/TextPollItem' +export default { + name: 'SideBarTabTextOptions', + + components: { + TextPollItem + }, + + data() { + return { + newPollText: '' + } + }, + + computed: { + ...mapState({ + options: state => state.options + }), + + ...mapGetters(['languageCodeShort', 'sortedOptions']) + }, + + methods: { + + addOption(pollOptionText) { + if (pollOptionText !== '') { + this.$store.dispatch('addOptionAsync', { + pollOptionText: pollOptionText + }) + this.newPollText = '' + } + }, + + removeOption(option) { + this.$store.dispatch('removeOptionAsync', { + option: option + }) + } + + } + +} +</script> + +<style lang="scss"> +.configBox { + display: flex; + flex-direction: column; + padding: 8px; + & > * { + padding-left: 21px; + } + + & > input { + margin-left: 24px; + width: auto; + + } + + & > textarea { + margin-left: 24px; + width: auto; + padding: 7px 6px; + } + + & > .title { + display: flex; + background-position: 0 2px; + padding-left: 24px; + opacity: 0.7; + font-weight: bold; + margin-bottom: 4px; + & > span { + padding-left: 4px; + } + } + + &.poll-table > li { + border-bottom-color: rgb(72, 72, 72); + margin-left: 18px; + } + +} + +.poll-table { + > li { + display: flex; + align-items: center; + padding-left: 8px; + padding-right: 8px; + line-height: 2em; + min-height: 4em; + border-bottom: 1px solid var(--color-border); + overflow: hidden; + white-space: nowrap; + + &:active, + &:hover { + transition: var(--background-dark) 0.3s ease; + background-color: var(--color-background-dark); //$hover-color; + } + + > div { + display: flex; + flex: 1; + font-size: 1.2em; + opacity: 0.7; + white-space: normal; + padding-right: 4px; + &.avatar { + flex: 0; + } + } + + > div:nth-last-child(1) { + justify-content: center; + flex: 0 0; + } + } +} +</style> |