Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge branch 'master' into t/97
Browse files Browse the repository at this point in the history
  • Loading branch information
scofalik committed Apr 14, 2017
2 parents 4465546 + c35c2ba commit 90c0506
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 71 deletions.
6 changes: 3 additions & 3 deletions src/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import ClickObserver from '@ckeditor/ckeditor5-engine/src/view/observer/clickobserver';
import LinkEngine from './linkengine';
import LinkElement from './linkelement';
import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/contextualballoon';
import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';

import clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';

Expand All @@ -27,7 +27,7 @@ import '../theme/theme.scss';
* The link plugin. It introduces the Link and Unlink buttons and the <kbd>Ctrl+K</kbd> keystroke.
*
* It uses the {@link module:link/linkengine~LinkEngine link engine plugin} and the
* {@link module:ui/contextualballoon~ContextualBalloon contextual balloon plugin}.
* {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.
*
* @extends module:core/plugin~Plugin
*/
Expand Down Expand Up @@ -63,7 +63,7 @@ export default class Link extends Plugin {
* The contextual balloon plugin instance.
*
* @private
* @member {module:ui/contextualballoon~ContextualBalloon}
* @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}
*/
this._balloon = this.editor.plugins.get( ContextualBalloon );

Expand Down
161 changes: 93 additions & 68 deletions tests/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-util

import Link from '../src/link';
import LinkEngine from '../src/linkengine';
import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/contextualballoon';
import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';

import Range from '@ckeditor/ckeditor5-engine/src/view/range';
Expand Down Expand Up @@ -41,8 +41,11 @@ describe( 'Link', () => {
balloon = editor.plugins.get( ContextualBalloon );
formView = linkFeature.formView;

// There is no point to execute `BalloonPanelView#attachTo` so override it.
// There is no point to execute BalloonPanelView attachTo and pin methods so lets override it.
testUtils.sinon.stub( balloon.view, 'attachTo', () => {} );
testUtils.sinon.stub( balloon.view, 'pin', () => {} );

return formView.init();
} );
} );

Expand Down Expand Up @@ -90,6 +93,8 @@ describe( 'Link', () => {
it( 'should add link form to the ContextualBalloon and attach balloon to the link element ' +
'when collapsed selection is inside link element',
() => {
const balloonAddSpy = testUtils.sinon.spy( balloon, 'add' );

editor.document.schema.allow( { name: '$text', inside: '$root' } );
setModelData( editor.document, '<$text linkHref="url">some[] url</$text>' );
editor.editing.view.isFocused = true;
Expand All @@ -98,13 +103,18 @@ describe( 'Link', () => {

const linkElement = editorElement.querySelector( 'a' );

sinon.assert.calledWithExactly( balloon.view.attachTo, sinon.match( {
target: linkElement,
limiter: editorElement
} ) );
sinon.assert.calledWithExactly( balloonAddSpy, {
view: formView,
position: {
target: linkElement,
limiter: editorElement
}
} );
} );

it( 'should add link form to the ContextualBalloon and attach balloon to the selection, when selection is non-collapsed', () => {
const balloonAddSpy = testUtils.sinon.spy( balloon, 'add' );

editor.document.schema.allow( { name: '$text', inside: '$root' } );
setModelData( editor.document, 'so[me ur]l' );
editor.editing.view.isFocused = true;
Expand All @@ -113,10 +123,13 @@ describe( 'Link', () => {

const selectedRange = editorElement.ownerDocument.getSelection().getRangeAt( 0 );

sinon.assert.calledWithExactly( balloon.view.attachTo, sinon.match( {
target: selectedRange,
limiter: editorElement
} ) );
sinon.assert.calledWithExactly( balloonAddSpy, {
view: formView,
position: {
target: selectedRange,
limiter: editorElement
}
} );
} );

it( 'should select link input value when link balloon is opened', () => {
Expand Down Expand Up @@ -203,21 +216,23 @@ describe( 'Link', () => {
sinon.assert.notCalled( spy );

// Balloon is visible, form focused.
balloon.add( { view: formView } );
formView.focusTracker.isFocused = true;
return balloon.add( { view: formView } )
.then( () => {
formView.focusTracker.isFocused = true;

editor.keystrokes.press( keyEvtData );
sinon.assert.notCalled( keyEvtData.preventDefault );
sinon.assert.notCalled( keyEvtData.stopPropagation );
sinon.assert.notCalled( spy );
editor.keystrokes.press( keyEvtData );
sinon.assert.notCalled( keyEvtData.preventDefault );
sinon.assert.notCalled( keyEvtData.stopPropagation );
sinon.assert.notCalled( spy );

// Balloon is still visible, form not focused.
formView.focusTracker.isFocused = false;
// Balloon is still visible, form not focused.
formView.focusTracker.isFocused = false;

editor.keystrokes.press( keyEvtData );
sinon.assert.calledOnce( keyEvtData.preventDefault );
sinon.assert.calledOnce( keyEvtData.stopPropagation );
sinon.assert.calledOnce( spy );
editor.keystrokes.press( keyEvtData );
sinon.assert.calledOnce( keyEvtData.preventDefault );
sinon.assert.calledOnce( keyEvtData.stopPropagation );
sinon.assert.calledOnce( spy );
} );
} );

describe( 'close listeners', () => {
Expand All @@ -230,12 +245,12 @@ describe( 'Link', () => {
};

// Balloon is visible.
balloon.add( { view: formView } );

editor.keystrokes.press( keyEvtData );
return balloon.add( { view: formView } ).then( () => {
editor.keystrokes.press( keyEvtData );

expect( balloon.visibleView ).to.null;
sinon.assert.notCalled( focusEditableSpy );
expect( balloon.visibleView ).to.null;
sinon.assert.notCalled( focusEditableSpy );
} );
} );

it( 'should not close after Esc key press (from editor) when panel is in stack but not visible', () => {
Expand All @@ -246,17 +261,21 @@ describe( 'Link', () => {
};

const viewMock = {
init: () => {},
destroy: () => {}
};

balloon.add( { view: formView } );
balloon.add( { view: viewMock } );

editor.keystrokes.press( keyEvtData );

expect( balloon.visibleView ).to.equal( viewMock );
expect( balloon.hasView( formView ) ).to.true;
sinon.assert.notCalled( focusEditableSpy );
return balloon.add( { view: formView } )
.then( () => {
return balloon.add( { view: viewMock } );
} )
.then( () => {
editor.keystrokes.press( keyEvtData );

expect( balloon.visibleView ).to.equal( viewMock );
expect( balloon.hasView( formView ) ).to.true;
sinon.assert.notCalled( focusEditableSpy );
} );
} );

it( 'should close after Esc key press (from the form) and focus editable', () => {
Expand All @@ -266,29 +285,34 @@ describe( 'Link', () => {
stopPropagation: sinon.spy()
};

balloon.add( { view: formView } );

formView.keystrokes.press( keyEvtData );
return balloon.add( { view: formView } )
.then( () => {
formView.keystrokes.press( keyEvtData );

expect( balloon.visibleView ).to.null;
sinon.assert.calledOnce( focusEditableSpy );
expect( balloon.visibleView ).to.null;
sinon.assert.calledOnce( focusEditableSpy );
} );
} );
} );

describe( 'mouse', () => {
it( 'should close and not focus editable on click outside the panel', () => {
balloon.add( { view: formView } );
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
return balloon.add( { view: formView } )
.then( () => {
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );

expect( balloon.visibleView ).to.null;
expect( focusEditableSpy.notCalled ).to.true;
expect( balloon.visibleView ).to.null;
expect( focusEditableSpy.notCalled ).to.true;
} );
} );

it( 'should not close on click inside the panel', () => {
balloon.add( { view: formView } );
balloon.view.element.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
return balloon.add( { view: formView } )
.then( () => {
balloon.view.element.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );

expect( balloon.visibleView ).to.equal( formView );
expect( balloon.visibleView ).to.equal( formView );
} );
} );
} );
} );
Expand Down Expand Up @@ -320,16 +344,15 @@ describe( 'Link', () => {

expect( balloon.visibleView ).to.equal( formView );

// Reset attachTo call counter.
balloon.view.attachTo.reset();
const updatePositionSpy = testUtils.sinon.spy( balloon, 'updatePosition' );

// Move selection.
editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 1, text, 1 ) ], true );
editor.editing.view.render();

// Check if balloon is still open and position was updated.
expect( balloon.visibleView ).to.equal( formView );
expect( balloon.view.attachTo.calledOnce ).to.true;
expect( updatePositionSpy.calledOnce ).to.true;
} );

it( 'should not duplicate `render` listener on `ViewDocument`', () => {
Expand Down Expand Up @@ -430,14 +453,13 @@ describe( 'Link', () => {
// Close balloon by dispatching `cancel` event on formView.
formView.fire( 'cancel' );

// Reset attachTo call counter.
balloon.view.attachTo.reset();
const updatePositionSpy = testUtils.sinon.spy( balloon, 'updatePosition' );

// Move selection inside link element.
editor.editing.view.selection.setRanges( [ Range.createFromParentsAndOffsets( text, 2, text, 2 ) ], true );
editor.editing.view.render();

expect( balloon.view.attachTo.notCalled ).to.true;
expect( updatePositionSpy.notCalled ).to.true;
} );

it( 'should not open when selection is not inside link element', () => {
Expand Down Expand Up @@ -494,12 +516,13 @@ describe( 'Link', () => {
} );

it( 'should hide and focus editable on formView#submit event', () => {
balloon.add( { view: formView } );

formView.fire( 'submit' );
return balloon.add( { view: formView } )
.then( () => {
formView.fire( 'submit' );

expect( balloon.visibleView ).to.null;
expect( focusEditableSpy.calledOnce ).to.true;
expect( balloon.visibleView ).to.null;
expect( focusEditableSpy.calledOnce ).to.true;
} );
} );

it( 'should execute unlink command on formView#unlink event', () => {
Expand All @@ -512,21 +535,23 @@ describe( 'Link', () => {
} );

it( 'should hide and focus editable on formView#unlink event', () => {
balloon.add( { view: formView } );

formView.fire( 'unlink' );
return balloon.add( { view: formView } )
.then( () => {
formView.fire( 'unlink' );

expect( balloon.visibleView ).to.null;
expect( focusEditableSpy.calledOnce ).to.true;
expect( balloon.visibleView ).to.null;
expect( focusEditableSpy.calledOnce ).to.true;
} );
} );

it( 'should hide and focus editable on formView#cancel event', () => {
balloon.add( { view: formView } );
return balloon.add( { view: formView } )
.then( () => {
formView.fire( 'cancel' );

formView.fire( 'cancel' );

expect( balloon.visibleView ).to.null;
expect( focusEditableSpy.calledOnce ).to.true;
expect( balloon.visibleView ).to.null;
expect( focusEditableSpy.calledOnce ).to.true;
} );
} );
} );
} );
Expand Down

0 comments on commit 90c0506

Please sign in to comment.