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

Improved pastefromword to retain cell borders #2219

Merged
merged 51 commits into from
Jun 3, 2019
Merged

Improved pastefromword to retain cell borders #2219

merged 51 commits into from
Jun 3, 2019

Conversation

jacekbogdanski
Copy link
Member

@jacekbogdanski jacekbogdanski commented Jul 12, 2018

What is the purpose of this pull request?

New feature

Does your PR contain necessary tests?

All patches which change the editor code must include tests. You can always read more
on PR testing,
how to set the testing environment and
how to create tests
in the official CKEditor documentation.

This PR contains

  • Unit tests
  • Manual tests

What changes did you make?

It's early PR which requires some changes. Among others:

  1. I didn't cover tests thus proposed changes kills 134 unit tests only for chrome. I will fix it and cover with tests after early acceptance.
  2. I was only able to test this feature on IE11, Chrome, Firefox. However, it looks like Safari and IE8 are not supported by pastefromword. Not sure about IE10 and IE9.

Closes #1490, closes #2924

@mlewand mlewand added the review:easy Pull requests that can be reviewed by a Junior Developer before being reviewed by the Reviewer. label Aug 13, 2018
@Comandeer Comandeer self-assigned this Aug 27, 2018
Copy link
Member

@Comandeer Comandeer left a comment

Choose a reason for hiding this comment

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

It's hard to say anything about this fix as there is no manual test. Please at least add some manual tests for it.

Copy link
Contributor

@mlewand mlewand left a comment

Choose a reason for hiding this comment

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

Just 2 cents: make sure to add unit test for this enhancement. Currently it is not covered.

plugins/pastefromword/filter/default.js Outdated Show resolved Hide resolved
@Comandeer Comandeer self-assigned this Nov 15, 2018
Copy link
Member

@Comandeer Comandeer left a comment

Choose a reason for hiding this comment

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

Seems like borders are not correctly parsed (tested on Chrome).

Excel:
screenshot 2018-11-15 at 14 23 06

CKEditor:
screenshot 2018-11-15 at 14 22 36

It doesn't work in Safari at all:
screenshot 2018-11-15 at 14 28 48

Raw HTML data: https://gist.github.com/Comandeer/ed20b6dd576b7350f972355f799cb29a

The unit tests are missing.

plugins/pastefromword/filter/default.js Outdated Show resolved Hide resolved
Style.createStyleStack( element, filter, editor,
/margin|text\-align|padding|list\-style\-type|width|height|border|white\-space|vertical\-align|background/i );

function mergeBorderStyles( borderType, borderValue ) {
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 also thinking about moving this function into CKEDITOR.tools.style. What a pity that CKEDITOR.tools.style.border is a function, because it would be a great namespace for such functions.

@bender-ui: collapsed
@bender-ckeditor-plugins: wysiwygarea, toolbar, pastefromword

1. Using Microsoft Excel copy table with custom cell borders. Use different colors and border types.
Copy link
Member

Choose a reason for hiding this comment

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

It'd be nice to create ready to use asset.

@@ -0,0 +1,14 @@
@bender-tags: bug, 4.11.0, 1490, pastefromword
Copy link
Member

Choose a reason for hiding this comment

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

Please update version tags.

@@ -0,0 +1,14 @@
@bender-tags: bug, 4.11.0, 1490, pastefromword
@bender-ui: collapsed
@bender-ckeditor-plugins: wysiwygarea, toolbar, pastefromword
Copy link
Member

Choose a reason for hiding this comment

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

Table from Excel is pastes as plain text. There are several missing plugins (e.g. table).

delete styles[ style ];
styles[ style.toLowerCase() ] = temp;
}
for ( var i = 0; i < allowedBorderTypes.length; i++ ) {
Copy link
Member

Choose a reason for hiding this comment

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

You use CKEDITOR.tools.array.forEach just right after this loop. Won't be better to use also here?

return borderObj.width + ' ' +
borderObj.style + ' ' +
// Replace old CSS2 `windowtext` color with `black`.
borderObj.color.replace( 'windowtext', 'black' );
Copy link
Member

Choose a reason for hiding this comment

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

windowtext isn't actually equal to black, it's platform dependent and could be changed by changing OS's theme or other settings. As for now every browser is supporting it, so I'm not sure if it's necessary to replace it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering here, it's tricky to work with these values.

95% (ofc my gut feeling) people use the default values, so it would kinda make sense to convert it anyway. And it is not rare to see MS Word using this:

image

We could expose a dedicated method in CKEDITOR.tools.style to replace these magic values. Then again I thought about possibility to adjust these values or even disable this replacement. So I kind of intuitively thought of CKEDITOR.config but on the second thought I'm not a fan of bloating (already enormous) config with very specific options like that.

So eventually it could hold some sort of public mapping in CKEDITOR.tools.style. That will allow only for global customization, but we don't need more than that.

@jacekbogdanski
Copy link
Member Author

The feature doesn't work on Safari and IE8 thus the issue: #2609

@jacekbogdanski
Copy link
Member Author

Just 2 cents: make sure to add a unit test for this enhancement. Currently, it is not covered.
The unit tests are missing.

Yes, I know that this PR is missing unit tests, I already wrote it in the PR description. No worries, I won't leave this code without test coverage. Although this implementation kills every test case which uses table (currently failing 132 unit tests only for chrome, some tests are written per browser so it may multiply fast) so I would really appropriate solid review before I start fixing unit tests. Small implementation change may require correcting all tests again and thus they are generated, it's a highly time-consuming task. Although I added a unit test for Chrome, so it will be easier to validate output HTML.

I'm wondering if https://github.com/ckeditor/ckeditor-dev/blob/015e1cc00b114d6a503421db9c0a35b71afe525e/plugins/pastefromword/plugin.js#L26-L27 ACF filter shouldn't be moved to the table plugin? As I know pastefromword should be a bit dumb in the case of allowed content inside the editor, so a user can decide which styles he wants to enable by importing correct plugin.

I'm not very fond of CKEDITOR.tools.style.parse.splitBorderStyles name and I think it may be misleading. Also, it doesn't play well with namespace when you look at the other function names. However, nothing else comes to my mind now. Maybe you have some idea about the name?

Copy link
Member

@Comandeer Comandeer left a comment

Choose a reason for hiding this comment

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

There are some differences between original table and pasted one:

Original:

screenshot 2018-12-19 at 13 21 57

Pasted one:

screenshot 2018-12-19 at 13 20 58

It's possible to fully mimic the behaviour of Excel by switching to border-collapse: separate and moving border-bottom from the first table cell (with [colspan=9]) to border-top of cells below:

screenshot 2018-12-19 at 13 26 32

Without moving borders we'd end with double borders:

screenshot 2018-12-19 at 13 27 06


Please also include changes described in #2219 (comment)

@@ -533,7 +519,7 @@
return;
}

if ( value === '' ) {
if ( value === '' || value == null ) {
Copy link
Member

Choose a reason for hiding this comment

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

It will also remove styles with 0 value, which can lead to bugs (e.g. showing borders that shouldn't be shown).

Copy link
Member Author

Choose a reason for hiding this comment

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

I will remove this change because it's not important for this PR, although I'm curious how could it remove styles with 0 value? In JS 0 == null and '0' == null gives false logical value. I'm using double equal operator here to perform null == undefined coercion.

plugins/pastefromword/filter/default.js Show resolved Hide resolved
@@ -23,6 +23,8 @@
// Snapshots are done manually by editable.insertXXX methods.
canUndo: false,
async: true,
allowedContent: 'table{border-collapse};' +
Copy link
Member

Choose a reason for hiding this comment

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

PFW shouldn't allow any content on its own. Content should be allowed by certain plugins. Such styles should be allowed by table, colorbutton etc.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, I already mentioned it in #2219 (comment), so we agree on this one. However, not sure how far can we go with changing ACF of the table plugin for this feature.

core/tools.js Outdated
* @returns {Number} return.left Left value.
* @member CKEDITOR.tools.style.parse
*/
shorthand: function( value, split ) {
Copy link
Member

Choose a reason for hiding this comment

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

This name is a little bit misleading, because there are several types of shorthands in CSS (e.g. one in border-radius property).

@mlewand
Copy link
Contributor

mlewand commented Jan 10, 2019

Just to add my 2 cents here, I like the proposal added by @Comandeer. Given that we're able to make it work 100% of the time and that it will not cause any side effects it would really improve the pasting experience.

However with this, this PR starts to do too many things™. We should extract this feature proposed by @Comandeer to a separate issue (as it is feature request) and fix the bug here.

core/tools.js Outdated
* @returns {String} return.border-left Border left style.
* @member CKEDITOR.tools.style.parse
*/
splitBorderStyles: function( styles, fallback ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Naming: it's already in style namespace, so there's no reason to call it splitBorderStyles because it would be CKEDITOR.tools.style.parse.splitBorderStyles (note style twice).

CKEDITOR.tools.style.parse.splitBorder is definitely simpler.

@mlewand
Copy link
Contributor

mlewand commented Jan 10, 2019

I have pushed t/1490-oop branch, where I added simplified introduction of BorderStyle. This is a type that I initially wanted to be returned by members like https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_tools_style_parse.html#method-border

But we decided not to add it in order to simplify the code (we didn't need this at this point). Now as there is more than 1 method working on borders it make sense to unify it.

Note that on this branch I didn't expose the type (for sure the types should be exposed, as they're useful).

Also I'd work on simplifying the shorthand interaction. It didn't work well inside splitBorderStyles in terms of API.

I think that BorderStyle type could accept object { size, type, color } instead of positioned arguments, or it could also handle simple array in a predefined order. Just do whatever makes the client-code simpler.

Finally this part is garbage, and should be simplfieid: https://github.com/ckeditor/ckeditor-dev/blob/t/1490-oop/core/tools.js#L1939-L1941 This acutally is related to the API mentioned before.

Anyway this is just a proposal for possible direction. As a result function returns border object that expose border information in a convenient way (just obj.color, obj.style instead of having to parse it over and over). It also stringifies well, so the use case that you're using in this particular ticket.

Note that with this approach there would be a little bit of API trickery - we should use BorderStyle for values returned by style.parse.border which we could change only in major release (but that's fine we'll extract it to a separate task).

@jacekbogdanski
Copy link
Member Author

jacekbogdanski commented Jan 10, 2019

I updated the code with the new BorderStyle type. Not sure if we want to enable _normalizeMap as public API - maybe wait if someone ask for it?

@mlewand The issue for this PR is labeled feature and is targetted into major, although you set the milestone to 4.11.13 - is milestone valid? I see a little problem with the minor release - CKEDITOR.tools.style.parse.border -> BorderStyle return type is required for this feature, so windowtext is correctly updated into black when using existing cell styles: https://github.com/ckeditor/ckeditor-dev/blob/0ddcf1be883ed121b86eb4838ac75488af1a1c2a/plugins/pastefromword/filter/default.js#L365
It makes it a little harder to update CKEDITOR.tools.style.parse.border as followup task.

TODO Update changelog with:

  • API change: new BorderStyle type
  • API change: CKEDITOR.tools.style.parse.border returns new type
  • Fixed: _findColor ignores windowtext

I will update changelog once we are sure about the API / release version.

@jacekbogdanski
Copy link
Member Author

At the moment BorderStyle._normalize a function is probably overcomplicated and should be inlined inside a constructor. However, I think it makes sense if we want to make normalizeMap public. WDYT?

@Comandeer Comandeer self-assigned this Jan 15, 2019
@Comandeer
Copy link
Member

Rebased onto latest major.

Copy link
Member

@Comandeer Comandeer left a comment

Choose a reason for hiding this comment

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

LGTM!

@Comandeer Comandeer merged commit 10bd7f9 into major Jun 3, 2019
@CKEditorBot CKEditorBot deleted the t/1490 branch June 3, 2019 11:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants