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 #99 from ckeditor/t/ckeditor5-alignment/16
Browse files Browse the repository at this point in the history
Other: Update naming of UI components & commands.

BREAKING CHANGE: Renamed the `'headings'` dropdown UI component to `'heading'`.
BREAKING CHANGE: The `'heading1'`, `'heading2'` and `'heading3'` commands are no longer available. They were replaced by the `'heading'` command that accepts heading model element name as a value.
BREAKING CHANGE: The `HeadingCommand#value` is no longer a boolean only. Now it stores a name of the heading model element when selection is inside a heading.
BREAKING CHANGE: The `HeadingCommand` constructor's second parameter is now an array of supported model elements.
  • Loading branch information
Reinmar authored Mar 11, 2018
2 parents bbf7d60 + d7bbf1f commit 72ee3d6
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 112 deletions.
8 changes: 4 additions & 4 deletions docs/features/headings.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ import Heading from '@ckeditor/ckeditor5-heading/src/heading';
ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ Heading, ... ],
toolbar: [ 'headings', ... ]
toolbar: [ 'heading', ... ]
} )
.then( ... )
.catch( ... );
Expand All @@ -132,13 +132,13 @@ ClassicEditor

The {@link module:heading/heading~Heading} plugin registers:

* The `'headings'` dropdown.
* The `'heading1'`, `'heading2'`, ..., `'headingN'` commands based on the {@link module:heading/heading~HeadingConfig#options `heading.options`} configuration option.
* The `'heading'` dropdown.
* The `'heading'` command that accepts value based on the {@link module:heading/heading~HeadingConfig#options `heading.options`} configuration option.

You can turn the currently selected block(s) to headings by executing one of these commands:

```js
editor.execute( 'heading2' );
editor.execute( 'heading', { value: 'heading2' } );
```

## Contribute
Expand Down
4 changes: 2 additions & 2 deletions src/heading.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ export default class Heading extends Plugin {
* That's assumption is used by features like {@link module:autoformat/autoformat~Autoformat} to know which element
* they should use when applying the first level heading.
*
* The defined headings are also available in {@link module:core/commandcollection~CommandCollection} under their model names.
* The defined headings are also available as values passed to `heading` command under their model names.
* For example, the below code will apply `<heading1>` to the current selection:
*
* editor.execute( 'heading1' );
* editor.execute( 'heading', { value: 'heading1' } );
*
* @member {Array.<module:heading/heading~HeadingOption>} module:heading/heading~HeadingConfig#options
*/
Expand Down
36 changes: 23 additions & 13 deletions src/headingcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,29 @@ export default class HeadingCommand extends Command {
* Creates an instance of the command.
*
* @param {module:core/editor/editor~Editor} editor Editor instance.
* @param {String} modelElement Name of the element which this command will apply in the model.
* @param {Array.<String>} modelElements Names of the element which this command can apply in the model.
*/
constructor( editor, modelElement ) {
constructor( editor, modelElements ) {
super( editor );

/**
* Whether the selection starts in a heading of {@link #modelElement this level}.
* If the selection starts in a heading (which {@link #modelElements is supported by this command})
* the value is set to the name of that heading model element.
* It is set to `false` otherwise.
*
* @observable
* @readonly
* @member {Boolean} #value
* @member {Boolean|String} #value
*/

/**
* Unique identifier of the command, also element's name in the model.
* Set of defined model's elements names that this command support.
* See {@link module:heading/heading~HeadingOption}.
*
* @readonly
* @member {String}
* @member {Array.<String>}
*/
this.modelElement = modelElement;
this.modelElements = modelElements;
}

/**
Expand All @@ -49,29 +51,37 @@ export default class HeadingCommand extends Command {
refresh() {
const block = first( this.editor.model.document.selection.getSelectedBlocks() );

this.value = !!block && block.is( this.modelElement );
this.isEnabled = !!block && checkCanBecomeHeading( block, this.modelElement, this.editor.model.schema );
this.value = !!block && this.modelElements.includes( block.name ) && block.name;
this.isEnabled = !!block && this.modelElements.some( heading => checkCanBecomeHeading( block, heading, this.editor.model.schema ) );
}

/**
* Executes the command. Applies the heading to the selected blocks or, if the first selected
* block is a heading already, turns selected headings (of this level only) to paragraphs.
*
* @param {Object} options
* @param {String} options.value Name of the element which this command will apply in the model.
* @fires execute
*/
execute() {
execute( options = {} ) {
const model = this.editor.model;
const document = model.document;

const modelElement = options.value;

if ( !this.modelElements.includes( modelElement ) ) {
return;
}

model.change( writer => {
const blocks = Array.from( document.selection.getSelectedBlocks() )
.filter( block => {
return checkCanBecomeHeading( block, this.modelElement, model.schema );
return checkCanBecomeHeading( block, modelElement, model.schema );
} );

for ( const block of blocks ) {
if ( !block.is( this.modelElement ) ) {
writer.rename( block, this.modelElement );
if ( !block.is( modelElement ) ) {
writer.rename( block, modelElement );
}
}
} );
Expand Down
8 changes: 6 additions & 2 deletions src/headingediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export default class HeadingEditing extends Plugin {
const editor = this.editor;
const options = editor.config.get( 'heading.options' );

const modelElements = [];

for ( const option of options ) {
// Skip paragraph - it is defined in required Paragraph feature.
if ( option.model !== defaultModelElement ) {
Expand All @@ -61,10 +63,12 @@ export default class HeadingEditing extends Plugin {

editor.conversion.elementToElement( option );

// Register the heading command for this option.
editor.commands.add( option.model, new HeadingCommand( editor, option.model ) );
modelElements.push( option.model );
}
}

// Register the heading command for this option.
editor.commands.add( 'heading', new HeadingCommand( editor, modelElements ) );
}

/**
Expand Down
34 changes: 23 additions & 11 deletions src/headingui.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,37 @@ export default class HeadingUI extends Plugin {
const dropdownTooltip = t( 'Heading' );

// Register UI component.
editor.ui.componentFactory.add( 'headings', locale => {
const commands = [];
editor.ui.componentFactory.add( 'heading', locale => {
const titles = {};
const dropdownItems = new Collection();

const headingCommand = editor.commands.get( 'heading' );
const paragraphCommand = editor.commands.get( 'paragraph' );

const commands = [ headingCommand ];

for ( const option of options ) {
const command = editor.commands.get( option.model );
const itemModel = new Model( {
commandName: option.model,
label: option.title,
class: option.class
} );

itemModel.bind( 'isActive' ).to( command, 'value' );
if ( option.model === 'paragraph' ) {
itemModel.bind( 'isActive' ).to( paragraphCommand, 'value' );
itemModel.set( 'commandName', 'paragraph' );
commands.push( paragraphCommand );
} else {
itemModel.bind( 'isActive' ).to( headingCommand, 'value', value => value === option.model );
itemModel.set( {
commandName: 'heading',
commandValue: option.model
} );
}

// Add the option to the collection.
dropdownItems.add( itemModel );

commands.push( command );
titles[ option.model ] = option.title;
}

const dropdownView = createDropdown( locale );
Expand All @@ -74,16 +87,15 @@ export default class HeadingUI extends Plugin {
return areEnabled.some( isEnabled => isEnabled );
} );

dropdownView.buttonView.bind( 'label' ).toMany( commands, 'value', ( ...areActive ) => {
const index = areActive.findIndex( value => value );

dropdownView.buttonView.bind( 'label' ).to( headingCommand, 'value', paragraphCommand, 'value', ( value, para ) => {
const whichModel = value || para && 'paragraph';
// If none of the commands is active, display default title.
return options[ index ] ? options[ index ].title : defaultTitle;
return titles[ whichModel ] ? titles[ whichModel ] : defaultTitle;
} );

// Execute command when an item from the dropdown is selected.
this.listenTo( dropdownView, 'execute', evt => {
editor.execute( evt.source.commandName );
editor.execute( evt.source.commandName, evt.source.commandValue ? { value: evt.source.commandValue } : undefined );
editor.editing.view.focus();
} );

Expand Down
Loading

0 comments on commit 72ee3d6

Please sign in to comment.