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

Commit

Permalink
Merge pull request #258 from ckeditor/i/6031
Browse files Browse the repository at this point in the history
Feature: Introduced an option to configure a manual decorator to be "on" by default. Closes ckeditor/ckeditor5#6031.
  • Loading branch information
Reinmar committed Apr 7, 2020
2 parents b86aa7f + b2dc424 commit 82f966e
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 42 deletions.
11 changes: 10 additions & 1 deletion docs/features/link.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ ClassicEditor
// ...
link: {
decorators: {
addTargetToExternalLinks: {
openInNewTab: {
mode: 'manual',
label: 'Open in a new tab',
attributes: {
Expand Down Expand Up @@ -195,6 +195,15 @@ ClassicEditor
attributes: {
download: 'file'
}
},
openInNewTab: {
mode: 'manual',
label: 'Open in a new tab',
defaultValue: true, // This option will be selected by default.
attributes: {
target: '_blank',
rel: 'noopener noreferrer'
}
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions src/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,13 @@ export default class Link extends Plugin {
*/

/**
* Represents a link decorator definition ({@link module:link/link~LinkDecoratorManualDefinition `'manual'`}
* or {@link module:link/link~LinkDecoratorAutomaticDefinition `'automatic'`}).
* A link decorator definition. Two types implement this defition:
*
* * {@link module:link/link~LinkDecoratorManualDefinition}
* * {@link module:link/link~LinkDecoratorAutomaticDefinition}
*
* Refer to their document for more information about available options or to the
* {@glink features/link#custom-link-attributes-decorators link feature guide} for general information.
*
* @interface LinkDecoratorDefinition
*/
Expand Down Expand Up @@ -203,6 +208,7 @@ export default class Link extends Plugin {
* {
* mode: 'manual',
* label: 'Open in a new tab',
* defaultValue: true,
* attributes: {
* target: '_blank',
* rel: 'noopener noreferrer'
Expand All @@ -215,4 +221,5 @@ export default class Link extends Plugin {
* @property {Object} attributes Key-value pairs used as link attributes added to the output during the
* {@glink framework/guides/architecture/editing-engine#conversion downcasting}.
* Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.
* @property {Boolean} [defaultValue] Controls whether the decorator is "on" by default.
*/
2 changes: 1 addition & 1 deletion src/linkcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,6 @@ export default class LinkCommand extends Command {
*/
_getDecoratorStateFromModel( decoratorName ) {
const doc = this.editor.model.document;
return doc.selection.getAttribute( decoratorName ) || false;
return doc.selection.getAttribute( decoratorName );
}
}
2 changes: 1 addition & 1 deletion src/linkui.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export default class LinkUI extends Plugin {
const editor = this.editor;
const linkCommand = editor.commands.get( 'link' );

const formView = new LinkFormView( editor.locale, linkCommand.manualDecorators );
const formView = new LinkFormView( editor.locale, linkCommand );

formView.urlInputView.fieldView.bind( 'value' ).to( linkCommand, 'value' );

Expand Down
22 changes: 11 additions & 11 deletions src/ui/linkformview.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ export default class LinkFormView extends View {
* Also see {@link #render}.
*
* @param {module:utils/locale~Locale} [locale] The localization services instance.
* @param {module:utils/collection~Collection} [manualDecorators] Reference to manual decorators in
* {@link module:link/linkcommand~LinkCommand#manualDecorators}.
* @param {module:link/linkcommand~LinkCommand} linkCommand Reference to {@link module:link/linkcommand~LinkCommand}.
*/
constructor( locale, manualDecorators = [] ) {
constructor( locale, linkCommand ) {
super( locale );

const t = locale.t;
Expand Down Expand Up @@ -94,15 +93,15 @@ export default class LinkFormView extends View {
* @readonly
* @type {module:ui/viewcollection~ViewCollection}
*/
this._manualDecoratorSwitches = this._createManualDecoratorSwitches( manualDecorators );
this._manualDecoratorSwitches = this._createManualDecoratorSwitches( linkCommand );

/**
* A collection of child views in the form.
*
* @readonly
* @type {module:ui/viewcollection~ViewCollection}
*/
this.children = this._createFormChildren( manualDecorators );
this.children = this._createFormChildren( linkCommand.manualDecorators );

/**
* A collection of views that can be focused in the form.
Expand Down Expand Up @@ -135,7 +134,7 @@ export default class LinkFormView extends View {

const classList = [ 'ck', 'ck-link-form' ];

if ( manualDecorators.length ) {
if ( linkCommand.manualDecorators.length ) {
classList.push( 'ck-link-form_layout-vertical' );
}

Expand Down Expand Up @@ -258,14 +257,13 @@ export default class LinkFormView extends View {
* made based on {@link module:link/linkcommand~LinkCommand#manualDecorators}.
*
* @private
* @param {module:utils/collection~Collection} manualDecorators A reference to the
* collection of manual decorators stored in the link command.
* @param {module:link/linkcommand~LinkCommand} linkCommand A reference to the link command.
* @returns {module:ui/viewcollection~ViewCollection} of switch buttons.
*/
_createManualDecoratorSwitches( manualDecorators ) {
_createManualDecoratorSwitches( linkCommand ) {
const switches = this.createCollection();

for ( const manualDecorator of manualDecorators ) {
for ( const manualDecorator of linkCommand.manualDecorators ) {
const switchButton = new SwitchButtonView( this.locale );

switchButton.set( {
Expand All @@ -274,7 +272,9 @@ export default class LinkFormView extends View {
withText: true
} );

switchButton.bind( 'isOn' ).to( manualDecorator, 'value' );
switchButton.bind( 'isOn' ).toMany( [ manualDecorator, linkCommand ], 'value', ( decoratorValue, commandValue ) => {
return commandValue === undefined && decoratorValue === undefined ? manualDecorator.defaultValue : decoratorValue;
} );

switchButton.on( 'execute', () => {
manualDecorator.set( 'value', !switchButton.isOn );
Expand Down
10 changes: 9 additions & 1 deletion src/utils/manualdecorator.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ export default class ManualDecorator {
* @param {String} config.label The label used in the user interface to toggle the manual decorator.
* @param {Object} config.attributes A set of attributes added to output data when the decorator is active for a specific link.
* Attributes should keep the format of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.
* @param {Boolean} [config.defaultValue] Controls whether the decorator is "on" by default.
*/
constructor( { id, label, attributes } ) {
constructor( { id, label, attributes, defaultValue } ) {
/**
* An ID of a manual decorator which is the name of the attribute in the model, for example: 'linkManualDecorator0'.
*
Expand All @@ -44,6 +45,13 @@ export default class ManualDecorator {
*/
this.set( 'value' );

/**
* The default value of manual decorator.
*
* @type {Boolean}
*/
this.defaultValue = defaultValue;

/**
* The label used in the user interface to toggle the manual decorator.
*
Expand Down
65 changes: 51 additions & 14 deletions tests/linkcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,18 @@ describe( 'LinkCommand', () => {
target: '_blank'
}
} ) );
command.manualDecorators.add( new ManualDecorator( {
id: 'linkIsSth',
label: 'Sth',
attributes: {
class: 'sth'
},
defaultValue: true
} ) );

model.schema.extend( '$text', {
allowIn: '$root',
allowAttributes: [ 'linkHref', 'linkIsFoo', 'linkIsBar' ]
allowAttributes: [ 'linkHref', 'linkIsFoo', 'linkIsBar', 'linkIsSth' ]
} );

model.schema.register( 'p', { inheritAllFrom: '$block' } );
Expand All @@ -302,19 +310,19 @@ describe( 'LinkCommand', () => {
it( 'should insert additional attributes to link when it is created', () => {
setData( model, 'foo[]bar' );

command.execute( 'url', { linkIsFoo: true, linkIsBar: true } );
command.execute( 'url', { linkIsFoo: true, linkIsBar: true, linkIsSth: true } );

expect( getData( model ) ).to
.equal( 'foo[<$text linkHref="url" linkIsBar="true" linkIsFoo="true">url</$text>]bar' );
.equal( 'foo[<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">url</$text>]bar' );
} );

it( 'should add additional attributes to link when link is modified', () => {
setData( model, 'f<$text linkHref="url">o[]oba</$text>r' );

command.execute( 'url', { linkIsFoo: true, linkIsBar: true } );
command.execute( 'url', { linkIsFoo: true, linkIsBar: true, linkIsSth: true } );

expect( getData( model ) ).to
.equal( 'f[<$text linkHref="url" linkIsBar="true" linkIsFoo="true">ooba</$text>]r' );
.equal( 'f[<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">ooba</$text>]r' );
} );

it( 'should remove additional attributes to link if those are falsy', () => {
Expand All @@ -330,19 +338,19 @@ describe( 'LinkCommand', () => {
it( 'should insert additional attributes to link when it is created', () => {
setData( model, 'f[ooba]r' );

command.execute( 'url', { linkIsFoo: true, linkIsBar: true } );
command.execute( 'url', { linkIsFoo: true, linkIsBar: true, linkIsSth: true } );

expect( getData( model ) ).to
.equal( 'f[<$text linkHref="url" linkIsBar="true" linkIsFoo="true">ooba</$text>]r' );
.equal( 'f[<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">ooba</$text>]r' );
} );

it( 'should add additional attributes to link when link is modified', () => {
setData( model, 'f[<$text linkHref="foo">ooba</$text>]r' );

command.execute( 'url', { linkIsFoo: true, linkIsBar: true } );
command.execute( 'url', { linkIsFoo: true, linkIsBar: true, linkIsSth: true } );

expect( getData( model ) ).to
.equal( 'f[<$text linkHref="url" linkIsBar="true" linkIsFoo="true">ooba</$text>]r' );
.equal( 'f[<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">ooba</$text>]r' );
} );

it( 'should remove additional attributes to link if those are falsy', () => {
Expand All @@ -356,25 +364,54 @@ describe( 'LinkCommand', () => {

describe( 'restoreManualDecoratorStates()', () => {
it( 'synchronize values with current model state', () => {
setData( model, 'foo<$text linkHref="url" linkIsBar="true" linkIsFoo="true">u[]rl</$text>bar' );
setData( model, 'foo<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="true">u[]rl</$text>bar' );

expect( decoratorStates( command.manualDecorators ) ).to.deep.equal( {
linkIsFoo: true,
linkIsBar: true
linkIsBar: true,
linkIsSth: true
} );

command.manualDecorators.first.value = false;

expect( decoratorStates( command.manualDecorators ) ).to.deep.equal( {
linkIsFoo: false,
linkIsBar: true
linkIsBar: true,
linkIsSth: true
} );

command.restoreManualDecoratorStates();

expect( decoratorStates( command.manualDecorators ) ).to.deep.equal( {
linkIsFoo: true,
linkIsBar: true,
linkIsSth: true
} );
} );

it( 'synchronize values with current model state when the decorator that is "on" default is "off"', () => {
setData( model, 'foo<$text linkHref="url" linkIsBar="true" linkIsFoo="true" linkIsSth="false">u[]rl</$text>bar' );

expect( decoratorStates( command.manualDecorators ) ).to.deep.equal( {
linkIsFoo: true,
linkIsBar: true,
linkIsSth: false
} );

command.manualDecorators.last.value = true;

expect( decoratorStates( command.manualDecorators ) ).to.deep.equal( {
linkIsFoo: true,
linkIsBar: true,
linkIsSth: true
} );

command.restoreManualDecoratorStates();

expect( decoratorStates( command.manualDecorators ) ).to.deep.equal( {
linkIsFoo: true,
linkIsBar: true
linkIsBar: true,
linkIsSth: false
} );
} );
} );
Expand All @@ -383,7 +420,7 @@ describe( 'LinkCommand', () => {
it( 'obtain current values from the model', () => {
setData( model, 'foo[<$text linkHref="url" linkIsBar="true">url</$text>]bar' );

expect( command._getDecoratorStateFromModel( 'linkIsFoo' ) ).to.be.false;
expect( command._getDecoratorStateFromModel( 'linkIsFoo' ) ).to.be.undefined;
expect( command._getDecoratorStateFromModel( 'linkIsBar' ) ).to.be.true;
} );
} );
Expand Down
Loading

0 comments on commit 82f966e

Please sign in to comment.