Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to create a command that will change text color? #481

Closed
djanosik opened this issue Jun 26, 2017 · 7 comments
Closed

How to create a command that will change text color? #481

djanosik opened this issue Jun 26, 2017 · 7 comments
Labels
resolution:expired This issue was closed due to lack of feedback. type:docs This issue reports a task related to documentation (e.g. an idea for a guide). type:question This issue asks a question (how to...).

Comments

@djanosik
Copy link

First, thank you! CKE5 is what we all have been waiting for :) I would like to use it right now, but I don't actually understand how to build custom commands. Is it documented somewhere? Can you explain what is required to create a command that will change text color (or inline style in general)?

@Reinmar
Copy link
Member

Reinmar commented Jun 26, 2017

Hi Dusan! Thanks for the kind words :)

The documentation is (unfortunately) still work in progress. We first focused on generating the API docs as we had the content already (in the code) but we needed a system to present them. You can see nightly builds of them on https://ckeditor5.github.io/docs/nightly/ckeditor5/latest/api/index.html. They are not reviewed yet, but they are pretty complete (although, we definitely need a lot more examples).

As for guides on how to write commands and how to build features in general, there's nothing yet. But if you'd like to try I can give you some hints and based on the existing code you should be able to figure out the rest.

First of all, some very brief introduction to the architecture of the engine.

Then, the ckeditor5-basic-styles package. It contains two features – bold and italic. Text color will be pretty similar to them, so it'll be a good read.

So, how to start?

  1. Create a plugin. You can simply extends the Plugin class like the BoldEngine does (see https://github.com/ckeditor/ckeditor5-basic-styles/blob/master/src/boldengine.js).

    (Note: There are Bold and BoldEngine plugins in this specific package as the latter is an extension of the former one. The former one gives you bold feature's engine, the latter the feature's UI parts).

  2. In the model an inline style (like bold or text color) is not any more represented by an element, but by a text node's attribue. You need to allow your new attribute in the model's schema:

    editor.document.schema.allow( { name: '$inline', attributes: 'textColor', inside: '$block' } );

    This will allow textColor attribute to be set in all types of nodes which schema recognises as $inline (which is a generic type from which $text inherits).

    (Note: Schema is awaiting a complete refactor so this API will soon change. Don't ask.)

  3. Now, you need to tell the engine how to convert the textColor attribute in the model to an element in the view (because you need a <span style="color: ..."> after all). It should look something like this:

     // Build converter from model to view for data and editing pipelines.
     buildModelConverter().for( data.modelToView, editing.modelToView )
     	.fromAttribute( 'textColor' )
     	.toElement( data => {
     		return new ViewAttributeElement( 'span', {
     			style: `color: ${ data.item.getAttribute( 'textColor' ) }`
     		} );
     	} );
    
     // Build converter from view to model for data pipeline.
     buildViewConverter().for( data.viewToModel )
     	.fromElement( 'span' )
     	.consuming( { attribute: [ 'color' ] } )
     	.toAttribute( viewElement => {
     		return { key: 'textColor', value: viewElement.getStyle( 'color' ) }
     	} );

    I wrote this from my memory and I'll check it with my colleagues tomorrow as we don't have such an example yet. So, before I verify that, it may not work at all :P.

  4. And last but not least, you need a command. You will need to register it like this:

    editor.commands.add( 'textColor', new TextColorCommand( editor ) );

    But of course you also need to implement the TextColorCommand class. The closest what we have right now in the code is the AttributeCommand (see its docs) used by the bold and italic features. You'll need to change it so it doesn't set the textColor attribute to true but to some string values like #FF0000. It also needs to accept this color as a param in execute(). And finally, once you'll have your editor up and running you'll just need to do:

    editor.execute( 'textColor', 'red' );

    And it should work.

This introduction is like 1/10th of what should be written in such a tutorial, but hopefully it will let you start hacking the editor.

Good luck :)

@Reinmar Reinmar added type:docs This issue reports a task related to documentation (e.g. an idea for a guide). type:question This issue asks a question (how to...). labels Jun 26, 2017
@djanosik
Copy link
Author

djanosik commented Jun 27, 2017

@Reinmar Thank you! One more question. Is any event raised when a text with some text color is selected?

@Reinmar
Copy link
Member

Reinmar commented Jun 27, 2017

I assume you're asking about how to refresh your command? How to know when the selection is in a text with some color applied and when it's not?

The most reliable and the simplest way to know where to refresh a state of a command is to listen to Document#changesDone event (editor.document#changesDone). This event is fired every time any change is done to the model (including selection changes). Or to be more precise – by the Document#enqueueChanges() method, so that's why every code which changes the model needs to be wrapped with it.

(Side note: We're planning to change this API too.)

So, listening to that event is the easiest solution. And the Command class does it automatically. So, YourCommand#refresh() will be called automatically if anything has changed.

Going to the second part of the question – how to check if some text color is selected? First of all, we need to define what "text color is selected" means? Without going into the details why, for us, a style (like text color) is selected if the selection starts inside it or right after.

In the previous post I mentioned that text nodes have attributes. Guess what? Selection has attributes too :) Quick justification – how do we represent change in the model for Ctrl+B pressed on a collapsed selection? We set the 'bold' attribute on the selection itself.

What's more – document selection's (editor.document.selection) attributes are automatically refreshed based on selection changes. This means that the value (whether bold is applied here or not) of the bold command can be refreshed in this simple way:

this.value = editor.document.selection.hasAttribute( 'bold' );

See the code.

Side note: Most of state changes in CKEditor 5 can be observer. Selection attributes changes fire Selection#change:attribute event, so the short answer to your question is that you can listen to this event to know where selection attributes change:

const sel = editor.document.selection;

sel.on( 'change:attribute', () => {
    console.log( sel.getAttribute( 'textColor' ) );
} );

@zhoufanglu
Copy link

I used it as above, but it didn't work...

@Reinmar Reinmar added this to the backlog milestone Feb 14, 2019
@pomek pomek removed this from the backlog milestone Feb 21, 2022
@CKEditorBot
Copy link
Collaborator

There has been no activity on this issue for the past year. We've marked it as stale and will close it in 30 days. We understand it may be relevant, so if you're interested in the solution, leave a comment or reaction under this issue.

@CKEditorBot
Copy link
Collaborator

There has been no activity on this issue for the past year. We've marked it as stale and will close it in 30 days. We understand it may still be relevant, so if you're interested in the solution, leave a comment or reaction under this issue.

@CKEditorBot
Copy link
Collaborator

We've closed your issue due to inactivity over the last year. We understand that the issue may still be relevant. If so, feel free to open a new one (and link this issue to it).

@CKEditorBot CKEditorBot added resolution:expired This issue was closed due to lack of feedback. and removed status:stale labels Jan 15, 2024
@CKEditorBot CKEditorBot closed this as not planned Won't fix, can't repro, duplicate, stale Jan 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
resolution:expired This issue was closed due to lack of feedback. type:docs This issue reports a task related to documentation (e.g. an idea for a guide). type:question This issue asks a question (how to...).
Projects
None yet
Development

No branches or pull requests

5 participants