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

Provide support for pasting lists from google docs #72

Merged
merged 35 commits into from
Aug 5, 2019
Merged

Provide support for pasting lists from google docs #72

merged 35 commits into from
Aug 5, 2019

Conversation

msamsel
Copy link
Contributor

@msamsel msamsel commented Jul 30, 2019

Suggested merge commit message (convention)

Feature: Provide support for pasting lists from Google Docs. Closes ckeditor/ckeditor5#2499 .


Additional information

When you copy-paste content from Safari, sometimes there is nothing to recognize that content cames from Google Docs. For example, try to copy-paste content from table.
That's why I create generic normalizer, which is applied if no other normalizer was run.
I saw 2 options here, either allow on multiple normalizers to run over the content or create a normalizer which will be executed if no other is found. I decide for the second option to not complicate code too much and have sure that only one normalizer will modify the data.content.

@coveralls
Copy link

coveralls commented Jul 30, 2019

Pull Request Test Coverage Report for Build 271

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 100.0%

Totals Coverage Status
Change from base Build 252: 0.0%
Covered Lines: 208
Relevant Lines: 208

💛 - Coveralls

@msamsel msamsel requested a review from Mgsy July 30, 2019 10:02
@msamsel
Copy link
Contributor Author

msamsel commented Jul 30, 2019

@Mgsy can you take a look for it? I copy-paste some general content and seems to work fine. However, maybe there is some strange browser or content structure, which might not be converted to lists properly.

@mlewand mlewand requested a review from jodator July 30, 2019 12:27
… properly recognized byt other normalizers. What can happen for partial copy-paste from Safari.
@Mgsy
Copy link
Member

Mgsy commented Jul 30, 2019

It crashes if a pasted list item is indented more than once.

Uncaught TypeError: Cannot read property 'childCount' of null
    at moveNestedListToListItem (common.js:48)
    at moveNestedListToListItem (common.js:52)
    at moveNestedListToListItem (common.js:52)
    at GoogleDocsNormalizer.execute (googledocsnormalizer.js:36)
    at Clipboard.editor.plugins.get.on.priority (pastefromoffice.js:69)
    at Clipboard.fire (emittermixin.js:207)
    at Document.listenTo.priority (clipboard.js:78)
    at Document.fire (emittermixin.js:207)
    at Document.handleInput (clipboardobserver.js:51)
    at Document.fire (emittermixin.js:207)

bug_cke5

Clipboard HTML:

<html>
<body>
<!--StartFragment--><meta charset="utf-8"><b style="font-weight:normal;" id="docs-internal-guid-51600ef9-7fff-81d2-c69b-dfa6f7e8dedc"><ol style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:decimal;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;margin-left: 36pt;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">Test</span></p></li><ol style="margin-top:0pt;margin-bottom:0pt;"><ol style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:lower-roman;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;margin-left: 36pt;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">test</span></p></li></ol></ol></ol></b><!--EndFragment-->
</body>
</html>

@msamsel
Copy link
Contributor Author

msamsel commented Jul 30, 2019

It crashes if a pasted list item is indented more than once.

OMG why they even allow on such a strange structure 😱. What is worse, that CKEditor doesn't support such a structure. And we could either remove those extra indentions or remove entire node with all children below :(

@Mgsy
Copy link
Member

Mgsy commented Jul 30, 2019

What is worse, that CKEditor doesn't support such a structure. And we could either remove those extra indentions or remove entire node with all children below :(

The same problem occurs for Word, actually, in this PR you'll find two proposals how to solve this issue - #53. We agreed that this kind of structures should be normalized.

@msamsel
Copy link
Contributor Author

msamsel commented Jul 30, 2019

I wonder about the normalization process in some specific situation:
image
This content has the following structure:

<ol>
    <li>A1</li>
    <ol>
        <ol>
            <ol>
                <li>B4</li>
            </ol>
            <li>C3</li>
            <ol>
                <li>D4</li>
            </ol>
        </ol>
        <li>E2</li>
    </ol>
</ol>

Element A1 possesses 2 wrong elements: B4 and C3.
D4 - is a child of C3 and E2 is a child of A1.

From the first look on task: #53 (comment) proposed normalization moves element B4 as a child of A1. However, it also ⚠️ makes element C3 a child of B4 ⚠️.
So the structure after normalization would look like:
image

Elements B4 and C3 are positioned incorrectly then both should become siblings and should be located as children of A1. So the correct structure should look like:
image

@Reinmar, @Mgsy WDYT?

// cc @scofalik last time you were not asked about your opinion. I won't repeat that mistake! WDYT? :trollface:

@msamsel
Copy link
Contributor Author

msamsel commented Jul 31, 2019

I've implemented the 2nd approach, which seems to be less time-consuming.
So right now if there is a nested list then might be 2 options:

  1. If it has a preceding list item sibling, then given list became a nested list inside the previous list item.
  2. If the first child of the list is another list, then the nested list is unwrapped. So all children of the nested list became children of the current list.

@jodator
Copy link
Contributor

jodator commented Jul 31, 2019

The normalization seems to look OK :) Probably @Mgsy could verify that. I can see that if user paste sub-list (ckeditor/ckeditor5#1930) nothing gets pasted.

Error in the console:

common.js:62 Uncaught TypeError: Cannot read property 'childCount' of null
    at moveNestedListToListItem (common.js:62)
    at moveNestedListToListItem (common.js:74)
    at GoogleDocsNormalizer.execute (googledocsnormalizer.js:36)
    at Clipboard.editor.plugins.get.on.priority (pastefromoffice.js:69)
    at Clipboard.fire (emittermixin.js:207)
    at Document.listenTo.priority (clipboard.js:78)
    at Document.fire (emittermixin.js:207)
    at Document.handleInput (clipboardobserver.js:51)
    at Document.fire (emittermixin.js:207)
    at ClipboardObserver.fire (domeventobserver.js:96)

pasted content:

<meta http-equiv="content-type" content="text/html; charset=utf-8"><meta charset="utf-8"><ul style="margin-top:0pt;margin-bottom:0pt;" id="docs-internal-guid-8a672c83-7fff-1b35-788b-9afb3dcf7487"><ul style="margin-top:0pt;margin-bottom:0pt;"><ul style="margin-top:0pt;margin-bottom:0pt;"><ul style="margin-top:0pt;margin-bottom:0pt;"><ul style="margin-top:0pt;margin-bottom:0pt;"><ul style="margin-top:0pt;margin-bottom:0pt;"><ul style="margin-top:0pt;margin-bottom:0pt;"><li dir="ltr" style="list-style-type:disc;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">E</span></p></li></ul></ul><li dir="ltr" style="list-style-type:circle;font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;"><p dir="ltr" style="line-height:1.38;margin-top:0pt;margin-bottom:0pt;"><span style="font-size:11pt;font-family:Arial;color:#000000;background-color:transparent;font-weight:400;font-style:normal;font-variant:normal;text-decoration:none;vertical-align:baseline;white-space:pre;white-space:pre-wrap;">F</span></p></li></ul></ul></ul></ul></ul>

@jodator jodator closed this Jul 31, 2019
@jodator jodator reopened this Jul 31, 2019
@msamsel
Copy link
Contributor Author

msamsel commented Jul 31, 2019

@jodator When I create normalize I wondered if a situation like this might happen. I couldn't find a way to generate content which has nested tags from the beginning :D. And now I see it's much easier than I thought ;)

@jodator
Copy link
Contributor

jodator commented Aug 1, 2019

You can find more details about why this normalizer was introduced in "Additional information" section of PR.

Oh sorry I've missed that - so remove the ifs ATM as in my comments there. We decide what to do with this problem later.

Copy link
Contributor

@jodator jodator left a comment

Choose a reason for hiding this comment

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

Almost there ;) Some minor docs improvements, extract unwrapping element to the engine's UpcastWriter and the Safari case is still on my mind as I would try to make things as specific as possible.

src/filters/list.js Outdated Show resolved Hide resolved
src/filters/list.js Outdated Show resolved Hide resolved
src/filters/list.js Outdated Show resolved Hide resolved
src/filters/list.js Outdated Show resolved Hide resolved
src/filters/list.js Outdated Show resolved Hide resolved
src/filters/list.js Outdated Show resolved Hide resolved
src/filters/list.js Outdated Show resolved Hide resolved
src/filters/list.js Outdated Show resolved Hide resolved
src/filters/list.js Outdated Show resolved Hide resolved
*
* @implements module:paste-from-office/normalizer~Normalizer
*/
export default class GenericNormalizer {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does it happen only on Safari? If so I'd still ad some env checking to be sure that this normalizer doesn't fire up too often. @mlewand WDYT? OTOH this normalizer will always fix pasted lists (even from other sources) so it may be beneficial.

I see two routes:

  1. Make it run only for Safari and name it more specific, like: SafariListNormalizer
  2. Make it general list fixer - the I'd name it NestedListNormalizer and maybe add a check if pasted content has broken list (AFAICS ul></ul, /p></li and /li><ul could be checked - with ul|ol variants check) - but the check idea is something to give another though if it makes sense.

@msamsel msamsel requested a review from jodator August 2, 2019 14:00
Copy link
Contributor

@jodator jodator left a comment

Choose a reason for hiding this comment

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

I've added small changes to the list.js file:

  • some re-organization (exported methods should be on top).
  • last list example was misaligned with the other two

@jodator jodator merged commit 6ad2a62 into master Aug 5, 2019
@jodator jodator deleted the t/69 branch August 5, 2019 12:58
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.

[PFGD] Add support for pasting lists from google docs
5 participants