diff --git a/src/trix/config/html_sanitizer_allowed_attributes.js b/src/trix/config/html_sanitizer_allowed_attributes.js
new file mode 100644
index 000000000..27bc6f871
--- /dev/null
+++ b/src/trix/config/html_sanitizer_allowed_attributes.js
@@ -0,0 +1,10 @@
+const attributes = [
+ "style",
+ "href",
+ "src",
+ "width",
+ "height",
+ "class",
+]
+
+export default attributes
diff --git a/src/trix/config/html_sanitizer_allowed_elements.js b/src/trix/config/html_sanitizer_allowed_elements.js
new file mode 100644
index 000000000..68580c96c
--- /dev/null
+++ b/src/trix/config/html_sanitizer_allowed_elements.js
@@ -0,0 +1,3 @@
+const allowedElements = []
+
+export default allowedElements
diff --git a/src/trix/config/html_sanitizer_allowed_protocols.js b/src/trix/config/html_sanitizer_allowed_protocols.js
new file mode 100644
index 000000000..286823a0f
--- /dev/null
+++ b/src/trix/config/html_sanitizer_allowed_protocols.js
@@ -0,0 +1,3 @@
+const allowedProtocols = []
+
+export default allowedProtocols
diff --git a/src/trix/config/html_sanitizer_forbidden_elements.js b/src/trix/config/html_sanitizer_forbidden_elements.js
new file mode 100644
index 000000000..7641ab742
--- /dev/null
+++ b/src/trix/config/html_sanitizer_forbidden_elements.js
@@ -0,0 +1,7 @@
+const forbiddenElements = [
+ "script",
+ "iframe",
+ "form",
+]
+
+export default forbiddenElements
diff --git a/src/trix/config/html_sanitizer_forbidden_protocols.js b/src/trix/config/html_sanitizer_forbidden_protocols.js
new file mode 100644
index 000000000..8b8f7b28d
--- /dev/null
+++ b/src/trix/config/html_sanitizer_forbidden_protocols.js
@@ -0,0 +1,5 @@
+const forbiddenProtocols = [
+ "javascript:",
+]
+
+export default forbiddenProtocols
diff --git a/src/trix/config/index.js b/src/trix/config/index.js
index 27f7abc2f..202cc5cf9 100644
--- a/src/trix/config/index.js
+++ b/src/trix/config/index.js
@@ -10,3 +10,8 @@ export { default as parser } from "./parser"
export { default as textAttributes } from "./text_attributes"
export { default as toolbar } from "./toolbar"
export { default as undo } from "./undo"
+export { default as htmlSanitizerAllowedAttributes } from "./html_sanitizer_allowed_attributes"
+export { default as htmlSanitizerAllowedElements } from "./html_sanitizer_allowed_elements"
+export { default as htmlSanitizerAllowedProtocols } from "./html_sanitizer_allowed_protocols"
+export { default as htmlSanitizerForbiddenElements } from "./html_sanitizer_forbidden_elements"
+export { default as htmlSanitizerForbiddenProtocols } from "./html_sanitizer_forbidden_protocols"
diff --git a/src/trix/models/html_sanitizer.js b/src/trix/models/html_sanitizer.js
index 6e342e51a..92616075d 100644
--- a/src/trix/models/html_sanitizer.js
+++ b/src/trix/models/html_sanitizer.js
@@ -1,10 +1,13 @@
import BasicObject from "trix/core/basic_object"
import { nodeIsAttachmentElement, removeNode, tagName, walkTree } from "trix/core/helpers"
-
-const DEFAULT_ALLOWED_ATTRIBUTES = "style href src width height class".split(" ")
-const DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ")
-const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form".split(" ")
+import {
+ htmlSanitizerAllowedAttributes,
+ htmlSanitizerAllowedElements,
+ htmlSanitizerAllowedProtocols,
+ htmlSanitizerForbiddenElements,
+ htmlSanitizerForbiddenProtocols
+} from "../config"
export default class HTMLSanitizer extends BasicObject {
static sanitize(html, options) {
@@ -13,11 +16,13 @@ export default class HTMLSanitizer extends BasicObject {
return sanitizer
}
- constructor(html, { allowedAttributes, forbiddenProtocols, forbiddenElements } = {}) {
+ constructor(html, { allowedAttributes, allowedElements, allowedProtocols, forbiddenProtocols, forbiddenElements } = {}) {
super(...arguments)
- this.allowedAttributes = allowedAttributes || DEFAULT_ALLOWED_ATTRIBUTES
- this.forbiddenProtocols = forbiddenProtocols || DEFAULT_FORBIDDEN_PROTOCOLS
- this.forbiddenElements = forbiddenElements || DEFAULT_FORBIDDEN_ELEMENTS
+ this.allowedAttributes = allowedAttributes || htmlSanitizerAllowedAttributes
+ this.allowedElements = allowedElements || htmlSanitizerAllowedElements
+ this.allowedProtocols = allowedProtocols || htmlSanitizerAllowedProtocols
+ this.forbiddenElements = forbiddenElements || htmlSanitizerForbiddenElements
+ this.forbiddenProtocols = forbiddenProtocols || htmlSanitizerForbiddenProtocols
this.body = createBodyElementForHTML(html)
}
@@ -63,7 +68,7 @@ export default class HTMLSanitizer extends BasicObject {
sanitizeElement(element) {
if (element.hasAttribute("href")) {
- if (this.forbiddenProtocols.includes(element.protocol)) {
+ if (this.forbiddenProtocols.includes(element.protocol) || this.allowedProtocols.length > 0 && !this.allowedProtocols.includes(element.protocol)) {
element.removeAttribute("href")
}
}
@@ -96,7 +101,7 @@ export default class HTMLSanitizer extends BasicObject {
}
elementIsForbidden(element) {
- return this.forbiddenElements.includes(tagName(element))
+ return this.forbiddenElements.includes(tagName(element)) || this.allowedElements.length > 0 && !this.allowedElements.includes(tagName(element))
}
elementIsntSerializable(element) {
diff --git a/src/trix/views/piece_view.js b/src/trix/views/piece_view.js
index c03d6c266..306478183 100644
--- a/src/trix/views/piece_view.js
+++ b/src/trix/views/piece_view.js
@@ -111,17 +111,25 @@ export default class PieceView extends ObjectView {
}
createContainerElement() {
+ const attributes = {}
+ let groupTagName
+
for (const key in this.attributes) {
const value = this.attributes[key]
const config = getTextConfig(key)
if (config) {
- if (config.groupTagName) {
- const attributes = {}
+ if (!groupTagName && config.groupTagName) {
+ attributes[key] = value
+ groupTagName = config.groupTagName
+ } else if (config.groupTagName && groupTagName === config.groupTagName) {
attributes[key] = value
- return makeElement(config.groupTagName, attributes)
}
}
}
+
+ if (Object.entries(attributes).length > 0 && groupTagName) {
+ return makeElement(groupTagName, attributes)
+ }
}
preserveSpaces(string) {