2010-09-29 Ryosuke Niwa <rniwa@webkit.org>
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Sep 2010 18:44:02 +0000 (18:44 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Sep 2010 18:44:02 +0000 (18:44 +0000)
        Reviewed by Darin Adler.

        queryCommandValue "formatBlock" always returns false
        https://bugs.webkit.org/show_bug.cgi?id=21305

        Implemented queryCommandValue('formatBlock'). We match the Firefox's behavior exactly
        because Firefox and Internet Explorer support the same set of elements
        (address, h1, h2, h3, h4, h5, h6, and p) and Firefox's behavior is more compatible with Opera.
        See the bug for the detailed discussion.

        WebKit's implementation returns the local name of the lowest common ancestor
        of the selection with the tag name address, h1, h2, h3, h4, h5, h6, or p.
        It returns "" when there is no such an ancestor or there is no selection.

        Test: editing/execCommand/query-format-block.html

        * editing/Editor.cpp:
        (WebCore::isElementForFormatBlockCommand):
        (WebCore::Editor::elementForFormatBlockCommand):
        * editing/Editor.h:
        * editing/EditorCommand.cpp:
        (WebCore::valueFormatBlock):
        (WebCore::createCommandMap):
2010-09-29  Ryosuke Niwa  <rniwa@webkit.org>

        Reviewed by Darin Adler.

        queryCommandValue "formatBlock" always returns false
        https://bugs.webkit.org/show_bug.cgi?id=21305

        Added a test for queryCommandValue('formatBlock').

        * editing/execCommand/query-format-block-expected.txt: Added.
        * editing/execCommand/query-format-block.html: Added.
        * editing/execCommand/script-tests/query-format-block.js: Added.
        (queryFormatBlock):
        (selectFirstPosition):
        (selectMiddleOfHelloWorld):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@68670 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/editing/execCommand/query-format-block-expected.txt [new file with mode: 0644]
LayoutTests/editing/execCommand/query-format-block.html [new file with mode: 0644]
LayoutTests/editing/execCommand/script-tests/query-format-block.js [new file with mode: 0644]
WebCore/ChangeLog
WebCore/editing/Editor.cpp
WebCore/editing/Editor.h
WebCore/editing/EditorCommand.cpp

index f81e1ac..8cfc630 100644 (file)
@@ -1,3 +1,19 @@
+2010-09-29  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Reviewed by Darin Adler.
+
+        queryCommandValue "formatBlock" always returns false
+        https://bugs.webkit.org/show_bug.cgi?id=21305
+
+        Added a test for queryCommandValue('formatBlock').
+
+        * editing/execCommand/query-format-block-expected.txt: Added.
+        * editing/execCommand/query-format-block.html: Added.
+        * editing/execCommand/script-tests/query-format-block.js: Added.
+        (queryFormatBlock):
+        (selectFirstPosition):
+        (selectMiddleOfHelloWorld):
+
 2010-09-29  Martin Robinson  <mrobinson@igalia.com>
 
         Reviewed by Chris Fleizach.
diff --git a/LayoutTests/editing/execCommand/query-format-block-expected.txt b/LayoutTests/editing/execCommand/query-format-block-expected.txt
new file mode 100644 (file)
index 0000000..ffc96d8
--- /dev/null
@@ -0,0 +1,29 @@
+Tests queryCommandValue('formatBlock')
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Basic cases
+PASS queryCommand('format') returned ""
+PASS queryCommand('format') returned ""
+PASS queryCommand('format') returned "address"
+PASS queryCommand('format') returned "h1"
+PASS queryCommand('format') returned "h2"
+PASS queryCommand('format') returned "h3"
+PASS queryCommand('format') returned "h4"
+PASS queryCommand('format') returned "h5"
+PASS queryCommand('format') returned "h6"
+PASS queryCommand('format') returned "p"
+PASS queryCommand('format') returned "pre"
+
+Nested cases
+PASS queryCommand('format') returned "h2"
+PASS queryCommand('format') returned "address"
+PASS queryCommand('format') returned "pre"
+PASS queryCommand('format') returned "pre"
+PASS queryCommand('format') returned "address"
+PASS queryCommand('format') returned ""
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/execCommand/query-format-block.html b/LayoutTests/editing/execCommand/query-format-block.html
new file mode 100644 (file)
index 0000000..15d1c1b
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="script-tests/query-format-block.js"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/editing/execCommand/script-tests/query-format-block.js b/LayoutTests/editing/execCommand/script-tests/query-format-block.js
new file mode 100644 (file)
index 0000000..4e84caf
--- /dev/null
@@ -0,0 +1,58 @@
+description("Tests queryCommandValue('formatBlock')")
+
+var testContainer = document.createElement("div");
+testContainer.contentEditable = true;
+document.body.appendChild(testContainer);
+
+function queryFormatBlock(selector, content, expected)
+{
+    testContainer.innerHTML = content;
+    selector(testContainer);
+    var actual = document.queryCommandValue('formatBlock');
+    var action = "queryCommand('format') returned \"" + actual + '"';
+    if (actual == expected)
+        testPassed(action);
+    else
+        testFailed(action + ' but expected "' + expected + '"');
+}
+
+function selectFirstPosition(container) {
+    while (container.firstChild)
+        container = container.firstChild;
+    window.getSelection().setPosition(container, 0);
+}
+
+function selectMiddleOfHelloWorld(container) {
+    window.getSelection().setPosition(container, 0);
+    window.getSelection().modify('move', 'forward', 'character');
+    window.getSelection().modify('move', 'forward', 'character');
+    window.getSelection().modify('extend', 'forward', 'word');
+    window.getSelection().modify('extend', 'forward', 'character');
+    window.getSelection().modify('extend', 'forward', 'character');
+    window.getSelection().modify('extend', 'forward', 'character');
+}
+
+debug('Basic cases');
+queryFormatBlock(function () {}, 'hello', '');
+queryFormatBlock(selectFirstPosition, 'hello', '');
+queryFormatBlock(selectFirstPosition, '<address>hello</address>', 'address');
+queryFormatBlock(selectFirstPosition, '<h1>hello</h1>', 'h1');
+queryFormatBlock(selectFirstPosition, '<h2>hello</h2>', 'h2');
+queryFormatBlock(selectFirstPosition, '<h3>hello</h3>', 'h3');
+queryFormatBlock(selectFirstPosition, '<h4>hello</h4>', 'h4');
+queryFormatBlock(selectFirstPosition, '<h5>hello</h5>', 'h5');
+queryFormatBlock(selectFirstPosition, '<h6>hello</h6>', 'h6');
+queryFormatBlock(selectFirstPosition, '<p>hello</p>', 'p');
+queryFormatBlock(selectFirstPosition, '<pre>hello</pre>', 'pre');
+
+debug('');
+debug('Nested cases');
+queryFormatBlock(selectFirstPosition, '<h1><h2>hello</h2></h1>', 'h2');
+queryFormatBlock(selectFirstPosition, '<h1><address>hello</address></h1>', 'address');
+queryFormatBlock(selectFirstPosition, '<pre>hello<p>world</p></pre>', 'pre');
+queryFormatBlock(selectMiddleOfHelloWorld, '<pre>hello<p>world</p></pre>', 'pre');
+queryFormatBlock(selectMiddleOfHelloWorld, '<address><h1>hello</h1>world</address>', 'address');
+queryFormatBlock(selectMiddleOfHelloWorld, '<h1>hello</h1>world', '');
+
+document.body.removeChild(testContainer);
+var successfullyParsed = true;
index 8ff170c..f4be967 100644 (file)
@@ -1,3 +1,29 @@
+2010-09-29  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Reviewed by Darin Adler.
+
+        queryCommandValue "formatBlock" always returns false
+        https://bugs.webkit.org/show_bug.cgi?id=21305
+
+        Implemented queryCommandValue('formatBlock'). We match the Firefox's behavior exactly
+        because Firefox and Internet Explorer support the same set of elements
+        (address, h1, h2, h3, h4, h5, h6, and p) and Firefox's behavior is more compatible with Opera.
+        See the bug for the detailed discussion.
+
+        WebKit's implementation returns the local name of the lowest common ancestor
+        of the selection with the tag name address, h1, h2, h3, h4, h5, h6, or p.
+        It returns "" when there is no such an ancestor or there is no selection.
+
+        Test: editing/execCommand/query-format-block.html
+
+        * editing/Editor.cpp:
+        (WebCore::isElementForFormatBlockCommand):
+        (WebCore::Editor::elementForFormatBlockCommand):
+        * editing/Editor.h:
+        * editing/EditorCommand.cpp:
+        (WebCore::valueFormatBlock):
+        (WebCore::createCommandMap):
+
 2010-09-29  Matt Perry  <mpcomplete@chromium.org>
 
         Reviewed by Darin Fisher.
index b267637..69ba7f4 100644 (file)
@@ -966,6 +966,37 @@ String Editor::selectionStartCSSPropertyValue(int propertyID)
     return value;
 }
 
+static bool isElementForFormatBlockCommand(const Node* node)
+{
+    return node->hasTagName(addressTag)
+        || node->hasTagName(h1Tag)
+        || node->hasTagName(h2Tag)
+        || node->hasTagName(h3Tag)
+        || node->hasTagName(h4Tag)
+        || node->hasTagName(h5Tag)
+        || node->hasTagName(h6Tag)
+        || node->hasTagName(pTag)
+        || node->hasTagName(preTag);
+}
+
+Element* Editor::elementForFormatBlockCommand() const
+{
+    const VisibleSelection& selection = m_frame->selection()->selection();
+    if (!selection.isNonOrphanedCaretOrRange() || !selection.isContentEditable())
+        return 0;
+
+    ExceptionCode ec;
+    Node* commonAncestor = selection.firstRange()->commonAncestorContainer(ec);
+    while (commonAncestor && !isElementForFormatBlockCommand(commonAncestor))
+        commonAncestor = commonAncestor->parentNode();
+
+    if (!commonAncestor)
+        return 0;
+
+    ASSERT(commonAncestor->isElementNode());
+    return static_cast<Element*>(commonAncestor);
+}
+
 void Editor::indent()
 {
     applyCommand(IndentOutdentCommand::create(m_frame->document(), IndentOutdentCommand::Indent));
index f167b16..99d6fe6 100644 (file)
@@ -125,6 +125,7 @@ public:
 
     TriState selectionHasStyle(CSSStyleDeclaration*) const;
     String selectionStartCSSPropertyValue(int propertyID);
+    Element* elementForFormatBlockCommand() const;
     const SimpleFontData* fontForSelection(bool&) const;
     WritingDirection textDirectionForSelection(bool&) const;
     
index 616c07b..261c015 100644 (file)
@@ -1346,6 +1346,14 @@ static String valueForeColor(Frame* frame, Event*)
     return valueStyle(frame, CSSPropertyColor);
 }
 
+static String valueFormatBlock(Frame* frame, Event*)
+{
+    Element* formatBlockElement = frame->editor()->elementForFormatBlockCommand();
+    if (!formatBlockElement)
+        return "";
+    return formatBlockElement->localName();
+}
+
 // Map of functions
 
 struct CommandEntry {
@@ -1382,7 +1390,7 @@ static const CommandMap& createCommandMap()
         { "FontSize", { executeFontSize, supported, enabledInEditableText, stateNone, valueFontSize, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "FontSizeDelta", { executeFontSizeDelta, supported, enabledInEditableText, stateNone, valueFontSizeDelta, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "ForeColor", { executeForeColor, supported, enabledInRichlyEditableText, stateNone, valueForeColor, notTextInsertion, doNotAllowExecutionWhenDisabled } },
-        { "FormatBlock", { executeFormatBlock, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
+        { "FormatBlock", { executeFormatBlock, supported, enabledInRichlyEditableText, stateNone, valueFormatBlock, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "ForwardDelete", { executeForwardDelete, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "HiliteColor", { executeBackColor, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
         { "IgnoreSpelling", { executeIgnoreSpelling, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },