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

Improved panel behavior upon document#render in certain situations.

Aleksander Nowodzinski 8 лет назад
Родитель
Сommit
6934fcda17
2 измененных файлов с 100 добавлено и 137 удалено
  1. 10 4
      packages/ckeditor5-link/src/link.js
  2. 90 133
      packages/ckeditor5-link/tests/link.js

+ 10 - 4
packages/ckeditor5-link/src/link.js

@@ -231,6 +231,7 @@ export default class Link extends Plugin {
 	_showPanel( focusInput ) {
 		const editing = this.editor.editing;
 		const showViewDocument = editing.view;
+		const showIsCollapsed = showViewDocument.selection.isCollapsed;
 		const showSelectedLink = this._getSelectedLinkElement();
 
 		// https://github.com/ckeditor/ckeditor5-link/issues/53
@@ -238,10 +239,15 @@ export default class Link extends Plugin {
 
 		this.listenTo( showViewDocument, 'render', () => {
 			const renderSelectedLink = this._getSelectedLinkElement();
-
-			// Hide the panel if the selection went out of the original link element
-			// upon the #render event (e.g. paragraph containing the link was removed).
-			if ( showSelectedLink !== renderSelectedLink ) {
+			const renderIsCollapsed = showViewDocument.selection.isCollapsed;
+			const hasSellectionExpanded = showIsCollapsed && !renderIsCollapsed;
+
+			// Hide the panel if:
+			//   * the selection went out of the original link element
+			//     (e.g. paragraph containing the link was removed),
+			//   * the selection has expanded
+			// upon the #render event.
+			if ( hasSellectionExpanded || showSelectedLink !== renderSelectedLink ) {
 				this._hidePanel( true );
 			}
 			// Update the position of the panel when:

+ 90 - 133
packages/ckeditor5-link/tests/link.js

@@ -215,29 +215,82 @@ describe( 'Link', () => {
 		} );
 
 		describe( 'when the document is rendering', () => {
-			it( 'updates the position of the panel – editing a link and the selection remains in the link upon #render', () => {
+			it( 'should not duplicate #render listeners', () => {
+				const viewDocument = editor.editing.view;
+
+				setModelData( editor.document, '<paragraph>f[]oo</paragraph>' );
+
+				const spy = testUtils.sinon.stub( balloon, 'updatePosition', () => {} );
+
+				return linkFeature._showPanel()
+					.then( () => {
+						viewDocument.render();
+						linkFeature._hidePanel();
+
+						return linkFeature._showPanel()
+							.then( () => {
+								viewDocument.render();
+								sinon.assert.calledTwice( spy );
+							} );
+					} );
+			} );
+
+			//https://github.com/ckeditor/ckeditor5-link/issues/113
+			it( 'updates the position of the panel – editing a link, then the selection remains in the link upon #render', () => {
 				const viewDocument = editor.editing.view;
 
 				setModelData( editor.document, '<paragraph><$text linkHref="url">f[]oo</$text></paragraph>' );
 
 				return linkFeature._showPanel()
 					.then( () => {
-						const spy = testUtils.sinon.spy( balloon, 'updatePosition' );
+						const spy = testUtils.sinon.stub( balloon, 'updatePosition', () => {} );
 
+						const root = viewDocument.getRoot();
+						const text = root.getChild( 0 ).getChild( 0 ).getChild( 0 );
+
+						// Move selection to foo[].
+						viewDocument.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 3, text, 3 ) ], true );
 						viewDocument.render();
+
 						sinon.assert.calledOnce( spy );
 						sinon.assert.calledWithExactly( spy );
 					} );
 			} );
 
-			it( 'hides of the panel – editing a link and the selection moved out of the link upon #render', () => {
+			//https://github.com/ckeditor/ckeditor5-link/issues/113
+			it( 'updates the position of the panel – creating a new link, then the selection moved upon #render', () => {
+				const viewDocument = editor.editing.view;
+
+				setModelData( editor.document, '<paragraph>f[]oo</paragraph>' );
+
+				return linkFeature._showPanel()
+					.then( () => {
+						const spy = testUtils.sinon.stub( balloon, 'updatePosition', () => {} );
+
+						// Fires #render.
+						const root = viewDocument.getRoot();
+						const text = root.getChild( 0 ).getChild( 0 );
+
+						viewDocument.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 3, text, 3 ) ], true );
+						viewDocument.render();
+
+						sinon.assert.calledOnce( spy );
+						sinon.assert.calledWithExactly( spy, {
+							target: editorElement.ownerDocument.getSelection().getRangeAt( 0 ),
+							limiter: editorElement
+						} );
+					} );
+			} );
+
+			//https://github.com/ckeditor/ckeditor5-link/issues/113
+			it( 'hides of the panel – editing a link, then the selection moved out of the link upon #render', () => {
 				const viewDocument = editor.editing.view;
 
 				setModelData( editor.document, '<paragraph><$text linkHref="url">f[]oo</$text>bar</paragraph>' );
 
 				return linkFeature._showPanel()
 					.then( () => {
-						const spyUpdate = testUtils.sinon.spy( balloon, 'updatePosition' );
+						const spyUpdate = testUtils.sinon.stub( balloon, 'updatePosition', () => {} );
 						const spyHide = testUtils.sinon.spy( linkFeature, '_hidePanel' );
 
 						const root = viewDocument.getRoot();
@@ -252,27 +305,49 @@ describe( 'Link', () => {
 					} );
 			} );
 
-			it( 'updates the position of the panel – creating a new link and the selection moved upon #render', () => {
+			//https://github.com/ckeditor/ckeditor5-link/issues/113
+			it( 'hides of the panel – editing a link, then the selection moved to another link upon #render', () => {
 				const viewDocument = editor.editing.view;
 
-				setModelData( editor.document, '<paragraph>f[]oo</paragraph>' );
+				setModelData( editor.document, '<paragraph><$text linkHref="url">f[]oo</$text>bar<$text linkHref="url">b[]az</$text></paragraph>' );
 
 				return linkFeature._showPanel()
 					.then( () => {
-						const spy = testUtils.sinon.spy( balloon, 'updatePosition' );
+						const spyUpdate = testUtils.sinon.stub( balloon, 'updatePosition', () => {} );
+						const spyHide = testUtils.sinon.spy( linkFeature, '_hidePanel' );
 
-						// Fires #render.
 						const root = viewDocument.getRoot();
-						const text = root.getChild( 0 ).getChild( 0 );
+						const text = root.getChild( 0 ).getChild( 2 ).getChild( 0 );
 
-						viewDocument.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 3, text, 3 ) ], true );
+						// Move selection to b[]az.
+						viewDocument.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 1 ) ], true );
 						viewDocument.render();
 
-						sinon.assert.calledOnce( spy );
-						sinon.assert.calledWithExactly( spy, {
-							target: editorElement.ownerDocument.getSelection().getRangeAt( 0 ),
-							limiter: editorElement
-						} );
+						sinon.assert.calledOnce( spyHide );
+						sinon.assert.notCalled( spyUpdate );
+					} );
+			} );
+
+			//https://github.com/ckeditor/ckeditor5-link/issues/113
+			it( 'hides the panel – editing a link, then the selection expands upon #render', () => {
+				const viewDocument = editor.editing.view;
+
+				setModelData( editor.document, '<paragraph><$text linkHref="url">f[]oo</$text></paragraph>' );
+
+				return linkFeature._showPanel()
+					.then( () => {
+						const spyUpdate = testUtils.sinon.stub( balloon, 'updatePosition', () => {} );
+						const spyHide = testUtils.sinon.spy( linkFeature, '_hidePanel' );
+
+						const root = viewDocument.getRoot();
+						const text = root.getChild( 0 ).getChild( 0 ).getChild( 0 );
+
+						// Move selection to f[o]o.
+						viewDocument.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 2 ) ], true );
+						viewDocument.render();
+
+						sinon.assert.calledOnce( spyHide );
+						sinon.assert.notCalled( spyUpdate );
 					} );
 			} );
 		} );
@@ -525,124 +600,6 @@ describe( 'Link', () => {
 				sinon.assert.calledWithExactly( spy );
 			} );
 
-			it( 'should keep open and update position until collapsed selection stay inside the same link element', () => {
-				// Method is stubbed because it returns internal promise which can't be returned in test.
-				const showSpy = testUtils.sinon.stub( linkFeature, '_showPanel', () => {} );
-				const hideSpy = testUtils.sinon.stub( linkFeature, '_hidePanel' );
-				const updatePositionSpy = testUtils.sinon.stub( balloon, 'updatePosition', () => {} );
-
-				editor.document.schema.allow( { name: '$text', inside: '$root' } );
-				setModelData( editor.document, '<$text linkHref="url">b[]ar</$text>' );
-
-				const root = editor.editing.view.getRoot();
-				const text = root.getChild( 0 ).getChild( 0 );
-
-				observer.fire( 'click', { target: document.body } );
-
-				// Panel is shown.
-				sinon.assert.calledOnce( showSpy );
-
-				// Move selection.
-				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 1 ) ], true );
-				editor.editing.view.render();
-
-				// Check if balloon is still opened (wasn't hide).
-				sinon.assert.notCalled( hideSpy );
-				// And position was updated
-				sinon.assert.calledOnce( updatePositionSpy );
-			} );
-
-			it( 'should not duplicate `render` listener on `ViewDocument`', () => {
-				const updatePositionSpy = testUtils.sinon.stub( balloon, 'updatePosition', () => {} );
-
-				// Method is stubbed because it returns internal promise which can't be returned in test.
-				testUtils.sinon.stub( linkFeature, '_showPanel', () => {} );
-
-				editor.document.schema.allow( { name: '$text', inside: '$root' } );
-				setModelData( editor.document, '<$text linkHref="url">b[]ar</$text>' );
-
-				// Click at the same link more than once.
-				observer.fire( 'click', { target: document.body } );
-				observer.fire( 'click', { target: document.body } );
-				observer.fire( 'click', { target: document.body } );
-
-				sinon.assert.notCalled( updatePositionSpy );
-
-				const root = editor.editing.view.getRoot();
-				const text = root.getChild( 0 ).getChild( 0 );
-
-				// Move selection.
-				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 1 ) ], true );
-				editor.editing.view.render();
-
-				// Position should be updated only once.
-				sinon.assert.calledOnce( updatePositionSpy );
-			} );
-
-			it( 'should close when selection goes outside the link element', () => {
-				const hideSpy = testUtils.sinon.stub( linkFeature, '_hidePanel' );
-
-				// Method is stubbed because it returns internal promise which can't be returned in test.
-				testUtils.sinon.stub( linkFeature, '_showPanel', () => {} );
-
-				editor.document.schema.allow( { name: '$text', inside: '$root' } );
-				setModelData( editor.document, 'foo <$text linkHref="url">b[]ar</$text>' );
-
-				const root = editor.editing.view.getRoot();
-				const text = root.getChild( 0 );
-
-				observer.fire( 'click', { target: document.body } );
-
-				sinon.assert.notCalled( hideSpy );
-
-				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 3, text, 3 ) ], true );
-				editor.editing.view.render();
-
-				sinon.assert.calledOnce( hideSpy );
-			} );
-
-			it( 'should close when selection goes to the other link element with the same href', () => {
-				const hideSpy = testUtils.sinon.stub( linkFeature, '_hidePanel' );
-
-				// Method is stubbed because it returns internal promise which can't be returned in test.
-				testUtils.sinon.stub( linkFeature, '_showPanel', () => {} );
-
-				editor.document.schema.allow( { name: '$text', inside: '$root' } );
-				setModelData( editor.document, '<$text linkHref="url">f[]oo</$text> bar <$text linkHref="url">biz</$text>' );
-
-				const root = editor.editing.view.getRoot();
-				const text = root.getChild( 2 ).getChild( 0 );
-
-				observer.fire( 'click', { target: document.body } );
-
-				sinon.assert.notCalled( hideSpy );
-
-				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 1 ) ], true );
-				editor.editing.view.render();
-
-				sinon.assert.calledOnce( hideSpy );
-			} );
-
-			it( 'should close when selection becomes non-collapsed', () => {
-				const hideSpy = testUtils.sinon.stub( linkFeature, '_hidePanel' );
-
-				// Method is stubbed because it returns internal promise which can't be returned in test.
-				testUtils.sinon.stub( linkFeature, '_showPanel', () => {} );
-
-				editor.document.schema.allow( { name: '$text', inside: '$root' } );
-				setModelData( editor.document, '<$text linkHref="url">f[]oo</$text>' );
-
-				const root = editor.editing.view.getRoot();
-				const text = root.getChild( 0 ).getChild( 0 );
-
-				observer.fire( 'click', { target: {} } );
-
-				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 2 ) ] );
-				editor.editing.view.render();
-
-				sinon.assert.calledOnce( hideSpy );
-			} );
-
 			it( 'should not open when selection is not inside link element', () => {
 				const showSpy = testUtils.sinon.stub( linkFeature, '_showPanel' );