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

t/33: Enabled configuration and localisation of headings #57

Merged
merged 11 commits into from
Mar 1, 2017
Merged

Conversation

oleq
Copy link
Member

@oleq oleq commented Feb 17, 2017

Suggested merge commit message (convention)

Feature: Enabled configuration and localization of headings. Closes ckeditor/ckeditor5#2418.

NOTE: Added config.heading.formats and config.heading.defaultFormatId config options.

tests/heading.js Outdated
beforeEach( () => {
const editorElement = document.createElement( 'div' );

const spy = testUtils.sinon.stub( Locale.prototype, '_t' ).returns( 'foo' );
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since items are localized in the heading plugin before stubbed editor.t would work, this is the only way I see to test it. TBH, I don't like it and I wish we had some easier way to assert localization because it will repeat in many places.

src/heading.js Outdated
withText: true,
items: collection
} );

// Bind dropdown model to command.
dropdownModel.bind( 'isEnabled' ).to( command, 'isEnabled' );
dropdownModel.bind( 'label' ).to( command, 'value', format => format.label );
dropdownModel.bind( 'label' ).to( command, 'value', ( { label } ) => label );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous version was much easier to read.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a matter of preference, I suppose. It's easier for me to read the second one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with every preference, I can't say that your's weird, but... it is :D.

My way of thinking is – format => format.label tells you that a format is turned into just its label. With the deconstruction pattern there you lose the context (the format). It's burried deep in the binding that you did, so the callback may be far from intiuitive at first.

src/heading.js Outdated
@@ -40,23 +40,22 @@ export default class Heading extends Plugin {
const collection = new Collection();

// Add formats to collection.
for ( let format of formats ) {
for ( let { id, label } of formats ) {
Copy link
Member

@Reinmar Reinmar Feb 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you really need to change this code (in this PR), then be comprehensive – this can be a const.

* @protected
* @type {Array.<module:heading/headingcommand~HeadingFormat>}
*/
get _formats() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OTOH, this more deserves to be a method – _getLocalizedFormats(). Plus, even the API doc is misleading now because it doesn't explain why this getter exists in the first place.

editor.config.define( 'heading', {
formats: [
{ id: 'paragraph', element: 'p', label: labels.Paragraph },
{ id: 'heading1', element: 'h2', label: labels[ 'Heading 1' ] },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the _formats getter localizes these labels, why are you using localized versions here too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that two things must be localized:

  1. Default config, which is editor.config.define( 'heading', { formats: [ ... ] } ).
  2. User config, which is editor.config.get( 'heading.formats' ).

* @protected
* @member {Object} #_localizedFormatLabels
*/
const labels = this._localizedFormatLabels = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must this be a property? It'd be a good private variable of this module.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rationale – don't bloat the class.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of the above #57 (comment). Both default config and user config must be localized. The first is localized in constructor(), the second in init(). I cannot share these labels in any other way because they require editor.t() to be created.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User config can be localised together with the default config when they are processed by the _getLocalizedOptions() method (currently _options property, but I commented that it shouldn't be a property). The default config doesn't have to be localized beforehand.

You're right about the other thing, though. The localized labels cannot be defined in the module scope, because they require the t() function. I missed that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, this property also shouldn't use the word "format".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking about the localization of user config and I'm afraid about one thing. Perhaps it's an edge case, but still...

Let's say you want editor in language X. So the _localizedOptionLabels contains e.g. map like:

Paragraph: 'X Paragraph',
'Heading 1': 'X Heading 1',
...

Now, someone also specifies config.heading.options, but want to use English strings there because for a weird case it make sense to keep them in English. But this turns to be impossible because they are automatically localized using _localizedOptionLabels mapping.

I hope that this case is really that edgy as it sounds now and can be ignored.

PS. This applies to the current implementation and the one proposed by me above.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If they want to use English strings so badly, they can write them with a ZWSP at the end, so _localizedOptionLabels does not translate them to current editor language and just passes them thru =)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an edge case, really. When someone translates the entire app but some labels.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know :D I thought about the same "solution".

So I guess it's all fine. But this can still be improved in the code:

User config can be localised together with the default config when they are processed by the _getLocalizedOptions() method (currently _options property, but I commented that it shouldn't be a property). The default config doesn't have to be localized beforehand.


if ( enterCommand ) {
this.listenTo( enterCommand, 'afterExecute', ( evt, data ) => {
const positionParent = editor.document.selection.getFirstPosition().parent;
const batch = data.batch;
const isHeading = formats.some( ( format ) => format.id == positionParent.name );
const isHeading = formats.some( ( { id } ) => id == positionParent.name );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this. The previous version was more readable.

@Reinmar
Copy link
Member

Reinmar commented Feb 19, 2017

Please consider https://github.com/ckeditor/ckeditor5-heading/issues/52. You added heading.formats while we'd like to get rid of that word in this context (it's a leftover from the time this was a formats feature).

What I don't know is how could the option be named ;> heading.options?

@Reinmar
Copy link
Member

Reinmar commented Feb 19, 2017

Last but not least – do we need to explicitly define the paragraph option? I wanted to ask the question because you may have a more concrete opinion about that, but personally I think that removing it from the config may only make things more complicated.

@Reinmar
Copy link
Member

Reinmar commented Feb 19, 2017

OK, that wasn't all yet :D.

config.heading.defaultFormatId config options.

We don't need this option yet. And I don't think that anyone will ever need it. Even if your editor implements some oddest editing use case, the <paragraph> element should still be the default editing block.

@fredck
Copy link

fredck commented Feb 20, 2017

What I don't know is how could the option be named ;> heading.options?

+1 Wanted to say exactly the same :)

{ id: 'heading2', element: 'h3', label: labels[ 'Heading 2' ] },
{ id: 'heading3', element: 'h4', label: labels[ 'Heading 3' ] }
],
defaultOptionId: 'paragraph'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still to be removed.

* @protected
* @type {Array.<module:heading/headingcommand~HeadingOption>}
*/
get _options() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still to not be a getter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take it easy ;-) It's a step–by–step refac.

* @readonly
* @member {Array.<module:heading/headingcommand~HeadingOption>} #_cachedLocalizedOptions
*/
return ( this._cachedLocalizedOptions = editor.config.get( 'heading.options' )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Srsly, a multiline assignment combined with a return statement? Please, de-obfuscate this :P

@Reinmar Reinmar merged commit de07a0c into master Mar 1, 2017
@Reinmar Reinmar deleted the t/33 branch March 1, 2017 17:00
@Reinmar
Copy link
Member

Reinmar commented Mar 1, 2017

I changed the message to:

Feature: Enabled configuration and localization of available headings. See config.heading.options. Closes #33.

BREAKING CHANGES: The heading command now accepts id option, not formatId.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

List of allowed headings should be configurable
3 participants