// // Copyright 2022-2024 New Vector Ltd. // // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. // import DTCoreText import Foundation public extension DTHTMLElement { /// Sanitize the element using the given parameters. /// - Parameters: /// - font: The default font to use when resetting the content of any unsupported tags. @objc func sanitize(font: UIFont) { if let name, !Self.allowedHTMLTags.contains(name) { // This is an unsupported tag. // Remove any attachments to fix rendering. textAttachment = nil // Handle special case for span with data-mx-external-payment-details // This could be based on Storefront.current.countryCode to show the link // content in unrestricted countries. e.g. currently USA if name == "span", let attributes = attributes as? [String: String], attributes["data-msc4286-external-payment-details"] != nil { parent.removeChildNode(self) return } // If the element has plain text content show that, // otherwise prevent the tag from displaying. if let stringContent = attributedString()?.string, !stringContent.isEmpty, let element = DTTextHTMLElement(name: nil, attributes: nil) { element.setText(stringContent) removeAllChildNodes() addChildNode(element) if let parent = parent() { element.inheritAttributes(from: parent) } else { fontDescriptor = DTCoreTextFontDescriptor() fontDescriptor.fontFamily = font.familyName fontDescriptor.fontName = font.fontName fontDescriptor.pointSize = font.pointSize paragraphStyle = DTCoreTextParagraphStyle.default() element.inheritAttributes(from: self) } element.interpretAttributes() } else if let parent = parent() { parent.removeChildNode(self) } else { didOutput = true } } else { // This element is a supported tag, but it may contain children that aren't, // so santize all child nodes to ensure correct tags. if let childNodes = childNodes as? [DTHTMLElement] { childNodes.forEach { $0.sanitize(font: font) } } } } private static let allowedHTMLTags = ["font", // custom to matrix for IRC-style font coloring "del", // for markdown "body", // added internally by DTCoreText "mx-reply", "h1", "h2", "h3", "h4", "h5", "h6", "blockquote", "p", "a", "ul", "ol", "nl", "li", "b", "i", "u", "strong", "em", "strike", "code", "hr", "br", "div", "table", "thead", "caption", "tbody", "tr", "th", "td", "pre"] }