diff options
author | Raimund Schlüßler <raimund.schluessler@mailbox.org> | 2020-01-23 14:09:49 +0300 |
---|---|---|
committer | Raimund Schlüßler <raimund.schluessler@mailbox.org> | 2020-02-05 00:49:17 +0300 |
commit | ae7bf7f69642244416c51237a2e808675124317c (patch) | |
tree | aa7805218784a9f3533c6556d634a69551436c4b /src/components | |
parent | 298803f8ac936b870a7265adb0b4953f519b8f28 (diff) |
Move calendar list entry into separate component
Signed-off-by: Raimund Schlüßler <raimund.schluessler@mailbox.org>
Diffstat (limited to 'src/components')
-rw-r--r-- | src/components/AppNavigation/CalendarShare.vue (renamed from src/components/CalendarShare.vue) | 2 | ||||
-rw-r--r-- | src/components/AppNavigation/CalendarSharee.vue (renamed from src/components/CalendarSharee.vue) | 0 | ||||
-rw-r--r-- | src/components/AppNavigation/Colorpicker.vue (renamed from src/components/Colorpicker.vue) | 0 | ||||
-rw-r--r-- | src/components/AppNavigation/Confirmation.vue (renamed from src/components/Confirmation.vue) | 0 | ||||
-rw-r--r-- | src/components/AppNavigation/List.vue | 241 | ||||
-rw-r--r-- | src/components/AppNavigation/ListItemCalendar.vue | 332 | ||||
-rw-r--r-- | src/components/AppNavigation/TheSettings.vue (renamed from src/components/TheSettings.vue) | 0 | ||||
-rw-r--r-- | src/components/TheList.vue | 446 |
8 files changed, 574 insertions, 447 deletions
diff --git a/src/components/CalendarShare.vue b/src/components/AppNavigation/CalendarShare.vue index 147b8c50..6ca4b77b 100644 --- a/src/components/CalendarShare.vue +++ b/src/components/AppNavigation/CalendarShare.vue @@ -49,7 +49,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. </template> <script> -import client from '../services/cdav' +import client from '../../services/cdav' import { Multiselect } from '@nextcloud/vue/dist/Components/Multiselect' import CalendarSharee from './CalendarSharee' diff --git a/src/components/CalendarSharee.vue b/src/components/AppNavigation/CalendarSharee.vue index 1d02bf27..1d02bf27 100644 --- a/src/components/CalendarSharee.vue +++ b/src/components/AppNavigation/CalendarSharee.vue diff --git a/src/components/Colorpicker.vue b/src/components/AppNavigation/Colorpicker.vue index 8e3f743b..8e3f743b 100644 --- a/src/components/Colorpicker.vue +++ b/src/components/AppNavigation/Colorpicker.vue diff --git a/src/components/Confirmation.vue b/src/components/AppNavigation/Confirmation.vue index 269e9b2a..269e9b2a 100644 --- a/src/components/Confirmation.vue +++ b/src/components/AppNavigation/Confirmation.vue diff --git a/src/components/AppNavigation/List.vue b/src/components/AppNavigation/List.vue new file mode 100644 index 00000000..26b3c836 --- /dev/null +++ b/src/components/AppNavigation/List.vue @@ -0,0 +1,241 @@ +<!-- +Nextcloud - Tasks + +@author Raimund Schlüßler +@copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +License as published by the Free Software Foundation; either +version 3 of the License, or any later version. + +This library 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 library. If not, see <http://www.gnu.org/licenses/>. + +--> + +<template> + <ul id="collections"> + <AppNavigationItem + v-for="collection in collections" + v-show="!hideCollection(collection)" + :id="'collection_' + collection.id" + :key="collection.id" + :collection-id="collection.id" + :icon="collection.icon" + :to="{ name: 'collections', params: { collectionId: collection.id } }" + :title="collection.displayName" + class="collection reactive" + @add="dropTaskOnCollection(...arguments, collection)"> + <AppNavigationCounter slot="counter"> + {{ collectionCount(collection.id) | counterFormatter }} + </AppNavigationCounter> + </AppNavigationItem> + <ListItemCalendar + v-for="calendar in calendars" + :key="calendar.id" + :calendar="calendar" /> + <AppNavigationItem v-click-outside="cancelCreate" + :title="$t('tasks', 'Add List…')" + icon="icon-add" + :class="{edit: creating}" + class="collection reactive" + @click="startCreate($event)"> + <div :class="{error: nameError}" class="app-navigation-entry-edit"> + <form> + <input id="newListInput" + v-model="newCalendarName" + v-tooltip="{ + content: tooltipMessage, + show: showTooltip('list_'), + trigger: 'manual' + }" + :placeholder="$t('tasks', 'New List')" + class="edit" + type="text" + @keyup="checkName($event, null, create)"> + <input :title="$t('tasks', 'Cancel')" + type="cancel" + value="" + class="action icon-close" + @click="cancelCreate"> + <input :title="$t('tasks', 'Save')" + type="button" + value="" + class="action icon-checkmark" + @click="create($event)"> + </form> + <Colorpicker :selected-color="selectedColor" @color-selected="setColor(...arguments)" /> + </div> + </AppNavigationItem> + </ul> +</template> + +<script> +import { mapState, mapGetters, mapActions } from 'vuex' +import ListItemCalendar from './ListItemCalendar' +import Colorpicker from './Colorpicker' + +import ClickOutside from 'vue-click-outside' +import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem' +import AppNavigationCounter from '@nextcloud/vue/dist/Components/AppNavigationCounter' + +export default { + components: { + ListItemCalendar, + Colorpicker, + AppNavigationItem, + AppNavigationCounter, + }, + directives: { + ClickOutside, + }, + filters: { + counterFormatter: function(count) { + switch (false) { + case count !== 0: + return '' + case count < 999: + return '999+' + default: + return count + } + }, + }, + data() { + return { + editing: '', + shareOpen: '', + copySuccess: false, + copied: false, + creating: false, + nameError: false, + newCalendarName: '', + selectedColor: '', + tooltipMessage: '', + tooltipTarget: '', + } + }, + computed: { + ...mapState({ + collections: state => state.collections.collections, + }), + ...mapGetters({ + calendars: 'getSortedCalendars', + collectionCount: 'getCollectionCount', + calendarCount: 'getCalendarCount', + isCalendarNameUsed: 'isCalendarNameUsed', + getTask: 'getTaskByUri', + }), + }, + methods: { + ...mapActions([ + 'appendCalendar', + 'setPriority', + 'setPercentComplete', + 'setDate', + ]), + dropTaskOnCollection: function($event, collection) { + let task + const taskAttribute = $event.item.attributes['task-id'] + if (taskAttribute) { + task = this.getTask(taskAttribute.value) + switch (collection.id) { + case 'starred': + this.setPriority({ task: task, priority: 1 }) + break + case 'completed': + this.setPercentComplete({ task: task, complete: 100 }) + break + case 'today': + this.setDate({ task: task, day: 0 }) + break + case 'week': + this.setDate({ task: task, day: 6 }) + break + } + } + }, + hideCollection: function(collection) { + switch (collection.show) { + case 0: + return true + case 1: + return false + case 2: + return this.collectionCount(collection.id) < 1 + } + }, + showTooltip: function(target) { + return this.tooltipTarget === target + }, + startCreate: function(e) { + if (this.$OCA.Theming) { + this.selectedColor = this.$OCA.Theming.color + } else { + this.selectedColor = '#0082C9' + } + this.newCalendarName = '' + this.creating = true + this.$nextTick( + () => document.getElementById('newListInput').focus() + ) + e.stopPropagation() + }, + cancelCreate: function() { + this.creating = false + }, + create: function() { + if (!this.isNameAllowed(this.newCalendarName, 'new').allowed) { + return + } + this.appendCalendar({ displayName: this.newCalendarName, color: this.selectedColor }) + this.creating = false + }, + checkName: function(event, calendar, callback) { + const calendarId = calendar ? calendar.id : '' + const check = this.isNameAllowed(this.newCalendarName, calendarId) + this.tooltipMessage = check.msg + if (!check.allowed) { + this.tooltipTarget = 'list_' + calendarId + this.nameError = true + } else { + this.tooltipTarget = '' + this.nameError = false + } + if (event.keyCode === 13) { + callback(calendar) + } + if (event.keyCode === 27) { + event.preventDefault() + this.tooltipTarget = '' + this.creating = false + this.editing = false + this.nameError = false + } + }, + isNameAllowed: function(name, id) { + const check = { + allowed: false, + msg: '', + } + if (this.isCalendarNameUsed(name, id)) { + check.msg = this.$t('tasks', 'The name "{calendar}" is already used.', { calendar: name }) + } else if (!name) { + check.msg = this.$t('tasks', 'An empty name is not allowed.') + } else { + check.allowed = true + } + return check + }, + setColor: function(color) { + this.selectedColor = color + }, + }, +} +</script> diff --git a/src/components/AppNavigation/ListItemCalendar.vue b/src/components/AppNavigation/ListItemCalendar.vue new file mode 100644 index 00000000..877af677 --- /dev/null +++ b/src/components/AppNavigation/ListItemCalendar.vue @@ -0,0 +1,332 @@ +<!-- +Nextcloud - Tasks + +@author Raimund Schlüßler +@copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +License as published by the Free Software Foundation; either +version 3 of the License, or any later version. + +This library 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 library. If not, see <http://www.gnu.org/licenses/>. + +--> + +<template> + <AppNavigationItem + :id="'list_' + calendar.id" + v-click-outside="resetView" + :calendar-id="calendar.id" + :to="{ name: 'calendars', params: { calendarId: calendar.id } }" + :title="calendar.displayName" + :class="{edit: editing}" + class="list reactive" + @add="dropTaskOnCalendar(...arguments, calendar)"> + <AppNavigationIconBullet slot="icon" :color="calendar.color" /> + + <template slot="counter"> + <AppNavigationCounter> + {{ calendarCount(calendar.id) | counterFormatter }} + </AppNavigationCounter> + <Actions v-if="!calendar.readOnly"> + <ActionButton + :icon="sharingIconClass" + @click="toggleShare"> + {{ sharedWithTooltip }} + </ActionButton> + </Actions> + <Avatar v-if="calendar.isSharedWithMe && calendar.loadedOwnerPrincipal" :user="calendar.ownerUserId" :display-name="calendar.ownerDisplayname" /> + <div v-if="calendar.isSharedWithMe && !calendar.loadedOwnerPrincipal" class="icon icon-loading" /> + </template> + + <template slot="actions"> + <ActionButton + v-if="!calendar.readOnly" + icon="icon-rename" + @click="editCalendar"> + {{ $t('tasks', 'Edit') }} + </ActionButton> + <ActionButton + icon="icon-public" + :close-after-click="true" + @click="copyCalDAVUrl($event, calendar)"> + {{ !copied + ? $t('tasks', 'Copy private link') + : copySuccess + ? $t('tasks', 'Copied') + : $t('tasks', 'Can not copy') }} + </ActionButton> + <ActionLink + icon="icon-download" + :close-after-click="true" + :href="exportUrl"> + {{ $t('tasks', 'Download') }} + </ActionLink> + <ActionButton + v-if="!calendar.readOnly" + v-tooltip="{ + placement: 'left', + boundariesElement: 'body', + content: deleteMessage + }" + icon="icon-delete" + @click="deleteCalendar"> + {{ !calendar.isSharedWithMe ? $t('calendar', 'Delete') : $t('calendar', 'Unshare') }} + </ActionButton> + </template> + + <ShareCalendar v-if="shareOpen && !calendar.readOnly" :calendar="calendar" /> + + <div :class="{error: nameError}" class="app-navigation-entry-edit"> + <form> + <input v-model="newCalendarName" + v-tooltip="{ + content: tooltipMessage, + show: showTooltip('list_' + calendar.id), + trigger: 'manual' + }" + class="edit" + type="text" + @keyup="checkName($event, calendar, save)"> + <input :title="$t('tasks', 'Cancel')" + type="cancel" + value="" + class="action icon-close" + @click="resetView"> + <input :title="$t('tasks', 'Save')" + type="button" + value="" + class="action icon-checkmark" + @click="save(calendar)"> + </form> + <Colorpicker :selected-color="selectedColor" @color-selected="setColor(...arguments)" /> + </div> + </AppNavigationItem> +</template> + +<script> +import { mapGetters, mapActions } from 'vuex' +import Colorpicker from './Colorpicker' +import ShareCalendar from './CalendarShare' + +import ClickOutside from 'vue-click-outside' +import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem' +import AppNavigationCounter from '@nextcloud/vue/dist/Components/AppNavigationCounter' +import AppNavigationIconBullet from '@nextcloud/vue/dist/Components/AppNavigationIconBullet' +import Actions from '@nextcloud/vue/dist/Components/Actions' +import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' +import ActionLink from '@nextcloud/vue/dist/Components/ActionLink' + +export default { + components: { + Colorpicker, + ShareCalendar, + AppNavigationItem, + AppNavigationCounter, + AppNavigationIconBullet, + Actions, + ActionButton, + ActionLink, + }, + directives: { + ClickOutside, + }, + filters: { + counterFormatter: function(count) { + switch (false) { + case count !== 0: + return '' + case count < 999: + return '999+' + default: + return count + } + }, + }, + props: { + calendar: { + type: Object, + required: true, + }, + }, + data() { + return { + editing: false, + shareOpen: false, + copySuccess: false, + copied: false, + nameError: false, + newCalendarName: '', + selectedColor: '', + tooltipMessage: '', + tooltipTarget: '', + } + }, + computed: { + ...mapGetters({ + calendarCount: 'getCalendarCount', + isCalendarNameUsed: 'isCalendarNameUsed', + getTask: 'getTaskByUri', + }), + + deleteMessage() { + return !this.calendar.isSharedWithMe + ? this.$t('tasks', 'This will delete the calendar "{calendar}" and all corresponding events and tasks.', { calendar: this.calendar.displayName }) + : this.$t('tasks', 'This will unshare the calendar "{calendar}".', { calendar: this.calendar.displayName }) + }, + sharingIconClass() { + if (this.calendar.shares.length) { + return 'icon-shared' + } + return 'icon-share' + }, + exportUrl() { + let url = this.calendar.url + // cut off last slash to have a fancy name for the ics + if (url.slice(url.length - 1) === '/') { + url = url.slice(0, url.length - 1) + } + url += '?export' + return url + }, + url() { + const rootURL = this.$OC.linkToRemote('dav') + return new URL(this.calendar.url, rootURL) + }, + hasShares() { + return this.calendar.shares.length > 0 + }, + // info tooltip about number of shares + sharedWithTooltip() { + return this.hasShares + ? this.$n('tasks', + 'Shared with {num} entity', + 'Shared with {num} entities', + this.calendar.shares.length, { + num: this.calendar.shares.length, + }) + : '' // disable the tooltip + }, + }, + methods: { + ...mapActions([ + 'changeCalendar', + 'deleteCalendar', + 'moveTask', + ]), + dropTaskOnCalendar: function($event, calendar) { + let task + const taskAttribute = $event.item.attributes['task-id'] + if (taskAttribute) { + task = this.getTask(taskAttribute.value) + if (calendar !== task.calendar) { + this.moveTask({ task: task, calendar: calendar, parent: undefined }) + } + } + }, + showTooltip: function(target) { + return this.tooltipTarget === target + }, + editCalendar() { + this.editing = true + this.newCalendarName = this.calendar.displayName + this.selectedColor = this.calendar.color + this.nameError = false + this.tooltipTarget = '' + this.$nextTick( + () => document.querySelector('#list_' + this.calendar.id + ' input.edit').focus() + ) + }, + + /** + * Toggles the visibility of the share menu + */ + toggleShare() { + this.shareOpen = !this.shareOpen + }, + resetView($event) { + this.editing = false + this.shareOpen = false + this.tooltipTarget = '' + }, + copyCalDAVUrl(event) { + // change to loading status + event.stopPropagation() + + const url = this.url + + // copy link for calendar to clipboard + this.$copyText(url) + .then(e => { + event.preventDefault() + this.copySuccess = true + this.copied = true + // Notify calendar url was copied + this.$OC.Notification.showTemporary(this.$t('tasks', 'Calendar link copied to clipboard.')) + }, e => { + this.copySuccess = false + this.copied = true + this.$OC.Notification.showTemporary(this.$t('tasks', 'Calendar link could not be copied to clipboard.')) + }).then(() => { + setTimeout(() => { + // stop loading status regardless of outcome + this.copied = false + }, 2000) + }) + }, + setColor: function(color) { + this.selectedColor = color + }, + save() { + if (!this.isNameAllowed(this.newCalendarName, this.calendar.id).allowed) { + return + } + this.changeCalendar({ calendar: this.calendar, newName: this.newCalendarName, newColor: this.selectedColor }) + this.editing = false + }, + checkName: function(event, calendar, callback) { + const calendarId = calendar ? calendar.id : '' + const check = this.isNameAllowed(this.newCalendarName, calendarId) + this.tooltipMessage = check.msg + if (!check.allowed) { + this.tooltipTarget = 'list_' + calendarId + this.nameError = true + } else { + this.tooltipTarget = '' + this.nameError = false + } + if (event.keyCode === 13) { + callback(calendar) + } + if (event.keyCode === 27) { + event.preventDefault() + this.tooltipTarget = '' + this.creating = false + this.editing = false + this.nameError = false + } + }, + isNameAllowed: function(name, id) { + const check = { + allowed: false, + msg: '', + } + if (this.isCalendarNameUsed(name, id)) { + check.msg = this.$t('tasks', 'The name "{calendar}" is already used.', { calendar: name }) + } else if (!name) { + check.msg = this.$t('tasks', 'An empty name is not allowed.') + } else { + check.allowed = true + } + return check + }, + }, +} +</script> diff --git a/src/components/TheSettings.vue b/src/components/AppNavigation/TheSettings.vue index fc026561..fc026561 100644 --- a/src/components/TheSettings.vue +++ b/src/components/AppNavigation/TheSettings.vue diff --git a/src/components/TheList.vue b/src/components/TheList.vue deleted file mode 100644 index 75fe67ff..00000000 --- a/src/components/TheList.vue +++ /dev/null @@ -1,446 +0,0 @@ -<!-- -Nextcloud - Tasks - -@author Raimund Schlüßler -@copyright 2018 Raimund Schlüßler <raimund.schluessler@mailbox.org> - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -License as published by the Free Software Foundation; either -version 3 of the License, or any later version. - -This library 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 library. If not, see <http://www.gnu.org/licenses/>. - ---> - -<template> - <ul id="collections"> - <AppNavigationItem - v-for="collection in collections" - v-show="!hideCollection(collection)" - :id="'collection_' + collection.id" - :key="collection.id" - :collection-id="collection.id" - :icon="collection.icon" - :to="{ name: 'collections', params: { collectionId: collection.id } }" - :title="collection.displayName" - class="collection reactive" - @add="dropTaskOnCollection(...arguments, collection)"> - <AppNavigationCounter slot="counter"> - {{ collectionCount(collection.id) | counterFormatter }} - </AppNavigationCounter> - </AppNavigationItem> - <AppNavigationItem - v-for="calendar in calendars" - :id="'list_' + calendar.id" - :key="calendar.id" - v-click-outside="() => resetView(calendar)" - :calendar-id="calendar.id" - :to="{ name: 'calendars', params: { calendarId: calendar.id } }" - :title="calendar.displayName" - :class="{edit: editing == calendar.id}" - class="list reactive" - @add="dropTaskOnCalendar(...arguments, calendar)"> - <AppNavigationIconBullet slot="icon" :color="calendar.color" /> - - <template slot="counter"> - <AppNavigationCounter> - {{ calendarCount(calendar.id) | counterFormatter }} - </AppNavigationCounter> - <Actions v-if="!calendar.readOnly"> - <ActionButton - :icon="sharingIconClass(calendar)" - @click="toggleShare(calendar)"> - {{ sharedWithTooltip(calendar) }} - </ActionButton> - </Actions> - <Avatar v-if="calendar.isSharedWithMe && calendar.loadedOwnerPrincipal" :user="calendar.ownerUserId" :display-name="calendar.ownerDisplayname" /> - <div v-if="calendar.isSharedWithMe && !calendar.loadedOwnerPrincipal" class="icon icon-loading" /> - </template> - - <template slot="actions"> - <ActionButton - v-if="!calendar.readOnly" - icon="icon-rename" - @click="edit(calendar)"> - {{ $t('tasks', 'Edit') }} - </ActionButton> - <ActionButton - icon="icon-public" - :close-after-click="true" - @click="copyCalDAVUrl($event, calendar)"> - {{ !copied - ? $t('tasks', 'Copy private link') - : copySuccess - ? $t('tasks', 'Copied') - : $t('tasks', 'Can not copy') }} - </ActionButton> - <ActionLink - icon="icon-download" - :close-after-click="true" - :href="exportUrl(calendar)"> - {{ $t('tasks', 'Download') }} - </ActionLink> - <ActionButton - v-if="!calendar.readOnly" - v-tooltip="{ - placement: 'left', - boundariesElement: 'body', - content: deleteMessage(calendar) - }" - icon="icon-delete" - @click="deleteCalendar(calendar)"> - {{ !calendar.isSharedWithMe ? $t('calendar', 'Delete') : $t('calendar', 'Unshare') }} - </ActionButton> - </template> - - <ShareCalendar v-if="shareOpen == calendar.id && !calendar.readOnly" :calendar="calendar" /> - - <div :class="{error: nameError}" class="app-navigation-entry-edit"> - <form> - <input v-model="newCalendarName" - v-tooltip="{ - content: tooltipMessage, - show: showTooltip('list_' + calendar.id), - trigger: 'manual' - }" - class="edit" - type="text" - @keyup="checkName($event, calendar, save)"> - <input :title="$t('tasks', 'Cancel')" - type="cancel" - value="" - class="action icon-close" - @click="resetView(calendar)"> - <input :title="$t('tasks', 'Save')" - type="button" - value="" - class="action icon-checkmark" - @click="save(calendar)"> - </form> - <Colorpicker :selected-color="selectedColor" @color-selected="setColor(...arguments)" /> - </div> - </AppNavigationItem> - <AppNavigationItem v-click-outside="cancelCreate" - :title="$t('tasks', 'Add List…')" - icon="icon-add" - :class="{edit: creating}" - class="collection reactive" - @click="startCreate($event)"> - <div :class="{error: nameError}" class="app-navigation-entry-edit"> - <form> - <input id="newListInput" - v-model="newCalendarName" - v-tooltip="{ - content: tooltipMessage, - show: showTooltip('list_'), - trigger: 'manual' - }" - :placeholder="$t('tasks', 'New List')" - class="edit" - type="text" - @keyup="checkName($event, null, create)"> - <input :title="$t('tasks', 'Cancel')" - type="cancel" - value="" - class="action icon-close" - @click="cancelCreate"> - <input :title="$t('tasks', 'Save')" - type="button" - value="" - class="action icon-checkmark" - @click="create($event)"> - </form> - <Colorpicker :selected-color="selectedColor" @color-selected="setColor(...arguments)" /> - </div> - </AppNavigationItem> - </ul> -</template> - -<script> -import { mapState, mapGetters, mapActions } from 'vuex' -import Colorpicker from './Colorpicker' -import ShareCalendar from './CalendarShare' - -import ClickOutside from 'vue-click-outside' -import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem' -import AppNavigationCounter from '@nextcloud/vue/dist/Components/AppNavigationCounter' -import AppNavigationIconBullet from '@nextcloud/vue/dist/Components/AppNavigationIconBullet' -import Actions from '@nextcloud/vue/dist/Components/Actions' -import ActionButton from '@nextcloud/vue/dist/Components/ActionButton' -import ActionLink from '@nextcloud/vue/dist/Components/ActionLink' - -export default { - components: { - Colorpicker, - ShareCalendar, - AppNavigationItem, - AppNavigationCounter, - AppNavigationIconBullet, - Actions, - ActionButton, - ActionLink, - }, - directives: { - ClickOutside, - }, - filters: { - counterFormatter: function(count) { - switch (false) { - case count !== 0: - return '' - case count < 999: - return '999+' - default: - return count - } - }, - }, - data() { - return { - editing: '', - shareOpen: '', - copySuccess: false, - copied: false, - creating: false, - nameError: false, - newCalendarName: '', - selectedColor: '', - tooltipMessage: '', - tooltipTarget: '', - dayOfMonth: moment().date(), - } - }, - computed: { - ...mapState({ - collections: state => state.collections.collections, - }), - ...mapGetters({ - calendars: 'getSortedCalendars', - collectionCount: 'getCollectionCount', - calendarCount: 'getCalendarCount', - isCalendarNameUsed: 'isCalendarNameUsed', - getTask: 'getTaskByUri', - }), - }, - methods: { - ...mapActions([ - 'changeCalendar', - 'deleteCalendar', - 'appendCalendar', - 'moveTask', - 'setPriority', - 'setPercentComplete', - 'setDate', - ]), - dropTaskOnCalendar: function($event, calendar) { - let task - const taskAttribute = $event.item.attributes['task-id'] - if (taskAttribute) { - task = this.getTask(taskAttribute.value) - if (calendar !== task.calendar) { - this.moveTask({ task: task, calendar: calendar, parent: undefined }) - } - } - }, - dropTaskOnCollection: function($event, collection) { - let task - const taskAttribute = $event.item.attributes['task-id'] - if (taskAttribute) { - task = this.getTask(taskAttribute.value) - switch (collection.id) { - case 'starred': - this.setPriority({ task: task, priority: 1 }) - break - case 'completed': - this.setPercentComplete({ task: task, complete: 100 }) - break - case 'today': - this.setDate({ task: task, day: 0 }) - break - case 'week': - this.setDate({ task: task, day: 6 }) - break - } - } - }, - hideCollection: function(collection) { - switch (collection.show) { - case 0: - return true - case 1: - return false - case 2: - return this.collectionCount(collection.id) < 1 - } - }, - showTooltip: function(target) { - return this.tooltipTarget === target - }, - edit: function(calendar) { - this.editing = calendar.id - this.newCalendarName = calendar.displayName - this.selectedColor = calendar.color - this.nameError = false - this.tooltipTarget = '' - this.$nextTick( - () => document.querySelector('#list_' + calendar.id + ' input.edit').focus() - ) - }, - toggleShare: function(calendar) { - if (this.shareOpen === calendar.id) { - this.shareOpen = '' - } else { - this.shareOpen = calendar.id - } - }, - hasShares: function(calendar) { - return calendar.shares.length > 0 - }, - // info tooltip about number of shares - sharedWithTooltip: function(calendar) { - return this.hasShares(calendar) - ? this.$n('tasks', - 'Shared with {num} entity', - 'Shared with {num} entities', - calendar.shares.length, { - num: calendar.shares.length, - }) - : '' // disable the tooltip - }, - resetView: function(calendar) { - if (this.editing === calendar.id) { - this.editing = '' - } - if (this.shareOpen === calendar.id) { - this.shareOpen = '' - } - this.tooltipTarget = '' - }, - copyCalDAVUrl(event, calendar) { - // change to loading status - event.stopPropagation() - - const url = this.url(calendar) - - // copy link for calendar to clipboard - this.$copyText(url) - .then(e => { - event.preventDefault() - this.copySuccess = true - this.copied = true - // Notify calendar url was copied - this.$OC.Notification.showTemporary(this.$t('tasks', 'Calendar link copied to clipboard.')) - }, e => { - this.copySuccess = false - this.copied = true - this.$OC.Notification.showTemporary(this.$t('tasks', 'Calendar link could not be copied to clipboard.')) - }).then(() => { - setTimeout(() => { - // stop loading status regardless of outcome - this.copied = false - }, 2000) - }) - }, - exportUrl(calendar) { - let url = calendar.url - // cut off last slash to have a fancy name for the ics - if (url.slice(url.length - 1) === '/') { - url = url.slice(0, url.length - 1) - } - url += '?export' - return url - }, - url(calendar) { - const rootURL = this.$OC.linkToRemote('dav') - return new URL(calendar.url, rootURL) - }, - setColor: function(color) { - this.selectedColor = color - }, - startCreate: function(e) { - if (this.$OCA.Theming) { - this.selectedColor = this.$OCA.Theming.color - } else { - this.selectedColor = '#0082C9' - } - this.newCalendarName = '' - this.creating = true - this.$nextTick( - () => document.getElementById('newListInput').focus() - ) - e.stopPropagation() - }, - cancelCreate: function() { - this.creating = false - }, - create: function() { - if (!this.isNameAllowed(this.newCalendarName, 'new').allowed) { - return - } - this.appendCalendar({ displayName: this.newCalendarName, color: this.selectedColor }) - this.creating = false - }, - save: function(calendar) { - if (!this.isNameAllowed(this.newCalendarName, calendar.id).allowed) { - return - } - this.changeCalendar({ calendar: calendar, newName: this.newCalendarName, newColor: this.selectedColor }) - this.editing = false - }, - checkName: function(event, calendar, callback) { - const calendarId = calendar ? calendar.id : '' - const check = this.isNameAllowed(this.newCalendarName, calendarId) - this.tooltipMessage = check.msg - if (!check.allowed) { - this.tooltipTarget = 'list_' + calendarId - this.nameError = true - } else { - this.tooltipTarget = '' - this.nameError = false - } - if (event.keyCode === 13) { - callback(calendar) - } - if (event.keyCode === 27) { - event.preventDefault() - this.tooltipTarget = '' - this.creating = false - this.editing = false - this.nameError = false - } - }, - isNameAllowed: function(name, id) { - const check = { - allowed: false, - msg: '', - } - if (this.isCalendarNameUsed(name, id)) { - check.msg = this.$t('tasks', 'The name "{calendar}" is already used.', { calendar: name }) - } else if (!name) { - check.msg = this.$t('tasks', 'An empty name is not allowed.') - } else { - check.allowed = true - } - return check - }, - deleteMessage: function(calendar) { - return !calendar.isSharedWithMe - ? this.$t('tasks', 'This will delete the calendar "{calendar}" and all corresponding events and tasks.', { calendar: calendar.displayName }) - : this.$t('tasks', 'This will unshare the calendar "{calendar}".', { calendar: calendar.displayName }) - }, - sharingIconClass(calendar) { - if (calendar.shares.length) { - return 'icon-shared' - } - return 'icon-share' - }, - }, -} -</script> |