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

The link rel attribute should be handled as a token list to allow mixing manual link decorators for the same attribute #17461

Open
wants to merge 54 commits into
base: master
Choose a base branch
from

Conversation

niegowski
Copy link
Contributor

@niegowski niegowski commented Nov 14, 2024

Suggested merge commit message (convention)

Fix (engine): The link rel attribute will now allow mixing manual link decorators for the same attribute, as it will be now handled as a token list. Closes #13985, closes #6436.

Fix (mention): Mention should not be wrapped with an additional <span> when GHS is enabled. Closes #15329.

Internal (html-support): Attribute matching updated to the new output of Matcher#matchAll().

MINOR BREAKING CHANGE (engine): The ViewConsumable.consumablesFromElement() is removed and replaced with view.Element#_getConsumables() internal method. You should use ViewConsumable.createFrom() To create consumables if needed.

MINOR BREAKING CHANGE (engine): The ViewElementConsumables now accepts and outputs only normalized data. The ViewConsumable still accepts normalized or non-normalized input.

MINOR BREAKING CHANGE (engine): The Matcher#match() and Matcher#matchAll() output is now normalized. The MatchResult#match now contains normalized data compatible with changes in the ViewConsumable.


Additional information

For example – encountered issues, assumptions you had to make, other affected tickets, etc.

…of attributes like class, style, rel or plain attribute.
@niegowski niegowski marked this pull request as ready for review December 17, 2024 14:33
@Witoso
Copy link
Member

Witoso commented Dec 17, 2024

@niegowski added closes #6436 as I think we mentioned it fixes this one as well.

@Witoso
Copy link
Member

Witoso commented Dec 17, 2024

Before merging, let's discuss the release strategy, if it's coupled or not with linking experience.

Copy link
Contributor

@scofalik scofalik 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 for me to approach this PR from top-level point of view and decide whether it is the best way to do it, but in overall, it makes sense and looks good. I rather focused on particular bits of code and possible logical/algorithmical/typo errors.

My two questions marks are:

  1. I am not sure if it was a good decision to move some of the code to view elements. I mean generating consumables and merging elements. I don't know what was the reason to move it (e.g. if multiple parts of the code wanted to perform the same logic and view element was the best to keep it). If you decide that this is a must have, I'd recommend taking care to see if all related elements are moved. In one place I commented that it is weird that view element imports a type from conversion. I had such feeling a few times. Right now I am not convinced that moving code to view elements was a necessary change, but I don't have the holistic view on this PR/improvement, you spent more time on it.
  2. Performance. Could you confirm that the performance does not drop, especially for samples where there is a lot of merging and unwrapping of view attribute elements (formattingLongPs, inlineStyles, wiki, ghs from the recently introduced performance tests).

packages/ckeditor5-engine/src/conversion/viewconsumable.ts Outdated Show resolved Hide resolved
Comment on lines 81 to 84
public add(
element: Element,
consumables: Consumables
element: Text | Element | DocumentFragment,
consumables?: Consumables | NormalizedConsumables
): void;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to keep this if this is the only way to use this method?

@@ -250,7 +239,7 @@ export default class ViewConsumable {
* @param consumables.classes Class name or array of class names.
* @param consumables.styles Style name or array of style names.
*/
public revert( element: Node, consumables: Consumables ): void {
public revert( element: Node, consumables: Consumables | Match ): void {
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't you want to add an example with Match as the second parameter to the API docs?

}

if ( from.is( 'documentFragment' ) ) {
else if ( from.is( 'element' ) || from.is( 'documentFragment' ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove new line before }

Copy link
Contributor

Choose a reason for hiding this comment

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

BTW, we test from to be text, element and document fragment. What else it could be (there is no else branch, but I guess there's coverage for it)? Text proxy? Isn't this $text?

for ( const child of ( from as Element | DocumentFragment ).getChildren() ) {
instance = ViewConsumable.createFrom( child, instance );
for ( const child of from.getChildren() ) {
instance = ViewConsumable.createFrom( child, instance );
Copy link
Contributor

Choose a reason for hiding this comment

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

The assignment here seems unnecessary and is confusing.

/**
* Used by the {@link module:engine/view/matcher~Matcher Matcher} to collect matching attribute tuples
* (attribute name and optional token).
*
Copy link
Contributor

Choose a reason for hiding this comment

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

AFAICS, this is a replacement for the old matchPatterns function which was earlier in Matcher.

The old function had a very extensive API docs, while this one explains nothing about the method. I have no idea what this will return and how it will behave in different conditions. I can only read the source code, but during the review, I have no idea what is the expected outcome.

Please add more explanation and examples.

Copy link
Contributor

Choose a reason for hiding this comment

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

Like, the description says that it collects something, but it returns boolean

And, reading the code, it seems that it can populate the match array a bit, but then return false anyway. Am I supposed to always pass empty match array, or is it supposed to be used throughout several calls?But if so, then partial-population seems to be a bug.

I understand that we have to consider 1) old existing code that uses it; 2) performance; but it would be great to straighten this up. Also, I'd like to avoid passing match array to be populated, if possible. Can't we return null | Array?

packages/ckeditor5-engine/src/view/element.ts Outdated Show resolved Hide resolved
* @returns Returns `true` if elements are merged.
*/
public _mergeAttributesFrom( otherElement: Element ): boolean {
if ( !this._canMergeAttributesFrom( otherElement ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Following what I wrote in DowncastWriter. I think that _mergeAttributesFrom() should not make this check, instead, writer could do it. This will not result in extra performance overhead and will simplify code in writer.

this._setAttribute( key, otherValue );
}
else {
value._mergeFrom( otherValue );
Copy link
Contributor

Choose a reason for hiding this comment

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

Not necessarily needs to fix it, but can't we use setAttribute with reset set to false? Isn't it the same? 🤔

Comment on lines +1057 to +1058
value instanceof StylesMap ? value._clone() :
new StylesMap( this.document.stylesProcessor ).setTo( String( value ) )
Copy link
Contributor

Choose a reason for hiding this comment

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

These two lines look complicated, please simplify.

Copy link
Contributor

Choose a reason for hiding this comment

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

Same below.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants