UNPKG

@limetech/lime-elements

Version:
295 lines (294 loc) • 11.9 kB
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" }]; } }