Jelajahi Sumber

Refactored link feature after UI architecture refactoring.

Oskar Wrobel 9 tahun lalu
induk
melakukan
1937ba4c94
2 mengubah file dengan 127 tambahan dan 142 penghapusan
  1. 62 74
      packages/ckeditor5-link/src/link.js
  2. 65 68
      packages/ckeditor5-link/tests/link.js

+ 62 - 74
packages/ckeditor5-link/src/link.js

@@ -8,17 +8,12 @@ import ClickObserver from '../engine/view/observer/clickobserver.js';
 import LinkEngine from './linkengine.js';
 import LinkElement from './linkelement.js';
 
-import Model from '../ui/model.js';
 import clickOutsideHandler from '../ui/bindings/clickoutsidehandler.js';
 import escPressHandler from '../ui/bindings/escpresshandler.js';
 
-import Button from '../ui/button/button.js';
 import ButtonView from '../ui/button/buttonview.js';
-
-import BalloonPanel from '../ui/balloonpanel/balloonpanel.js';
 import BalloonPanelView from '../ui/balloonpanel/balloonpanelview.js';
 
-import LinkForm from './ui/linkform.js';
 import LinkFormView from './ui/linkformview.js';
 
 /**
@@ -44,18 +39,18 @@ export default class Link extends Feature {
 		this.editor.editing.view.addObserver( ClickObserver );
 
 		/**
-		 * Balloon panel component to display the main UI.
+		 * Balloon panel view to display the main UI.
 		 *
-		 * @member {link.ui.LinkBalloonPanel} link.Link#balloonPanel
+		 * @member {link.ui.LinkBalloonPanelView} link.Link#balloonPanelView
 		 */
-		this.balloonPanel = this._createBalloonPanel();
+		this.balloonPanelView = this._createBalloonPanel();
 
 		/**
-		 * The form component inside {@link link.Link#balloonPanel}.
+		 * The form view inside {@link link.Link#balloonPanelView}.
 		 *
-		 * @member {link.ui.LinkForm} link.Link#form
+		 * @member {link.ui.LinkFormView} link.Link#formView
 		 */
-		this.form = this._createForm();
+		this.formView = this._createForm();
 
 		// Create toolbar buttons.
 		this._createToolbarLinkButton();
@@ -73,26 +68,26 @@ export default class Link extends Feature {
 		const linkCommand = editor.commands.get( 'link' );
 		const t = editor.t;
 
-		// Create button model.
-		const linkButtonModel = new Model( {
-			isEnabled: true,
-			isOn: false,
-			label: t( 'Link' ),
-			icon: 'link',
-			keystroke: 'CTRL+K'
-		} );
+		// Handle `Ctrl+K` keystroke and show panel.
+		editor.keystrokes.set( 'CTRL+K', () => this._showPanel() );
+
+		// Add link button to feature components.
+		editor.ui.featureComponents.add( 'link', ( locale ) => {
+			const button = new ButtonView( locale );
 
-		// Bind button model to the command.
-		linkButtonModel.bind( 'isEnabled' ).to( linkCommand, 'isEnabled' );
+			button.isEnabled = true;
+			button.label = t( 'Link' );
+			button.icon = 'link';
+			button.keystroke = 'CTRL+K';
 
-		// Show the panel on button click only when editor is focused.
-		this.listenTo( linkButtonModel, 'execute', () => this._showPanel() );
+			// Bind button to the command.
+			button.bind( 'isEnabled' ).to( linkCommand, 'isEnabled' );
 
-		// Add link button to feature components.
-		editor.ui.featureComponents.add( 'link', Button, ButtonView, linkButtonModel );
+			// Show the panel on button click.
+			this.listenTo( button, 'execute', () => this._showPanel() );
 
-		// Handle `Ctrl+K` keystroke and show panel.
-		editor.keystrokes.set( 'CTRL+K', () => this._showPanel() );
+			return button;
+		} );
 	}
 
 	/**
@@ -106,24 +101,22 @@ export default class Link extends Feature {
 		const t = editor.t;
 		const unlinkCommand = editor.commands.get( 'unlink' );
 
-		// Create the button model.
-		const unlinkButtonModel = new Model( {
-			isEnabled: false,
-			isOn: false,
-			label: t( 'Unlink' ),
-			icon: 'unlink'
-		} );
+		// Add unlink button to feature components.
+		editor.ui.featureComponents.add( 'unlink', ( locale ) => {
+			const button = new ButtonView( locale );
 
-		// Bind button model to the command.
-		unlinkButtonModel.bind( 'isEnabled' ).to( unlinkCommand, 'isEnabled' );
+			button.isEnabled = false;
+			button.label = t( 'Unlink' );
+			button.icon = 'unlink';
 
-		// Execute unlink command and hide panel, if open.
-		this.listenTo( unlinkButtonModel, 'execute', () => {
-			editor.execute( 'unlink' );
-		} );
+			// Bind button to the command.
+			button.bind( 'isEnabled' ).to( unlinkCommand, 'isEnabled' );
 
-		// Add unlink button to feature components.
-		editor.ui.featureComponents.add( 'unlink', Button, ButtonView, unlinkButtonModel );
+			// Execute unlink command and hide panel, if open on button click.
+			this.listenTo( button, 'execute', () => editor.execute( 'unlink' ) );
+
+			return button;
+		} );
 	}
 
 	/**
@@ -137,16 +130,13 @@ export default class Link extends Feature {
 		const viewDocument = editor.editing.view;
 
 		// Create the balloon panel instance.
-		const balloonPanel = new BalloonPanel(
-			new Model( {
-				maxWidth: 300
-			} ),
-			new BalloonPanelView( editor.locale )
-		);
+		const balloonPanelView = new BalloonPanelView( editor.locale );
+
+		balloonPanelView.maxWidth = 300;
 
 		// Add balloonPanel.view#element to FocusTracker.
 		// @TODO: Do it automatically ckeditor5-core#23
-		editor.focusTracker.add( balloonPanel.view.element );
+		editor.focusTracker.add( balloonPanelView.element );
 
 		// Handle click on view document and show panel when selection is placed inside the link element.
 		// Keep panel open until selection will be inside the same link element.
@@ -167,30 +157,30 @@ export default class Link extends Feature {
 					}
 				} );
 
-				this.listenTo( balloonPanel.view, 'change:isVisible', () => this.stopListening( viewDocument, 'render' ) );
+				this.listenTo( balloonPanelView, 'change:isVisible', () => this.stopListening( viewDocument, 'render' ) );
 			}
 		} );
 
 		// Close on `ESC` press.
 		escPressHandler( {
-			controller: balloonPanel.view,
-			model: balloonPanel.view,
+			controller: balloonPanelView,
+			model: balloonPanelView,
 			activeIf: 'isVisible',
 			callback: () => this._hidePanel( true )
 		} );
 
 		// Close on click outside of balloon panel element.
 		clickOutsideHandler( {
-			controller: balloonPanel.view,
-			model: balloonPanel.view,
+			controller: balloonPanelView,
+			model: balloonPanelView,
 			activeIf: 'isVisible',
-			contextElement: balloonPanel.view.element,
+			contextElement: balloonPanelView.element,
 			callback: () => this._hidePanel()
 		} );
 
-		editor.ui.add( 'body', balloonPanel );
+		editor.ui.body.add( balloonPanelView );
 
-		return balloonPanel;
+		return balloonPanelView;
 	}
 
 	/**
@@ -201,30 +191,28 @@ export default class Link extends Feature {
 	 */
 	_createForm() {
 		const editor = this.editor;
-		const formModel = new Model();
-
-		formModel.bind( 'url' ).to( editor.commands.get( 'link' ), 'value' );
+		const formView = new LinkFormView( editor.locale );
 
-		const form = new LinkForm( formModel, new LinkFormView( editor.locale ) );
+		formView.urlInputView.bind( 'value' ).to( editor.commands.get( 'link' ), 'value' );
 
-		// Execute link command after clicking on balloon panel `Link` button.
-		this.listenTo( formModel, 'submit', () => {
-			editor.execute( 'link', this.form.urlInput.value );
+		// Execute link command after clicking on formView `Save` button.
+		this.listenTo( formView, 'submit', () => {
+			editor.execute( 'link', formView.urlInputView.value );
 			this._hidePanel( true );
 		} );
 
-		// Execute unlink command after clicking on balloon panel `Unlink` button.
-		this.listenTo( formModel, 'unlink', () => {
+		// Execute unlink command after clicking on formView `Unlink` button.
+		this.listenTo( formView, 'unlink', () => {
 			editor.execute( 'unlink' );
 			this._hidePanel( true );
 		} );
 
-		// Hide balloon panel after clicking on balloon panel `Cancel` button.
-		this.listenTo( formModel, 'cancel', () => this._hidePanel( true ) );
+		// Hide balloon panel after clicking on formView `Cancel` button.
+		this.listenTo( formView, 'cancel', () => this._hidePanel( true ) );
 
-		this.balloonPanel.add( 'content', form );
+		this.balloonPanelView.content.add( formView );
 
-		return form;
+		return formView;
 	}
 
 	/**
@@ -242,14 +230,14 @@ export default class Link extends Feature {
 
 		// When selection is inside link element, then attach panel to this element.
 		if ( targetLink ) {
-			this.balloonPanel.view.attachTo(
+			this.balloonPanelView.attachTo(
 				viewDocument.domConverter.getCorrespondingDomElement( targetLink ),
 				domEditableElement
 			);
 		}
 		// Otherwise attach panel to the selection.
 		else {
-			this.balloonPanel.view.attachTo(
+			this.balloonPanelView.attachTo(
 				viewDocument.domConverter.viewRangeToDom( viewDocument.selection.getFirstRange() ),
 				domEditableElement
 			);
@@ -263,7 +251,7 @@ export default class Link extends Feature {
 	 * @param {Boolean} [focusEditable=false] When `true` then editable focus will be restored on panel hide.
 	 */
 	_hidePanel( focusEditable ) {
-		this.balloonPanel.view.hide();
+		this.balloonPanelView.hide();
 
 		if ( focusEditable ) {
 			this.editor.editing.view.focus();
@@ -277,7 +265,7 @@ export default class Link extends Feature {
 	 */
 	_showPanel() {
 		this._attachPanelToElement();
-		this.form.urlInput.view.select();
+		this.formView.urlInputView.select();
 	}
 }
 

+ 65 - 68
packages/ckeditor5-link/tests/link.js

@@ -12,8 +12,8 @@ import { setData as setModelData } from 'ckeditor5/engine/dev-utils/model.js';
 
 import Link from 'ckeditor5/link/link.js';
 import LinkEngine from 'ckeditor5/link/linkengine.js';
-import Button from 'ckeditor5/ui/button/button.js';
-import BalloonPanel from 'ckeditor5/ui/balloonpanel/balloonpanel.js';
+import ButtonView from 'ckeditor5/ui/button/buttonview.js';
+import BalloonPanelView from 'ckeditor5/ui/balloonpanel/balloonpanelview.js';
 
 import Range from 'ckeditor5/engine/view/range.js';
 import ClickObserver from 'ckeditor5/engine/view/observer/clickobserver.js';
@@ -21,7 +21,7 @@ import ClickObserver from 'ckeditor5/engine/view/observer/clickobserver.js';
 testUtils.createSinonSandbox();
 
 describe( 'Link', () => {
-	let editor, linkFeature, linkButton, unlinkButton, balloonPanel, form, editorElement;
+	let editor, linkFeature, linkButton, unlinkButton, balloonPanelView, formView, editorElement;
 
 	beforeEach( () => {
 		editorElement = document.createElement( 'div' );
@@ -38,8 +38,8 @@ describe( 'Link', () => {
 			linkFeature = editor.plugins.get( Link );
 			linkButton = editor.ui.featureComponents.create( 'link' );
 			unlinkButton = editor.ui.featureComponents.create( 'unlink' );
-			balloonPanel = linkFeature.balloonPanel;
-			form = linkFeature.form;
+			balloonPanelView = linkFeature.balloonPanelView;
+			formView = linkFeature.formView;
 		} );
 	} );
 
@@ -61,34 +61,33 @@ describe( 'Link', () => {
 
 	describe( 'link toolbar button', () => {
 		it( 'should register link feature component', () => {
-			expect( linkButton ).to.instanceOf( Button );
+			expect( linkButton ).to.instanceOf( ButtonView );
 		} );
 
-		it( 'should bind linkButton#model to link command', () => {
-			const model = linkButton.model;
+		it( 'should bind linkButtonView to link command', () => {
 			const command = editor.commands.get( 'link' );
 
 			command.isEnabled = true;
-			expect( model.isEnabled ).to.be.true;
+			expect( linkButton.isEnabled ).to.be.true;
 
 			command.isEnabled = false;
-			expect( model.isEnabled ).to.be.false;
+			expect( linkButton.isEnabled ).to.be.false;
 		} );
 
-		it( 'should open panel on linkButton#model execute event', () => {
-			linkButton.model.fire( 'execute' );
+		it( 'should open panel on linkButtonView execute event', () => {
+			linkButton.fire( 'execute' );
 
-			expect( linkFeature.balloonPanel.view.isVisible ).to.true;
+			expect( linkFeature.balloonPanelView.isVisible ).to.true;
 		} );
 
 		it( 'should open panel attached to the link element, when collapsed selection is inside link element', () => {
-			const attachToSpy = testUtils.sinon.spy( balloonPanel.view, 'attachTo' );
+			const attachToSpy = testUtils.sinon.spy( balloonPanelView, 'attachTo' );
 
 			editor.document.schema.allow( { name: '$text', inside: '$root' } );
 			setModelData( editor.document, '<$text linkHref="url">some[] url</$text>' );
 			editor.editing.view.isFocused = true;
 
-			linkButton.model.fire( 'execute' );
+			linkButton.fire( 'execute' );
 
 			const linkElement = editorElement.querySelector( 'a' );
 
@@ -96,13 +95,13 @@ describe( 'Link', () => {
 		} );
 
 		it( 'should open panel attached to the selection, when there is non-collapsed selection', () => {
-			const attachToSpy = testUtils.sinon.spy( balloonPanel.view, 'attachTo' );
+			const attachToSpy = testUtils.sinon.spy( balloonPanelView, 'attachTo' );
 
 			editor.document.schema.allow( { name: '$text', inside: '$root' } );
 			setModelData( editor.document, 'so[me ur]l' );
 			editor.editing.view.isFocused = true;
 
-			linkButton.model.fire( 'execute' );
+			linkButton.fire( 'execute' );
 
 			const selectedRange = editorElement.ownerDocument.getSelection().getRangeAt( 0 );
 
@@ -110,11 +109,11 @@ describe( 'Link', () => {
 		} );
 
 		it( 'should select panel input value when panel is opened', () => {
-			const selectUrlInputSpy = testUtils.sinon.spy( linkFeature.form.urlInput.view, 'select' );
+			const selectUrlInputSpy = testUtils.sinon.spy( linkFeature.formView.urlInputView, 'select' );
 
 			editor.editing.view.isFocused = true;
 
-			linkButton.model.fire( 'execute' );
+			linkButton.fire( 'execute' );
 
 			expect( selectUrlInputSpy.calledOnce ).to.true;
 		} );
@@ -122,24 +121,23 @@ describe( 'Link', () => {
 
 	describe( 'unlink toolbar button', () => {
 		it( 'should register unlink feature component', () => {
-			expect( unlinkButton ).to.instanceOf( Button );
+			expect( unlinkButton ).to.instanceOf( ButtonView );
 		} );
 
-		it( 'should bind unlinkButton#model to unlink command', () => {
-			const model = unlinkButton.model;
+		it( 'should bind unlinkButtonView to unlink command', () => {
 			const command = editor.commands.get( 'unlink' );
 
 			command.isEnabled = true;
-			expect( model.isEnabled ).to.be.true;
+			expect( unlinkButton.isEnabled ).to.be.true;
 
 			command.isEnabled = false;
-			expect( model.isEnabled ).to.be.false;
+			expect( unlinkButton.isEnabled ).to.be.false;
 		} );
 
-		it( 'should execute unlink command on unlinkButton#model execute event', () => {
+		it( 'should execute unlink command on unlinkButtonView execute event', () => {
 			const executeSpy = testUtils.sinon.spy( editor, 'execute' );
 
-			unlinkButton.model.fire( 'execute' );
+			unlinkButton.fire( 'execute' );
 
 			expect( executeSpy.calledOnce ).to.true;
 			expect( executeSpy.calledWithExactly( 'unlink' ) ).to.true;
@@ -150,31 +148,31 @@ describe( 'Link', () => {
 		let hidePanelSpy, focusEditableSpy;
 
 		beforeEach( () => {
-			hidePanelSpy = testUtils.sinon.spy( balloonPanel.view, 'hide' );
+			hidePanelSpy = testUtils.sinon.spy( balloonPanelView, 'hide' );
 			focusEditableSpy = testUtils.sinon.spy( editor.editing.view, 'focus' );
 		} );
 
 		it( 'should be created', () => {
-			expect( balloonPanel ).to.instanceOf( BalloonPanel );
+			expect( balloonPanelView ).to.instanceOf( BalloonPanelView );
 		} );
 
 		it( 'should be appended to the document body', () => {
-			expect( document.body.contains( balloonPanel.view.element ) );
+			expect( document.body.contains( balloonPanelView.element ) );
 		} );
 
 		it( 'should open with selected url input on `CTRL+K` keystroke', () => {
-			const selectUrlInputSpy = testUtils.sinon.spy( linkFeature.form.urlInput.view, 'select' );
+			const selectUrlInputSpy = testUtils.sinon.spy( linkFeature.formView.urlInputView, 'select' );
 
 			editor.keystrokes.press( { keyCode: keyCodes.k, ctrlKey: true } );
 
-			expect( balloonPanel.view.isVisible ).to.true;
+			expect( balloonPanelView.isVisible ).to.true;
 			expect( selectUrlInputSpy.calledOnce ).to.true;
 		} );
 
 		it( 'should add balloon panel element to focus tracker', () => {
 			editor.focusTracker.isFocused = false;
 
-			balloonPanel.view.element.dispatchEvent( new Event( 'focus' ) );
+			balloonPanelView.element.dispatchEvent( new Event( 'focus' ) );
 
 			expect( editor.focusTracker.isFocused ).to.true;
 		} );
@@ -182,7 +180,7 @@ describe( 'Link', () => {
 		describe( 'close listeners', () => {
 			describe( 'keyboard', () => {
 				it( 'should close after `ESC` press', () => {
-					balloonPanel.view.isVisible = true;
+					balloonPanelView.isVisible = true;
 
 					dispatchKeyboardEvent( document, 'keydown', keyCodes.esc );
 
@@ -193,7 +191,7 @@ describe( 'Link', () => {
 
 			describe( 'mouse', () => {
 				it( 'should close and not focus editable on click outside the panel', () => {
-					balloonPanel.view.isVisible = true;
+					balloonPanelView.isVisible = true;
 					document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
 
 					expect( hidePanelSpy.calledOnce ).to.true;
@@ -201,8 +199,8 @@ describe( 'Link', () => {
 				} );
 
 				it( 'should not close on click inside the panel', () => {
-					balloonPanel.view.isVisible = true;
-					balloonPanel.view.element.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
+					balloonPanelView.isVisible = true;
+					balloonPanelView.element.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
 
 					expect( hidePanelSpy.notCalled ).to.true;
 				} );
@@ -211,7 +209,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.form.urlInput.view, 'select' );
+				const selectUrlInputSpy = testUtils.sinon.spy( linkFeature.formView.urlInputView, 'select' );
 				const observer = editor.editing.view.getObserver( ClickObserver );
 
 				editor.document.schema.allow( { name: '$text', inside: '$root' } );
@@ -219,7 +217,7 @@ describe( 'Link', () => {
 
 				observer.fire( 'click', { target: document.body } );
 
-				expect( balloonPanel.view.isVisible ).to.true;
+				expect( balloonPanelView.isVisible ).to.true;
 				expect( selectUrlInputSpy.notCalled ).to.true;
 			} );
 
@@ -234,14 +232,14 @@ describe( 'Link', () => {
 
 				observer.fire( 'click', { target: document.body } );
 
-				expect( balloonPanel.view.isVisible ).to.true;
+				expect( balloonPanelView.isVisible ).to.true;
 
-				const attachToSpy = testUtils.sinon.spy( balloonPanel.view, 'attachTo' );
+				const attachToSpy = testUtils.sinon.spy( balloonPanelView, 'attachTo' );
 
 				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 1 ) ], true );
 				editor.editing.view.render();
 
-				expect( balloonPanel.view.isVisible ).to.true;
+				expect( balloonPanelView.isVisible ).to.true;
 				expect( attachToSpy.calledOnce ).to.true;
 			} );
 
@@ -256,12 +254,12 @@ describe( 'Link', () => {
 
 				observer.fire( 'click', { target: document.body } );
 
-				expect( balloonPanel.view.isVisible ).to.true;
+				expect( balloonPanelView.isVisible ).to.true;
 
 				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 3, text, 3 ) ], true );
 				editor.editing.view.render();
 
-				expect( balloonPanel.view.isVisible ).to.false;
+				expect( balloonPanelView.isVisible ).to.false;
 			} );
 
 			it( 'should close when selection goes to the other link element with the same href', () => {
@@ -275,12 +273,12 @@ describe( 'Link', () => {
 
 				observer.fire( 'click', { target: document.body } );
 
-				expect( balloonPanel.view.isVisible ).to.true;
+				expect( balloonPanelView.isVisible ).to.true;
 
 				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 1 ) ], true );
 				editor.editing.view.render();
 
-				expect( balloonPanel.view.isVisible ).to.false;
+				expect( balloonPanelView.isVisible ).to.false;
 			} );
 
 			it( 'should close when selection becomes non-collapsed', () => {
@@ -294,12 +292,12 @@ describe( 'Link', () => {
 
 				observer.fire( 'click', { target: {} } );
 
-				expect( balloonPanel.view.isVisible ).to.true;
+				expect( balloonPanelView.isVisible ).to.true;
 
 				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 2 ) ] );
 				editor.editing.view.render();
 
-				expect( balloonPanel.view.isVisible ).to.false;
+				expect( balloonPanelView.isVisible ).to.false;
 			} );
 
 			it( 'should stop updating position after close', () => {
@@ -313,11 +311,11 @@ describe( 'Link', () => {
 
 				observer.fire( 'click', { target: {} } );
 
-				expect( balloonPanel.view.isVisible ).to.true;
+				expect( balloonPanelView.isVisible ).to.true;
 
-				balloonPanel.view.isVisible = false;
+				balloonPanelView.isVisible = false;
 
-				const attachToSpy = testUtils.sinon.spy( balloonPanel.view, 'attachTo' );
+				const attachToSpy = testUtils.sinon.spy( balloonPanelView, 'attachTo' );
 
 				editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 2, text, 2 ) ], true );
 				editor.editing.view.render();
@@ -332,7 +330,7 @@ describe( 'Link', () => {
 
 				observer.fire( 'click', { target: {} } );
 
-				expect( balloonPanel.view.isVisible ).to.false;
+				expect( balloonPanelView.isVisible ).to.false;
 			} );
 
 			it( 'should not open when selection is non-collapsed', () => {
@@ -343,7 +341,7 @@ describe( 'Link', () => {
 
 				observer.fire( 'click', { target: document.body } );
 
-				expect( balloonPanel.view.isVisible ).to.false;
+				expect( balloonPanelView.isVisible ).to.false;
 			} );
 		} );
 	} );
@@ -352,56 +350,55 @@ describe( 'Link', () => {
 		let hidePanelSpy, focusEditableSpy;
 
 		beforeEach( () => {
-			hidePanelSpy = testUtils.sinon.spy( balloonPanel.view, 'hide' );
+			hidePanelSpy = testUtils.sinon.spy( balloonPanelView, 'hide' );
 			focusEditableSpy = testUtils.sinon.spy( editor.editing.view, 'focus' );
 		} );
 
 		describe( 'binding', () => {
-			it( 'should bind form.model#url to link command value', () => {
-				const model = linkFeature.form.model;
+			it( 'should bind formView.urlInputView#value to link command value', () => {
 				const command = editor.commands.get( 'link' );
 
-				expect( model.value ).to.undefined;
+				expect( formView.urlInputView.value ).to.undefined;
 
 				command.value = 'http://cksource.com';
-				expect( model.url ).to.equal( 'http://cksource.com' );
+				expect( formView.urlInputView.value ).to.equal( 'http://cksource.com' );
 			} );
 
-			it( 'should execute link command on form.model#submit event', () => {
+			it( 'should execute link command on formView#submit event', () => {
 				const executeSpy = testUtils.sinon.spy( editor, 'execute' );
 
-				form.model.url = 'http://cksource.com';
-				form.model.fire( 'submit' );
+				formView.urlInputView.value = 'http://cksource.com';
+				formView.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', () => {
-				form.model.fire( 'submit' );
+			it( 'should hide and focus editable on formView#submit event', () => {
+				formView.fire( 'submit' );
 
 				expect( hidePanelSpy.calledOnce ).to.true;
 				expect( focusEditableSpy.calledOnce ).to.true;
 			} );
 
-			it( 'should execute unlink command on form.model#unlink event', () => {
+			it( 'should execute unlink command on formView#unlink event', () => {
 				const executeSpy = testUtils.sinon.spy( editor, 'execute' );
 
-				form.model.fire( 'unlink' );
+				formView.fire( 'unlink' );
 
 				expect( executeSpy.calledOnce ).to.true;
 				expect( executeSpy.calledWithExactly( 'unlink' ) ).to.true;
 			} );
 
-			it( 'should hide and focus editable on form.model#unlink event', () => {
-				form.model.fire( 'unlink' );
+			it( 'should hide and focus editable on formView#unlink event', () => {
+				formView.fire( 'unlink' );
 
 				expect( hidePanelSpy.calledOnce ).to.true;
 				expect( focusEditableSpy.calledOnce ).to.true;
 			} );
 
-			it( 'should hide and focus editable on form.model#cancel event', () => {
-				form.model.fire( 'cancel' );
+			it( 'should hide and focus editable on formView#cancel event', () => {
+				formView.fire( 'cancel' );
 
 				expect( hidePanelSpy.calledOnce ).to.true;
 				expect( focusEditableSpy.calledOnce ).to.true;