mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-05 07:27:04 +03:00
Support JSON-LD #1422
This commit is contained in:
parent
a46484755b
commit
f0d97b52d9
3 changed files with 59 additions and 23 deletions
|
|
@ -87,12 +87,6 @@ export class MessageModel extends AbstractModel {
|
||||||
size: 0,
|
size: 0,
|
||||||
readReceipt: '',
|
readReceipt: '',
|
||||||
preview: null,
|
preview: null,
|
||||||
/**
|
|
||||||
* Basic support for Linked Data (Structured Email)
|
|
||||||
* https://json-ld.org/
|
|
||||||
* https://structured.email/
|
|
||||||
**/
|
|
||||||
linkedData: [],
|
|
||||||
|
|
||||||
attachments: ko.observableArray(new AttachmentCollectionModel),
|
attachments: ko.observableArray(new AttachmentCollectionModel),
|
||||||
threads: ko.observableArray(),
|
threads: ko.observableArray(),
|
||||||
|
|
@ -130,6 +124,13 @@ export class MessageModel extends AbstractModel {
|
||||||
// rfc8621
|
// rfc8621
|
||||||
id: '',
|
id: '',
|
||||||
// threadId: ''
|
// threadId: ''
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic support for Linked Data (Structured Email)
|
||||||
|
* https://json-ld.org/
|
||||||
|
* https://structured.email/
|
||||||
|
**/
|
||||||
|
linkedData: []
|
||||||
});
|
});
|
||||||
|
|
||||||
addComputablesTo(this, {
|
addComputablesTo(this, {
|
||||||
|
|
@ -375,7 +376,7 @@ export class MessageModel extends AbstractModel {
|
||||||
this.hasExternals(result.hasExternals);
|
this.hasExternals(result.hasExternals);
|
||||||
this.hasImages(!!result.hasExternals);
|
this.hasImages(!!result.hasExternals);
|
||||||
this.hasTracking(!!result.tracking);
|
this.hasTracking(!!result.tracking);
|
||||||
this.linkedData = result.linkedData;
|
this.linkedData(result.linkedData);
|
||||||
body.innerHTML = result.html;
|
body.innerHTML = result.html;
|
||||||
if (!this.isSpam && FolderUserStore.spamFolder() != this.folder) {
|
if (!this.isSpam && FolderUserStore.spamFolder() != this.folder) {
|
||||||
if ('always' === SettingsUserStore.viewImages()) {
|
if ('always' === SettingsUserStore.viewImages()) {
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ class ViewICSPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
{
|
{
|
||||||
const
|
const
|
||||||
NAME = 'View ICS',
|
NAME = 'View ICS',
|
||||||
VERSION = '2.0',
|
VERSION = '2.1',
|
||||||
RELEASE = '2023-08-28',
|
RELEASE = '2024-02-06',
|
||||||
CATEGORY = 'Messages',
|
CATEGORY = 'Messages',
|
||||||
DESCRIPTION = 'Display ICS attachment details',
|
DESCRIPTION = 'Display ICS attachment or JSON-LD details',
|
||||||
REQUIRED = '2.27.0';
|
REQUIRED = '2.34.0';
|
||||||
|
|
||||||
public function Init() : void
|
public function Init() : void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,20 @@
|
||||||
template = document.getElementById(templateId),
|
template = document.getElementById(templateId),
|
||||||
view = e.detail,
|
view = e.detail,
|
||||||
attachmentsPlace = template.content.querySelector('.attachmentsPlace'),
|
attachmentsPlace = template.content.querySelector('.attachmentsPlace'),
|
||||||
dateRegEx = /(TZID=(?<tz>[^:]+):)?(?<year>[0-9]{4})(?<month>[0-9]{2})(?<day>[0-9]{2})T(?<hour>[0-9]{2})(?<minute>[0-9]{2})(?<second>[0-9]{2})(?<utc>Z?)/;
|
dateRegEx = /(TZID=(?<tz>[^:]+):)?(?<year>[0-9]{4})(?<month>[0-9]{2})(?<day>[0-9]{2})T(?<hour>[0-9]{2})(?<minute>[0-9]{2})(?<second>[0-9]{2})(?<utc>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(`
|
attachmentsPlace.after(Element.fromHTML(`
|
||||||
<details data-bind="if: viewICS, visible: viewICS">
|
<details data-bind="if: viewICS, visible: viewICS">
|
||||||
|
|
@ -26,12 +39,44 @@
|
||||||
|
|
||||||
view.viewICS = ko.observable(null);
|
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
|
* TODO
|
||||||
*/
|
*/
|
||||||
view.message.subscribe(msg => {
|
view.message.subscribe(msg => {
|
||||||
view.viewICS(null);
|
view.viewICS(null);
|
||||||
if (msg) {
|
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 => 'application/ics' == attachment.mimeType);
|
||||||
let ics = msg.attachments.find(attachment => 'text/calendar' == attachment.mimeType);
|
let ics = msg.attachments.find(attachment => 'text/calendar' == attachment.mimeType);
|
||||||
if (ics && ics.download) {
|
if (ics && ics.download) {
|
||||||
|
|
@ -71,17 +116,7 @@
|
||||||
VEVENT[line[1]].push(line[2]);
|
VEVENT[line[1]].push(line[2]);
|
||||||
} else {
|
} else {
|
||||||
if ('DTSTART' === line[1] || 'DTEND' === line[1]) {
|
if ('DTSTART' === line[1] || 'DTEND' === line[1]) {
|
||||||
let parts = dateRegEx.exec(line[2])?.groups,
|
line[2] = parseDate(line[2]);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
VEVENT[line[1]] = line[2];
|
VEVENT[line[1]] = line[2];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue