diff --git a/api/js/jsapi/egw_links.js b/api/js/jsapi/egw_links.js index 08f9c6cab5..5bf2a4fcc7 100644 --- a/api/js/jsapi/egw_links.js +++ b/api/js/jsapi/egw_links.js @@ -138,22 +138,31 @@ egw.extend('links', egw.MODULE_GLOBAL, function() /** * Get mime-type information from app-registry * - * We prefer a full match over a wildcard like 'text/*' (written as regualr expr. "/^text\\//" + * We prefer a full match over a wildcard like 'text/*' (written as regular expr. "/^text\\//" * * @param {string} _type + * @param {number|string} _app_or_num default 1, return 1st, 2nd, n-th match, or match from application _app_or_num only * @return {object} with values for keys 'menuaction', 'mime_id' (path) or 'mime_url' and options 'mime_popup' and other values to pass one */ - get_mime_info: function(_type) + get_mime_info: function(_type, _app_or_num) { + if (typeof _app_or_num === 'undefined') _app_or_num = 1; let wildcard_mime; - for(var app in link_registry) + for(const app of isNaN(_app_or_num) ? [_app_or_num] : Object.keys(link_registry)) { const reg = link_registry[app]; - if (typeof reg.mime !== 'undefined') + if (typeof reg?.mime !== 'undefined') { for(let mime in reg.mime) { - if (mime === _type) return reg.mime[_type]; + if (mime === _type) + { + if (isNaN(_app_or_num) || !--_app_or_num) + { + return reg.mime[_type]; + } + continue; + } if (mime[0] === '/' && _type.match(new RegExp(mime.substring(1, mime.length-1), 'i'))) { wildcard_mime = reg.mime[mime]; @@ -168,11 +177,12 @@ egw.extend('links', egw.MODULE_GLOBAL, function() * Get handler (link-data) for given path and mime-type * * @param {string|object} _path vfs path, egw_link::set_data() id or - * object with attr path, optinal download_url or id, app2 and id2 (path=/apps/app2/id2/id) + * object with attr path, optional download_url or id, app2 and id2 (path=/apps/app2/id2/id) * @param {string} _type mime-type, if not given in _path object + * @param {number|string} _app_or_num default 1, use 1st, 2nd, n-th match, or match from application _app_or_num only * @return {string|object} string with EGw relative link, array with get-parameters for '/index.php' or null (directory and not filemanager access) */ - mime_open: function(_path, _type) + mime_open: function(_path, _type, _app_or_num) { let path; if (typeof _path === 'object') @@ -198,11 +208,11 @@ egw.extend('links', egw.MODULE_GLOBAL, function() { path = _path; } - let mime_info = this.get_mime_info(_type); + let mime_info = this.get_mime_info(_type, _app_or_num); let data = {}; if (mime_info) { - if (this.isCollaborable(_type)) + if ((typeof _app_or_num === 'undefined' || _app_or_num === 'collabora') && this.isCollaborable(_type)) { data = { 'menuaction': 'collabora.EGroupware\\collabora\\Ui.editor', @@ -216,9 +226,16 @@ egw.extend('links', egw.MODULE_GLOBAL, function() switch(attr) { case 'mime_url': - data[mime_info.mime_url] = 'vfs://default' + path; + if (path) + { + data[mime_info.mime_url] = 'vfs://default' + path; + } break; case 'mime_data': + if (!path && _path && typeof _path === 'string') + { + data[mime_info.mime_data] = _path; + } break; case 'mime_type': data[mime_info.mime_type] = _type; diff --git a/api/js/jsapi/egw_open.js b/api/js/jsapi/egw_open.js index a8b90a38a8..384e638c32 100644 --- a/api/js/jsapi/egw_open.js +++ b/api/js/jsapi/egw_open.js @@ -321,7 +321,7 @@ egw.extend('open', egw.MODULE_WND_LOCAL, function(_egw, _wnd) { url = this.webserverUrl + url; } - var mime_info = _mime_type ? this.get_mime_info(_mime_type) : undefined; + var mime_info = _mime_type ? this.get_mime_info(_mime_type, _target_app) : undefined; if (mime_info && (mime_info.mime_url || mime_info.mime_data)) { var data = {}; diff --git a/api/src/Link.php b/api/src/Link.php index 87860667d3..5967887221 100644 --- a/api/src/Link.php +++ b/api/src/Link.php @@ -83,7 +83,7 @@ namespace EGroupware\Api; * 'mime' => array( // Optional register mime-types application can open * 'text/something' => array( * 'mime_url' => $attr, // either mime_url or mime_data is required for server-side processing! - * 'mime_data' => $attr, // md5-hash returned from Link::set_data() to retrive content (only server-side) + * 'mime_data' => $attr, // md5-hash returned from Link::set_data() to retrieve content (only server-side) * 'menuaction' => 'app.class.method', // method to call * 'mime_popup' => '400x300', // optional size of popup * 'mime_target' => '_self', // optional target, default _blank @@ -1059,11 +1059,12 @@ class Link extends Link\Storage * We prefer full matches over wildcards like "text/*" written as regexp "/^text\\//". * * @param string $type + * @param ?string $_app check only $_app, if given * @return array with values for keys 'menuaction', 'mime_id' (path) or 'mime_url' and options 'mime_popup' and other values to pass one */ - static function get_mime_info($type) + static function get_mime_info($type, string $_app=null) { - foreach(self::$app_register as $app => $registry) + foreach($_app ? [$_app => self::$app_register[$_app] ?? []] : self::$app_register as $app => $registry) { if (isset($registry['mime']) && (isset($GLOBALS['egw_info']['user']['apps'][$app]) || diff --git a/api/src/MimeMagic.php b/api/src/MimeMagic.php index 9f8e0d6a56..6e6540e218 100644 --- a/api/src/MimeMagic.php +++ b/api/src/MimeMagic.php @@ -200,8 +200,7 @@ class MimeMagic * a temp file creation and clean up method wrapper for analyze_file() * * @param string $data the data to analyze - * - * @param string MIME type false for none. + * @return string|false MIME type false for none. * * @author skwashd */ diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 0fbcf26569..76a2cc219c 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -2527,7 +2527,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2); $acc_id = $hA['profileID']; $attachmentHTML[$key]['mime_data'] = Link::set_data($value['mimeType'], 'EGroupware\\Api\\Mail::getAttachmentAccount', array( - $acc_id, $mailbox, $uid, $value['partID'], $value['is_winmail'], true + $acc_id, $mailbox, $uid, $value['partID'], $value['is_winmail'] ?? false, true )); $attachmentHTML[$key]['size']=Vfs::hsize($value['size']); $attachmentHTML[$key]['attachment_number']=$key; @@ -2638,7 +2638,16 @@ $filter['before']= date("d-M-Y", $cutoffdate2); if (empty($attachmentHTML[$key]['mime_data'])) { $attachmentHTML[$key]['mime_url'] = Egw::link('/index.php',$linkData); - unset($attachmentHTML[$key]['mime_data']); + // always check invoices too and then add mime_data unconditionally + if (Link::get_mime_info($attachmentHTML[$key]['type'], 'invoices')) + { + $attachmentHTML[$key]['mime_data'] = Link::set_data($value['mimeType'], 'EGroupware\\Api\\Mail::getAttachmentAccount', + [$acc_id, $mailbox, $uid, $value['partID'], $value['is_winmail'] ?? false, true], true); + } + else + { + unset($attachmentHTML[$key]['mime_data']); + } } $attachmentHTML[$key]['windowName'] = $windowName; diff --git a/mail/js/app.js b/mail/js/app.js index b9126b7bf5..a21ad76cc8 100755 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -1264,6 +1264,16 @@ app.classes.mail = AppJS.extend( sel_options.attachmentsBlock[_item.attachment_number + "[actions]"] = [collabora, ...actions]; } } + // if mime-type is supported by invoices, add it at the end + if (egw.get_mime_info(_item.type, 'invoices')) + { + sel_options.attachmentsBlock[_item.attachment_number + "[actions]"] = [...actions, { + id: 'invoices', + label: 'invoices', + icon: 'invoices/navbar', + value: 'invoices' + }]; + } }); sel_options.attachmentsBlock.actions = actions; @@ -3364,6 +3374,10 @@ app.classes.mail = AppJS.extend( document.body.style.cursor = ''; }); break; + case 'invoices': + default: + egw.open_link(attachments[row_id].mime_data, '_blank', '', action, true, attachments[row_id].type); + break; } },