diff --git a/src/collections.js b/src/collections.js
index 0be2e318331..28c90820715 100644
--- a/src/collections.js
+++ b/src/collections.js
@@ -3,55 +3,28 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import Vue from 'vue'
+import { t } from '@nextcloud/l10n'
-// eslint-disable-next-line no-unexpected-multiline
-(function(OCP, OC) {
+import { requestRoomSelection } from './utils/requestRoomSelection.js'
- // eslint-disable-next-line
- __webpack_nonce__ = btoa(OC.requestToken)
- // eslint-disable-next-line
- __webpack_public_path__ = OC.linkTo('spreed', 'js/')
+// eslint-disable-next-line
+__webpack_nonce__ = btoa(OC.requestToken)
+// eslint-disable-next-line
+__webpack_public_path__ = OC.linkTo('spreed', 'js/')
- Vue.prototype.t = t
- Vue.prototype.n = n
- Vue.prototype.OC = OC
-
- OCP.Collaboration.registerType('room', {
- action: () => {
- return new Promise((resolve, reject) => {
- const container = document.createElement('div')
- container.id = 'spreed-room-select'
- const body = document.getElementById('body-user')
- body.appendChild(container)
-
- const RoomSelector = () => import('./components/RoomSelector.vue')
- const ComponentVM = new Vue({
- el: container,
- render: h => h(RoomSelector, {
- props: {
- // Even if it is used from Talk the Collections menu is
- // independently loaded, so the properties that depend
- // on the store need to be explicitly injected.
- container: window.store ? window.store.getters.getMainContainerSelector() : undefined,
- isPlugin: true,
- },
- }),
- })
-
- ComponentVM.$root.$on('close', () => {
- ComponentVM.$el.remove()
- ComponentVM.$destroy()
- reject(new Error('User cancelled resource selection'))
- })
- ComponentVM.$root.$on('select', ({ token }) => {
- resolve(token)
- ComponentVM.$el.remove()
- ComponentVM.$destroy()
- })
- })
- },
- typeString: t('spreed', 'Link to a conversation'),
- typeIconClass: 'icon-talk',
- })
-})(window.OCP, window.OC)
+window.OCP.Collaboration.registerType('room', {
+ action: async () => {
+ const conversation = await requestRoomSelection('spreed-room-select', {
+ // Even if it is used from Talk the Collections menu is
+ // independently loaded, so the properties that depend
+ // on the store need to be explicitly injected.
+ container: window.store ? window.store.getters.getMainContainerSelector() : undefined,
+ })
+ if (!conversation) {
+ throw new Error('User cancelled resource selection')
+ }
+ return conversation.token
+ },
+ typeString: t('spreed', 'Link to a conversation'),
+ typeIconClass: 'icon-talk',
+})
diff --git a/src/deck.js b/src/deck.js
index 33bc3c43e49..73bf57aac00 100644
--- a/src/deck.js
+++ b/src/deck.js
@@ -4,109 +4,81 @@
*/
import escapeHtml from 'escape-html'
-import Vue from 'vue'
import { getRequestToken } from '@nextcloud/auth'
import { showSuccess, showError } from '@nextcloud/dialogs'
-import { translate, translatePlural } from '@nextcloud/l10n'
+import { t } from '@nextcloud/l10n'
import { generateFilePath, generateUrl } from '@nextcloud/router'
import { postRichObjectToConversation } from './services/messagesService.ts'
+import { requestRoomSelection } from './utils/requestRoomSelection.js'
import '@nextcloud/dialogs/style.css'
-(function(OC, OCA, t, n) {
- /**
- * @param {object} card The card object given by the deck app
- * @param {object} conversation The conversation object given by the RoomSelector
- * @param {string} conversation.token The conversation token
- * @param {string} conversation.displayName The conversation display name
- */
- async function postCardToRoom(card, { token, displayName }) {
- try {
- const response = await postRichObjectToConversation(token, {
- objectType: 'deck-card',
- objectId: card.id,
- metaData: JSON.stringify(card),
- })
+/**
+ * @param {object} card The card object given by the deck app
+ * @param {object} conversation The conversation object given by the RoomSelector
+ * @param {string} conversation.token The conversation token
+ * @param {string} conversation.displayName The conversation display name
+ */
+async function postCardToRoom(card, { token, displayName }) {
+ try {
+ const response = await postRichObjectToConversation(token, {
+ objectType: 'deck-card',
+ objectId: card.id,
+ metaData: JSON.stringify(card),
+ })
- const messageId = response.data.ocs.data.id
- const targetUrl = generateUrl('/call/{token}#message_{messageId}', { token, messageId })
+ const messageId = response.data.ocs.data.id
+ const targetUrl = generateUrl('/call/{token}#message_{messageId}', { token, messageId })
- showSuccess(t('spreed', 'Deck card has been posted to {conversation}')
- .replace(/\{conversation}/g, `${escapeHtml(displayName)} ↗`),
- {
- isHTML: true,
- })
- } catch (exception) {
- console.error('Error posting deck card to conversation', exception, exception.response?.status)
- if (exception.response?.status === 403) {
- showError(t('spreed', 'No permission to post messages in this conversation'))
- } else {
- showError(t('spreed', 'An error occurred while posting deck card to conversation'))
- }
+ showSuccess(t('spreed', 'Deck card has been posted to {conversation}')
+ .replace(/\{conversation}/g, `${escapeHtml(displayName)} ↗`),
+ {
+ isHTML: true,
+ })
+ } catch (exception) {
+ console.error('Error posting deck card to conversation', exception, exception.response?.status)
+ if (exception.response?.status === 403) {
+ showError(t('spreed', 'No permission to post messages in this conversation'))
+ } else {
+ showError(t('spreed', 'An error occurred while posting deck card to conversation'))
}
}
+}
- /**
- *
- */
- function init() {
- if (!OCA.Deck) {
- return
- }
-
- OCA.Deck.registerCardAction({
- label: t('spreed', 'Post to a conversation'),
- icon: 'icon-talk',
- callback: (card) => {
- const container = document.createElement('div')
- container.id = 'spreed-post-card-to-room-select'
- const body = document.getElementById('body-user')
- body.appendChild(container)
-
- const RoomSelector = () => import('./components/RoomSelector.vue')
- const vm = new Vue({
- el: container,
- render: h => h(RoomSelector, {
- props: {
- dialogTitle: t('spreed', 'Post to conversation'),
- showPostableOnly: true,
- isPlugin: true,
- },
- }),
- })
-
- vm.$root.$on('close', () => {
- vm.$el.remove()
- vm.$destroy()
- })
- vm.$root.$on('select', (conversation) => {
- vm.$el.remove()
- vm.$destroy()
-
- postCardToRoom(card, conversation)
- })
- },
- })
+/**
+ *
+ */
+function init() {
+ if (!window.OCA.Deck) {
+ return
}
- // CSP config for webpack dynamic chunk loading
- // eslint-disable-next-line
- __webpack_nonce__ = btoa(getRequestToken())
-
- // Correct the root of the app for chunk loading
- // OC.linkTo matches the apps folders
- // OC.generateUrl ensure the index.php (or not)
- // We do not want the index.php since we're loading files
- // eslint-disable-next-line
- __webpack_public_path__ = generateFilePath('spreed', '', 'js/')
-
- Vue.prototype.t = translate
- Vue.prototype.n = translatePlural
- Vue.prototype.OC = OC
- Vue.prototype.OCA = OCA
-
- document.addEventListener('DOMContentLoaded', init)
-
-})(window.OC, window.OCA, t, n)
+ window.OCA.Deck.registerCardAction({
+ label: t('spreed', 'Post to a conversation'),
+ icon: 'icon-talk',
+ callback: async (card) => {
+ const conversation = await requestRoomSelection('spreed-post-card-to-room-select', {
+ dialogTitle: t('spreed', 'Post to conversation'),
+ showPostableOnly: true,
+ })
+ if (conversation) {
+ postCardToRoom(card, conversation)
+ }
+ },
+ })
+}
+
+// CSP config for webpack dynamic chunk loading
+// eslint-disable-next-line
+__webpack_nonce__ = btoa(getRequestToken())
+
+// Correct the root of the app for chunk loading
+// OC.linkTo matches the apps folders
+// OC.generateUrl ensure the index.php (or not)
+// We do not want the index.php since we're loading files
+// eslint-disable-next-line
+__webpack_public_path__ = generateFilePath('spreed', '', 'js/')
+
+document.addEventListener('DOMContentLoaded', init)
diff --git a/src/maps.js b/src/maps.js
index 178e00ddfaa..cf268e4786b 100644
--- a/src/maps.js
+++ b/src/maps.js
@@ -4,108 +4,79 @@
*/
import escapeHtml from 'escape-html'
-import Vue from 'vue'
import { getRequestToken } from '@nextcloud/auth'
import { showSuccess, showError } from '@nextcloud/dialogs'
-import { translate, translatePlural } from '@nextcloud/l10n'
+import { t } from '@nextcloud/l10n'
import { generateFilePath, generateUrl } from '@nextcloud/router'
import { postRichObjectToConversation } from './services/messagesService.ts'
+import { requestRoomSelection } from './utils/requestRoomSelection.js'
import '@nextcloud/dialogs/style.css'
-(function(OC, OCA, t, n) {
- /**
- * @param {object} location Geo location object
- * @param {object} conversation The conversation object given by the RoomSelector
- * @param {string} conversation.token The conversation token
- * @param {string} conversation.displayName The conversation display name
- */
- async function postLocationToRoom(location, { token, displayName }) {
- try {
- const response = await postRichObjectToConversation(token, {
- objectType: 'geo-location',
- objectId: location.id,
- metaData: JSON.stringify(location),
- })
- const messageId = response.data.ocs.data.id
- const targetUrl = generateUrl('/call/{token}#message_{messageId}', { token, messageId })
+/**
+ * @param {object} location Geo location object
+ * @param {object} conversation The conversation object given by the RoomSelector
+ * @param {string} conversation.token The conversation token
+ * @param {string} conversation.displayName The conversation display name
+ */
+async function postLocationToRoom(location, { token, displayName }) {
+ try {
+ const response = await postRichObjectToConversation(token, {
+ objectType: 'geo-location',
+ objectId: location.id,
+ metaData: JSON.stringify(location),
+ })
+ const messageId = response.data.ocs.data.id
+ const targetUrl = generateUrl('/call/{token}#message_{messageId}', { token, messageId })
- showSuccess(t('spreed', 'Location has been posted to {conversation}')
- .replace(/\{conversation}/g, `${escapeHtml(displayName)} ↗`),
- {
- isHTML: true,
- })
- } catch (exception) {
- console.error('Error posting location to conversation', exception, exception.response?.status)
- if (exception.response?.status === 403) {
- showError(t('spreed', 'No permission to post messages in this conversation'))
- } else {
- showError(t('spreed', 'An error occurred while posting location to conversation'))
- }
+ showSuccess(t('spreed', 'Location has been posted to {conversation}')
+ .replace(/\{conversation}/g, `${escapeHtml(displayName)} ↗`),
+ {
+ isHTML: true,
+ })
+ } catch (exception) {
+ console.error('Error posting location to conversation', exception, exception.response?.status)
+ if (exception.response?.status === 403) {
+ showError(t('spreed', 'No permission to post messages in this conversation'))
+ } else {
+ showError(t('spreed', 'An error occurred while posting location to conversation'))
}
}
+}
- /**
- * Initialise the maps action
- */
- function init() {
- if (!OCA.Maps?.registerMapsAction) {
- return
- }
-
- OCA.Maps.registerMapsAction({
- label: t('spreed', 'Share to a conversation'),
- icon: 'icon-talk',
- callback: (location) => {
- const container = document.createElement('div')
- container.id = 'spreed-post-location-to-room-select'
- const body = document.getElementById('body-user')
- body.appendChild(container)
-
- const RoomSelector = () => import('./components/RoomSelector.vue')
- const vm = new Vue({
- el: container,
- render: h => h(RoomSelector, {
- props: {
- dialogTitle: t('spreed', 'Share to conversation'),
- showPostableOnly: true,
- isPlugin: true,
- },
- }),
- })
-
- vm.$root.$on('close', () => {
- vm.$el.remove()
- vm.$destroy()
- })
- vm.$root.$on('select', (conversation) => {
- vm.$el.remove()
- vm.$destroy()
-
- postLocationToRoom(location, conversation)
- })
- },
- })
+/**
+ * Initialise the maps action
+ */
+function init() {
+ if (!window.OCA.Maps?.registerMapsAction) {
+ return
}
- // CSP config for webpack dynamic chunk loading
- // eslint-disable-next-line
- __webpack_nonce__ = btoa(getRequestToken())
+ window.OCA.Maps.registerMapsAction({
+ label: t('spreed', 'Share to a conversation'),
+ icon: 'icon-talk',
+ callback: async (location) => {
+ const conversation = await requestRoomSelection('spreed-post-location-to-room-select', {
+ dialogTitle: t('spreed', 'Share to conversation'),
+ showPostableOnly: true,
+ })
- // Correct the root of the app for chunk loading
- // OC.linkTo matches the apps folders
- // OC.generateUrl ensure the index.php (or not)
- // We do not want the index.php since we're loading files
- // eslint-disable-next-line
- __webpack_public_path__ = generateFilePath('spreed', '', 'js/')
+ postLocationToRoom(location, conversation)
+ },
+ })
+}
- Vue.prototype.t = translate
- Vue.prototype.n = translatePlural
- Vue.prototype.OC = OC
- Vue.prototype.OCA = OCA
+// CSP config for webpack dynamic chunk loading
+// eslint-disable-next-line
+__webpack_nonce__ = btoa(getRequestToken())
- document.addEventListener('DOMContentLoaded', init)
+// Correct the root of the app for chunk loading
+// OC.linkTo matches the apps folders
+// OC.generateUrl ensure the index.php (or not)
+// We do not want the index.php since we're loading files
+// eslint-disable-next-line
+__webpack_public_path__ = generateFilePath('spreed', '', 'js/')
-})(window.OC, window.OCA, t, n)
+document.addEventListener('DOMContentLoaded', init)
diff --git a/src/search.js b/src/search.js
index 3c6d092124f..06c0f865889 100644
--- a/src/search.js
+++ b/src/search.js
@@ -3,82 +3,54 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import Vue from 'vue'
-
import { getRequestToken } from '@nextcloud/auth'
import { emit } from '@nextcloud/event-bus'
-import { translate, translatePlural } from '@nextcloud/l10n'
+import { t } from '@nextcloud/l10n'
import { generateFilePath, imagePath } from '@nextcloud/router'
-import '@nextcloud/dialogs/style.css'
-
-(function(OC, OCA, t, n) {
+import { requestRoomSelection } from './utils/requestRoomSelection.js'
- /**
- *
- */
- function init() {
- if (!OCA.UnifiedSearch) {
- return
- }
- console.debug('Initializing unified search plugin-filters from talk')
- OCA.UnifiedSearch.registerFilterAction({
- id: 'talk-message',
- appId: 'spreed',
- label: t('spreed', 'In conversation'),
- icon: imagePath('spreed', 'app.svg'),
- callback: () => {
- const container = document.createElement('div')
- container.id = 'spreed-unified-search-conversation-select'
- const body = document.getElementById('body-user')
- body.appendChild(container)
-
- const RoomSelector = () => import('./components/RoomSelector.vue')
- const vm = new Vue({
- el: container,
- render: h => h(RoomSelector, {
- props: {
- dialogTitle: t('spreed', 'Select conversation'),
- isPlugin: true,
- },
- }),
- })
-
- vm.$root.$on('close', () => {
- vm.$el.remove()
- vm.$destroy()
- })
- vm.$root.$on('select', (conversation) => {
- vm.$el.remove()
- vm.$destroy()
+import '@nextcloud/dialogs/style.css'
- emit('nextcloud:unified-search:add-filter', {
- id: 'talk-message',
- payload: conversation,
- filterUpdateText: t('spreed', 'Search in conversation: {conversation}', { conversation: conversation.displayName }),
- filterParams: { conversation: conversation.token }
- })
- })
- },
- })
+/**
+ *
+ */
+function init() {
+ if (!window.OCA.UnifiedSearch) {
+ return
}
-
- // CSP config for webpack dynamic chunk loading
- // eslint-disable-next-line
- __webpack_nonce__ = btoa(getRequestToken())
-
- // Correct the root of the app for chunk loading
- // OC.linkTo matches the apps folders
- // OC.generateUrl ensure the index.php (or not)
- // We do not want the index.php since we're loading files
- // eslint-disable-next-line
- __webpack_public_path__ = generateFilePath('spreed', '', 'js/')
-
- Vue.prototype.t = translate
- Vue.prototype.n = translatePlural
- Vue.prototype.OC = OC
- Vue.prototype.OCA = OCA
-
- document.addEventListener('DOMContentLoaded', init)
-
-})(window.OC, window.OCA, t, n)
+ console.debug('Initializing unified search plugin-filters from talk')
+ window.OCA.UnifiedSearch.registerFilterAction({
+ id: 'talk-message',
+ appId: 'spreed',
+ label: t('spreed', 'In conversation'),
+ icon: imagePath('spreed', 'app.svg'),
+ callback: async () => {
+ const conversation = await requestRoomSelection('spreed-unified-search-conversation-select', {
+ dialogTitle: t('spreed', 'Select conversation'),
+ })
+
+ if (conversation) {
+ emit('nextcloud:unified-search:add-filter', {
+ id: 'talk-message',
+ payload: conversation,
+ filterUpdateText: t('spreed', 'Search in conversation: {conversation}', { conversation: conversation.displayName }),
+ filterParams: { conversation: conversation.token }
+ })
+ }
+ },
+ })
+}
+
+// CSP config for webpack dynamic chunk loading
+// eslint-disable-next-line
+__webpack_nonce__ = btoa(getRequestToken())
+
+// Correct the root of the app for chunk loading
+// OC.linkTo matches the apps folders
+// OC.generateUrl ensure the index.php (or not)
+// We do not want the index.php since we're loading files
+// eslint-disable-next-line
+__webpack_public_path__ = generateFilePath('spreed', '', 'js/')
+
+document.addEventListener('DOMContentLoaded', init)
diff --git a/src/utils/requestRoomSelection.js b/src/utils/requestRoomSelection.js
new file mode 100644
index 00000000000..1b459e5156c
--- /dev/null
+++ b/src/utils/requestRoomSelection.js
@@ -0,0 +1,52 @@
+/**
+ * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import Vue, { defineAsyncComponent } from 'vue'
+
+import { t, n } from '@nextcloud/l10n'
+
+Vue.prototype.t = t
+Vue.prototype.n = n
+Vue.prototype.OC = window.OC
+Vue.prototype.OCA = window.OCA
+Vue.prototype.OCP = window.OCP
+
+/**
+ *
+ * @param {string} containerId - id of the container to append the RoomSelector component to
+ * @param {object} roomSelectorProps - props data to pass to RoomSelector component
+ * @return {Promise