Bug 30836 - Creating a link when selecting multiple nodes creates multiple links
Summary: Creating a link when selecting multiple nodes creates multiple links
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: HTML Editing (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Ryosuke Niwa
URL: http://www.mozilla.org/editor/midasdemo/
Keywords: GoogleBug
Depends on:
Blocks:
 
Reported: 2009-10-27 14:52 PDT by Marcos Almeida
Modified: 2010-08-25 14:15 PDT (History)
5 users (show)

See Also:


Attachments
initial patch (31.75 KB, patch)
2010-08-24 18:55 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff
fixed per Tony's comment (34.75 KB, patch)
2010-08-25 13:33 PDT, Ryosuke Niwa
tony: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Marcos Almeida 2009-10-27 14:52:44 PDT
1. Go to http://www.mozilla.org/editor/midasdemo/
2. type "abc"
3. select "b" and press the italic button on the second toolbar
4. press ctrl-a to select all
5. press the create link button (the globe icon with a chain link, on the first toolbar)
6. type abc in the dialog that pops up and press ok
7. click the "view html source" checkbox at the bottom to see the generated html

Expected:
<a href="abc">a<i>b</i>c</a>

Actual:
<a href="abc">a</a><i><a href="abc">b</a></i><a href="abc">c</a>


This affects Google properties.
Comment 2 Ryosuke Niwa 2010-08-24 18:55:11 PDT
Created attachment 65356 [details]
initial patch
Comment 3 Tony Chang 2010-08-25 12:12:28 PDT
Comment on attachment 65356 [details]
initial patch

> Index: WebCore/editing/ApplyStyleCommand.cpp
> +    bool operator==(const StyleChange& other)
> +    {
> +        return m_cssStyle == other.m_cssStyle

I am worried that this will regress someday when someone adds a new member, but I don't have a good suggestion on how to avoid this.

> -            while (sibling && sibling != pastEndNode && (!sibling->isElementNode() || sibling->hasTagName(brTag)) && !isBlock(sibling)) {
> +            StyleChange startChange(style, Position(node, 0));
> +            while (sibling && sibling != pastEndNode && !sibling->contains(pastEndNode)) {
> +                if (isBlock(sibling) && !sibling->hasTagName(brTag))
> +                    break;
> +                if (StyleChange(style, Position(sibling, 0)) != startChange)
> +                    break;

Was there a reason to move conditions into separate if statements?  Seems like these could be merged with the while condition.

> +        RefPtr<StyledElement> styledElement;
> +        if (current->isStyledElement() && m_styledInlineElement && current->hasTagName(m_styledInlineElement->tagQName()))
> +            styledElement = static_cast<StyledElement*>(current);

Does |styledElement| need to be a RefPtr?


> Index: WebCore/editing/ApplyStyleCommand.h
> -    void addInlineStyleIfNeeded(CSSMutableStyleDeclaration*, Node* start, Node* end);
> +    void addInlineStyleIfNeeded(CSSMutableStyleDeclaration*, Node* start, Node* end, bool shouldAddStyledElement = true);

Can we use an enum instead of a bool?


Can you also add a test for anchors with inline styles.
Comment 4 Ryosuke Niwa 2010-08-25 13:33:28 PDT
Created attachment 65469 [details]
fixed per Tony's comment
Comment 5 Ryosuke Niwa 2010-08-25 13:34:45 PDT
(In reply to comment #3)
> (From update of attachment 65356 [details])
> > Index: WebCore/editing/ApplyStyleCommand.cpp
> > +    bool operator==(const StyleChange& other)
> > +    {
> > +        return m_cssStyle == other.m_cssStyle
> 
> I am worried that this will regress someday when someone adds a new member, but I don't have a good suggestion on how to avoid this.

I know.  I spent some time thinking about it but couldn't come up with a better way either.

> > -            while (sibling && sibling != pastEndNode && (!sibling->isElementNode() || sibling->hasTagName(brTag)) && !isBlock(sibling)) {
> > +            StyleChange startChange(style, Position(node, 0));
> > +            while (sibling && sibling != pastEndNode && !sibling->contains(pastEndNode)) {
> > +                if (isBlock(sibling) && !sibling->hasTagName(brTag))
> > +                    break;
> > +                if (StyleChange(style, Position(sibling, 0)) != startChange)
> > +                    break;
> 
> Was there a reason to move conditions into separate if statements?  Seems like these could be merged with the while condition.

Merged.

> > +        RefPtr<StyledElement> styledElement;
> > +        if (current->isStyledElement() && m_styledInlineElement && current->hasTagName(m_styledInlineElement->tagQName()))
> > +            styledElement = static_cast<StyledElement*>(current);
> 
> Does |styledElement| need to be a RefPtr?

Yes, because extractInlineStyleToPushDown may remove "current" in which case it may be destroyed if we didn't kept a pointer.

> > Index: WebCore/editing/ApplyStyleCommand.h
> > -    void addInlineStyleIfNeeded(CSSMutableStyleDeclaration*, Node* start, Node* end);
> > +    void addInlineStyleIfNeeded(CSSMutableStyleDeclaration*, Node* start, Node* end, bool shouldAddStyledElement = true);
> 
> Can we use an enum instead of a bool?

Fixed.

> Can you also add a test for anchors with inline styles.

Good thing we talked about this.  There were a couple of bugs revealed by new test cases.
Comment 6 Ryosuke Niwa 2010-08-25 14:15:47 PDT
Committed r66040: <http://trac.webkit.org/changeset/66040>