Bug 19795 - execCommand FormatBlock creates lots of blockquotes
Summary: execCommand FormatBlock creates lots of blockquotes
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: HTML Editing (show other bugs)
Version: 525.x (Safari 3.1)
Hardware: PC OS X 10.5
: P2 Normal
Assignee: Ryosuke Niwa
URL: http://nick-santos.com/tests/formatbl...
Keywords: GoogleBug, InRadar
Depends on: 46504 46840 47098 47233 47575
Blocks: 44918 47712
  Show dependency treegraph
 
Reported: 2008-06-27 14:22 PDT by Nick Santos
Modified: 2010-10-14 23:04 PDT (History)
6 users (show)

See Also:


Attachments
work in progress (9.26 KB, patch)
2010-09-25 21:41 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff
fixes the bug (27.98 KB, patch)
2010-10-07 19:49 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff
added minor fix to ApplyBlockElementCommand (28.65 KB, patch)
2010-10-08 01:24 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff
fixed moveParagraphWithClones for fast/html/nav-element.html (27.50 KB, patch)
2010-10-13 01:10 PDT, Ryosuke Niwa
darin: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Nick Santos 2008-06-27 14:22:25 PDT
Repro steps:
1) Select a few lines of text in a contentEditable block
2) run document.execCommand('FormatBlock', false, 'blockquote')

Expected:
1 blockquote

Actual:
lots o' blockquotes
Comment 1 Mark Rowe (bdash) 2008-06-27 21:38:44 PDT
<rdar://problem/6041710>
Comment 2 Ryosuke Niwa 2010-09-25 21:41:33 PDT
Created attachment 68840 [details]
work in progress

In this patch, I tried to match the code of FormatBlock as closely as possible to that of IndentOutdentCommand.  As a result much of FormatBlockCommand is rewritten but I think this is a good direction because we can probably share a lot of code between FormatBlockCommand and IndentOutdentCommand.  Now the question is how we share the code.  One option is to extract the shared code and move it to CompositeEditCommand.  Another option is to add a base class for IndentOutdentCommand, FormatBlockCommand, & InsertListCommand that inherits from CompositeEditCommand.  Since these three commands do very similar things, we might find this approach valuable if we wanted to avoid adding specialized functions to CompositeEditCommand.

Darin, Enrica, Ojan, & Tony, any thoughts on this?
Comment 3 Darin Adler 2010-09-27 11:53:05 PDT
(In reply to comment #2)
>  Another option is to add a base class for IndentOutdentCommand, FormatBlockCommand, & InsertListCommand that inherits from CompositeEditCommand. Since these three commands do very similar things, we might find this approach valuable if we wanted to avoid adding specialized functions to CompositeEditCommand.

Either approach sounds fine to me.

If there is some data involved then we definitely would want a new class. If it’s just functions, then I think putting it in CompositeEditCommand is OK for now.
Comment 4 Ryosuke Niwa 2010-09-29 13:19:29 PDT
(In reply to comment #3)
> Either approach sounds fine to me.
> 
> If there is some data involved then we definitely would want a new class. If it’s just functions, then I think putting it in CompositeEditCommand is OK for now.

I don't think there's any data involved (except possibly tagName for FormatBlock) but I'd really like to use virtual functions.  For example, indentIntoBlockquote and indentIntoBlockNode share very similar overall structure but it needs to do slightly different things at two places.  It'll really help to isolate those two logics into helper functions and override them in IndentOutdentCommand and FormatBlockCommand.
Comment 5 Ryosuke Niwa 2010-10-07 19:49:14 PDT
Created attachment 70194 [details]
fixes the bug
Comment 6 Ryosuke Niwa 2010-10-08 01:24:30 PDT
Created attachment 70208 [details]
added minor fix to ApplyBlockElementCommand
Comment 7 Tony Chang 2010-10-12 12:32:51 PDT
Comment on attachment 70208 [details]
added minor fix to ApplyBlockElementCommand

View in context: https://bugs.webkit.org/attachment.cgi?id=70208&action=review

Some questions to help my understanding of this code.

> WebCore/editing/FormatBlockCommand.h:41
> +    static bool isElementToApplyInFormatBlockCommand(const QualifiedName& tagName);

Is this part of FormatBlockCommand because you want to merge it with the code in Editor.cpp?  Seems like it could just be in the cpp file.

> WebCore/editing/FormatBlockCommand.h:47
> +    Node* enclosingBlockToSplitTreeTo(Node* startNode) const;

This method also seems like it could be static and fully in the cpp file.

> LayoutTests/editing/execCommand/format-block-multiple-paragraphs-expected.txt:64
> +| <div>
> +|   <p>
> +|     "<#selection-anchor>hello"
> +|     <br>
> +|     "world<#selection-focus>"

Why doesn't <p> replace the <div> in this case?

> LayoutTests/editing/execCommand/format-block-multiple-paragraphs-expected.txt:180
> +|   <br>
> +|   "worl<#selection-focus>d"

This looks like it's off by a letter.  Maybe just file a bug for this case since it's <pre>.

> LayoutTests/editing/execCommand/format-block-multiple-paragraphs-expected.txt:202
> +| <div>
> +|   contenteditable=""
> +|   id="test9"
> +|   "

Did you mean to include all this in this test?

> LayoutTests/editing/execCommand/format-block-multiple-paragraphs-expected.txt:339
> +|   <ul>
> +|     <li>
> +|       "<#selection-anchor>hello"
> +|   <ul>

The merging of these ul seems like something we can try to fix in a follow up change.
Comment 8 Ryosuke Niwa 2010-10-12 12:44:44 PDT
Thanks for the review!

(In reply to comment #7)
> > WebCore/editing/FormatBlockCommand.h:41
> > +    static bool isElementToApplyInFormatBlockCommand(const QualifiedName& tagName);
> 
> Is this part of FormatBlockCommand because you want to merge it with the code in Editor.cpp?  Seems like it could just be in the cpp file.

No, this is called in WebCore/editing/EditorCommand.cpp where we invoke FormatBlockCommand.

> > WebCore/editing/FormatBlockCommand.h:47
> > +    Node* enclosingBlockToSplitTreeTo(Node* startNode) const;
> 
> This method also seems like it could be static and fully in the cpp file.

Sure.  I could do that.

> > LayoutTests/editing/execCommand/format-block-multiple-paragraphs-expected.txt:64
> > +| <div>
> > +|   <p>
> > +|     "<#selection-anchor>hello"
> > +|     <br>
> > +|     "world<#selection-focus>"
> 
> Why doesn't <p> replace the <div> in this case?

We should.  But we can't do that right now because we can't figure out whether or not div is fully selected.

> > LayoutTests/editing/execCommand/format-block-multiple-paragraphs-expected.txt:180
> > +|   <br>
> > +|   "worl<#selection-focus>d"
> 
> This looks like it's off by a letter.  Maybe just file a bug for this case since it's <pre>.

I suspect that it's a bug in text iterator.

> > LayoutTests/editing/execCommand/format-block-multiple-paragraphs-expected.txt:202
> > +| <div>
> > +|   contenteditable=""
> > +|   id="test9"
> > +|   "
> 
> Did you mean to include all this in this test?

No. Will fix.

> > LayoutTests/editing/execCommand/format-block-multiple-paragraphs-expected.txt:339
> > +|   <ul>
> > +|     <li>
> > +|       "<#selection-anchor>hello"
> > +|   <ul>
> 
> The merging of these ul seems like something we can try to fix in a follow up change.

Yes, I'm intending to fix a bunch of bugs like that in the bug 44918.  In this patch, I wanted to preserve the existing behavior as much as possible since I'm basically rewriting the entire function.
Comment 9 Ryosuke Niwa 2010-10-12 23:01:37 PDT
Committed r69639: <http://trac.webkit.org/changeset/69639>
Comment 10 Ryosuke Niwa 2010-10-13 01:10:26 PDT
Created attachment 70586 [details]
fixed moveParagraphWithClones for fast/html/nav-element.html
Comment 11 Ryosuke Niwa 2010-10-13 01:11:33 PDT
(In reply to comment #9)
> Committed r69639: <http://trac.webkit.org/changeset/69639>

It turned out that this broke fast/html/nav-element.html because moveParagraphWithClones adds extra br.  My new patch fixes this problem as well.
Comment 12 Ryosuke Niwa 2010-10-13 01:12:25 PDT
Reopening the bug since the first commit has been rolled out.
Comment 13 Darin Adler 2010-10-13 09:55:17 PDT
Comment on attachment 70586 [details]
fixed moveParagraphWithClones for fast/html/nav-element.html

View in context: https://bugs.webkit.org/attachment.cgi?id=70586&action=review

> WebCore/editing/EditorCommand.cpp:445
> +    if (!FormatBlockCommand::isElementToApplyInFormatBlockCommand(qualifiedTagName))
> +        return false;
> +
>      applyCommand(FormatBlockCommand::create(frame->document(), qualifiedTagName));

If I was doing this, I would have put this logic into FormatBlockCommand::create and had it return 0 if it’s an element it should not apply to. That seems easier to use than a separate function you have to know to call.

> WebCore/editing/FormatBlockCommand.cpp:78
> +// FIXME: We should consider mering this function with isElementForFormatBlockCommand in Editor.cpp

Typo: "mering".

> WebCore/editing/FormatBlockCommand.h:41
> +    static bool isElementToApplyInFormatBlockCommand(const QualifiedName& tagName);

I don’t understand the phrase “element to apply in command”. What does that mean?
Comment 14 Ryosuke Niwa 2010-10-13 11:27:24 PDT
(In reply to comment #13)
> > WebCore/editing/EditorCommand.cpp:445
> > +    if (!FormatBlockCommand::isElementToApplyInFormatBlockCommand(qualifiedTagName))
> > +        return false;
> > +
> >      applyCommand(FormatBlockCommand::create(frame->document(), qualifiedTagName));
> 
> If I was doing this, I would have put this logic into FormatBlockCommand::create and had it return 0 if it’s an element it should not apply to. That seems easier to use than a separate function you have to know to call.

I like that design better too.  I was considering to do it in this patch as well but then this patch was already pretty big so I avoided it.  I'll probably do that when I merge isElementToApplyInFormatBlockCommand and isElementForFormatBlockCommand.

> > WebCore/editing/FormatBlockCommand.cpp:78
> > +// FIXME: We should consider mering this function with isElementForFormatBlockCommand in Editor.cpp
> 
> Typo: "mering".

Thanks.  Will fix.

> > WebCore/editing/FormatBlockCommand.h:41
> > +    static bool isElementToApplyInFormatBlockCommand(const QualifiedName& tagName);
> 
> I don’t understand the phrase “element to apply in command”. What does that mean?

We're checking whether or not an element can be applied using format block command or whether or not the element should be replaced by new element.  I think isElementForFormatBlockCommand is a better name but I didn't want to use the same name.  I'll merge this function with isElementForFormatBlockCommand so this function should be gone in no time.
Comment 15 Ryosuke Niwa 2010-10-14 21:10:04 PDT
Committed r69836: <http://trac.webkit.org/changeset/69836>