8
0
Просмотр исходного кода

Refactored view placeholder code.

Szymon Kupś 9 лет назад
Родитель
Сommit
cdbf7505a5
1 измененных файлов с 53 добавлено и 10 удалено
  1. 53 10
      packages/ckeditor5-engine/src/view/placeholder.js

+ 53 - 10
packages/ckeditor5-engine/src/view/placeholder.js

@@ -17,10 +17,12 @@ const DATA_ATTRIBUTE = 'data-placeholder';
 const listener = {};
 extend( listener, EmitterMixin );
 
-const elements = new WeakSet();
+// Each document stores information about its placeholder elements and check functions.
+const documentPlaceholders = new Map();
 
 /**
- * Attaches placeholder to provided element and updates it's visibility.
+ * Attaches placeholder to provided element and updates it's visibility. To change placeholder simply call method
+ * once again with new parameters.
  *
  * @param {module:engine/view/element~Element} element Element to attach placeholder to.
  * @param {String} placeholderText Placeholder text to use.
@@ -28,6 +30,9 @@ const elements = new WeakSet();
  * If function returns `false` placeholder will not be showed.
  */
 export default function attachPlaceholder( element, placeholderText, checkFunction ) {
+	// Detach placeholder if was used before.
+	detachPlaceholder( element );
+
 	const document = element.document;
 
 	if ( !document ) {
@@ -39,24 +44,62 @@ export default function attachPlaceholder( element, placeholderText, checkFuncti
 		throw new CKEditorError( 'view-placeholder-element-is-detached: Provided element is not placed in document.' );
 	}
 
+	// Single listener per document.
+	if ( !documentPlaceholders.has( document ) ) {
+		documentPlaceholders.set( document, new Map() );
+		listener.listenTo( document, 'render', () => updateAllPlaceholders( document ), { priority: 'high' } );
+	}
+
+	// Store text in element's data attribute.
+	// This data attribute is used in CSS class to show the placeholder.
 	element.setAttribute( DATA_ATTRIBUTE, placeholderText );
 
-	// If element was not used already - add listener to it.
-	if ( !elements.has( element ) ) {
-		listener.listenTo( document, 'render', () => updateCSSClass( element, checkFunction ), { priority: 'high' } );
-		elements.add( element );
-	}
+	// Store information about placeholder.
+	documentPlaceholders.get( document ).set( element, checkFunction );
 
 	// Update right away too.
-	updateCSSClass( element, checkFunction );
+	updateSinglePlaceholder( element, checkFunction );
+}
+
+/**
+ * Removes placeholder functionality from given element.
+ *
+ * @param {module:engine/view/element~Element} element
+ */
+export function detachPlaceholder( element ) {
+	element.removeClass( CSS_CLASS );
+	element.removeAttribute( DATA_ATTRIBUTE );
+
+	for ( let placeholders of documentPlaceholders.values() ) {
+		placeholders.delete( element );
+	}
+}
+
+// Updates all placeholders of given document.
+//
+// @private
+// @param {module:engine/view/document~Document} document
+function updateAllPlaceholders( document ) {
+	const placeholders = documentPlaceholders.get( document );
+
+	for ( let [ element, checkFunction ] of placeholders ) {
+		updateSinglePlaceholder( element, checkFunction );
+	}
 }
 
 // Updates placeholder class of given element.
 //
 // @private
-function updateCSSClass( element, checkFunction ) {
-	// TODO: when element is removedfrom document this should not be executed.
+// @param {module:engine/view/element~Element} element
+// @param {Function} checkFunction
+function updateSinglePlaceholder( element, checkFunction ) {
 	const document = element.document;
+
+	// Element was removed from document.
+	if ( !document ) {
+		return;
+	}
+
 	const viewSelection = document.selection;
 	const anchor = viewSelection.anchor;