Przeglądaj źródła

Added unlink button to link balloon panel.

Oskar Wrobel 9 lat temu
rodzic
commit
be6d7f7db5

+ 7 - 0
packages/ckeditor5-link/src/link.js

@@ -186,6 +186,13 @@ export default class Link extends Feature {
 			balloonPanel.view.hide();
 		} );
 
+		// Observe `LinkBalloonPanelMode#execute-unlink` event from within the model of the panel,
+		// which means that the `Unlink` button has been clicked.
+		this.listenTo( panelModel, 'execute-unlink', () => {
+			editor.execute( 'unlink' );
+			balloonPanel.view.hide();
+		} );
+
 		// Always focus editor on panel hide.
 		this.listenTo( panelModel, 'hide', () => viewDocument.focus() );
 

+ 45 - 6
packages/ckeditor5-link/src/ui/linkballoonpanel.js

@@ -99,9 +99,12 @@ export default class LinkBalloonPanel extends BalloonPanel {
 	 * @returns {ui.box.Box} Box component.
 	 */
 	_createButtons() {
-		const box = new Box( new Model( {
-			alignRight: true
+		const wrapper = new Box( new Model( {
+			alignContent: 'right'
 		} ), new BoxView( this.locale ) );
+		wrapper.view.element.classList.add( 'ck-link-balloon-panel_actions' );
+
+		const additionalActions = new Box( new Model(), new BoxView( this.locale ) );
 
 		/**
 		 * Button component for submitting form.
@@ -117,11 +120,23 @@ export default class LinkBalloonPanel extends BalloonPanel {
 		 */
 		this.cancelButton = this._createCancelButton();
 
-		// Add `Cancel` and `Save` buttons as a box content.
-		box.add( 'content', this.cancelButton );
-		box.add( 'content', this.saveButton );
+		/**
+		 * Button component for unlinking.
+		 *
+		 * @member {ui.button.Button} link.ui.LinkBalloonPanel#unlinkButton
+		 */
+		this.unlinkButton = this._createUnlinkButton();
+
+		// Add `Save`, `Cancel` and `Unlink` buttons as a wrapper content.
+		wrapper.add( 'content', this.saveButton );
+		wrapper.add( 'content', this.cancelButton );
+
+		// Append Unlink button into additional action box.
+		additionalActions.add( 'content', this.unlinkButton );
 
-		return box;
+		wrapper.add( 'content', additionalActions );
+
+		return wrapper;
 	}
 
 	/**
@@ -166,4 +181,28 @@ export default class LinkBalloonPanel extends BalloonPanel {
 
 		return new Button( cancelModel, new ButtonView( this.locale ) );
 	}
+
+	/**
+	 * Initialize {@link ui.button.Button Button} for unlinking command.
+	 *
+	 * @private
+	 * @returns {ui.button.Button} Unlink button component.
+	 */
+	_createUnlinkButton() {
+		const t = this.view.t;
+		const unlinkModel = new Model( {
+			isEnabled: true,
+			isOn: false,
+			label: t( 'Unlink' ),
+			withText: true
+		} );
+
+		unlinkModel.on( 'execute', () => this.model.fire( 'execute-unlink' ) );
+
+		const button = new Button( unlinkModel, new ButtonView( this.locale ) );
+
+		button.view.element.classList.add( 'ck-button-action' );
+
+		return button;
+	}
 }

+ 25 - 0
packages/ckeditor5-link/tests/link.js

@@ -174,6 +174,31 @@ describe( 'Link', () => {
 			expect( executeSpy.calledWithExactly( 'link', 'http://cksource.com' ) ).to.true;
 		} );
 
+		it( 'should hide balloon panel on balloonPanel#model execute event', () => {
+			const hideSpy = testUtils.sinon.spy( balloonPanel.view, 'hide' );
+
+			balloonPanel.model.fire( 'execute' );
+
+			expect( hideSpy.calledOnce ).to.true;
+		} );
+
+		it( 'should execute unlink command on balloonPanel#model execute-unlink event', () => {
+			const executeSpy = testUtils.sinon.spy( editor, 'execute' );
+
+			balloonPanel.model.fire( 'execute-unlink' );
+
+			expect( executeSpy.calledOnce ).to.true;
+			expect( executeSpy.calledWithExactly( 'unlink' ) ).to.true;
+		} );
+
+		it( 'should hide balloon panel on balloonPanel#model execute-unlink event', () => {
+			const hideSpy = testUtils.sinon.spy( balloonPanel.view, 'hide' );
+
+			balloonPanel.model.fire( 'execute-unlink' );
+
+			expect( hideSpy.calledOnce ).to.true;
+		} );
+
 		it( 'should append panel element to the body', () => {
 			expect( document.body.contains( balloonPanel.view.element ) );
 		} );

+ 17 - 1
packages/ckeditor5-link/tests/ui/linkballoonpanel.js

@@ -78,7 +78,7 @@ describe( 'LinkBalloonPanel', () => {
 					expect( linkBalloonPanel.saveButton ).to.instanceof( Button );
 				} );
 
-				it( 'should trigger model#execute event after clicking', ( done ) => {
+				it( 'should fire model#execute event on DOM click event', ( done ) => {
 					const executeSpy = sinon.spy();
 
 					model.on( 'execute', executeSpy );
@@ -109,6 +109,22 @@ describe( 'LinkBalloonPanel', () => {
 					expect( hideSpy.calledOnce ).to.true;
 				} );
 			} );
+
+			describe( 'unlinkButton', () => {
+				it( 'should create Button instance', () => {
+					expect( linkBalloonPanel.unlinkButton ).to.instanceof( Button );
+				} );
+
+				it( 'should fire model#execute-unlink event on unlinkButton.model#execute event', () => {
+					const executeUnlinkSpy = sinon.spy();
+
+					model.on( 'execute-unlink', executeUnlinkSpy );
+
+					linkBalloonPanel.unlinkButton.model.fire( 'execute' );
+
+					expect( executeUnlinkSpy.calledOnce ).to.true;
+				} );
+			} );
 		} );
 	} );
 } );

+ 17 - 0
packages/ckeditor5-link/theme/components/linkballoonpanel.scss

@@ -3,4 +3,21 @@
 
 .ck-link-balloon-panel {
 	padding: ck-spacing();
+
+	// Box to accommodate buttons.
+	&_actions {
+		display: flex;
+		flex-direction: row-reverse;
+		padding-top: ck-spacing();
+
+		.ck-button {
+			& + .ck-button {
+				margin-right: ck-spacing( 'medium' );
+			}
+		}
+
+		.ck-box {
+			flex-grow: 2;
+		}
+	}
 }