Skip to content

Commit b1b3c0f

Browse files
committed
Issue #3265054 by krisahil: CKEditor should be aware of (dis)allowed HTML tags
1 parent 0f03f26 commit b1b3c0f

File tree

12 files changed

+155
-2
lines changed

12 files changed

+155
-2
lines changed

README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,52 @@ sending it to the pattern's template (e.g., to a Twig file). Even though you
121121
select a Text format in order to load CKEditor, Patternkit will not process the
122122
contents of a WYSIWYG field through that text format's filters.
123123

124+
##### CKEditor content filtering
125+
126+
If using CKEditor as the wysiwyg plugin, you can configure the schema to allow
127+
or disallow certain HTML tags and attributes. This feature uses [CKEditor's
128+
content filtering
129+
system](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_acf.html).
130+
131+
###### Setting allowed content
132+
133+
To set which content is allowed, use property `allowedContent` in the `options`
134+
key of your schema. The property's value will be passed as-is to CKEditor's
135+
`allowedContent` configuration ([expected
136+
format](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_allowed_content_rules.html)).
137+
138+
###### Setting disallowed content
139+
140+
Conversely, to prevent certain content, use property `disallowedContent` in the
141+
`options` key of your schema. The property's value will be passed as-is to
142+
CKEditor's `disallowedContent` configuration ([expected
143+
format](https://ckeditor.com/docs/ckeditor4/latest/guide/dev_disallowed_content.html)).
144+
145+
###### Example
146+
147+
In this example, only links, bold/strong, and italic/emphasis tags are allowed.
148+
You can use any attributes on these elements (including class, style, and other
149+
attributes), except ones prefixed with `data-`.
150+
151+
```json
152+
"formatted_text": {
153+
"title": "Formatted Text",
154+
"type": "string",
155+
"format": "html",
156+
"options": {
157+
"wysiwyg": true,
158+
"allowedContent": "a b strong em i[*](*){*}",
159+
"disallowedContent": "*[data-*]"
160+
}
161+
},
162+
```
163+
164+
_Security note_: Filtering content at the CKEditor layer (i.e., at content
165+
entry) does not filter it when rendered. For example, if you disallow `onclick`
166+
attributes in CKEditor but the pattern's template (e.g., Twig) does not strip
167+
those attibutes, a user might possibly save content with an `onclick` attribute,
168+
and that attribute would be rendered to the page.
169+
124170
### Other settings
125171
The following settings are not available for configuration in the UI, so you must set
126172
them in config item `patternkit.settings` manually:

js/patternkit.jsoneditor.ckeditor.es6.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ class DrupalCKEditor extends JSONEditor.defaults.editors.string {
3232
format: this.options.ckeditor_config.selected_toolbar,
3333
};
3434

35+
// The schema can determine which HTML tags are allowed and disallowed.
36+
// These settings are passed as-is to CKEditor's ACF (content filtering)
37+
// system. See https://ckeditor.com/docs/ckeditor4/latest/guide/dev_acf.html.
38+
if (this.schema.options.allowedContent) {
39+
this.options.ckeditor_config.allowedContent = this.schema.options.allowedContent;
40+
}
41+
if (this.schema.options.disallowedContent) {
42+
this.options.ckeditor_config.disallowedContent = this.schema.options.disallowedContent;
43+
}
44+
3545
// @see Drupal.editors.ckeditor._loadExternalPlugins
3646
const externalPlugins = this.options.ckeditor_config.drupalExternalPlugins;
3747
if (externalPlugins) {
@@ -109,6 +119,8 @@ class DrupalCKEditor extends JSONEditor.defaults.editors.string {
109119
if (this.always_disabled) {
110120
return;
111121
}
122+
// @TODO Fix this because, when the form is initially loaded, this throws a
123+
// JS error.
112124
if (this.ckeditor_instance) {
113125
this.ckeditor_instance.setReadOnly(false);
114126
}

js/patternkit.jsoneditor.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,18 @@ var DrupalCKEditor = /*#__PURE__*/function (_JSONEditor$defaults$) {
8282

8383
this.options.ckeditor_config.drupal = {
8484
format: this.options.ckeditor_config.selected_toolbar
85-
}; // @see Drupal.editors.ckeditor._loadExternalPlugins
85+
}; // The schema can determine which HTML tags are allowed and disallowed.
86+
// These settings are passed as-is to CKEditor's ACF (content filtering)
87+
// system. See https://ckeditor.com/docs/ckeditor4/latest/guide/dev_acf.html.
88+
89+
if (this.schema.options.allowedContent) {
90+
this.options.ckeditor_config.allowedContent = this.schema.options.allowedContent;
91+
}
92+
93+
if (this.schema.options.disallowedContent) {
94+
this.options.ckeditor_config.disallowedContent = this.schema.options.disallowedContent;
95+
} // @see Drupal.editors.ckeditor._loadExternalPlugins
96+
8697

8798
var externalPlugins = this.options.ckeditor_config.drupalExternalPlugins;
8899

@@ -161,7 +172,9 @@ var DrupalCKEditor = /*#__PURE__*/function (_JSONEditor$defaults$) {
161172
value: function enable() {
162173
if (this.always_disabled) {
163174
return;
164-
}
175+
} // @TODO Fix this because, when the form is initially loaded, this throws a
176+
// JS error.
177+
165178

166179
if (this.ckeditor_instance) {
167180
this.ckeditor_instance.setReadOnly(false);

modules/patternkit_example/lib/patternkit/src/atoms/example_filtered/dist/example_filtered.css

Whitespace-only changes.

modules/patternkit_example/lib/patternkit/src/atoms/example_filtered/dist/example_filtered.min.js

Whitespace-only changes.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
(function () {
2+
'use strict';
3+
4+
import './src/example_filtered.scss';
5+
import example_filtered from './dist/example_filtered';
6+
7+
var element = Object.create(HTMLElement.prototype);
8+
element.createdCallback = function () {};
9+
element.attachedCallback = function () {};
10+
element.detachedCallback = function () {};
11+
element.attributeChangedCallback = function (attr, oldVal, newVal) {};
12+
document.registerElement('example_filtered', {
13+
prototype: element
14+
});
15+
}());
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"category": "atom",
4+
"title": "Example with filtered content",
5+
"type": "object",
6+
"format": "grid",
7+
"properties": {
8+
"text": {
9+
"title": "Text",
10+
"type": "string",
11+
"options": {
12+
"grid_columns": 4
13+
}
14+
},
15+
"formatted_text": {
16+
"title": "Formatted Text",
17+
"type": "string",
18+
"description": "Only links, bold/strong, and italic/emphasis tags are allowed (assuming CKEditor is the wysiwyg plugin). You can use any attributes on these elements (including class, style, and other attributes), except ones prefixed with \"data-\". This field's schema uses the \"disallowedContent\" rule to instruct CKEditor to strip these attributes. However, there is no server-side process that strips them. See Patternkit's README for details.",
19+
"format": "html",
20+
"options": {
21+
"wysiwyg": true,
22+
"allowedContent": "a b strong em i[*](*){*}",
23+
"disallowedContent": "*[data-*]"
24+
}
25+
},
26+
"hidden": {
27+
"title": "hidden",
28+
"type": "string"
29+
}
30+
}
31+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
This is an example Web Component showing content filtered by CKEditor, implemented as a Twig UI Pattern.
2+
3+
It includes the following files:
4+
5+
## example_filtered.json
6+
The JSON schema file delineates the schema of the pattern. In some cases, libraries may generate these from the Twig Docblock of the pattern Twig template file.
7+
8+
## example_filtered.md
9+
This file. The text here should appear as pattern documentation in any Style Guide, Pattern Library, or pattern developer tool.
10+
11+
This documentation often will include Style Rulesets, brand guidelines, designer intention, as well as usage advice.
12+
13+
## example_filtered.scss
14+
Optional SASS to be compiled to CSS
15+
16+
## example_filtered.ts
17+
Optional Typescript file to be transpiled to the final JS module. In some libraries, vanilla JS or other variants are used.
18+
19+
## example_filtered.twig
20+
The HTML template for the pattern. Some libraries may also use Nunjucks, JSX, or Handlebars.
21+
22+
## example_filtered.yml
23+
Sample data for the pattern. This can be used to generate demo sites, style guide example_filtereds, or pre-fill schema editors.
24+
25+
## index.js
26+
The Web Component entry point.

modules/patternkit_example/lib/patternkit/src/atoms/example_filtered/src/example_filtered.scss

Whitespace-only changes.

modules/patternkit_example/lib/patternkit/src/atoms/example_filtered/src/example_filtered.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)