瀏覽代碼

Moved form creation logic from the Link Feature to LinkForm.

Aleksander Nowodzinski 9 年之前
父節點
當前提交
cd8bf35c3d

+ 8 - 53
packages/ckeditor5-link/src/link.js

@@ -21,9 +21,6 @@ import BalloonPanelView from '../ui/balloonpanel/balloonpanelview.js';
 import LinkForm from './ui/linkform.js';
 import LinkFormView from './ui/linkformview.js';
 
-import LabeledInput from '../ui/labeledinput/labeledinput.js';
-import InputText from '../ui/inputtext/inputtext.js';
-
 /**
  * The link feature. It introduces the Link and Unlink buttons and the <kbd>Ctrl+K</kbd> keystroke.
  *
@@ -63,13 +60,6 @@ export default class Link extends Feature {
 		// Create toolbar buttons.
 		this._createToolbarLinkButton();
 		this._createToolbarUnlinkButton();
-
-		/**
-		 * The URL input inside {@link link.Link#form}.
-		 *
-		 * @protected
-		 * @member {ui.input.labeled.LabeledInput} think.Link#_urlInput
-		 */
 	}
 
 	/**
@@ -211,61 +201,26 @@ export default class Link extends Feature {
 	 */
 	_createForm() {
 		const editor = this.editor;
-		const t = this.editor.t;
-		const linkCommand = editor.commands.get( 'link' );
+		const formModel = new Model();
 
-		const formView = new LinkFormView( editor.locale );
-		const form = new LinkForm( new Model(), formView );
+		formModel.bind( 'url' ).to( editor.commands.get( 'link' ), 'value' );
 
-		// Create component models.
-		const urlInputModel = new Model( {
-			label: t( 'Link URL' )
-		} );
-
-		urlInputModel.bind( 'value' ).to( linkCommand, 'value' );
-
-		const saveButtonModel = new Model( {
-			isEnabled: true,
-			isOn: false,
-			label: t( 'Save' ),
-			withText: true,
-			type: 'submit'
-		} );
-
-		const cancelButtonModel = new Model( {
-			isEnabled: true,
-			isOn: false,
-			label: t( 'Cancel' ),
-			withText: true
-		} );
-
-		const unlinkButtonModel = new Model( {
-			isEnabled: true,
-			isOn: false,
-			label: t( 'Unlink' ),
-			icon: 'unlink'
-		} );
-
-		// Add components to the form.
-		form.add( this._urlInput = new LabeledInput( urlInputModel, formView.urlInputView, InputText, new Model() ) );
-		form.add( this._saveButton = new Button( saveButtonModel, formView.saveButtonView ) );
-		form.add( this._cancelButton = new Button( cancelButtonModel, formView.cancelButtonView ) );
-		form.add( this._unlinkButton = new Button( unlinkButtonModel, formView.unlinkButtonView ) );
+		const form = new LinkForm( formModel, new LinkFormView( editor.locale ) );
 
 		// Execute link command after clicking on balloon panel `Link` button.
-		this.listenTo( form.model, 'submit', () => {
-			editor.execute( 'link', this._urlInput.value );
+		this.listenTo( formModel, 'submit', () => {
+			editor.execute( 'link', this.form.urlInput.value );
 			this._hidePanel( true );
 		} );
 
 		// Execute unlink command after clicking on balloon panel `Unlink` button.
-		this.listenTo( unlinkButtonModel, 'execute', () => {
+		this.listenTo( formModel, 'unlink', () => {
 			editor.execute( 'unlink' );
 			this._hidePanel( true );
 		} );
 
 		// Hide balloon panel after clicking on balloon panel `Cancel` button.
-		this.listenTo( cancelButtonModel, 'execute', () => this._hidePanel( true ) );
+		this.listenTo( formModel, 'cancel', () => this._hidePanel( true ) );
 
 		this.balloonPanel.add( 'content', form );
 
@@ -322,7 +277,7 @@ export default class Link extends Feature {
 	 */
 	_showPanel() {
 		this._attachPanelToElement();
-		this._urlInput.view.select();
+		this.form.urlInput.view.select();
 	}
 }
 

+ 94 - 2
packages/ckeditor5-link/src/ui/linkform.js

@@ -3,8 +3,13 @@
  * For licensing, see LICENSE.md.
  */
 
+import Model from '../../ui/model.js';
 import Controller from '../../ui/controller.js';
 
+import Button from '../../ui/button/button.js';
+import LabeledInput from '../../ui/labeledinput/labeledinput.js';
+import InputText from '../../ui/inputtext/inputtext.js';
+
 /**
  * The link form class.
  *
@@ -13,7 +18,7 @@ import Controller from '../../ui/controller.js';
  * See {@link link.ui.LinkFormView}.
  *
  * @memberOf link.ui
- * @extends ui.form.Form
+ * @extends ui.Controller
  */
 export default class LinkForm extends Controller {
 	/**
@@ -25,7 +30,74 @@ export default class LinkForm extends Controller {
 	constructor( model, view ) {
 		super( model, view );
 
+		const t = this.view.t;
+		const urlInputModel = new Model( {
+			label: t( 'Link URL' )
+		} );
+
+		// Bind LabeledInputModel#value to LinkFormModel#url.
+		urlInputModel.bind( 'value' ).to( model, 'url' );
+
+		/**
+		 * The URL input inside {@link link.ui.LinkForm}.
+		 *
+		 * @member {ui.input.labeled.LabeledInput} link.ui.LinkForm#urlInput
+		 */
+		this.urlInput = new LabeledInput( urlInputModel, view.urlInputView, InputText, new Model() );
+
+		/**
+		 * The save button inside {@link link.ui.LinkForm}.
+		 *
+		 * @member {ui.button.Button} link.ui.LinkForm#saveButton
+		 */
+		this.saveButton = new Button( new Model( {
+			isEnabled: true,
+			isOn: false,
+			label: t( 'Save' ),
+			withText: true,
+			type: 'submit'
+		} ), view.saveButtonView );
+
+		/**
+		 * The cancel button inside {@link link.ui.LinkForm}.
+		 *
+		 * @member {ui.button.Button} link.ui.LinkForm#cancelButton
+		 */
+		this.cancelButton = new Button( new Model( {
+			isEnabled: true,
+			isOn: false,
+			label: t( 'Cancel' ),
+			withText: true
+		} ), view.cancelButtonView );
+
+		/**
+		 * The unlink button inside {@link link.ui.LinkForm}.
+		 *
+		 * @member {ui.button.Button} link.ui.LinkForm#unlinkButton
+		 */
+		this.unlinkButton = new Button( new Model( {
+			isEnabled: true,
+			isOn: false,
+			label: t( 'Unlink' ),
+			icon: 'unlink'
+		} ), view.unlinkButtonView );
+
 		view.delegate( 'submit' ).to( model );
+
+		// TODO: Delegate event with changed name.
+		this.listenTo( this.cancelButton.model, 'execute', () => {
+			this.model.fire( 'cancel' );
+		} );
+
+		this.listenTo( this.unlinkButton.model, 'execute', () => {
+			this.model.fire( 'unlink' );
+		} );
+
+		// TODO: add() should accept multiple items.
+		this.add( this.urlInput );
+		this.add( this.saveButton );
+		this.add( this.cancelButton );
+		this.add( this.unlinkButton );
 	}
 }
 
@@ -36,7 +108,27 @@ export default class LinkForm extends Controller {
  */
 
 /**
- * Fired when the view is submitted by the user.
+ * The url value as in {@link link.ui.LinkForm#urlInput}.
+ *
+ * @observable
+ * @member {String} link.ui.LinkFormModel#url
+ */
+
+/**
+ * Fired when the view is submitted by the user, i.e. when
+ * the {@link link.ui.LinkForm#saveButton} has been executed.
  *
  * @event link.ui.LinkFormModel#submit
  */
+
+/**
+ * Fired when the {@link link.ui.LinkForm#cancelButton} has been executed.
+ *
+ * @event link.ui.LinkFormModel#cancel
+ */
+
+/**
+ * Fired when the {@link link.ui.LinkForm#unlinkButton} has been executed.
+ *
+ * @event link.ui.LinkFormModel#unlink
+ */

+ 1 - 1
packages/ckeditor5-link/src/ui/linkformview.js

@@ -18,7 +18,7 @@ import submitHandler from '../../ui/bindings/submithandler.js';
  * See {@link link.ui.LinkForm}.
  *
  * @memberOf link.ui
- * @extends ui.form.FormView
+ * @extends ui.View
  */
 export default class LinkFormView extends View {
 	/**

+ 15 - 16
packages/ckeditor5-link/tests/link.js

@@ -110,7 +110,7 @@ describe( 'Link', () => {
 		} );
 
 		it( 'should select panel input value when panel is opened', () => {
-			const selectUrlInputSpy = testUtils.sinon.spy( linkFeature._urlInput.view, 'select' );
+			const selectUrlInputSpy = testUtils.sinon.spy( linkFeature.form.urlInput.view, 'select' );
 
 			editor.editing.view.isFocused = true;
 
@@ -163,7 +163,7 @@ describe( 'Link', () => {
 		} );
 
 		it( 'should open with selected url input on `CTRL+K` keystroke', () => {
-			const selectUrlInputSpy = testUtils.sinon.spy( linkFeature._urlInput.view, 'select' );
+			const selectUrlInputSpy = testUtils.sinon.spy( linkFeature.form.urlInput.view, 'select' );
 
 			editor.keystrokes.press( { keyCode: keyCodes.k, ctrlKey: true } );
 
@@ -211,7 +211,7 @@ describe( 'Link', () => {
 
 		describe( 'click on editable', () => {
 			it( 'should open with not selected url input when collapsed selection is inside link element', () => {
-				const selectUrlInputSpy = testUtils.sinon.spy( linkFeature._urlInput.view, 'select' );
+				const selectUrlInputSpy = testUtils.sinon.spy( linkFeature.form.urlInput.view, 'select' );
 				const observer = editor.editing.view.getObserver( ClickObserver );
 
 				editor.document.schema.allow( { name: '$text', inside: '$root' } );
@@ -357,52 +357,51 @@ describe( 'Link', () => {
 		} );
 
 		describe( 'binding', () => {
-			it( 'should bind _urlInput#model to link command', () => {
-				const model = linkFeature._urlInput.model;
+			it( 'should bind form.model#url to link command value', () => {
+				const model = linkFeature.form.model;
 				const command = editor.commands.get( 'link' );
 
 				expect( model.value ).to.undefined;
 
 				command.value = 'http://cksource.com';
-
-				expect( model.value ).to.equal( 'http://cksource.com' );
+				expect( model.url ).to.equal( 'http://cksource.com' );
 			} );
 
-			it( 'should execute link command on _saveButton#model submit event', () => {
+			it( 'should execute link command on form.model#submit event', () => {
 				const executeSpy = testUtils.sinon.spy( editor, 'execute' );
 
-				linkFeature._urlInput.model.value = 'http://cksource.com';
+				form.model.url = 'http://cksource.com';
 				form.model.fire( 'submit' );
 
 				expect( executeSpy.calledOnce ).to.true;
 				expect( executeSpy.calledWithExactly( 'link', 'http://cksource.com' ) ).to.true;
 			} );
 
-			it( 'should hide and focus editable on form#model submit event', () => {
+			it( 'should hide and focus editable on form.model#submit event', () => {
 				form.model.fire( 'submit' );
 
 				expect( hidePanelSpy.calledOnce ).to.true;
 				expect( focusEditableSpy.calledOnce ).to.true;
 			} );
 
-			it( 'should execute unlink command on _unlinkButton#model execute event', () => {
+			it( 'should execute unlink command on form.model#unlink event', () => {
 				const executeSpy = testUtils.sinon.spy( editor, 'execute' );
 
-				linkFeature._unlinkButton.model.fire( 'execute' );
+				form.model.fire( 'unlink' );
 
 				expect( executeSpy.calledOnce ).to.true;
 				expect( executeSpy.calledWithExactly( 'unlink' ) ).to.true;
 			} );
 
-			it( 'should hide and focus editable on _unlinkButton#model execute event', () => {
-				linkFeature._unlinkButton.model.fire( 'execute' );
+			it( 'should hide and focus editable on form.model#unlink event', () => {
+				form.model.fire( 'unlink' );
 
 				expect( hidePanelSpy.calledOnce ).to.true;
 				expect( focusEditableSpy.calledOnce ).to.true;
 			} );
 
-			it( 'should hide and focus editable on _cancelButton#model cancel event', () => {
-				linkFeature._cancelButton.model.fire( 'execute' );
+			it( 'should hide and focus editable on form.model#cancel event', () => {
+				form.model.fire( 'cancel' );
 
 				expect( hidePanelSpy.calledOnce ).to.true;
 				expect( focusEditableSpy.calledOnce ).to.true;

+ 83 - 2
packages/ckeditor5-link/tests/ui/linkform.js

@@ -9,12 +9,19 @@ import LinkForm from '/ckeditor5/link/ui/linkform.js';
 import LinkFormView from '/ckeditor5/link/ui/linkformview.js';
 import Model from '/ckeditor5/ui/model.js';
 
+import Button from '/ckeditor5/ui/button/button.js';
+import LabeledInput from '/ckeditor5/ui/labeledinput/labeledinput.js';
+
 describe( 'LinkForm', () => {
 	let linkForm, view, model;
 
 	beforeEach( () => {
-		view = new LinkFormView();
-		model = new Model();
+		view = new LinkFormView( {
+			t: () => {}
+		} );
+		model = new Model( {
+			url: 'foo'
+		} );
 		linkForm = new LinkForm( model, view );
 	} );
 
@@ -28,4 +35,78 @@ describe( 'LinkForm', () => {
 			expect( spy.calledOnce ).to.be.true;
 		} );
 	} );
+
+	describe( 'child components', () => {
+		describe( 'urlInput', () => {
+			it( 'is created', () => {
+				expect( linkForm.urlInput ).to.be.instanceOf( LabeledInput );
+			} );
+
+			it( 'belongs to anonymous collection', () => {
+				expect( linkForm.collections.get( '_anonymous' ).find( ( item ) => {
+					return item === linkForm.urlInput;
+				} ) ).to.be.not.undefined;
+			} );
+
+			it( 'binds urlInput.model#value to linkForm.model#url', () => {
+				expect( linkForm.urlInput.model.value ).to.equal( 'foo' );
+
+				model.url = 'bar';
+
+				expect( linkForm.urlInput.model.value ).to.equal( 'bar' );
+			} );
+		} );
+
+		describe( 'saveButton', () => {
+			it( 'is created', () => {
+				expect( linkForm.saveButton ).to.be.instanceOf( Button );
+			} );
+
+			it( 'belongs to anonymous collection', () => {
+				expect( linkForm.collections.get( '_anonymous' ).find( ( item ) => {
+					return item === linkForm.saveButton;
+				} ) ).to.be.not.undefined;
+			} );
+		} );
+
+		describe( 'cancelButton', () => {
+			it( 'is created', () => {
+				expect( linkForm.cancelButton ).to.be.instanceOf( Button );
+			} );
+
+			it( 'belongs to anonymous collection', () => {
+				expect( linkForm.collections.get( '_anonymous' ).find( ( item ) => {
+					return item === linkForm.cancelButton;
+				} ) ).to.be.not.undefined;
+			} );
+
+			it( 'passes cancelButton.model#execute as linkForm.model#cancel', ( done ) => {
+				model.on( 'cancel', () => {
+					done();
+				} );
+
+				linkForm.cancelButton.model.fire( 'execute' );
+			} );
+		} );
+
+		describe( 'unlinkButton', () => {
+			it( 'is created', () => {
+				expect( linkForm.unlinkButton ).to.be.instanceOf( Button );
+			} );
+
+			it( 'belongs to anonymous collection', () => {
+				expect( linkForm.collections.get( '_anonymous' ).find( ( item ) => {
+					return item === linkForm.unlinkButton;
+				} ) ).to.be.not.undefined;
+			} );
+
+			it( 'passes unlinkButton.model#execute as linkForm.model#unlink', ( done ) => {
+				model.on( 'unlink', () => {
+					done();
+				} );
+
+				linkForm.unlinkButton.model.fire( 'execute' );
+			} );
+		} );
+	} );
 } );