Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/tasks.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaimund Schlüßler <raimund.schluessler@mailbox.org>2020-01-23 14:09:49 +0300
committerRaimund Schlüßler <raimund.schluessler@mailbox.org>2020-02-05 00:49:17 +0300
commitae7bf7f69642244416c51237a2e808675124317c (patch)
treeaa7805218784a9f3533c6556d634a69551436c4b /src/components
parent298803f8ac936b870a7265adb0b4953f519b8f28 (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.vue241
-rw-r--r--src/components/AppNavigation/ListItemCalendar.vue332
-rw-r--r--src/components/AppNavigation/TheSettings.vue (renamed from src/components/TheSettings.vue)0
-rw-r--r--src/components/TheList.vue446
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>