diff --git a/dev/Model/Message.js b/dev/Model/Message.js index 78d487ff1..e7d4fcaf2 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -87,12 +87,6 @@ export class MessageModel extends AbstractModel { size: 0, readReceipt: '', preview: null, - /** - * Basic support for Linked Data (Structured Email) - * https://json-ld.org/ - * https://structured.email/ - **/ - linkedData: [], attachments: ko.observableArray(new AttachmentCollectionModel), threads: ko.observableArray(), @@ -130,6 +124,13 @@ export class MessageModel extends AbstractModel { // rfc8621 id: '', // threadId: '' + + /** + * Basic support for Linked Data (Structured Email) + * https://json-ld.org/ + * https://structured.email/ + **/ + linkedData: [] }); addComputablesTo(this, { @@ -375,7 +376,7 @@ export class MessageModel extends AbstractModel { this.hasExternals(result.hasExternals); this.hasImages(!!result.hasExternals); this.hasTracking(!!result.tracking); - this.linkedData = result.linkedData; + this.linkedData(result.linkedData); body.innerHTML = result.html; if (!this.isSpam && FolderUserStore.spamFolder() != this.folder) { if ('always' === SettingsUserStore.viewImages()) { diff --git a/plugins/view-ics/index.php b/plugins/view-ics/index.php index febaeb875..b3f81418b 100644 --- a/plugins/view-ics/index.php +++ b/plugins/view-ics/index.php @@ -4,11 +4,11 @@ class ViewICSPlugin extends \RainLoop\Plugins\AbstractPlugin { const NAME = 'View ICS', - VERSION = '2.0', - RELEASE = '2023-08-28', + VERSION = '2.1', + RELEASE = '2024-02-06', CATEGORY = 'Messages', - DESCRIPTION = 'Display ICS attachment details', - REQUIRED = '2.27.0'; + DESCRIPTION = 'Display ICS attachment or JSON-LD details', + REQUIRED = '2.34.0'; public function Init() : void { diff --git a/plugins/view-ics/message.js b/plugins/view-ics/message.js index cb768402e..5689c1f63 100644 --- a/plugins/view-ics/message.js +++ b/plugins/view-ics/message.js @@ -8,7 +8,20 @@ template = document.getElementById(templateId), view = e.detail, attachmentsPlace = template.content.querySelector('.attachmentsPlace'), - dateRegEx = /(TZID=(?[^:]+):)?(?[0-9]{4})(?[0-9]{2})(?[0-9]{2})T(?[0-9]{2})(?[0-9]{2})(?[0-9]{2})(?Z?)/; + dateRegEx = /(TZID=(?[^:]+):)?(?[0-9]{4})(?[0-9]{2})(?[0-9]{2})T(?[0-9]{2})(?[0-9]{2})(?[0-9]{2})(?Z?)/, + parseDate = str => { + let parts = dateRegEx.exec(str)?.groups, + options = {dateStyle: 'long', timeStyle: 'short'}; + parts?.tz && (options.timeZone = parts.tz); + return (parts ? new Date( + parseInt(parts.year, 10), + parseInt(parts.month, 10) - 1, + parseInt(parts.day, 10), + parseInt(parts.hour, 10), + parseInt(parts.minute, 10), + parseInt(parts.second, 10) + ) : new Date(str)).format(options); + }; attachmentsPlace.after(Element.fromHTML(`
@@ -26,12 +39,44 @@ view.viewICS = ko.observable(null); + view.saveICS = () => { + let VEVENT = view.VEVENT(); + if (VEVENT) { + if (rl.nextcloud && VEVENT.rawText) { + rl.nextcloud.selectCalendar() + .then(href => href && rl.nextcloud.calendarPut(href, VEVENT)); + } else { + // TODO + } + } + } + /** * TODO */ view.message.subscribe(msg => { view.viewICS(null); if (msg) { + // JSON-LD after parsing HTML + msg.linkedData.subscribe(data => { + if (!view.viewICS()) { + data.forEach(item => { + if (item["ical:summary"]) { + let VEVENT = { + SUMMARY: item["ical:summary"], + DTSTART: parseDate(item["ical:dtstart"]), +// DTEND: parseDate(item["ical:dtend"]), +// TRANSP: item["ical:transp"], +// LOCATION: item["ical:location"], + ATTENDEE: [] + } + view.viewICS(VEVENT); + return; + } + }); + } + }); + // ICS attachment // let ics = msg.attachments.find(attachment => 'application/ics' == attachment.mimeType); let ics = msg.attachments.find(attachment => 'text/calendar' == attachment.mimeType); if (ics && ics.download) { @@ -71,17 +116,7 @@ VEVENT[line[1]].push(line[2]); } else { if ('DTSTART' === line[1] || 'DTEND' === line[1]) { - let parts = dateRegEx.exec(line[2])?.groups, - options = {dateStyle: 'long', timeStyle: 'short'}; - parts.tz && (options.timeZone = parts.tz); - line[2] = new Date( - parseInt(parts.year, 10), - parseInt(parts.month, 10) - 1, - parseInt(parts.day, 10), - parseInt(parts.hour, 10), - parseInt(parts.minute, 10), - parseInt(parts.second, 10) - ).format(options); + line[2] = parseDate(line[2]); } VEVENT[line[1]] = line[2]; }