Sfoglia il codice sorgente

Merge branch 'master' into i/6265

Piotrek Koszuliński 5 anni fa
parent
commit
4b361cef88

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

@@ -1,6 +1,38 @@
 Changelog
 =========
 
+## [18.0.0](https://github.com/ckeditor/ckeditor5-engine/compare/v17.0.0...v18.0.0) (2020-03-19)
+
+### MAJOR BREAKING CHANGES
+
+* `EditingController` requires an instance of `StylesProcessor` in its constructor.
+* `DataController` requires an instance of `StylesProcessor` in its constructor.
+* `DomConverter`, `HtmlDataProcessor` and `XmlDataProcessor` require an instance of the view document in their constructors.
+* The `View` class requires an instance of `StylesProcessor` as its first argument.
+* The `createViewElementFromHighlightDescriptor()` function that is exported by `src/conversion/downcasthelpers.js` file requires an instance of the view document as its first argument.
+* Method `view.Document#addStyleProcessorRules()` has been moved to the `DataController` class.
+* The `#document` getter was removed from model nodes. Only the root element holds the reference to the model document. For attached nodes, use `node.root.document` to access it.
+
+### MINOR BREAKING CHANGES
+
+* `DataController` does not accept the data processor instance any more.
+
+### Features
+
+* Implemented the model and view `Range#getContainedElement()` methods. Closes [ckeditor/ckeditor5#6364](https://github.com/ckeditor/ckeditor5/issues/6364). ([8fb1efa](https://github.com/ckeditor/ckeditor5-engine/commit/8fb1efa))
+
+### Bug fixes
+
+* Fixed renderer bug causing editor crash in a range of scenarios involving reusing DOM elements. Closes [ckeditor/ckeditor5#6092](https://github.com/ckeditor/ckeditor5/issues/6092). ([67884da](https://github.com/ckeditor/ckeditor5-engine/commit/67884da))
+
+### Other changes
+
+* `DataController` will now use a single instance of the view document for all its operations (`DataController#viewDocument`). Closes [ckeditor/ckeditor5#6381](https://github.com/ckeditor/ckeditor5/issues/6381). ([851bac6](https://github.com/ckeditor/ckeditor5-engine/commit/851bac6))
+* `Document#version` is no longer read-only. ([968b193](https://github.com/ckeditor/ckeditor5-engine/commit/968b193))
+* `StylesProcessor` rules will not be stored in a singleton, which made them shared between editor instances. In order to allow binding a styles processor instance to a specific view document, we had to replace a dynamic `#document` property in view nodes with a static one, set upon node creation. Closes [ckeditor/ckeditor5#6091](https://github.com/ckeditor/ckeditor5/issues/6091). ([0e2f02e](https://github.com/ckeditor/ckeditor5-engine/commit/0e2f02e))
+* Introduced support for multi-range selections. Closes [ckeditor/ckeditor5#6116](https://github.com/ckeditor/ckeditor5/issues/6116). ([ffce577](https://github.com/ckeditor/ckeditor5-engine/commit/ffce577))
+
+
 ## [17.0.0](https://github.com/ckeditor/ckeditor5-engine/compare/v16.0.0...v17.0.0) (2020-02-19)
 
 ### Features

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

@@ -1,6 +1,6 @@
 {
   "name": "@ckeditor/ckeditor5-engine",
-  "version": "17.0.0",
+  "version": "18.0.0",
   "description": "The editing engine of CKEditor 5 – the best browser-based rich text editor.",
   "keywords": [
     "wysiwyg",
@@ -21,25 +21,25 @@
     "ckeditor 5"
   ],
   "dependencies": {
-    "@ckeditor/ckeditor5-utils": "^17.0.0",
+    "@ckeditor/ckeditor5-utils": "^18.0.0",
     "lodash-es": "^4.17.10"
   },
   "devDependencies": {
-    "@ckeditor/ckeditor5-basic-styles": "^17.0.0",
-    "@ckeditor/ckeditor5-block-quote": "^17.0.0",
-    "@ckeditor/ckeditor5-core": "^17.0.0",
-    "@ckeditor/ckeditor5-editor-classic": "^17.0.0",
-    "@ckeditor/ckeditor5-enter": "^17.0.0",
-    "@ckeditor/ckeditor5-essentials": "^17.0.0",
-    "@ckeditor/ckeditor5-heading": "^17.0.0",
-    "@ckeditor/ckeditor5-link": "^17.0.0",
-    "@ckeditor/ckeditor5-list": "^17.0.0",
-    "@ckeditor/ckeditor5-paragraph": "^17.0.0",
-    "@ckeditor/ckeditor5-theme-lark": "^17.0.0",
-    "@ckeditor/ckeditor5-typing": "^17.0.0",
-    "@ckeditor/ckeditor5-undo": "^17.0.0",
-    "@ckeditor/ckeditor5-widget": "^17.0.0",
-    "@ckeditor/ckeditor5-table": "^17.0.0",
+    "@ckeditor/ckeditor5-basic-styles": "^18.0.0",
+    "@ckeditor/ckeditor5-block-quote": "^18.0.0",
+    "@ckeditor/ckeditor5-core": "^18.0.0",
+    "@ckeditor/ckeditor5-editor-classic": "^18.0.0",
+    "@ckeditor/ckeditor5-enter": "^18.0.0",
+    "@ckeditor/ckeditor5-essentials": "^18.0.0",
+    "@ckeditor/ckeditor5-heading": "^18.0.0",
+    "@ckeditor/ckeditor5-link": "^18.0.0",
+    "@ckeditor/ckeditor5-list": "^18.0.0",
+    "@ckeditor/ckeditor5-paragraph": "^18.0.0",
+    "@ckeditor/ckeditor5-table": "^18.0.0",
+    "@ckeditor/ckeditor5-theme-lark": "^18.0.0",
+    "@ckeditor/ckeditor5-typing": "^18.0.0",
+    "@ckeditor/ckeditor5-undo": "^18.0.0",
+    "@ckeditor/ckeditor5-widget": "^18.0.0",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^2.0.0",
     "husky": "^1.3.1",

+ 5 - 1
packages/ckeditor5-engine/src/model/model.js

@@ -196,6 +196,9 @@ export default class Model {
 	 * 			console.log( 3 );
 	 *		} ); // Will log: 1, 3, 2.
 	 *
+	 * In addition to that, the changes enqueued with `enqueueChange()` will be converted separately from the changes
+	 * done in the outer `change()` block.
+	 *
 	 * Second, it lets you define the {@link module:engine/model/batch~Batch} into which you want to add your changes.
 	 * By default, a new batch is created. In the sample above, `change` and `enqueueChange` blocks use a different
 	 * batch (and different {@link module:engine/model/writer~Writer} since each of them operates on the separate batch).
@@ -206,7 +209,8 @@ export default class Model {
 	 *			writer.insertText( 'foo', paragraph, 'end' );
 	 *		} );
 	 *
-	 * The batch instance can be obtained from {@link module:engine/model/writer~Writer#batch the writer}.
+	 * In order to make a nested `enqueueChange()` create a single undo step together with the changes done in the outer `change()`
+	 * block, you can obtain the batch instance from the  {@link module:engine/model/writer~Writer#batch writer} of the outer block.
 	 *
 	 * @param {module:engine/model/batch~Batch|'transparent'|'default'} batchOrType Batch or batch type should be used in the callback.
 	 * If not defined, a new batch will be created.

+ 4 - 0
packages/ckeditor5-engine/src/view/observer/selectionobserver.js

@@ -143,9 +143,13 @@ export default class SelectionObserver extends Observer {
 		// It means that the DOM selection is in some way incorrect. Ranges that were in the DOM selection could not be
 		// converted to the view. This happens when the DOM selection was moved outside of the editable element.
 		if ( newViewSelection.rangeCount == 0 ) {
+			this.view.hasDomSelection = false;
+
 			return;
 		}
 
+		this.view.hasDomSelection = true;
+
 		if ( this.selection.isEqual( newViewSelection ) && this.domConverter.isDomSelectionCorrect( domSelection ) ) {
 			return;
 		}

+ 8 - 0
packages/ckeditor5-engine/src/view/view.js

@@ -101,6 +101,14 @@ export default class View {
 		this.set( 'isRenderingInProgress', false );
 
 		/**
+		 * Informs whether the DOM selection is inside any of the DOM roots managed by the view.
+		 *
+		 * @readonly
+		 * @member {Boolean} #hasDomSelection
+		 */
+		this.set( 'hasDomSelection', false );
+
+		/**
 		 * Instance of the {@link module:engine/view/renderer~Renderer renderer}.
 		 *
 		 * @protected

+ 64 - 1
packages/ckeditor5-engine/tests/view/view/view.js

@@ -3,7 +3,7 @@
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  */
 
-/* globals document, console */
+/* globals document, console, setTimeout */
 
 import View from '../../../src/view/view';
 import Observer from '../../../src/view/observer/observer';
@@ -514,6 +514,69 @@ describe( 'view', () => {
 		} );
 	} );
 
+	describe( 'hasDomSelection', () => {
+		let domElement, domP, domSelection;
+
+		// Focus tests are too unstable on Firefox to run them.
+		if ( env.isGecko ) {
+			return;
+		}
+
+		beforeEach( () => {
+			const viewRoot = createViewRoot( viewDocument, 'div', 'main' );
+
+			view.attachDomRoot( domRoot );
+
+			viewRoot._appendChild( new ViewElement( viewDocument, 'p' ) );
+			view.forceRender();
+
+			domElement = createElement( document, 'div', { contenteditable: 'true' } );
+			document.body.appendChild( domElement );
+
+			domSelection = document.getSelection();
+			domP = domRoot.childNodes[ 0 ];
+		} );
+
+		afterEach( () => {
+			domElement.remove();
+		} );
+
+		it( 'should be true if selection is inside a DOM root element', done => {
+			domSelection.collapse( domP, 0 );
+
+			// Wait for async selectionchange event on DOM document.
+			setTimeout( () => {
+				expect( view.hasDomSelection ).to.be.true;
+
+				done();
+			}, 100 );
+		} );
+
+		it( 'should be true if selection is inside a DOM root element - no focus', done => {
+			domSelection.collapse( domP, 0 );
+			domRoot.blur();
+
+			// Wait for async selectionchange event on DOM document.
+			setTimeout( () => {
+				expect( view.hasDomSelection ).to.be.true;
+				expect( view.document.isFocused ).to.be.false;
+
+				done();
+			}, 100 );
+		} );
+
+		it( 'should be false if selection is outside DOM root element', done => {
+			domSelection.collapse( domElement, 0 );
+
+			// Wait for async selectionchange event on DOM document.
+			setTimeout( () => {
+				expect( view.hasDomSelection ).to.be.false;
+
+				done();
+			}, 100 );
+		} );
+	} );
+
 	describe( 'forceRender()', () => {
 		it( 'disable observers, renders and enable observers', () => {
 			const observerMock = view.addObserver( ObserverMock );