@limetech/lime-elements
Version:
295 lines (294 loc) • 11.9 kB
JavaScript
import { h, Host, } from "@stencil/core";
import translate from "../../global/translations";
import { applyRemoteImagesPolicy, containsRemoteImages } from "./remote-images";
import { splitEmailAddressList } from "./split-email-address-list";
import { formatBytes } from "../../util/format-bytes";
/**
* This is a private component, used to render `.eml` files inside
* `limel-file-viewer`.
*
* :::note
* If `bodyHtml` is provided, it will be rendered using `innerHTML`.
* Consumers should pre-sanitize `bodyHtml` before passing it to the component.
* :::
*
* @exampleComponent limel-example-email-viewer-plain-text
* @exampleComponent limel-example-email-viewer-inline-image
* @exampleComponent limel-example-email-viewer-remote-image-policy
*
* @private
*/
export class EmailViewer {
constructor() {
/**
* Defines the localization for translations.
*/
this.language = 'en';
this.allowRemoteImagesState = false;
this.renderAttachment = (attachment, index) => {
var _a, _b;
const filename = ((_a = attachment.filename) === null || _a === void 0 ? void 0 : _a.trim()) ||
this.getTranslation('file-viewer.email.attachment.unnamed');
const mimeType = ((_b = attachment.mimeType) === null || _b === void 0 ? void 0 : _b.trim()) || '';
return (h("li", { key: `attachment-${index}` }, h("span", { class: "attachment-filename" }, filename), h("span", { class: "attachment-mime-type" }, " ", mimeType), this.renderSizeBadge(attachment.size)));
};
this.renderSizeBadge = (size) => {
if (typeof size !== 'number') {
return;
}
return (h("limel-badge", { class: "attachment-size", label: formatBytes(size) }));
};
this.onEnableRemoteImagesClick = (event) => {
var _a;
(_a = event === null || event === void 0 ? void 0 : event.stopPropagation) === null || _a === void 0 ? void 0 : _a.call(event);
this.enableRemoteImages();
};
this.enableRemoteImages = () => {
if (this.allowRemoteImages !== undefined) {
this.allowRemoteImagesChange.emit(true);
return;
}
this.allowRemoteImagesState = true;
};
}
resetAllowRemoteImages(newEmail, oldEmail) {
if (!newEmail) {
this.allowRemoteImagesState = false;
return;
}
if (newEmail.from !== (oldEmail === null || oldEmail === void 0 ? void 0 : oldEmail.from)) {
this.allowRemoteImagesState = false;
}
}
render() {
return (h(Host, { key: 'b37cad79c4d85f9cef78ef741d882d5384c039db' }, h("div", { key: '89e9fa6c9c39234ec9268d93837f0b27f328d046', class: "email", part: "email" }, this.renderHeaders(), this.renderRemoteImageBanner(), h("section", { key: '01f4c97918464218bc0d4ab4e79214027993360d' }, this.renderAttachments(), this.renderBody()))));
}
renderHeaders() {
const headerFields = [
'subject',
'from',
'to',
'cc',
'date',
];
return (h("div", { class: "email-headers", part: "email-headers" }, headerFields.map((type) => {
var _a;
return this.renderEmailHeader(type, this.getTranslation(`file-viewer.email.${type}`), (_a = this.email) === null || _a === void 0 ? void 0 : _a[type]);
})));
}
renderBody() {
return (this.renderBodyHtml() ||
this.renderBodyText() ||
this.renderFallbackUrl() || h("slot", { name: "fallback" }));
}
renderBodyHtml() {
var _a;
const bodyHtml = (_a = this.email) === null || _a === void 0 ? void 0 : _a.bodyHtml;
if (!bodyHtml) {
return;
}
const innerHtml = applyRemoteImagesPolicy(bodyHtml, this.getAllowRemoteImages());
return h("div", { class: "body", innerHTML: innerHtml, part: "email-body" });
}
renderBodyText() {
var _a;
const bodyText = (_a = this.email) === null || _a === void 0 ? void 0 : _a.bodyText;
if (!bodyText) {
return;
}
return (h("pre", { class: "body plain-text", part: "email-body" }, bodyText));
}
renderFallbackUrl() {
if (!this.fallbackUrl) {
return;
}
return (h("object", { data: this.fallbackUrl, type: "text/plain" }, h("slot", { name: "fallback" })));
}
renderEmailHeader(type, label, value) {
if (!value) {
return;
}
const values = this.getHeaderValues(type, value);
return (h("dl", { class: `headers ${type}` }, h("dt", null, label), values.map((headerValue, index) => (h("dd", { key: `${type}-${index}` }, headerValue)))));
}
getHeaderValues(type, value) {
if (type === 'to' || type === 'cc') {
return splitEmailAddressList(value);
}
return [value];
}
renderAttachments() {
var _a;
const attachments = (_a = this.email) === null || _a === void 0 ? void 0 : _a.attachments;
if (!(attachments === null || attachments === void 0 ? void 0 : attachments.length)) {
return;
}
const label = this.getTranslation('file-viewer.email.attachments');
return (h("div", { class: "attachments" }, h("span", null, label), h("ul", null, attachments.map((attachment, index) => this.renderAttachment(attachment, index)))));
}
getTranslation(key) {
return translate.get(key, this.language);
}
shouldShowRemoteImagesBanner() {
var _a;
const bodyHtml = (_a = this.email) === null || _a === void 0 ? void 0 : _a.bodyHtml;
if (!bodyHtml || this.getAllowRemoteImages()) {
return false;
}
return containsRemoteImages(bodyHtml);
}
renderRemoteImageBanner() {
if (!this.shouldShowRemoteImagesBanner()) {
return;
}
const icon = {
name: 'warning_shield',
color: 'rgb(var(--color-orange-default))',
};
const heading = this.getTranslation('file-viewer.email.remote-images.warning');
const description = this.getTranslation('file-viewer.email.remote-images.warning.description');
const buttonLabel = this.getTranslation('file-viewer.email.remote-images.load');
return (h("limel-collapsible-section", { header: heading, icon: icon, language: this.language }, h("button", { type: "button", class: "load-images", slot: "header", onClick: this.onEnableRemoteImagesClick }, buttonLabel), h("limel-markdown", { value: description })));
}
getAllowRemoteImages() {
var _a;
return (_a = this.allowRemoteImages) !== null && _a !== void 0 ? _a : this.allowRemoteImagesState;
}
static get is() { return "limel-email-viewer"; }
static get encapsulation() { return "shadow"; }
static get originalStyleUrls() {
return {
"$": ["email-viewer.scss"]
};
}
static get styleUrls() {
return {
"$": ["email-viewer.css"]
};
}
static get properties() {
return {
"email": {
"type": "unknown",
"mutable": false,
"complexType": {
"original": "Email",
"resolved": "Email",
"references": {
"Email": {
"location": "import",
"path": "./email-viewer.types",
"id": "src/components/email-viewer/email-viewer.types.ts::Email",
"referenceLocation": "Email"
}
}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "The email message to display.\n\nIf `email.bodyHtml` is set directly, consumers must provide sanitized\nHTML."
},
"getter": false,
"setter": false
},
"fallbackUrl": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Optional URL to render as a final fallback using an `<object type=\"text/plain\">`."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "fallback-url"
},
"language": {
"type": "string",
"mutable": false,
"complexType": {
"original": "Languages",
"resolved": "\"da\" | \"de\" | \"en\" | \"fi\" | \"fr\" | \"nb\" | \"nl\" | \"no\" | \"sv\"",
"references": {
"Languages": {
"location": "import",
"path": "../date-picker/date.types",
"id": "src/components/date-picker/date.types.ts::Languages",
"referenceLocation": "Languages"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Defines the localization for translations."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "language",
"defaultValue": "'en'"
},
"allowRemoteImages": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "Controls whether remote images (http/https) are loaded.\n\nIf omitted, the component treats this as a per-email setting.\nConsumers that want to remember the choice (per session/global) can\nprovide this prop and listen for `allowRemoteImagesChange`."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "allow-remote-images"
}
};
}
static get states() {
return {
"allowRemoteImagesState": {}
};
}
static get events() {
return [{
"method": "allowRemoteImagesChange",
"name": "allowRemoteImagesChange",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [{
"name": "internal",
"text": undefined
}],
"text": "Emitted when the user requests remote images to be loaded."
},
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
}
}];
}
static get watchers() {
return [{
"propName": "email",
"methodName": "resetAllowRemoteImages"
}];
}
}