8
0
فهرست منبع

Improved the configuration.

Kamil Piechaczek 5 سال پیش
والد
کامیت
b1ef4b98d5

+ 1 - 0
packages/ckeditor5-html-embed/package.json

@@ -14,6 +14,7 @@
     "@ckeditor/ckeditor5-engine": "^23.0.0",
     "@ckeditor/ckeditor5-ui": "^23.0.0",
     "@ckeditor/ckeditor5-widget": "^23.0.0",
+    "lodash-es": "^4.17.15",
     "sanitize-html": "^2.1.0"
   },
   "devDependencies": {},

+ 64 - 10
packages/ckeditor5-html-embed/src/htmlembedediting.js

@@ -9,11 +9,13 @@
 
 import sanitizeHtml from 'sanitize-html';
 import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';
 import HTMLEmbedCommand from './htmlembedcommand';
+import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
+import { clone } from 'lodash-es';
 
 import '../theme/htmlembed.css';
-import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils';
-import { stringify as viewStringify } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
 
 /**
  * The HTML embed editing feature.
@@ -36,6 +38,12 @@ export default class HTMLEmbedEditing extends Plugin {
 		const t = editor.t;
 		const schema = editor.model.schema;
 		const conversion = editor.conversion;
+		const viewDocument = editor.editing.view.document;
+
+		const upcastWriter = new UpcastWriter( viewDocument );
+		const htmlProcessor = new HtmlDataProcessor( viewDocument );
+
+		const saniteHtmlConfig = getSaniteHtmlConfig( sanitizeHtml.defaults );
 
 		schema.register( 'rawHtml', {
 			isObject: true,
@@ -49,13 +57,11 @@ export default class HTMLEmbedEditing extends Plugin {
 				classes: 'raw-html-embed'
 			},
 			model: ( viewElement, { writer } ) => {
-				// Replace all view elements with their string presentations.
-				const innerHTML = [ ...viewElement.getChildren() ]
-					.map( child => viewStringify( child ) )
-					.join( '' );
+				const fragment = upcastWriter.createDocumentFragment( viewElement.getChildren() );
+				const innerHtml = htmlProcessor.toData( fragment );
 
 				return writer.createElement( 'rawHtml', {
-					value: innerHTML
+					value: innerHtml
 				} );
 			}
 		} );
@@ -75,9 +81,8 @@ export default class HTMLEmbedEditing extends Plugin {
 				const label = t( 'HTML snippet' );
 				const viewWrapper = writer.createContainerElement( 'div' );
 
-				// TODO: `viewWrapper` should not be here but `toWidget` can be used only with the container element.
 				const rawElement = writer.createRawElement( 'div', { class: 'raw-html-embed' }, function( domElement ) {
-					domElement.innerHTML = sanitizeHtml( modelElement.getAttribute( 'value' ) );
+					domElement.innerHTML = sanitizeHtml( modelElement.getAttribute( 'value' ), saniteHtmlConfig );
 				} );
 
 				writer.insert( writer.createPositionAt( viewWrapper, 0 ), rawElement );
@@ -100,7 +105,56 @@ export default class HTMLEmbedEditing extends Plugin {
 //  @param {String} label The element's label.
 //  @returns {module:engine/view/element~Element}
 function toRawHtmlWidget( viewElement, writer, label ) {
-	writer.setCustomProperty( 'rawHTML', true, viewElement );
+	writer.setCustomProperty( 'rawHtml', true, viewElement );
 
 	return toWidget( viewElement, writer, { label } );
 }
+
+// Modifies the `defaultConfig` in order to match our needs. See #8204.
+//
+// @params {String} defaultConfig The default configuration that will be extended.
+// @returns {Object}
+function getSaniteHtmlConfig( defaultConfig ) {
+	const config = clone( defaultConfig );
+
+	config.allowedTags.push(
+		// Allows embedding iframes.
+		'iframe',
+
+		// Allows embedding media.
+		'audio',
+		'video',
+		'picture',
+		'source',
+		'img'
+	);
+
+	config.selfClosing.push( 'source' );
+
+	// Remove duplicates.
+	config.allowedTags = [ ...new Set( config.allowedTags ) ];
+
+	config.allowedSchemesAppliedToAttributes.push(
+		// Responsive images.
+		'srcset'
+	);
+
+	for ( const htmlTag of config.allowedTags ) {
+		if ( !Array.isArray( config.allowedAttributes[ htmlTag ] ) ) {
+			config.allowedAttributes[ htmlTag ] = [];
+		}
+
+		// Allow inlining styles for all elements.
+		config.allowedAttributes[ htmlTag ].push( 'style' );
+	}
+
+	// Should we allow the `controls` attribute?
+	config.allowedAttributes.video.push( 'width', 'height', 'controls' );
+	config.allowedAttributes.audio.push( 'controls' );
+
+	config.allowedAttributes.iframe.push( 'src' );
+	config.allowedAttributes.img.push( 'srcset', 'sizes', 'src' );
+	config.allowedAttributes.source.push( 'src', 'srcset', 'media', 'sizes', 'type' );
+
+	return config;
+}

+ 0 - 1
packages/ckeditor5-html-embed/tests/manual/htmlembed.html

@@ -16,6 +16,5 @@
             <li>Pour the water into the cup.</li>
             <li>Optional: Add milk.</li>
         </ol>
-        <script>alert(1)</script>
     </div>
 </div>