diff options
author | Grigorii Shartsev <grigorii.shartsev@nextcloud.com> | 2023-03-12 21:12:39 +0100 |
---|---|---|
committer | Grigorii Shartsev <grigorii.shartsev@nextcloud.com> | 2023-03-21 15:10:00 +0100 |
commit | 3603b566bc5bab03b60f7361a3a7abb97bd4be1b (patch) | |
tree | 41ededd34645623862b33fed4c706de5f6f9a48d /src | |
parent | 6d887a87a749efbcd0d080f7b3d6e5ef22f27649 (diff) |
feat: add utils for generating absolute links and copy a chat link
- Add `generateAbsoluteUrl` util
- Add `copyLinkToConversation` method for copying conversation links to the clipboard with dialogs
- Remove unused
- Use dialogs on new conversation confirmation
Signed-off-by: Grigorii Shartsev <grigorii.shartsev@nextcloud.com>
Diffstat (limited to 'src')
9 files changed, 113 insertions, 116 deletions
diff --git a/src/components/CallView/shared/EmptyCallView.vue b/src/components/CallView/shared/EmptyCallView.vue index 662773910..81e2028a8 100644 --- a/src/components/CallView/shared/EmptyCallView.vue +++ b/src/components/CallView/shared/EmptyCallView.vue @@ -29,19 +29,17 @@ </p> <NcButton v-if="showLink" type="primary" - @click.stop.prevent="copyLinkToConversation"> + @click.stop.prevent="handleCopyLink"> {{ t('spreed', 'Copy link') }} </NcButton> </div> </template> <script> -import { showError, showSuccess } from '@nextcloud/dialogs' -import { generateUrl } from '@nextcloud/router' - import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import { CONVERSATION, PARTICIPANT } from '../../../constants.js' +import { copyLinkToConversation } from '../../../services/urlService.js' export default { @@ -161,24 +159,13 @@ export default { showLink() { return this.isPublicConversation && !this.isPasswordRequestConversation && !this.isFileConversation }, - - linkToConversation() { - return window.location.protocol + '//' + window.location.host + generateUrl('/call/' + this.token) - }, - }, methods: { - async copyLinkToConversation() { - try { - await navigator.clipboard.writeText(this.linkToConversation) - showSuccess(t('spreed', 'Conversation link copied to clipboard')) - } catch (error) { - showError(t('spreed', 'The link could not be copied')) - } + async handleCopyLink() { + await copyLinkToConversation(this.token) }, }, - } </script> @@ -201,12 +188,13 @@ export default { width: 64px; margin: 0 auto 15px; } + button { margin: 4px auto; } h2, p { - color: #ffffff; + color: #FFFFFF; } &--sidebar { diff --git a/src/components/ConversationSettings/LinkShareSettings.vue b/src/components/ConversationSettings/LinkShareSettings.vue index cc67af8e7..023549d5c 100644 --- a/src/components/ConversationSettings/LinkShareSettings.vue +++ b/src/components/ConversationSettings/LinkShareSettings.vue @@ -98,13 +98,13 @@ import ClipboardTextOutline from 'vue-material-design-icons/ClipboardTextOutline import Email from 'vue-material-design-icons/Email.vue' import { showError, showSuccess } from '@nextcloud/dialogs' -import { generateUrl } from '@nextcloud/router' import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' import NcPasswordField from '@nextcloud/vue/dist/Components/NcPasswordField.js' import { CONVERSATION } from '../../constants.js' +import { copyLinkToConversation } from '../../services/urlService.js' export default { name: 'LinkShareSettings', @@ -142,10 +142,6 @@ export default { conversation() { return this.$store.getters.conversation(this.token) || this.$store.getters.dummyConversation }, - - linkToConversation() { - return window.location.protocol + '//' + window.location.host + generateUrl('/call/' + this.token) - }, }, methods: { @@ -236,12 +232,7 @@ export default { }, async handleCopyLink() { - try { - await navigator.clipboard.writeText(this.linkToConversation) - showSuccess(t('spreed', 'Conversation link copied to clipboard.')) - } catch (error) { - showError(t('spreed', 'The link could not be copied.')) - } + await copyLinkToConversation(this.token) }, async handleResendInvitations() { diff --git a/src/components/LeftSidebar/ConversationsList/Conversation.vue b/src/components/LeftSidebar/ConversationsList/Conversation.vue index 6f36d8fc8..afdfc5ca9 100644 --- a/src/components/LeftSidebar/ConversationsList/Conversation.vue +++ b/src/components/LeftSidebar/ConversationsList/Conversation.vue @@ -59,7 +59,7 @@ {{ labelFavorite }} </NcActionButton> <NcActionButton icon="icon-clippy" - @click.stop.prevent="copyLinkToConversation"> + @click.stop.prevent="handleCopyLink"> {{ t('spreed', 'Copy link') }} </NcActionButton> <NcActionButton :close-after-click="true" @@ -106,9 +106,8 @@ import ExitToApp from 'vue-material-design-icons/ExitToApp.vue' import EyeOutline from 'vue-material-design-icons/EyeOutline.vue' import Star from 'vue-material-design-icons/Star.vue' -import { showError, showSuccess } from '@nextcloud/dialogs' +import { showError } from '@nextcloud/dialogs' import { emit } from '@nextcloud/event-bus' -import { generateUrl } from '@nextcloud/router' import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js' @@ -116,9 +115,11 @@ import NcListItem from '@nextcloud/vue/dist/Components/NcListItem.js' import ConversationIcon from './../../ConversationIcon.vue' import { CONVERSATION, PARTICIPANT, ATTENDEE } from '../../../constants.js' +import { copyLinkToConversation } from '../../../services/urlService.js' export default { name: 'Conversation', + components: { Cog, ConversationIcon, @@ -129,6 +130,7 @@ export default { NcListItem, Star, }, + props: { isSearchResult: { type: Boolean, @@ -155,7 +157,6 @@ export default { }, computed: { - counterType() { if (this.item.unreadMentionDirect || (this.item.unreadMessages !== 0 && ( this.item.type === CONVERSATION.TYPE.ONE_TO_ONE || this.item.type === CONVERSATION.TYPE.ONE_TO_ONE_FORMER @@ -168,10 +169,6 @@ export default { } }, - linkToConversation() { - return window.location.protocol + '//' + window.location.host + generateUrl('/call/' + this.item.token) - }, - canFavorite() { return this.item.participantType !== PARTICIPANT.TYPE.USER_SELF_JOINED }, @@ -331,14 +328,8 @@ export default { }, methods: { - async copyLinkToConversation() { - try { - await navigator.clipboard.writeText(this.linkToConversation) - showSuccess(t('spreed', 'Conversation link copied to clipboard')) - } catch (error) { - console.error('Error copying link: ', error) - showError(t('spreed', 'The link could not be copied')) - } + async handleCopyLink() { + await copyLinkToConversation(this.item.token) }, markConversationAsRead() { diff --git a/src/components/LeftSidebar/NewGroupConversation/Confirmation/Confirmation.vue b/src/components/LeftSidebar/NewGroupConversation/Confirmation/Confirmation.vue index e9efb0eac..acf0766c7 100644 --- a/src/components/LeftSidebar/NewGroupConversation/Confirmation/Confirmation.vue +++ b/src/components/LeftSidebar/NewGroupConversation/Confirmation/Confirmation.vue @@ -34,15 +34,11 @@ {{ t('spreed', 'All set') }} </p> <NcButton id="copy-link" - slot="trigger" type="secondary" class="confirmation__copy-link" @click="onClickCopyLink"> {{ t('spreed', 'Copy conversation link') }} </NcButton> - <p class="confirmation__warning"> - {{ confirmationText }} - </p> </template> </template> <template v-else> @@ -57,12 +53,18 @@ <script> import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' +import { copyLinkToConversation } from '../../../../services/urlService.js' + export default { name: 'Confirmation', components: { NcButton, }, props: { + token: { + type: String, + required: true, + }, conversationName: { type: String, required: true, @@ -83,42 +85,11 @@ export default { type: Boolean, required: true, }, - linkToConversation: { - type: String, - required: true, - }, - }, - - data() { - return { - showTooltip: false, - confirmationText: '', - showConfirmationText: false, - } }, methods: { - async onClickCopyLink() { - try { - await navigator.clipboard.writeText(this.linkToConversation) - this.onCopy() - } catch (error) { - this.onError() - } - }, - onCopy() { - this.confirmationText = t('spreed', 'Link copied to the clipboard!') - this.showConfirmationText = true - setTimeout(function() { - this.showConfirmationText = false - }, 800) - }, - onError() { - this.confirmationText = t('spreed', 'Error') - this.showConfirmationText = true - setTimeout(function() { - this.showConfirmationText = false - }, 800) + onClickCopyLink() { + copyLinkToConversation(this.token) }, }, @@ -130,13 +101,16 @@ export default { .confirmation { display: flex; flex-direction: column; - &__icon{ + + &__icon { padding-top: 80px; } - &__warning{ + + &__warning { margin-top: 10px; text-align: center; } + &__copy-link { margin: 50px auto 0 auto; } diff --git a/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue b/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue index 326fe08ed..fa4d57a0c 100644 --- a/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue +++ b/src/components/LeftSidebar/NewGroupConversation/NewGroupConversation.vue @@ -71,12 +71,12 @@ </template> <!-- Third page --> <template v-if="page === 2"> - <Confirmation :conversation-name="conversationName" + <Confirmation :token="token" + :conversation-name="conversationName" :error="error" :is-loading="isLoading" :success="success" - :is-public="isPublic" - :link-to-conversation="linkToConversation" /> + :is-public="isPublic" /> </template> </div> <!-- Navigation: different buttons with different actions and @@ -125,8 +125,6 @@ import Plus from 'vue-material-design-icons/Plus.vue' -import { generateUrl } from '@nextcloud/router' - import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js' import NcModal from '@nextcloud/vue/dist/Components/NcModal.js' @@ -148,6 +146,7 @@ import { } from '../../../services/conversationsService.js' import { EventBus } from '../../../services/EventBus.js' import { addParticipant } from '../../../services/participantsService.js' +import { generateFullConversationLink } from '../../../services/urlService.js' export default { @@ -198,12 +197,6 @@ export default { conversationName() { return this.conversationNameInput.trim() }, - // Generates the link to the current conversation - linkToConversation() { - if (this.token !== '') { - return window.location.protocol + '//' + window.location.host + generateUrl('/call/' + this.token) - } else return '' - }, // Controls the disabled/enabled state of the first page's button. disabled() { return this.conversationName === '' || (this.passwordProtect && this.password === '') diff --git a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue index d32bb6412..76bba8531 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessageButtonsBar/MessageButtonsBar.vue @@ -169,9 +169,7 @@ import Plus from 'vue-material-design-icons/Plus.vue' import Reply from 'vue-material-design-icons/Reply.vue' import Share from 'vue-material-design-icons/Share.vue' -import { showError, showSuccess } from '@nextcloud/dialogs' import moment from '@nextcloud/moment' -import { generateUrl } from '@nextcloud/router' import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js' @@ -184,6 +182,7 @@ import Forwarder from './Forwarder.vue' import { PARTICIPANT, CONVERSATION, ATTENDEE } from '../../../../../constants.js' import { EventBus } from '../../../../../services/EventBus.js' +import { copyLinkToConversation } from '../../../../../services/urlService.js' // Keep version in sync with @nextcloud/vue in case of issues @@ -212,6 +211,7 @@ export default { Reply, Share, }, + props: { token: { type: String, @@ -469,14 +469,7 @@ export default { }, async handleCopyMessageLink() { - try { - const link = window.location.protocol + '//' + window.location.host + generateUrl('/call/' + this.token) + '#message_' + this.id - await navigator.clipboard.writeText(link) - showSuccess(t('spreed', 'Message link copied to clipboard')) - } catch (error) { - console.error('Error copying link: ', error) - showError(t('spreed', 'The link could not be copied')) - } + await copyLinkToConversation(this.token, this.id) }, async handleMarkAsUnread() { diff --git a/src/components/TopBar/TopBar.vue b/src/components/TopBar/TopBar.vue index 025dc2abc..f1480ad8f 100644 --- a/src/components/TopBar/TopBar.vue +++ b/src/components/TopBar/TopBar.vue @@ -136,7 +136,6 @@ import MessageText from 'vue-material-design-icons/MessageText.vue' import { showMessage } from '@nextcloud/dialogs' import { emit } from '@nextcloud/event-bus' -import { generateUrl } from '@nextcloud/router' import NcButton from '@nextcloud/vue/dist/Components/NcButton.js' import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js' @@ -245,14 +244,6 @@ export default { return this.conversation.unreadMention }, - linkToConversation() { - if (this.token !== '') { - return window.location.protocol + '//' + window.location.host + generateUrl('/call/' + this.token) - } else { - return '' - } - }, - renderedDescription() { return this.renderContent(this.conversation.description) }, diff --git a/src/components/TopBar/TopBarMenu.vue b/src/components/TopBar/TopBarMenu.vue index 53bcd34e4..376c50a46 100644 --- a/src/components/TopBar/TopBarMenu.vue +++ b/src/components/TopBar/TopBarMenu.vue @@ -170,7 +170,6 @@ import VideoIcon from 'vue-material-design-icons/Video.vue' import { getCapabilities } from '@nextcloud/capabilities' import { emit } from '@nextcloud/event-bus' -import { generateUrl } from '@nextcloud/router' import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' import NcActionLink from '@nextcloud/vue/dist/Components/NcActionLink.js' @@ -183,6 +182,7 @@ import PromotedView from '../missingMaterialDesignIcons/PromotedView.vue' import { CALL, CONVERSATION, PARTICIPANT } from '../../constants.js' import isInCall from '../../mixins/isInCall.js' +import { generateAbsoluteUrl } from '../../services/urlService.js' import { callParticipantCollection } from '../../utils/webrtc/index.js' export default { @@ -280,7 +280,7 @@ export default { linkToFile() { if (this.isFileConversation) { - return window.location.protocol + '//' + window.location.host + generateUrl('/f/' + this.conversation.objectId) + return generateAbsoluteUrl('/f/{objectId}', { objectId: this.conversation.objectId }) } else { return '' } diff --git a/src/services/urlService.js b/src/services/urlService.js new file mode 100644 index 000000000..3b9dd6cda --- /dev/null +++ b/src/services/urlService.js @@ -0,0 +1,76 @@ +/* + * @copyright Copyright (c) 2023 Grigorii Shartsev <grigorii.shartsev@nextcloud.com> + * + * @author Grigorii Shartsev <grigorii.shartsev@nextcloud.com> + * + * @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/>. + */ + +import { showError, showSuccess } from '@nextcloud/dialogs' +import { generateUrl } from '@nextcloud/router' + +/** + * Generate a full absolute link with @nextcloud/router.generateUrl + * + * @see @nextcloud/router.generateUrl + * @param {string} url + * @param {object} [params] parameters to be replaced into the address + * @param {import('@nextcloud/router').UrlOptions} [options] options for the parameter replacement + * @param {boolean} options.noRewrite True if you want to force index.php being added + * @param {boolean} options.escape Set to false if parameters should not be URL encoded (default true) + * @return {string} Full absolute URL + */ +export function generateAbsoluteUrl(url, params, options) { + // TODO: add this function to @nextcloud/router? + const fullPath = generateUrl(url, params, options) + if (!IS_DESKTOP) { + return `${window.location.protocol}//${window.location.host}${fullPath}` + } else { + return fullPath + } +} + +/** + * Generate full link to conversation + * + * @param {string} token - Conversation token + * @param {string} [messageId] - messageId for message in conversation link + * @return {string} - Absolute URL to conversation + */ +export function generateFullConversationLink(token, messageId) { + return messageId !== undefined + ? generateAbsoluteUrl('/call/{token}#message_{messageId}', { + token, + messageId, + }) + : generateAbsoluteUrl('/call/{token}', { token }) +} + +/** + * Try to copy conversation link to a clipboard and display the result with dialogs + * + * @param {string} token - conversation token + * @param {string} [messageId] - messageId for message in conversation link + * @return {Promise<void>} + */ +export async function copyLinkToConversation(token, messageId) { + try { + await navigator.clipboard.writeText(generateFullConversationLink(token, messageId)) + showSuccess(t('spreed', 'Conversation link copied to clipboard')) + } catch (error) { + showError(t('spreed', 'The link could not be copied')) + } +} |