Reviewed by John
authorkocienda <kocienda@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Dec 2004 17:39:44 +0000 (17:39 +0000)
committerkocienda <kocienda@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 6 Dec 2004 17:39:44 +0000 (17:39 +0000)
        * khtml/dom/dom_string.cpp:
        (DOM::DOMString::substring): Expose method already on DOMStrimgImpl.
        * khtml/dom/dom_string.h: Ditto.
        * khtml/editing/htmlediting.cpp:
        (khtml::CompositeEditCommand::rebalanceWhitespace): New helper to create and execute a
        RebalanceWhitespaceCommand instance.
        (khtml::DeleteSelectionCommand::doApply): Call rebalanceWhitespace() after running command.
        (khtml::InsertLineBreakCommand::doApply): Ditto.
        (khtml::InsertParagraphSeparatorCommand::doApply): Ditto.
        (khtml::InsertParagraphSeparatorInQuotedContentCommand::doApply): Ditto.
        (khtml::InsertTextCommand::input): Ditto.
        (khtml::RebalanceWhitespaceCommand::RebalanceWhitespaceCommand): New command.
        (khtml::RebalanceWhitespaceCommand::~RebalanceWhitespaceCommand): Ditto.
        (khtml::RebalanceWhitespaceCommand::doApply): Ditto.
        (khtml::RebalanceWhitespaceCommand::doUnapply): Ditto.
        (khtml::RebalanceWhitespaceCommand::preservesTypingStyle): Ditto.
        (khtml::ReplaceSelectionCommand::completeHTMLReplacement): Ditto.
        * khtml/editing/htmlediting.h: Ditto.
        (khtml::RebalanceWhitespaceCommand::): Ditto.

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

LayoutTests/editing/editing.js
WebCore/ChangeLog-2005-08-23
WebCore/khtml/dom/dom_string.cpp
WebCore/khtml/dom/dom_string.h
WebCore/khtml/editing/htmlediting.cpp
WebCore/khtml/editing/htmlediting.h

index 468e8c6..ff3da95 100644 (file)
@@ -283,6 +283,21 @@ function insertLineBreakCommand() {
 }
 
 //-------------------------------------------------------------------------------------------------------
+function execInsertParagraphCommand() {
+    document.execCommand("InsertParagraph");
+}
+function insertParagraphCommand() {
+    if (commandDelay > 0) {
+        window.setTimeout(execInsertParagraphCommand, commandCount * commandDelay);
+        commandCount++;
+    }
+    else {
+        execInsertParagraphCommand();
+    }
+}
+
+//-------------------------------------------------------------------------------------------------------
 
 function execTypeCharacterCommand(c) {
     if (arguments.length == 0 || c == undefined || c.length == 0 || c.length > 1)
index 391626d..6bc843b 100644 (file)
@@ -1,3 +1,27 @@
+2004-12-06  Ken Kocienda  <kocienda@apple.com>
+        Reviewed by John
+        
+        * khtml/dom/dom_string.cpp:
+        (DOM::DOMString::substring): Expose method already on DOMStrimgImpl.
+        * khtml/dom/dom_string.h: Ditto.
+        * khtml/editing/htmlediting.cpp:
+        (khtml::CompositeEditCommand::rebalanceWhitespace): New helper to create and execute a
+        RebalanceWhitespaceCommand instance.
+        (khtml::DeleteSelectionCommand::doApply): Call rebalanceWhitespace() after running command.
+        (khtml::InsertLineBreakCommand::doApply): Ditto.
+        (khtml::InsertParagraphSeparatorCommand::doApply): Ditto.
+        (khtml::InsertParagraphSeparatorInQuotedContentCommand::doApply): Ditto.
+        (khtml::InsertTextCommand::input): Ditto.
+        (khtml::RebalanceWhitespaceCommand::RebalanceWhitespaceCommand): New command.
+        (khtml::RebalanceWhitespaceCommand::~RebalanceWhitespaceCommand): Ditto.
+        (khtml::RebalanceWhitespaceCommand::doApply): Ditto.
+        (khtml::RebalanceWhitespaceCommand::doUnapply): Ditto.
+        (khtml::RebalanceWhitespaceCommand::preservesTypingStyle): Ditto.
+        (khtml::ReplaceSelectionCommand::completeHTMLReplacement): Ditto.
+        * khtml/editing/htmlediting.h: Ditto.
+        (khtml::RebalanceWhitespaceCommand::): Ditto.
+
 2004-12-05  Darin Adler  <darin@apple.com>
 
         - fixed small problem in my check-in from yesterday
index a1e132c..2132018 100644 (file)
@@ -172,6 +172,13 @@ void DOMString::remove(unsigned int pos, int len)
   if(impl) impl->remove(pos, len);
 }
 
+DOMString DOMString::substring(unsigned int pos, unsigned int len)
+{
+    if (!impl) 
+        return DOMString();
+    return impl->substring(pos, len);
+}
+
 DOMString DOMString::split(unsigned int pos)
 {
   if(!impl) return DOMString();
index 999c63f..c106018 100644 (file)
@@ -83,6 +83,9 @@ public:
     uint length() const;
     void truncate( unsigned int len );
     void remove(unsigned int pos, int len=1);
+
+    DOMString substring(unsigned int pos, unsigned int len);
+
     /**
      * Splits the string into two. The original string gets truncated to pos, and the rest is returned.
      */
index e38dbf8..290992a 100644 (file)
@@ -762,6 +762,19 @@ void CompositeEditCommand::setNodeAttribute(ElementImpl *element, int attribute,
     applyCommandToComposite(cmd);
 }
 
+void CompositeEditCommand::rebalanceWhitespace()
+{
+    Selection selection = endingSelection();
+    if (selection.isCaretOrRange()) {
+        EditCommandPtr startCmd(new RebalanceWhitespaceCommand(document(), endingSelection().start()));
+        applyCommandToComposite(startCmd);
+        if (selection.isRange()) {
+            EditCommandPtr endCmd(new RebalanceWhitespaceCommand(document(), endingSelection().end()));
+            applyCommandToComposite(endCmd);
+        }
+    }
+}
+
 NodeImpl *CompositeEditCommand::applyTypingStyle(NodeImpl *child) const
 {
     // FIXME: This function should share code with ApplyStyleCommand::applyStyleIfNeeded
@@ -1911,6 +1924,7 @@ void DeleteSelectionCommand::doApply()
     setEndingSelection(m_endingPosition);
     debugPosition("endingPosition   ", m_endingPosition);
     clearTransientState();
+    rebalanceWhitespace();
 }
 
 bool DeleteSelectionCommand::preservesTypingStyle() const
@@ -2081,6 +2095,7 @@ void InsertLineBreakCommand::doApply()
         
         setEndingSelection(endingPosition);
     }
+    rebalanceWhitespace();
 }
 
 //------------------------------------------------------------------------------------------
@@ -2160,6 +2175,7 @@ void InsertParagraphSeparatorCommand::doApply()
         if (doneAfterDelete) {
             document()->updateLayout();
             setEndingSelection(endingSelection().start().downstream());
+            rebalanceWhitespace();
             return;
         }
         pos = endingSelection().start().upstream();
@@ -2252,6 +2268,7 @@ void InsertParagraphSeparatorCommand::doApply()
     
     // Put the selection right at the start of the added block.
     setEndingSelection(Position(addedBlock, 0));
+    rebalanceWhitespace();
 }
 
 //------------------------------------------------------------------------------------------
@@ -2390,6 +2407,7 @@ void InsertParagraphSeparatorInQuotedContentCommand::doApply()
     
     // Put the selection right before the break.
     setEndingSelection(Position(m_breakNode, 0));
+    rebalanceWhitespace();
 }
 
 //------------------------------------------------------------------------------------------
@@ -2527,6 +2545,7 @@ void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
         // a set number of spaces. This also seems to be the HTML editing convention.
         for (int i = 0; i < spacesPerTab; i++) {
             insertSpace(textNode, offset);
+            rebalanceWhitespace();
             document()->updateLayout();
         }
         if (selectInsertedText)
@@ -2542,6 +2561,7 @@ void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
         else
             setEndingSelection(Position(textNode, offset + 1));
         m_charactersAdded++;
+        rebalanceWhitespace();
     }
     else {
         const DOMString &existingText = textNode->data();
@@ -2712,6 +2732,108 @@ void MoveSelectionCommand::doApply()
 }
 
 //------------------------------------------------------------------------------------------
+// RebalanceWhitespaceCommand
+
+RebalanceWhitespaceCommand::RebalanceWhitespaceCommand(DocumentImpl *document, const Position &pos)
+    : EditCommand(document), m_position(pos), m_upstreamOffset(InvalidOffset), m_downstreamOffset(InvalidOffset)
+{
+}
+
+RebalanceWhitespaceCommand::~RebalanceWhitespaceCommand()
+{
+}
+
+void RebalanceWhitespaceCommand::doApply()
+{
+    static DOMString space(" ");
+
+    if (m_position.isNull() || !m_position.node()->isTextNode())
+        return;
+        
+    TextImpl *textNode = static_cast<TextImpl *>(m_position.node());
+    DOMString text = textNode->data();
+    if (text.length() == 0)
+        return;
+    
+    // find upstream offset
+    long upstream = m_position.offset();
+    while (upstream > 0 && isWS(text[upstream - 1]) || isNBSP(text[upstream - 1])) {
+        upstream--;
+        m_upstreamOffset = upstream;
+    }
+
+    // find downstream offset
+    long downstream = m_position.offset();
+    while ((unsigned)downstream < text.length() && isWS(text[downstream]) || isNBSP(text[downstream])) {
+        downstream++;
+        m_downstreamOffset = downstream;
+    }
+
+    if (m_upstreamOffset == InvalidOffset && m_downstreamOffset == InvalidOffset)
+        return;
+        
+    m_upstreamOffset = upstream;
+    m_downstreamOffset = downstream;
+    long length = m_downstreamOffset - m_upstreamOffset;
+    
+    m_beforeString = text.substring(m_upstreamOffset, length);
+    
+    // The following loop figures out a "rebalanced" whitespace string for any length
+    // string, and takes into account the special cases that need to handled for the
+    // start and end of strings (i.e. first and last character must be an nbsp.
+    long i = m_upstreamOffset;
+    while (i < m_downstreamOffset) {
+        long add = (m_downstreamOffset - i) % 3;
+        switch (add) {
+            case 0:
+                m_afterString += nonBreakingSpaceString();
+                m_afterString += space;
+                m_afterString += nonBreakingSpaceString();
+                add = 3;
+                break;
+            case 1:
+                if (i == 0 || (unsigned)i + 1 == text.length()) // at start or end of string
+                    m_afterString += nonBreakingSpaceString();
+                else
+                    m_afterString += space;
+                break;
+            case 2:
+                if ((unsigned)i + 2 == text.length()) {
+                     // at end of string
+                    m_afterString += nonBreakingSpaceString();
+                    m_afterString += nonBreakingSpaceString();
+                }
+                else {
+                    m_afterString += nonBreakingSpaceString();
+                    m_afterString += space;
+                }
+                break;
+        }
+        i += add;
+    }
+    
+    text.remove(m_upstreamOffset, length);
+    text.insert(m_afterString, m_upstreamOffset);
+}
+
+void RebalanceWhitespaceCommand::doUnapply()
+{
+    if (m_upstreamOffset == InvalidOffset && m_downstreamOffset == InvalidOffset)
+        return;
+    
+    ASSERT(m_position.node()->isTextNode());
+    TextImpl *textNode = static_cast<TextImpl *>(m_position.node());
+    DOMString text = textNode->data();
+    text.remove(m_upstreamOffset, m_afterString.length());
+    text.insert(m_beforeString, m_upstreamOffset);
+}
+
+bool RebalanceWhitespaceCommand::preservesTypingStyle() const
+{
+    return true;
+}
+
+//------------------------------------------------------------------------------------------
 // RemoveCSSPropertyCommand
 
 RemoveCSSPropertyCommand::RemoveCSSPropertyCommand(DocumentImpl *document, CSSStyleDeclarationImpl *decl, int property)
@@ -3322,6 +3444,7 @@ void ReplaceSelectionCommand::completeHTMLReplacement(const Position &start, con
     if (start.isNull() || !start.node()->inDocument() || end.isNull() || !end.node()->inDocument())
         return;
     m_selectReplacement ? setEndingSelection(Selection(start, end)) : setEndingSelection(end);
+    rebalanceWhitespace();
 }
 
 void ReplaceSelectionCommand::completeHTMLReplacement(NodeImpl *firstNodeInserted, NodeImpl *lastNodeInserted)
@@ -3359,6 +3482,7 @@ void ReplaceSelectionCommand::completeHTMLReplacement(NodeImpl *firstNodeInserte
         // Place the cursor after what was inserted, and mark misspellings in the inserted content.
         setEndingSelection(end);
     }
+    rebalanceWhitespace();
 }
 
 //------------------------------------------------------------------------------------------
index e2d150c..39e469b 100644 (file)
@@ -195,6 +195,7 @@ protected:
     void insertParagraphSeparator();
     void insertTextIntoNode(DOM::TextImpl *node, long offset, const DOM::DOMString &text);
     void joinTextNodes(DOM::TextImpl *text1, DOM::TextImpl *text2);
+    void rebalanceWhitespace();
     void removeCSSProperty(DOM::CSSStyleDeclarationImpl *, int property);
     void removeFullySelectedNode(DOM::NodeImpl *);
     void removeNodeAttribute(DOM::ElementImpl *, int attribute);
@@ -496,6 +497,30 @@ private:
 };
 
 //------------------------------------------------------------------------------------------
+// RebalanceWhitespaceCommand
+
+class RebalanceWhitespaceCommand : public EditCommand
+{
+public:
+    RebalanceWhitespaceCommand(DOM::DocumentImpl *, const DOM::Position &);
+    virtual ~RebalanceWhitespaceCommand();
+
+    virtual void doApply();
+    virtual void doUnapply();
+
+private:
+    enum { InvalidOffset = -1 };
+
+    virtual bool preservesTypingStyle() const;
+
+    DOM::DOMString m_beforeString;
+    DOM::DOMString m_afterString;
+    DOM::Position m_position;
+    long m_upstreamOffset;
+    long m_downstreamOffset;
+};
+
+//------------------------------------------------------------------------------------------
 // RemoveCSSPropertyCommand
 
 class RemoveCSSPropertyCommand : public EditCommand