浏览代码

Introduce concept of normalizers.

Mateusz Samsel 6 年之前
父节点
当前提交
3f04e0612d

+ 70 - 0
packages/ckeditor5-paste-from-office/src/contentnormalizer.js

@@ -0,0 +1,70 @@
+/**
+ * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/**
+ * @module paste-from-office/contentnormalizer
+ */
+
+export default class ContentNormalizer {
+	constructor( { activationTrigger } ) {
+		this.data = null;
+
+		this.activationTrigger = activationTrigger;
+
+		this._active = false;
+		this._filters = new Set();
+		this._fullContentFilters = new Set();
+	}
+
+	get isActive() {
+		return this._active;
+	}
+
+	addData( data ) {
+		const html = data.dataTransfer.getData( 'text/html' );
+
+		if ( html && this.activationTrigger( html ) ) {
+			this.data = data;
+			this._active = true;
+
+			if ( this.data.isTransformedWithPasteFromOffice === undefined ) {
+				this.data.isTransformedWithPasteFromOffice = false;
+			}
+		} else {
+			this.data = undefined;
+			this._active = false;
+		}
+
+		return this;
+	}
+
+	addFilter( filterDefinition ) {
+		if ( filterDefinition.fullContent ) {
+			this._fullContentFilters.add( filterDefinition );
+		} else {
+			this._filters.add( filterDefinition );
+		}
+	}
+
+	filter() {
+		if ( this.data && !this.data.isTransformedWithPasteFromOffice ) {
+			this._applyFullContentFilters();
+
+			this.data.isTransformedWithPasteFromOffice = true;
+		}
+
+		return this;
+	}
+
+	_applyFullContentFilters() {
+		if ( !this._fullContentFilters.size ) {
+			return;
+		}
+
+		for ( const filter of this._fullContentFilters ) {
+			filter.exec( this.data );
+		}
+	}
+}

+ 55 - 17
packages/ckeditor5-paste-from-office/src/pastefromoffice.js

@@ -13,6 +13,8 @@ import { parseHtml } from './filters/parse';
 import { transformListItemLikeElementsIntoLists } from './filters/list';
 import { replaceImagesSourceWithBase64 } from './filters/image';
 import { removeBoldTagWrapper } from './filters/common';
+import ContentNormalizer from './contentnormalizer';
+import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 
 /**
  * The Paste from Office plugin.
@@ -28,6 +30,18 @@ export default class PasteFromOffice extends Plugin {
 	/**
 	 * @inheritDoc
 	 */
+	constructor( editor ) {
+		super( editor );
+
+		this._normalizers = new Collection();
+
+		this._normalizers.add( this._getWordNormalizer() );
+		this._normalizers.add( this._getGoogleDocsNormalizer() );
+	}
+
+	/**
+	 * @inheritDoc
+	 */
 	static get pluginName() {
 		return 'PasteFromOffice';
 	}
@@ -41,11 +55,45 @@ export default class PasteFromOffice extends Plugin {
 		this.listenTo(
 			editor.plugins.get( 'Clipboard' ),
 			'inputTransformation',
-			PasteFromOffice._inputTransformationListener,
+			this._inputTransformationListener.bind( this ),
 			{ priority: 'high' }
 		);
 	}
 
+	_getWordNormalizer() {
+		const wordNormalizer = new ContentNormalizer( {
+			activationTrigger: contentString =>
+				/<meta\s*name="?generator"?\s*content="?microsoft\s*word\s*\d+"?\/?>/i.test( contentString ) ||
+				/xmlns:o="urn:schemas-microsoft-com/i.test( contentString )
+		} );
+
+		wordNormalizer.addFilter( {
+			fullContent: true,
+			exec: data => {
+				const html = data.dataTransfer.getData( 'text/html' );
+
+				data.content = PasteFromOffice._normalizeWordInput( html, data.dataTransfer );
+			}
+		} );
+
+		return wordNormalizer;
+	}
+
+	_getGoogleDocsNormalizer() {
+		const googleDocsNormalizer = new ContentNormalizer( {
+			activationTrigger: contentString => /id=("|')docs-internal-guid-[-0-9a-f]+("|')/.test( contentString )
+		} );
+
+		googleDocsNormalizer.addFilter( {
+			fullContent: true,
+			exec: data => {
+				removeBoldTagWrapper( data.content );
+			}
+		} );
+
+		return googleDocsNormalizer;
+	}
+
 	/**
 	 * Listener fired during {@link module:clipboard/clipboard~Clipboard#event:inputTransformation `inputTransformation` event}.
 	 * Detects if content comes from a recognized source and normalize it.
@@ -56,23 +104,13 @@ export default class PasteFromOffice extends Plugin {
 	 * @param {module:utils/eventinfo~EventInfo} evt
 	 * @param {Object} data same structure like {@link module:clipboard/clipboard~Clipboard#event:inputTransformation input transformation}
 	 */
-	static _inputTransformationListener( evt, data ) {
-		const html = data.dataTransfer.getData( 'text/html' );
-
-		if ( data.pasteFromOfficeProcessed !== true ) {
-			switch ( PasteFromOffice._getInputType( html ) ) {
-				case 'msword':
-					data.content = PasteFromOffice._normalizeWordInput( html, data.dataTransfer );
-					break;
-				case 'gdocs':
-					data.content = PasteFromOffice._normalizeGoogleDocsInput( data.content );
-					break;
-				default:
-					break;
-			}
+	_inputTransformationListener( evt, data ) {
+		for ( const normalizer of this._normalizers ) {
+			normalizer.addData( data );
 
-			// Set the flag so if `inputTransformation` is re-fired, PFO will not process it again (#44).
-			data.pasteFromOfficeProcessed = true;
+			if ( normalizer.isActive ) {
+				normalizer.filter();
+			}
 		}
 	}