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

Fix for: Pasting inside editor which contains a table after selecting all content is not working #3561

Merged
merged 33 commits into from
Dec 4, 2019

Conversation

Dumluregn
Copy link
Contributor

@Dumluregn Dumluregn commented Oct 9, 2019

What is the purpose of this pull request?

Bugfix

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 is the proposed changelog entry for this pull request?

[#875](https://github.com/ckeditor/ckeditor4/issues/875): Fix for: Pasting inside editor which contains a table with [Table Selection plugin](https://ckeditor.com/cke4/addon/tableselection) after selecting all content is not working.

What changes did you make?

The issue here was caused by the custom pasteListener() for table selection plugin. It overrides the default paste logic by moving selection during paste to the first table cell and ignoring the rest of editor:

// In case of mixed content or non table content just select first cell, and erase content of other selected cells.
// Selection is left in first cell, so that default CKEditor logic puts pasted content in the selection (#520).
if ( !pastedTable ) {
	selectCellContents( tableSel.cells.first );

	// Due to limitations of our undo manager, in case of mixed content
	// cells must be emptied after pasting (#520).
	editor.once( 'afterPaste', function() {
		editor.fire( 'lockSnapshot' );
		tableSel.emptyCells( tableSel.cells.all.slice( 1 ) );
		// Reselecting cells allows to create correct undo snapshot (#763).
		fakeSelectCells( editor, tableSel.cells.all );
		editor.fire( 'unlockSnapshot' );
	} );

	return;
}

To solve this, I added an extra condition for ignoring this custom pasting.

Closes #875.

@f1ames f1ames requested a review from msamsel October 15, 2019 10:14
Copy link
Contributor

@msamsel msamsel left a comment

Choose a reason for hiding this comment

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

Your fix covers only the case where selection boundaries are located directly in the editable. There should be a more generic approach. I'd like to avoid the situation in the near future, where it is necessary to fix a very similar issue, but for content surrounded by div, blockquote, nested in another table, etc.
For example, you can add blockuote plugin to your manual test and check that fix stops working in such case:
Oct-15-2019 14-35-04

You can also improve code style inside pasteListener function, as there is already a modification in this part. I would move all helper function to the beginning or to the end of a function scope, so those won't make extra noise during code reading.

I haven't check tests as there is some space for improvement in the proposed fix itself.

@msamsel msamsel assigned msamsel and unassigned msamsel Oct 15, 2019
@msamsel msamsel assigned msamsel and unassigned msamsel Nov 18, 2019
@msamsel msamsel self-requested a review November 18, 2019 08:43
@msamsel msamsel assigned msamsel and Dumluregn and unassigned msamsel Nov 18, 2019
@Dumluregn
Copy link
Contributor Author

Short summary:

I had some major doubts about explicitly naming table elements in this line, but didn't manage to find any existing abstraction for them 🤔

@Dumluregn Dumluregn assigned msamsel and unassigned Dumluregn Nov 19, 2019
Copy link
Contributor

@msamsel msamsel left a comment

Choose a reason for hiding this comment

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

I noticed one bug, however, I see it was also present in 4.12.1.
When you use delete or backspace the content in table cell remains, however when you paste new content, then the entire table cell is cleared out. I couldn't find any similar issue reported.
Maybe you could make short research if this is somehow related to your fix and link it or report as a new issue. I don't want to spend too much time on it as it looks like an edge case.
Correct:
Nov-20-2019 14-19-31
Wrong:
Nov-20-2019 14-20-26

@Dumluregn
Copy link
Contributor Author

Using rangeContainsTableElement() seems to fix also the bug you mentioned here:
pastingInNestedTable

@Dumluregn Dumluregn requested a review from msamsel November 21, 2019 17:31
@Dumluregn
Copy link
Contributor Author

I had to add one positive early return in isCustomPaste() as tests pasting table into boundary selection had detected bugs.

@msamsel msamsel self-assigned this Nov 27, 2019
Copy link
Contributor

@msamsel msamsel left a comment

Choose a reason for hiding this comment

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

Overall we're closer to the final solution.
Can you also propose the unit tests for cases checked in point 2 and 5? I couldn't find any unit test utilize those and it could be nice to have proper unit tests for them as well.

Comment on lines 876 to 879
// 2. It's a boundary position but with no table pasted.
isBoundaryWithoutTable = ( boundarySelection && !pastedTable );

if ( isBoundaryWithoutTable ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

There are a few places like this one, where are:

  • comment describing what is happening
  • named variable

It's not always necessary, especially for simple conditions, as it duplicates the same information. I would choose one approach and use it here and in further cases.
Situations like this also tend to desynchronize the code, because the condition might be updated without comment modification or variable name remain the same when conditions are modified and new ones are added.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, maybe I indeed created an information overflow here 🤔. As most of the conditions aren't that long, I'd give up creating variables and go with comments before ifs as they have some added value in helping to understand the conditions, while variable names are sometimes unclear.

// cell, part of cell etc.
isCollapsedPartial = selectedCells.length === 1 &&
!isTableElement &&
!boundarySelection;
Copy link
Contributor

Choose a reason for hiding this comment

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

!boundarySelection it seems to be always true, as all the opposite cases when boundarySelection === true was already caught in line 884, point 2.1.

Copy link
Contributor

Choose a reason for hiding this comment

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

However, if you consider my comment to point 2.1, it might be required to remain this check here. It might result that boundarySelection will be able to have different values here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please check out this comment.

// 5. It's single range that does not fully contain table element and is not boundary, e.g. collapsed selection within
// cell, part of cell etc.
isCollapsedPartial = selectedCells.length === 1 &&
!isTableElement &&
Copy link
Contributor

Choose a reason for hiding this comment

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

!isTableElement will be always false, because of cases when !isTableElement === true was already catched in point 3, by earlier if statement.

Copy link
Contributor Author

@Dumluregn Dumluregn Nov 28, 2019

Choose a reason for hiding this comment

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

On one hand it is totally logical, but on the other hand here we explicitly added unrequired parameters to function just to avoid misleading in the future. I'm afraid that if we remove conditions that are unnecessary with current check order above and here, we will lose the information that they are still important and we don't place them just to keep code DRY. We could keep information about omitted conditions in comment, but it won't be save neither as code may desynchronize with comments as you mentioned here. WDYT?

@Dumluregn
Copy link
Contributor Author

Added mentioned tests:

  • test isBoundaryWithoutTable case covers point 2. (btw now it's point 3.)
  • test isCollapsedPartial case covers point 5.

@Dumluregn Dumluregn requested a review from msamsel November 28, 2019 12:15
@msamsel msamsel self-assigned this Nov 29, 2019
Copy link
Contributor

@msamsel msamsel left a comment

Choose a reason for hiding this comment

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

Unfortunately unit test checking collapsed-partial fails. Can you take a look what 's happening?
Screenshot 2019-11-29 at 09 39 24

@Dumluregn
Copy link
Contributor Author

In the course of changing conditions for inCustomPaste() the last one called by me isCollapsedPartial became irrelevant as you noticed here, so I removed it - everything seems to be working fine.

@Dumluregn Dumluregn requested a review from msamsel December 2, 2019 10:16
@f1ames
Copy link
Contributor

f1ames commented Dec 4, 2019

Rebased onto latest master.

Copy link
Contributor

@f1ames f1ames left a comment

Choose a reason for hiding this comment

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

LGTM, good job @Dumluregn and @msamsel 👍 🎉

@f1ames f1ames merged commit a72568f into master Dec 4, 2019
@CKEditorBot CKEditorBot deleted the t/875 branch December 4, 2019 09:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants