Bladeren bron

Merge branch 'master' into t/ckeditor5/383

Piotr Jasiun 6 jaren geleden
bovenliggende
commit
3daff85263

+ 5 - 0
packages/ckeditor5-engine/CHANGELOG.md

@@ -1,6 +1,11 @@
 Changelog
 =========
 
+## [13.2.1](https://github.com/ckeditor/ckeditor5-engine/compare/v13.2.0...v13.2.1) (2019-07-10)
+
+Internal changes only (updated dependencies, documentation, etc.).
+
+
 ## [13.2.0](https://github.com/ckeditor/ckeditor5-engine/compare/v13.1.1...v13.2.0) (2019-07-04)
 
 ### Features

+ 16 - 16
packages/ckeditor5-engine/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@ckeditor/ckeditor5-engine",
-  "version": "13.2.0",
+  "version": "13.2.1",
   "description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.",
   "keywords": [
     "wysiwyg",
@@ -21,24 +21,24 @@
     "ckeditor 5"
   ],
   "dependencies": {
-    "@ckeditor/ckeditor5-utils": "^13.0.0",
+    "@ckeditor/ckeditor5-utils": "^13.0.1",
     "lodash-es": "^4.17.10"
   },
   "devDependencies": {
-    "@ckeditor/ckeditor5-basic-styles": "^11.1.2",
-    "@ckeditor/ckeditor5-block-quote": "^11.1.1",
-    "@ckeditor/ckeditor5-core": "^12.2.0",
-    "@ckeditor/ckeditor5-editor-classic": "^12.1.2",
-    "@ckeditor/ckeditor5-enter": "^11.0.3",
-    "@ckeditor/ckeditor5-essentials": "^11.0.3",
-    "@ckeditor/ckeditor5-heading": "^11.0.3",
-    "@ckeditor/ckeditor5-link": "^11.1.0",
-    "@ckeditor/ckeditor5-list": "^12.0.3",
-    "@ckeditor/ckeditor5-paragraph": "^11.0.3",
-    "@ckeditor/ckeditor5-theme-lark": "^14.1.0",
-    "@ckeditor/ckeditor5-typing": "^12.1.0",
-    "@ckeditor/ckeditor5-undo": "^11.0.3",
-    "@ckeditor/ckeditor5-widget": "^11.0.3",
+    "@ckeditor/ckeditor5-basic-styles": "^11.1.3",
+    "@ckeditor/ckeditor5-block-quote": "^11.1.2",
+    "@ckeditor/ckeditor5-core": "^12.2.1",
+    "@ckeditor/ckeditor5-editor-classic": "^12.1.3",
+    "@ckeditor/ckeditor5-enter": "^11.0.4",
+    "@ckeditor/ckeditor5-essentials": "^11.0.4",
+    "@ckeditor/ckeditor5-heading": "^11.0.4",
+    "@ckeditor/ckeditor5-link": "^11.1.1",
+    "@ckeditor/ckeditor5-list": "^12.0.4",
+    "@ckeditor/ckeditor5-paragraph": "^11.0.4",
+    "@ckeditor/ckeditor5-theme-lark": "^14.1.1",
+    "@ckeditor/ckeditor5-typing": "^12.1.1",
+    "@ckeditor/ckeditor5-undo": "^11.0.4",
+    "@ckeditor/ckeditor5-widget": "^11.0.4",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^1.3.1",

+ 3 - 4
packages/ckeditor5-engine/src/conversion/downcasthelpers.js

@@ -732,9 +732,8 @@ function removeUIElement() {
 			return;
 		}
 
-		conversionApi.mapper.unbindElementsFromMarkerName( data.markerName );
-
 		for ( const element of elements ) {
+			conversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );
 			conversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );
 		}
 
@@ -1033,9 +1032,9 @@ function removeHighlight( highlightDescriptor ) {
 			return;
 		}
 
-		conversionApi.mapper.unbindElementsFromMarkerName( data.markerName );
-
 		for ( const element of elements ) {
+			conversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );
+
 			if ( element.is( 'attributeElement' ) ) {
 				conversionApi.writer.unwrap( conversionApi.writer.createRangeOn( element ), viewHighlightElement );
 			} else {

+ 12 - 3
packages/ckeditor5-engine/src/conversion/mapper.js

@@ -174,12 +174,21 @@ export default class Mapper {
 	}
 
 	/**
-	 * Unbinds all elements from given marker name.
+	 * Unbinds an element from given marker name.
 	 *
+	 * @param {module:engine/view/element~Element} element Element to unbind.
 	 * @param {String} name Marker name.
 	 */
-	unbindElementsFromMarkerName( name ) {
-		this._markerNameToElements.delete( name );
+	unbindElementFromMarkerName( element, name ) {
+		const elements = this._markerNameToElements.get( name );
+
+		if ( elements ) {
+			elements.delete( element );
+
+			if ( elements.size == 0 ) {
+				this._markerNameToElements.delete( name );
+			}
+		}
 	}
 
 	/**

+ 26 - 0
packages/ckeditor5-engine/src/model/differ.js

@@ -111,6 +111,32 @@ export default class Differ {
 	}
 
 	/**
+	 * Marks given `item` in differ to be "refreshed". It means that the item will be marked as removed and inserted in the differ changes
+	 * set, so it will be effectively re-converted when differ changes will be handled by a dispatcher.
+	 *
+	 * @param {module:engine/model/item~Item} item Item to refresh.
+	 */
+	refreshItem( item ) {
+		if ( this._isInInsertedElement( item.parent ) ) {
+			return;
+		}
+
+		this._markRemove( item.parent, item.startOffset, item.offsetSize );
+		this._markInsert( item.parent, item.startOffset, item.offsetSize );
+
+		const range = Range._createOn( item );
+
+		for ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {
+			const markerRange = marker.getRange();
+
+			this.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData );
+		}
+
+		// Clear cache after each buffered operation as it is no longer valid.
+		this._cachedChanges = null;
+	}
+
+	/**
 	 * Buffers the given operation. An operation has to be buffered before it is executed.
 	 *
 	 * Operation type is checked and it is checked which nodes it will affect. These nodes are then stored in `Differ`

+ 2 - 1
packages/ckeditor5-engine/src/model/schema.js

@@ -140,7 +140,7 @@ export default class Schema {
 			 * {@link #register registered} yet.
 			 *
 			 * @param itemName The name of the model element which is being extended.
-			 * @error schema-cannot-register-item-twice
+			 * @error schema-cannot-extend-missing-item
 			 */
 			throw new CKEditorError( 'schema-cannot-extend-missing-item: Cannot extend an item which was not registered yet.', this, {
 				itemName
@@ -1363,6 +1363,7 @@ export class SchemaContext {
  * @typedef {Object} module:engine/model/schema~AttributeProperties
  * @property {Boolean} [isFormatting] Indicates that the attribute should be considered as a visual formatting, like `bold`, `italic` or
  * `fontSize` rather than semantic attribute (such as `src`, `listType`, etc.). For example, it is used by the "Remove format" feature.
+ * @property {Boolean} [copyOnEnter] Indicates that given text attribute should be copied to the next block when enter is pressed.
  */
 
 function compileBaseItemRule( sourceItemRules, itemName ) {

+ 11 - 6
packages/ckeditor5-engine/tests/conversion/mapper.js

@@ -643,20 +643,25 @@ describe( 'Mapper', () => {
 			expect( elements ).to.deep.equal( [ viewA, viewB, viewC ] );
 		} );
 
-		it( 'should unbind all elements from a marker name', () => {
+		it( 'should unbind element from a marker name', () => {
 			const viewA = new ViewElement( 'a' );
 			const viewB = new ViewElement( 'b' );
-			const viewC = new ViewElement( 'c' );
 
 			mapper.bindElementToMarker( viewA, 'marker' );
 			mapper.bindElementToMarker( viewB, 'marker' );
-			mapper.bindElementToMarker( viewC, 'marker' );
 
-			mapper.unbindElementsFromMarkerName( 'marker' );
+			mapper.unbindElementFromMarkerName( viewA, 'marker' );
 
-			const elements = mapper.markerNameToElements( 'marker' );
+			expect( Array.from( mapper.markerNameToElements( 'marker' ) ) ).to.deep.equal( [ viewB ] );
+
+			mapper.unbindElementFromMarkerName( viewB, 'marker' );
+
+			expect( mapper.markerNameToElements( 'marker' ) ).to.be.null;
+
+			// Removing an element from non-existing group or non-bound element should not cause a crash.
+			mapper.unbindElementFromMarkerName( viewB, 'marker' );
 
-			expect( elements ).to.be.null;
+			expect( mapper.markerNameToElements( 'marker' ) ).to.be.null;
 		} );
 	} );
 

+ 70 - 0
packages/ckeditor5-engine/tests/model/differ.js

@@ -1759,6 +1759,76 @@ describe( 'Differ', () => {
 		} );
 	} );
 
+	describe( 'refreshItem()', () => {
+		it( 'should mark given element to be removed and added again', () => {
+			const p = root.getChild( 0 );
+
+			differ.refreshItem( p );
+
+			expectChanges( [
+				{ type: 'remove', name: 'paragraph', length: 1, position: model.createPositionBefore( p ) },
+				{ type: 'insert', name: 'paragraph', length: 1, position: model.createPositionBefore( p ) }
+			], true );
+		} );
+
+		it( 'should mark given text proxy to be removed and added again', () => {
+			const p = root.getChild( 0 );
+			const range = model.createRangeIn( p );
+			const textProxy = [ ...range.getItems() ][ 0 ];
+
+			differ.refreshItem( textProxy );
+
+			expectChanges( [
+				{ type: 'remove', name: '$text', length: 3, position: model.createPositionAt( p, 0 ) },
+				{ type: 'insert', name: '$text', length: 3, position: model.createPositionAt( p, 0 ) }
+			], true );
+		} );
+
+		it( 'inside a new element', () => {
+			// Since the refreshed element is inside a new element, it should not be listed on changes list.
+			model.change( () => {
+				insert( new Element( 'blockQuote', null, new Element( 'paragraph' ) ), new Position( root, [ 2 ] ) );
+
+				differ.refreshItem( root.getChild( 2 ).getChild( 0 ) );
+
+				expectChanges( [
+					{ type: 'insert', name: 'blockQuote', length: 1, position: new Position( root, [ 2 ] ) }
+				] );
+			} );
+		} );
+
+		it( 'markers refreshing', () => {
+			model.change( () => {
+				// Refreshed element contains marker.
+				model.markers._set( 'markerA', new Range( new Position( root, [ 1, 1 ] ), new Position( root, [ 1, 2 ] ) ) );
+
+				// Marker contains refreshed element.
+				model.markers._set( 'markerB', new Range( new Position( root, [ 0 ] ), new Position( root, [ 2 ] ) ) );
+
+				// Intersecting.
+				model.markers._set( 'markerC', new Range( new Position( root, [ 0, 2 ] ), new Position( root, [ 1, 2 ] ) ) );
+
+				// Not intersecting.
+				model.markers._set( 'markerD', new Range( new Position( root, [ 0, 0 ] ), new Position( root, [ 1 ] ) ) );
+			} );
+
+			const markersToRefresh = [ 'markerA', 'markerB', 'markerC' ];
+
+			differ.refreshItem( root.getChild( 1 ) );
+
+			expectChanges( [
+				{ type: 'remove', name: 'paragraph', length: 1, position: new Position( root, [ 1 ] ) },
+				{ type: 'insert', name: 'paragraph', length: 1, position: new Position( root, [ 1 ] ) }
+			] );
+
+			const markersToRemove = differ.getMarkersToRemove().map( entry => entry.name );
+			const markersToAdd = differ.getMarkersToAdd().map( entry => entry.name );
+
+			expect( markersToRefresh ).to.deep.equal( markersToRemove );
+			expect( markersToRefresh ).to.deep.equal( markersToAdd );
+		} );
+	} );
+
 	describe( 'getChanges()', () => {
 		let position, p1, rangeAttrChange, range;