Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ckeditor/ckeditor5-link

Package Overview
Dependencies
Maintainers
1
Versions
709
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ckeditor/ckeditor5-link - npm Package Compare versions

Comparing version 0.4.0 to 0.5.0

3

lang/contexts.json
{
"Unlink": "Toolbar button tooltip for the Unlink feature.",
"Link": "Toolbar button tooltip for the Link feature.",
"Link URL": "Label for the url input in the Link dialog.",
"Cancel": "Label for the cancel button in the Link dialog."
"Link URL": "Label for the url input in the Link dialog."
}
{
"name": "@ckeditor/ckeditor5-link",
"version": "0.4.0",
"version": "0.5.0",
"description": "Link feature for CKEditor 5.",

@@ -5,0 +5,0 @@ "keywords": [],

@@ -16,3 +16,2 @@ /**

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

@@ -172,9 +171,18 @@ import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';

// Close on `ESC` press.
escPressHandler( {
emitter: balloonPanelView,
activator: () => balloonPanelView.isVisible,
callback: () => this._hidePanel( true )
// Focus the form if balloon panel is open and tab key has been pressed.
editor.keystrokes.set( 'Tab', ( data, cancel ) => {
if ( balloonPanelView.isVisible && !this.formView.focusTracker.isFocused ) {
this.formView.focus();
cancel();
}
} );
// Close the panel on esc key press when editable has focus.
editor.keystrokes.set( 'Esc', ( data, cancel ) => {
if ( balloonPanelView.isVisible ) {
this._hidePanel( true );
cancel();
}
} );
// Close on click outside of balloon panel element.

@@ -217,2 +225,8 @@ clickOutsideHandler( {

// Close the panel on esc key press when the form has focus.
formView.keystrokes.set( 'Esc', ( data, cancel ) => {
this._hidePanel( true );
cancel();
} );
// Hide balloon panel after clicking on formView `Cancel` button.

@@ -219,0 +233,0 @@ this.listenTo( formView, 'cancel', () => this._hidePanel( true ) );

@@ -12,2 +12,3 @@ /**

import Template from '@ckeditor/ckeditor5-ui/src/template';
import ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';

@@ -19,2 +20,5 @@ import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';

import submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';
import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
import FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';
import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';

@@ -38,2 +42,18 @@ /**

/**
* Tracks information about DOM focus in the form.
*
* @readonly
* @member {module:utils/focustracker~FocusTracker}
*/
this.focusTracker = new FocusTracker();
/**
* Instance of the {@link module:core/keystrokehandler~KeystrokeHandler}.
*
* @readonly
* @member {module:core/keystrokehandler~KeystrokeHandler}
*/
this.keystrokes = new KeystrokeHandler();
/**
* The url input view.

@@ -67,5 +87,31 @@ *

// Register child views.
this.addChildren( [ this.urlInputView, this.saveButtonView, this.cancelButtonView, this.unlinkButtonView ] );
/**
* A collection of views which can be focused in the form.
*
* @readonly
* @protected
* @member {module:ui/viewcollection~ViewCollection}
*/
this._focusables = new ViewCollection();
/**
* Helps cycling over {@link #_focusables} in the form.
*
* @readonly
* @protected
* @member {module:ui/focuscycler~FocusCycler}
*/
this._focusCycler = new FocusCycler( {
focusables: this._focusables,
focusTracker: this.focusTracker,
keystrokeHandler: this.keystrokes,
actions: {
// Navigate form fields backwards using the shift + tab keystroke.
focusPrevious: 'shift + tab',
// Navigate form fields forwards using the tab key.
focusNext: 'tab'
}
} );
Template.extend( this.saveButtonView.template, {

@@ -111,5 +157,37 @@ attributes: {

} );
const childViews = [
this.urlInputView,
this.saveButtonView,
this.cancelButtonView,
this.unlinkButtonView
];
childViews.forEach( v => {
// Register the view as focusable.
this._focusables.add( v );
// Register the view in the focus tracker.
this.focusTracker.add( v.element );
} );
}
/**
* @inheritDoc
*/
init() {
// Start listening for the keystrokes coming from #element.
this.keystrokes.listenTo( this.element );
return super.init();
}
/**
* Focuses the fist {@link #_focusables} in the form.
*/
focus() {
this._focusCycler.focusFirst();
}
/**
* Create labeled input view.

@@ -116,0 +194,0 @@ *

@@ -186,12 +186,75 @@ /**

it( 'should focus the link form on Tab key press', () => {
const keyEvtData = {
keyCode: keyCodes.tab,
preventDefault: sinon.spy(),
stopPropagation: sinon.spy()
};
// Mock balloon invisible, form not focused.
balloonPanelView.isVisible = false;
formView.focusTracker.isFocused = false;
const spy = sinon.spy( formView, 'focus' );
editor.keystrokes.press( keyEvtData );
sinon.assert.notCalled( keyEvtData.preventDefault );
sinon.assert.notCalled( keyEvtData.stopPropagation );
sinon.assert.notCalled( spy );
// Mock balloon visible, form focused.
balloonPanelView.isVisible = true;
formView.focusTracker.isFocused = true;
editor.keystrokes.press( keyEvtData );
sinon.assert.notCalled( keyEvtData.preventDefault );
sinon.assert.notCalled( keyEvtData.stopPropagation );
sinon.assert.notCalled( spy );
// Mock balloon visible, form not focused.
balloonPanelView.isVisible = true;
formView.focusTracker.isFocused = false;
editor.keystrokes.press( keyEvtData );
sinon.assert.calledOnce( keyEvtData.preventDefault );
sinon.assert.calledOnce( keyEvtData.stopPropagation );
sinon.assert.calledOnce( spy );
} );
describe( 'close listeners', () => {
describe( 'keyboard', () => {
it( 'should close after `ESC` press', () => {
it( 'should close after Esc key press (from editor)', () => {
const keyEvtData = {
keyCode: keyCodes.esc,
preventDefault: sinon.spy(),
stopPropagation: sinon.spy()
};
balloonPanelView.isVisible = false;
editor.keystrokes.press( keyEvtData );
sinon.assert.notCalled( hidePanelSpy );
sinon.assert.notCalled( focusEditableSpy );
balloonPanelView.isVisible = true;
dispatchKeyboardEvent( document, 'keydown', keyCodes.esc );
editor.keystrokes.press( keyEvtData );
expect( hidePanelSpy.calledOnce ).to.true;
expect( focusEditableSpy.calledOnce ).to.true;
sinon.assert.calledOnce( hidePanelSpy );
sinon.assert.calledOnce( focusEditableSpy );
} );
it( 'should close after Esc key press (from the form)', () => {
const keyEvtData = {
keyCode: keyCodes.esc,
preventDefault: sinon.spy(),
stopPropagation: sinon.spy()
};
formView.keystrokes.press( keyEvtData );
sinon.assert.calledOnce( hidePanelSpy );
sinon.assert.calledOnce( focusEditableSpy );
} );
} );

@@ -419,17 +482,1 @@

} );
// Creates and dispatches keyboard event with specified keyCode.
//
// @private
// @param {EventTarget} eventTarget
// @param {String} eventName
// @param {Number} keyCode
function dispatchKeyboardEvent( element, eventName, keyCode ) {
const event = document.createEvent( 'Events' );
event.initEvent( eventName, true, true );
event.which = keyCode;
event.keyCode = keyCode;
element.dispatchEvent( event );
}

@@ -6,5 +6,13 @@ /**

import LinkFormView from '../../src/ui/linkformview';
import View from '@ckeditor/ckeditor5-ui/src/view';
import LinkFormView from '../../src/ui/linkformview';
import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
import FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';
import ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';
import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
testUtils.createSinonSandbox();
describe( 'LinkFormView', () => {

@@ -16,3 +24,3 @@ let view;

view.init();
return view.init();
} );

@@ -37,2 +45,38 @@

it( 'should create #focusTracker instance', () => {
expect( view.focusTracker ).to.be.instanceOf( FocusTracker );
} );
it( 'should create #keystrokes instance', () => {
expect( view.keystrokes ).to.be.instanceOf( KeystrokeHandler );
} );
it( 'should create #_focusCycler instance', () => {
expect( view._focusCycler ).to.be.instanceOf( FocusCycler );
} );
it( 'should create #_focusables view collection', () => {
expect( view._focusables ).to.be.instanceOf( ViewCollection );
} );
it( 'should register child views in #_focusables', () => {
expect( view._focusables.map( f => f ) ).to.have.members( [
view.urlInputView,
view.saveButtonView,
view.cancelButtonView,
view.unlinkButtonView
] );
} );
it( 'should register child views\' #element in #focusTracker', () => {
const spy = testUtils.sinon.spy( FocusTracker.prototype, 'add' );
view = new LinkFormView( { t: () => {} } );
sinon.assert.calledWithExactly( spy.getCall( 0 ), view.urlInputView.element );
sinon.assert.calledWithExactly( spy.getCall( 1 ), view.saveButtonView.element );
sinon.assert.calledWithExactly( spy.getCall( 2 ), view.cancelButtonView.element );
sinon.assert.calledWithExactly( spy.getCall( 3 ), view.unlinkButtonView.element );
} );
it( 'should fire `cancel` event on cancelButtonView#execute', () => {

@@ -77,2 +121,56 @@ const spy = sinon.spy();

describe( 'init()', () => {
it( 'starts listening for #keystrokes coming from #element', () => {
view = new LinkFormView( { t: () => {} } );
const spy = sinon.spy( view.keystrokes, 'listenTo' );
return view.init().then( () => {
sinon.assert.calledOnce( spy );
sinon.assert.calledWithExactly( spy, view.element );
} );
} );
describe( 'activates keyboard navigation for the toolbar', () => {
it( 'so "tab" the next focusable item', () => {
const keyEvtData = {
keyCode: keyCodes.tab,
preventDefault: sinon.spy(),
stopPropagation: sinon.spy()
};
// Mock the url input is focused.
view.focusTracker.isFocused = true;
view.focusTracker.focusedElement = view.urlInputView.element;
const spy = sinon.spy( view.saveButtonView, 'focus' );
view.keystrokes.press( keyEvtData );
sinon.assert.calledOnce( keyEvtData.preventDefault );
sinon.assert.calledOnce( keyEvtData.stopPropagation );
sinon.assert.calledOnce( spy );
} );
it( 'so "shift + tab" focuses the previous focusable item', () => {
const keyEvtData = {
keyCode: keyCodes.tab,
shiftKey: true,
preventDefault: sinon.spy(),
stopPropagation: sinon.spy()
};
// Mock the cancel button is focused.
view.focusTracker.isFocused = true;
view.focusTracker.focusedElement = view.cancelButtonView.element;
const spy = sinon.spy( view.saveButtonView, 'focus' );
view.keystrokes.press( keyEvtData );
sinon.assert.calledOnce( keyEvtData.preventDefault );
sinon.assert.calledOnce( keyEvtData.stopPropagation );
sinon.assert.calledOnce( spy );
} );
} );
} );
describe( 'DOM bindings', () => {

@@ -90,2 +188,12 @@ describe( 'submit event', () => {

} );
describe( 'focus()', () => {
it( 'focuses the #urlInputView', () => {
const spy = sinon.spy( view.urlInputView, 'focus' );
view.focus();
sinon.assert.calledOnce( spy );
} );
} );
} );

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc