diff --git a/lib/Listener/LoadFilesPluginListener.php b/lib/Listener/LoadFilesPluginListener.php
index 2969c939..43bcafe0 100644
--- a/lib/Listener/LoadFilesPluginListener.php
+++ b/lib/Listener/LoadFilesPluginListener.php
@@ -36,7 +36,12 @@ public function handle(Event $event): void {
'fileActions' => $exFilesActions,
'instanceId' => $this->config->getSystemValue('instanceid'),
]);
- Util::addScript(Application::APP_ID, Application::APP_ID . '-filesplugin');
+ $ncVersion = $this->config->getSystemValueString('version', '0.0.0');
+ if (version_compare($ncVersion, '28.0', '<')) {
+ Util::addScript(Application::APP_ID, Application::APP_ID . '-filesplugin');
+ } else {
+ Util::addScript(Application::APP_ID, Application::APP_ID . '-filesplugin28');
+ }
Util::addStyle(Application::APP_ID, 'filesactions');
}
}
diff --git a/src/filesplugin.js b/src/filesplugin.js
index 7d8d945e..ffa70466 100644
--- a/src/filesplugin.js
+++ b/src/filesplugin.js
@@ -2,29 +2,10 @@ import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import { loadState } from '@nextcloud/initial-state'
import { translate as t } from '@nextcloud/l10n'
-import { registerFileAction, FileAction } from '@nextcloud/files'
import { getCurrentUser } from '@nextcloud/auth'
const state = loadState('app_api', 'ex_files_actions_menu')
-function loadStaticAppAPIInlineSvgIcon() {
- return ''
-}
-
-function loadExAppInlineSvgIcon(appId, route) {
- const url = generateAppAPIProxyUrl(appId, route)
- return axios.get(url).then((response) => {
- // Check content type to be svg image
- if (response.headers['content-type'] !== 'image/svg+xml') {
- return null
- }
- return response.data
- }).catch((error) => {
- console.error('Failed to load ExApp FileAction icon inline svg', error)
- return null
- })
-}
-
function generateAppAPIProxyUrl(appId, route) {
return generateUrl(`/apps/app_api/proxy/${appId}/${route}`)
}
@@ -32,6 +13,41 @@ function generateAppAPIProxyUrl(appId, route) {
if (OCA.Files && OCA.Files.fileActions) { // NC 27
state.fileActions.forEach(fileAction => {
const mimes = fileAction.mime.split(',').map(mime => mime.trim()) // multiple mimes are separated by comma
+
+ const actionHandler = (fileName, context) => {
+ const file = context.$file[0]
+ const exAppFileActionHandler = generateAppAPIProxyUrl(fileAction.appid, fileAction.action_handler)
+ axios.post(exAppFileActionHandler, {
+ fileId: Number(file.dataset.id),
+ name: fileName,
+ directory: file.dataset.path,
+ etag: file.dataset.etag,
+ mime: file.dataset.mime,
+ favorite: file.dataset.favorite || 'false',
+ permissions: Number(file.dataset.permissions),
+ fileType: file.dataset.type,
+ size: Number(file.dataset.size),
+ mtime: Number(file.dataset.mtime) / 1000, // convert ms to s
+ shareTypes: file.dataset?.shareTypes || null,
+ shareAttributes: file.dataset?.shareAttributes || null,
+ sharePermissions: file.dataset?.sharePermissions || null,
+ shareOwner: file.dataset?.shareOwner || null,
+ shareOwnerId: file.dataset?.shareOwnerId || null,
+ userId: getCurrentUser().uid,
+ instanceId: state.instanceId,
+ }).then((response) => {
+ if (response.status === 200) {
+ OC.dialogs.info(t('app_api', 'Action request sent to ExApp'), t(fileAction.appid, fileAction.display_name))
+ } else {
+ console.debug(response)
+ OC.dialogs.info(t('app_api', 'Error while sending File action request to ExApp'), t(fileAction.appid, fileAction.display_name))
+ }
+ }).catch((error) => {
+ console.error('error', error)
+ OC.dialogs.info(t('app_api', 'Error while sending File action request to ExApp'), t(fileAction.appid, fileAction.display_name))
+ })
+ }
+
mimes.forEach((mimeType) => {
const action = {
name: fileAction.name,
@@ -41,126 +57,9 @@ if (OCA.Files && OCA.Files.fileActions) { // NC 27
order: Number(fileAction.order),
icon: fileAction.icon !== '' ? generateAppAPIProxyUrl(fileAction.appid, fileAction.icon) : null,
iconClass: fileAction.icon === '' ? 'icon-app-api' : '',
- actionHandler: (fileName, context) => {
- const file = context.$file[0]
- const exAppFileActionHandler = generateAppAPIProxyUrl(fileAction.appid, fileAction.action_handler)
- axios.post(exAppFileActionHandler, {
- fileId: Number(file.dataset.id),
- name: fileName,
- directory: file.dataset.path,
- etag: file.dataset.etag,
- mime: file.dataset.mime,
- favorite: file.dataset.favorite || 'false',
- permissions: Number(file.dataset.permissions),
- fileType: file.dataset.type,
- size: Number(file.dataset.size),
- mtime: Number(file.dataset.mtime) / 1000, // convert ms to s
- shareTypes: file.dataset?.shareTypes || null,
- shareAttributes: file.dataset?.shareAttributes || null,
- sharePermissions: file.dataset?.sharePermissions || null,
- shareOwner: file.dataset?.shareOwner || null,
- shareOwnerId: file.dataset?.shareOwnerId || null,
- userId: getCurrentUser().uid,
- instanceId: state.instanceId,
- }).then((response) => {
- if (response.status === 200) {
- OC.dialogs.info(t('app_api', 'Action request sent to ExApp'), t(fileAction.appid, fileAction.display_name))
- } else {
- console.debug(response)
- OC.dialogs.info(t('app_api', 'Error while sending File action request to ExApp'), t(fileAction.appid, fileAction.display_name))
- }
- }).catch((error) => {
- console.error('error', error)
- OC.dialogs.info(t('app_api', 'Error while sending File action request to ExApp'), t(fileAction.appid, fileAction.display_name))
- })
- },
+ actionHandler,
}
OCA.Files.fileActions.registerAction(action)
})
})
-} else { // NC 28+
- state.fileActions.forEach(fileAction => {
- if (fileAction.icon === '') {
- const inlineSvgIcon = loadStaticAppAPIInlineSvgIcon()
- registerFileAction28(fileAction, inlineSvgIcon)
- } else {
- loadExAppInlineSvgIcon(fileAction.appid, fileAction.icon).then((svg) => {
- if (svg !== null) {
- // Set css filter for theming
- const parser = new DOMParser()
- const icon = parser.parseFromString(svg, 'image/svg+xml')
- icon.documentElement.setAttribute('style', 'filter: var(--background-invert-if-dark);')
- // Convert back to inline string
- const inlineSvgIcon = icon.documentElement.outerHTML
- registerFileAction28(fileAction, inlineSvgIcon)
- }
- })
- }
- })
-}
-
-function registerFileAction28(fileAction, inlineSvgIcon) {
- const action = new FileAction({
- id: fileAction.name,
- displayName: () => fileAction.display_name,
- iconSvgInline: () => inlineSvgIcon,
- order: Number(fileAction.order),
- enabled(files, view) {
- if (files.length === 1) {
- // Check for multiple mimes separated by comma
- let isMimeMatch = false
- fileAction.mime.split(',').forEach((mime) => {
- if (files[0].mime.indexOf(mime.trim()) !== -1) {
- isMimeMatch = true
- }
- })
- return isMimeMatch
- } else if (files.length > 1) {
- // Check all files match fileAction mime
- return files.every((file) => {
- // Check for multiple mimes separated by comma
- let isMimeMatch = false
- fileAction.mime.split(',').forEach((mime) => {
- if (file.mime.indexOf(mime.trim()) !== -1) {
- isMimeMatch = true
- }
- })
- return isMimeMatch
- })
- }
- },
- async exec(node, view, dir) {
- const exAppFileActionHandler = generateAppAPIProxyUrl(fileAction.appid, fileAction.action_handler)
- return axios.post(exAppFileActionHandler, {
- fileId: node.fileid,
- name: node.basename,
- directory: node.dirname,
- etag: node.attributes.etag,
- mime: node.mime,
- favorite: Boolean(node.attributes.favorite).toString(),
- permissions: node.permissions,
- fileType: node.type,
- size: Number(node.size),
- mtime: new Date(node.mtime).getTime() / 1000, // convert ms to s
- shareTypes: node.attributes.shareTypes || null,
- shareAttributes: node.attributes.shareAttributes || null,
- sharePermissions: node.attributes.sharePermissions || null,
- shareOwner: node.attributes.ownerDisplayName || null,
- shareOwnerId: node.attributes.ownerId || null,
- userId: getCurrentUser().uid,
- instanceId: state.instanceId,
- }).then((response) => {
- return true
- }).catch((error) => {
- console.error('Failed to send FileAction request to ExApp', error)
- return false
- })
- },
- async execBatch(nodes, view, dir) {
- return Promise.all(nodes.map((node) => {
- return this.exec(node, view, dir)
- }))
- },
- })
- registerFileAction(action)
}
diff --git a/src/filesplugin28.js b/src/filesplugin28.js
new file mode 100644
index 00000000..1eb723a0
--- /dev/null
+++ b/src/filesplugin28.js
@@ -0,0 +1,114 @@
+import axios from '@nextcloud/axios'
+import { generateUrl } from '@nextcloud/router'
+import { loadState } from '@nextcloud/initial-state'
+import { registerFileAction, FileAction } from '@nextcloud/files'
+import { getCurrentUser } from '@nextcloud/auth'
+
+const state = loadState('app_api', 'ex_files_actions_menu')
+
+function loadStaticAppAPIInlineSvgIcon() {
+ return ''
+}
+
+function loadExAppInlineSvgIcon(appId, route) {
+ const url = generateAppAPIProxyUrl(appId, route)
+ return axios.get(url).then((response) => {
+ // Check content type to be svg image
+ if (response.headers['content-type'] !== 'image/svg+xml') {
+ return null
+ }
+ return response.data
+ }).catch((error) => {
+ console.error('Failed to load ExApp FileAction icon inline svg', error)
+ return null
+ })
+}
+
+function generateAppAPIProxyUrl(appId, route) {
+ return generateUrl(`/apps/app_api/proxy/${appId}/${route}`)
+}
+
+state.fileActions.forEach(fileAction => {
+ if (fileAction.icon === '') {
+ const inlineSvgIcon = loadStaticAppAPIInlineSvgIcon()
+ registerFileAction28(fileAction, inlineSvgIcon)
+ } else {
+ loadExAppInlineSvgIcon(fileAction.appid, fileAction.icon).then((svg) => {
+ if (svg !== null) {
+ // Set css filter for theming
+ const parser = new DOMParser()
+ const icon = parser.parseFromString(svg, 'image/svg+xml')
+ icon.documentElement.setAttribute('style', 'filter: var(--background-invert-if-dark);')
+ // Convert back to inline string
+ const inlineSvgIcon = icon.documentElement.outerHTML
+ registerFileAction28(fileAction, inlineSvgIcon)
+ }
+ })
+ }
+})
+
+function registerFileAction28(fileAction, inlineSvgIcon) {
+ const action = new FileAction({
+ id: fileAction.name,
+ displayName: () => fileAction.display_name,
+ iconSvgInline: () => inlineSvgIcon,
+ order: Number(fileAction.order),
+ enabled(files, view) {
+ if (files.length === 1) {
+ // Check for multiple mimes separated by comma
+ let isMimeMatch = false
+ fileAction.mime.split(',').forEach((mime) => {
+ if (files[0].mime.indexOf(mime.trim()) !== -1) {
+ isMimeMatch = true
+ }
+ })
+ return isMimeMatch
+ } else if (files.length > 1) {
+ // Check all files match fileAction mime
+ return files.every((file) => {
+ // Check for multiple mimes separated by comma
+ let isMimeMatch = false
+ fileAction.mime.split(',').forEach((mime) => {
+ if (file.mime.indexOf(mime.trim()) !== -1) {
+ isMimeMatch = true
+ }
+ })
+ return isMimeMatch
+ })
+ }
+ },
+ async exec(node, view, dir) {
+ const exAppFileActionHandler = generateAppAPIProxyUrl(fileAction.appid, fileAction.action_handler)
+ return axios.post(exAppFileActionHandler, {
+ fileId: node.fileid,
+ name: node.basename,
+ directory: node.dirname,
+ etag: node.attributes.etag,
+ mime: node.mime,
+ favorite: Boolean(node.attributes.favorite).toString(),
+ permissions: node.permissions,
+ fileType: node.type,
+ size: Number(node.size),
+ mtime: new Date(node.mtime).getTime() / 1000, // convert ms to s
+ shareTypes: node.attributes.shareTypes || null,
+ shareAttributes: node.attributes.shareAttributes || null,
+ sharePermissions: node.attributes.sharePermissions || null,
+ shareOwner: node.attributes.ownerDisplayName || null,
+ shareOwnerId: node.attributes.ownerId || null,
+ userId: getCurrentUser().uid,
+ instanceId: state.instanceId,
+ }).then((response) => {
+ return true
+ }).catch((error) => {
+ console.error('Failed to send FileAction request to ExApp', error)
+ return false
+ })
+ },
+ async execBatch(nodes, view, dir) {
+ return Promise.all(nodes.map((node) => {
+ return this.exec(node, view, dir)
+ }))
+ },
+ })
+ registerFileAction(action)
+}
diff --git a/webpack.js b/webpack.js
index 203ae358..a40f03fc 100644
--- a/webpack.js
+++ b/webpack.js
@@ -22,6 +22,7 @@ webpackConfig.entry = {
main: { import: path.join(__dirname, 'src', 'main.js'), filename: appId + '-main.js' },
adminSettings: { import: path.join(__dirname, 'src', 'adminSettings.js'), filename: appId + '-adminSettings.js' },
filesplugin: { import: path.join(__dirname, 'src', 'filesplugin.js'), filename: appId + '-filesplugin.js' },
+ filesplugin28: { import: path.join(__dirname, 'src', 'filesplugin28.js'), filename: appId + '-filesplugin28.js' },
}
webpackConfig.plugins.push(