diff --git a/mozilla/editor/base/nsHTMLDataTransfer.cpp b/mozilla/editor/base/nsHTMLDataTransfer.cpp index be450f456b2..4aed039c590 100644 --- a/mozilla/editor/base/nsHTMLDataTransfer.cpp +++ b/mozilla/editor/base/nsHTMLDataTransfer.cpp @@ -357,9 +357,14 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString & // Loop over the node list and paste the nodes: PRBool bDidInsert = PR_FALSE; - nsCOMPtr lastInsertNode, insertedContextParent; + nsCOMPtr parentBlock, lastInsertNode, insertedContextParent; PRUint32 listCount, j; nodeList->Count(&listCount); + if (IsBlockNode(parentNode)) + parentBlock = parentNode; + else + parentBlock = GetBlockNodeParent(parentNode); + for (j=0; j isupports = dont_AddRef(nodeList->ElementAt(j)); @@ -425,8 +430,26 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString & curNode->GetFirstChild(getter_AddRefs(child)); } } + // check for pre's going into pre's. + else if (nsHTMLEditUtils::IsPre(parentBlock) && nsHTMLEditUtils::IsPre(curNode)) + { + nsCOMPtr child, tmp; + curNode->GetFirstChild(getter_AddRefs(child)); + while (child) + { + res = InsertNodeAtPoint(child, address_of(parentNode), &offsetOfNewNode, PR_TRUE); + if (NS_SUCCEEDED(res)) + { + bDidInsert = PR_TRUE; + lastInsertNode = child; + offsetOfNewNode++; + } + curNode->GetFirstChild(getter_AddRefs(child)); + } + } else { + // try to insert res = InsertNodeAtPoint(curNode, address_of(parentNode), &offsetOfNewNode, PR_TRUE); if (NS_SUCCEEDED(res)) diff --git a/mozilla/editor/base/nsHTMLEditRules.cpp b/mozilla/editor/base/nsHTMLEditRules.cpp index 0392ac4f6fe..dcffe5abd7c 100644 --- a/mozilla/editor/base/nsHTMLEditRules.cpp +++ b/mozilla/editor/base/nsHTMLEditRules.cpp @@ -400,6 +400,13 @@ nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection if (NS_FAILED(res)) return res; } + // if we created a new block, make sure selection lands in it + if (mNewBlock) + { + res = PinSelectionToNewBlock(selection); + mNewBlock = 0; + } + // adjust selection for insert text, html paste, and delete actions if ((action == nsEditor::kOpInsertText) || (action == nsEditor::kOpInsertIMEText) || @@ -410,10 +417,15 @@ nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection res = AdjustSelection(selection, aDirection); if (NS_FAILED(res)) return res; } + } // detect empty doc res = CreateBogusNodeIfNeeded(selection); + + // adjust selection HINT if needed + if (NS_FAILED(res)) return res; + res = CheckInterlinePosition(selection); return res; } @@ -1841,135 +1853,140 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection, } if (endNode.get() != startNode.get()) { - // block parents the same? use default deletion - nsCOMPtr leftParent; - nsCOMPtr rightParent; - if (IsBlockNode(startNode)) - leftParent = startNode; - else - leftParent = mHTMLEditor->GetBlockNodeParent(startNode); - if (IsBlockNode(endNode)) - rightParent = endNode; - else - rightParent = mHTMLEditor->GetBlockNodeParent(endNode); - if (leftParent.get() == rightParent.get()) return NS_OK; - - // deleting across blocks - // are the blocks of same type? - - // are the blocks siblings? - nsCOMPtr leftBlockParent; - nsCOMPtr rightBlockParent; - leftParent->GetParentNode(getter_AddRefs(leftBlockParent)); - rightParent->GetParentNode(getter_AddRefs(rightBlockParent)); - - // MOOSE: this could conceivably screw up a table.. fix me. - if ( (leftBlockParent.get() == rightBlockParent.get()) - && (mHTMLEditor->NodesSameType(leftParent, rightParent)) ) { - if (nsHTMLEditUtils::IsParagraph(leftParent)) - { - // first delete the selection - *aHandled = PR_TRUE; - res = mHTMLEditor->DeleteSelectionImpl(aAction); - if (NS_FAILED(res)) return res; - // then join para's, insert break - res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset); - if (NS_FAILED(res)) return res; - // fix up selection - res = aSelection->Collapse(selNode,selOffset); - return res; - } - if (nsHTMLEditUtils::IsListItem(leftParent) - || nsHTMLEditUtils::IsHeader(leftParent)) - { - // first delete the selection - *aHandled = PR_TRUE; - res = mHTMLEditor->DeleteSelectionImpl(aAction); - if (NS_FAILED(res)) return res; - // join blocks - res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset); - if (NS_FAILED(res)) return res; - // fix up selection - res = aSelection->Collapse(selNode,selOffset); - return res; - } - } + // track end location of where we are deleting + nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(endNode), &endOffset); - // else blocks not same type, or not siblings. Delete everything except - // table elements. - *aHandled = PR_TRUE; - nsCOMPtr enumerator; - nsCOMPtr selPriv(do_QueryInterface(aSelection)); - res = selPriv->GetEnumerator(getter_AddRefs(enumerator)); - if (NS_FAILED(res)) return res; - if (!enumerator) return NS_ERROR_UNEXPECTED; + // block parents the same? use default deletion + nsCOMPtr leftParent; + nsCOMPtr rightParent; + if (IsBlockNode(startNode)) + leftParent = startNode; + else + leftParent = mHTMLEditor->GetBlockNodeParent(startNode); + if (IsBlockNode(endNode)) + rightParent = endNode; + else + rightParent = mHTMLEditor->GetBlockNodeParent(endNode); + if (leftParent.get() == rightParent.get()) return NS_OK; + + // deleting across blocks + // are the blocks of same type? + + // are the blocks siblings? + nsCOMPtr leftBlockParent; + nsCOMPtr rightBlockParent; + leftParent->GetParentNode(getter_AddRefs(leftBlockParent)); + rightParent->GetParentNode(getter_AddRefs(rightBlockParent)); - for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next()) - { - nsCOMPtr currentItem; - res = enumerator->CurrentItem(getter_AddRefs(currentItem)); + // MOOSE: this could conceivably screw up a table.. fix me. + if ( (leftBlockParent.get() == rightBlockParent.get()) + && (mHTMLEditor->NodesSameType(leftParent, rightParent)) ) + { + if (nsHTMLEditUtils::IsParagraph(leftParent)) + { + // first delete the selection + *aHandled = PR_TRUE; + res = mHTMLEditor->DeleteSelectionImpl(aAction); + if (NS_FAILED(res)) return res; + // then join para's, insert break + res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset); + if (NS_FAILED(res)) return res; + // fix up selection + res = aSelection->Collapse(selNode,selOffset); + return res; + } + if (nsHTMLEditUtils::IsListItem(leftParent) + || nsHTMLEditUtils::IsHeader(leftParent)) + { + // first delete the selection + *aHandled = PR_TRUE; + res = mHTMLEditor->DeleteSelectionImpl(aAction); + if (NS_FAILED(res)) return res; + // join blocks + res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset); + if (NS_FAILED(res)) return res; + // fix up selection + res = aSelection->Collapse(selNode,selOffset); + return res; + } + } + + // else blocks not same type, or not siblings. Delete everything except + // table elements. + *aHandled = PR_TRUE; + nsCOMPtr enumerator; + nsCOMPtr selPriv(do_QueryInterface(aSelection)); + res = selPriv->GetEnumerator(getter_AddRefs(enumerator)); if (NS_FAILED(res)) return res; - if (!currentItem) return NS_ERROR_UNEXPECTED; + if (!enumerator) return NS_ERROR_UNEXPECTED; - // build a list of nodes in the range - nsCOMPtr range( do_QueryInterface(currentItem) ); - nsCOMPtr arrayOfNodes; - nsTrivialFunctor functor; - nsDOMSubtreeIterator iter; - res = iter.Init(range); - if (NS_FAILED(res)) return res; - res = iter.MakeList(functor, address_of(arrayOfNodes)); - if (NS_FAILED(res)) return res; - - // now that we have the list, delete non table elements - PRUint32 listCount; - PRUint32 j; - nsCOMPtr somenode; - nsCOMPtr isupports; - - arrayOfNodes->Count(&listCount); - for (j = 0; j < listCount; j++) + for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next()) { - isupports = dont_AddRef(arrayOfNodes->ElementAt(0)); - somenode = do_QueryInterface(isupports); - res = DeleteNonTableElements(somenode); - arrayOfNodes->RemoveElementAt(0); - } - } + nsCOMPtr currentItem; + res = enumerator->CurrentItem(getter_AddRefs(currentItem)); + if (NS_FAILED(res)) return res; + if (!currentItem) return NS_ERROR_UNEXPECTED; + + // build a list of nodes in the range + nsCOMPtr range( do_QueryInterface(currentItem) ); + nsCOMPtr arrayOfNodes; + nsTrivialFunctor functor; + nsDOMSubtreeIterator iter; + res = iter.Init(range); + if (NS_FAILED(res)) return res; + res = iter.MakeList(functor, address_of(arrayOfNodes)); + if (NS_FAILED(res)) return res; - // check endopints for possible text deletion. - // we can assume that if text node is found, we can - // delete to end or to begining as appropriate, - // since the case where both sel endpoints in same - // text node was already handled (we wouldn't be here) - if ( mHTMLEditor->IsTextNode(startNode) ) - { - // delete to last character - nsCOMPtrnodeAsText; - PRUint32 len; - nodeAsText = do_QueryInterface(startNode); - nodeAsText->GetLength(&len); - if (len > (PRUint32)startOffset) - { - res = mHTMLEditor->DeleteText(nodeAsText,startOffset,len-startOffset); - if (NS_FAILED(res)) return res; + // now that we have the list, delete non table elements + PRUint32 listCount; + PRUint32 j; + nsCOMPtr somenode; + nsCOMPtr isupports; + + arrayOfNodes->Count(&listCount); + for (j = 0; j < listCount; j++) + { + isupports = dont_AddRef(arrayOfNodes->ElementAt(0)); + somenode = do_QueryInterface(isupports); + res = DeleteNonTableElements(somenode); + arrayOfNodes->RemoveElementAt(0); + } } - } - if ( mHTMLEditor->IsTextNode(endNode) ) - { - // delete to first character - nsCOMPtrnodeAsText; - nodeAsText = do_QueryInterface(endNode); - if (endOffset) + + // check endopints for possible text deletion. + // we can assume that if text node is found, we can + // delete to end or to begining as appropriate, + // since the case where both sel endpoints in same + // text node was already handled (we wouldn't be here) + if ( mHTMLEditor->IsTextNode(startNode) ) { - res = mHTMLEditor->DeleteText(nodeAsText,0,endOffset); - if (NS_FAILED(res)) return res; + // delete to last character + nsCOMPtrnodeAsText; + PRUint32 len; + nodeAsText = do_QueryInterface(startNode); + nodeAsText->GetLength(&len); + if (len > (PRUint32)startOffset) + { + res = mHTMLEditor->DeleteText(nodeAsText,startOffset,len-startOffset); + if (NS_FAILED(res)) return res; + } + } + if ( mHTMLEditor->IsTextNode(endNode) ) + { + // delete to first character + nsCOMPtrnodeAsText; + nodeAsText = do_QueryInterface(endNode); + if (endOffset) + { + res = mHTMLEditor->DeleteText(nodeAsText,0,endOffset); + if (NS_FAILED(res)) return res; + } } } if (aAction == nsIEditor::eNext) { - res = aSelection->Collapse(endNode,0); + res = aSelection->Collapse(endNode,endOffset); } else { @@ -2100,6 +2117,8 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, if (NS_FAILED(res)) return res; res = mHTMLEditor->CreateNode(itemType, theList, 0, getter_AddRefs(theListItem)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = theListItem; // put selection in new list item res = aSelection->Collapse(theListItem,0); selectionResetter.Abort(); // to prevent selection reseter from overriding us. @@ -2254,6 +2273,8 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection, if (NS_FAILED(res)) return res; res = mHTMLEditor->CreateNode(*aListType, curParent, offset, getter_AddRefs(curList)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = curList; // curList is now the correct thing to put curNode in prevListItem = 0; } @@ -2431,6 +2452,8 @@ nsHTMLEditRules::WillMakeBasicBlock(nsISelection *aSelection, if (NS_FAILED(res)) return res; res = mHTMLEditor->CreateNode(*aBlockType, parent, offset, getter_AddRefs(theBlock)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = theBlock; // delete anything that was in the list of nodes nsCOMPtr isupports = dont_AddRef(arrayOfNodes->ElementAt(0)); nsCOMPtr curNode; @@ -2530,6 +2553,8 @@ nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * if (NS_FAILED(res)) return res; res = mHTMLEditor->CreateNode(quoteType, parent, offset, getter_AddRefs(theBlock)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = theBlock; // delete anything that was in the list of nodes nsCOMPtr isupports = dont_AddRef(arrayOfNodes->ElementAt(0)); nsCOMPtr curNode; @@ -2587,6 +2612,8 @@ nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * res = mHTMLEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList)); if (NS_FAILED(res)) return res; // curList is now the correct thing to put curNode in + // remember our new block for postprocessing + mNewBlock = curList; } // tuck the node into the end of the active list PRUint32 listLen; @@ -2607,6 +2634,8 @@ nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool * if (NS_FAILED(res)) return res; res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curQuote)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = curQuote; /* !!!!!!!!!!!!!!! TURNED OFF PER BUG 33213 !!!!!!!!!!!!!!!!!!!! // set style to not have unwanted vertical margins @@ -3134,6 +3163,8 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection, } res = mHTMLEditor->CreateNode(divType, parent, offset, getter_AddRefs(theDiv)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = theDiv; // set up the alignment on the div nsCOMPtr divElem = do_QueryInterface(theDiv); nsAutoString attr; attr.AssignWithConversion("align"); @@ -3203,6 +3234,8 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection, if (NS_FAILED(res)) return res; res = mHTMLEditor->CreateNode(divType, curParent, offset, getter_AddRefs(curDiv)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = curDiv; // set up the alignment on the div nsCOMPtr divElem = do_QueryInterface(curDiv); nsAutoString attr; attr.AssignWithConversion("align"); @@ -4918,6 +4951,9 @@ nsHTMLEditRules::MakeBlockquote(nsISupportsArray *arrayOfNodes) if (NS_FAILED(res)) return res; res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curBlock)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = curBlock; + // note: doesn't matter if we set mNewBlock multiple times. } PRUint32 blockLen; @@ -5179,6 +5215,9 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab if (NS_FAILED(res)) return res; res = mHTMLEditor->CreateNode(*aBlockTag, curParent, offset, getter_AddRefs(curBlock)); if (NS_FAILED(res)) return res; + // remember our new block for postprocessing + mNewBlock = curBlock; + // note: doesn't matter if we set mNewBlock multiple times. } // if curNode is a Break, replace it with a return if we are going to
@@ -5397,6 +5436,111 @@ nsHTMLEditRules::AdjustWhitespace(nsISelection *aSelection)
   return nsWSRunObject(mHTMLEditor, selNode, selOffset).AdjustWhitespace();
 }
 
+nsresult 
+nsHTMLEditRules::PinSelectionToNewBlock(nsISelection *aSelection)
+{
+  if (!aSelection) return NS_ERROR_NULL_POINTER;
+  PRBool bCollapsed;
+  nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
+  if (NS_FAILED(res)) return res;
+  if (!bCollapsed) return res;
+
+  // get the (collapsed) selection location
+  nsCOMPtr selNode, temp;
+  PRInt32 selOffset;
+  res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
+  if (NS_FAILED(res)) return res;
+  temp = selNode;
+  
+  // use ranges and mRangeHelper to compare sel point to new block
+  nsCOMPtr range = do_CreateInstance(kRangeCID);
+  res = range->SetStart(selNode, selOffset);
+  if (NS_FAILED(res)) return res;
+  res = range->SetEnd(selNode, selOffset);
+  if (NS_FAILED(res)) return res;
+  nsCOMPtr block (do_QueryInterface(mNewBlock));
+  if (!block) return NS_ERROR_NO_INTERFACE;
+  PRBool nodeBefore, nodeAfter;
+  res = mHTMLEditor->mRangeHelper->CompareNodeToRange(block, range, &nodeBefore, &nodeAfter);
+  if (NS_FAILED(res)) return res;
+  
+  if (nodeBefore && nodeAfter)
+    return NS_OK;  // selection is inside block
+  else if (nodeBefore)
+  {
+    // selection is after block.  put at end of block.
+    nsCOMPtr tmp = mNewBlock;
+    mHTMLEditor->GetLastEditableChild(mNewBlock, address_of(tmp));
+    PRUint32 endPoint;
+    if (mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp))
+    {
+      res = nsEditor::GetLengthOfDOMNode(tmp, endPoint);
+      if (NS_FAILED(res)) return res;
+    }
+    else
+    {
+      nsCOMPtr tmp2;
+      res = nsEditor::GetNodeLocation(tmp, address_of(tmp2), (PRInt32*)&endPoint);
+      if (NS_FAILED(res)) return res;
+      tmp = tmp2;
+      endPoint++;  // want to be after this node
+    }
+    return aSelection->Collapse(tmp, (PRInt32)endPoint);
+  }
+  else
+  {
+    // selection is before block.  put at start of block.
+    nsCOMPtr tmp = mNewBlock;
+    mHTMLEditor->GetFirstEditableChild(mNewBlock, address_of(tmp));
+    PRInt32 offset;
+    if (!(mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp)))
+    {
+      nsCOMPtr tmp2;
+      res = nsEditor::GetNodeLocation(tmp, address_of(tmp2), &offset);
+      if (NS_FAILED(res)) return res;
+      tmp = tmp2;
+    }
+    return aSelection->Collapse(tmp, 0);
+  }
+}
+
+nsresult 
+nsHTMLEditRules::CheckInterlinePosition(nsISelection *aSelection)
+{
+  if (!aSelection) return NS_ERROR_NULL_POINTER;
+  nsCOMPtr selection(aSelection);
+  nsCOMPtr selPriv(do_QueryInterface(selection));
+
+  // if the selection isn't collapsed, do nothing.
+  PRBool bCollapsed;
+  nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
+  if (NS_FAILED(res)) return res;
+  if (!bCollapsed) return res;
+
+  // get the (collapsed) selection location
+  nsCOMPtr selNode, node;
+  PRInt32 selOffset;
+  res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
+  if (NS_FAILED(res)) return res;
+  
+  // are we after a block?  If so try set caret to following content
+  mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(node));
+  if (node && IsBlockNode(node))
+  {
+    selPriv->SetInterlinePosition(PR_TRUE);
+    return NS_OK;
+  }
+
+  // are we before a block?  If so try set caret to prior content
+  mHTMLEditor->GetNextHTMLSibling(selNode, selOffset, address_of(node));
+  if (node && IsBlockNode(node))
+  {
+    selPriv->SetInterlinePosition(PR_FALSE);
+    return NS_OK;
+  }
+  return NS_OK;
+}
+
 nsresult 
 nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aAction)
 {
diff --git a/mozilla/editor/base/nsHTMLEditRules.h b/mozilla/editor/base/nsHTMLEditRules.h
index 6738407d515..e9b9c791926 100644
--- a/mozilla/editor/base/nsHTMLEditRules.h
+++ b/mozilla/editor/base/nsHTMLEditRules.h
@@ -179,6 +179,8 @@ protected:
   nsresult RemoveListStructure(nsIDOMNode *aList);
   nsresult AdjustSpecialBreaks(PRBool aSafeToAskFrames = PR_FALSE);
   nsresult AdjustWhitespace(nsISelection *aSelection);
+  nsresult PinSelectionToNewBlock(nsISelection *aSelection);
+  nsresult CheckInterlinePosition(nsISelection *aSelection);
   nsresult AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aAction);
   nsresult FindNearSelectableNode(nsIDOMNode *aSelNode, 
                                   PRInt32 aSelOffset, 
@@ -202,6 +204,7 @@ protected:
   PRBool                  mReturnInEmptyLIKillsList;
   nsCOMPtr   mUtilRange;
   PRUint32                mJoinOffset;  // need to remember an int across willJoin/didJoin...
+  nsCOMPtr    mNewBlock;
 
 };
 
diff --git a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp
index be450f456b2..4aed039c590 100644
--- a/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLDataTransfer.cpp
@@ -357,9 +357,14 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString &
 
     // Loop over the node list and paste the nodes:
     PRBool bDidInsert = PR_FALSE;
-    nsCOMPtr lastInsertNode, insertedContextParent;
+    nsCOMPtr parentBlock, lastInsertNode, insertedContextParent;
     PRUint32 listCount, j;
     nodeList->Count(&listCount);
+    if (IsBlockNode(parentNode))
+      parentBlock = parentNode;
+    else
+      parentBlock = GetBlockNodeParent(parentNode);
+      
     for (j=0; j isupports = dont_AddRef(nodeList->ElementAt(j));
@@ -425,8 +430,26 @@ nsresult nsHTMLEditor::InsertHTMLWithCharsetAndContext(const nsAReadableString &
           curNode->GetFirstChild(getter_AddRefs(child));
         }
       }
+      // check for pre's going into pre's.  
+      else if (nsHTMLEditUtils::IsPre(parentBlock) && nsHTMLEditUtils::IsPre(curNode))
+      {
+        nsCOMPtr child, tmp;
+        curNode->GetFirstChild(getter_AddRefs(child));
+        while (child)
+        {
+          res = InsertNodeAtPoint(child, address_of(parentNode), &offsetOfNewNode, PR_TRUE);
+          if (NS_SUCCEEDED(res)) 
+          {
+            bDidInsert = PR_TRUE;
+            lastInsertNode = child;
+            offsetOfNewNode++;
+          }
+          curNode->GetFirstChild(getter_AddRefs(child));
+        }
+      }
       else
       {
+        
         // try to insert
         res = InsertNodeAtPoint(curNode, address_of(parentNode), &offsetOfNewNode, PR_TRUE);
         if (NS_SUCCEEDED(res)) 
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
index 0392ac4f6fe..dcffe5abd7c 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -400,6 +400,13 @@ nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection
       if (NS_FAILED(res)) return res;
     }
     
+    // if we created a new block, make sure selection lands in it
+    if (mNewBlock)
+    {
+      res = PinSelectionToNewBlock(selection);
+      mNewBlock = 0;
+    }
+
     // adjust selection for insert text, html paste, and delete actions
     if ((action == nsEditor::kOpInsertText) || 
         (action == nsEditor::kOpInsertIMEText) ||
@@ -410,10 +417,15 @@ nsHTMLEditRules::AfterEditInner(PRInt32 action, nsIEditor::EDirection aDirection
       res = AdjustSelection(selection, aDirection);
       if (NS_FAILED(res)) return res;
     }
+    
   }
 
   // detect empty doc
   res = CreateBogusNodeIfNeeded(selection);
+  
+  // adjust selection HINT if needed
+  if (NS_FAILED(res)) return res;
+  res = CheckInterlinePosition(selection);
   return res;
 }
 
@@ -1841,135 +1853,140 @@ nsHTMLEditRules::WillDeleteSelection(nsISelection *aSelection,
   }
   if (endNode.get() != startNode.get())
   {
-    // block parents the same?  use default deletion
-    nsCOMPtr leftParent;
-    nsCOMPtr rightParent;
-    if (IsBlockNode(startNode))
-      leftParent = startNode;
-    else
-      leftParent = mHTMLEditor->GetBlockNodeParent(startNode);
-    if (IsBlockNode(endNode))
-      rightParent = endNode;
-    else
-      rightParent = mHTMLEditor->GetBlockNodeParent(endNode);
-    if (leftParent.get() == rightParent.get()) return NS_OK;
-    
-    // deleting across blocks
-    // are the blocks of same type?
-    
-    // are the blocks siblings?
-    nsCOMPtr leftBlockParent;
-    nsCOMPtr rightBlockParent;
-    leftParent->GetParentNode(getter_AddRefs(leftBlockParent));
-    rightParent->GetParentNode(getter_AddRefs(rightBlockParent));
-
-    // MOOSE: this could conceivably screw up a table.. fix me.
-    if (   (leftBlockParent.get() == rightBlockParent.get())
-        && (mHTMLEditor->NodesSameType(leftParent, rightParent))  )
     {
-      if (nsHTMLEditUtils::IsParagraph(leftParent))
-      {
-        // first delete the selection
-        *aHandled = PR_TRUE;
-        res = mHTMLEditor->DeleteSelectionImpl(aAction);
-        if (NS_FAILED(res)) return res;
-        // then join para's, insert break
-        res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
-        if (NS_FAILED(res)) return res;
-        // fix up selection
-        res = aSelection->Collapse(selNode,selOffset);
-        return res;
-      }
-      if (nsHTMLEditUtils::IsListItem(leftParent)
-          || nsHTMLEditUtils::IsHeader(leftParent))
-      {
-        // first delete the selection
-        *aHandled = PR_TRUE;
-        res = mHTMLEditor->DeleteSelectionImpl(aAction);
-        if (NS_FAILED(res)) return res;
-        // join blocks
-        res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
-        if (NS_FAILED(res)) return res;
-        // fix up selection
-        res = aSelection->Collapse(selNode,selOffset);
-        return res;
-      }
-    }
+      // track end location of where we are deleting
+      nsAutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, address_of(endNode), &endOffset);
     
-    // else blocks not same type, or not siblings.  Delete everything except
-    // table elements.
-    *aHandled = PR_TRUE;
-    nsCOMPtr enumerator;
-    nsCOMPtr selPriv(do_QueryInterface(aSelection));
-    res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
-    if (NS_FAILED(res)) return res;
-    if (!enumerator) return NS_ERROR_UNEXPECTED;
+      // block parents the same?  use default deletion
+      nsCOMPtr leftParent;
+      nsCOMPtr rightParent;
+      if (IsBlockNode(startNode))
+        leftParent = startNode;
+      else
+        leftParent = mHTMLEditor->GetBlockNodeParent(startNode);
+      if (IsBlockNode(endNode))
+        rightParent = endNode;
+      else
+        rightParent = mHTMLEditor->GetBlockNodeParent(endNode);
+      if (leftParent.get() == rightParent.get()) return NS_OK;
+      
+      // deleting across blocks
+      // are the blocks of same type?
+      
+      // are the blocks siblings?
+      nsCOMPtr leftBlockParent;
+      nsCOMPtr rightBlockParent;
+      leftParent->GetParentNode(getter_AddRefs(leftBlockParent));
+      rightParent->GetParentNode(getter_AddRefs(rightBlockParent));
 
-    for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
-    {
-      nsCOMPtr currentItem;
-      res = enumerator->CurrentItem(getter_AddRefs(currentItem));
+      // MOOSE: this could conceivably screw up a table.. fix me.
+      if (   (leftBlockParent.get() == rightBlockParent.get())
+          && (mHTMLEditor->NodesSameType(leftParent, rightParent))  )
+      {
+        if (nsHTMLEditUtils::IsParagraph(leftParent))
+        {
+          // first delete the selection
+          *aHandled = PR_TRUE;
+          res = mHTMLEditor->DeleteSelectionImpl(aAction);
+          if (NS_FAILED(res)) return res;
+          // then join para's, insert break
+          res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
+          if (NS_FAILED(res)) return res;
+          // fix up selection
+          res = aSelection->Collapse(selNode,selOffset);
+          return res;
+        }
+        if (nsHTMLEditUtils::IsListItem(leftParent)
+            || nsHTMLEditUtils::IsHeader(leftParent))
+        {
+          // first delete the selection
+          *aHandled = PR_TRUE;
+          res = mHTMLEditor->DeleteSelectionImpl(aAction);
+          if (NS_FAILED(res)) return res;
+          // join blocks
+          res = mHTMLEditor->JoinNodeDeep(leftParent,rightParent,address_of(selNode),&selOffset);
+          if (NS_FAILED(res)) return res;
+          // fix up selection
+          res = aSelection->Collapse(selNode,selOffset);
+          return res;
+        }
+      }
+      
+      // else blocks not same type, or not siblings.  Delete everything except
+      // table elements.
+      *aHandled = PR_TRUE;
+      nsCOMPtr enumerator;
+      nsCOMPtr selPriv(do_QueryInterface(aSelection));
+      res = selPriv->GetEnumerator(getter_AddRefs(enumerator));
       if (NS_FAILED(res)) return res;
-      if (!currentItem) return NS_ERROR_UNEXPECTED;
+      if (!enumerator) return NS_ERROR_UNEXPECTED;
 
-      // build a list of nodes in the range
-      nsCOMPtr range( do_QueryInterface(currentItem) );
-      nsCOMPtr arrayOfNodes;
-      nsTrivialFunctor functor;
-      nsDOMSubtreeIterator iter;
-      res = iter.Init(range);
-      if (NS_FAILED(res)) return res;
-      res = iter.MakeList(functor, address_of(arrayOfNodes));
-      if (NS_FAILED(res)) return res;
-  
-      // now that we have the list, delete non table elements
-      PRUint32 listCount;
-      PRUint32 j;
-      nsCOMPtr somenode;
-      nsCOMPtr isupports;
-
-      arrayOfNodes->Count(&listCount);
-      for (j = 0; j < listCount; j++)
+      for (enumerator->First(); NS_OK!=enumerator->IsDone(); enumerator->Next())
       {
-        isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
-        somenode = do_QueryInterface(isupports);
-        res = DeleteNonTableElements(somenode);
-        arrayOfNodes->RemoveElementAt(0);
-      }
-    }
+        nsCOMPtr currentItem;
+        res = enumerator->CurrentItem(getter_AddRefs(currentItem));
+        if (NS_FAILED(res)) return res;
+        if (!currentItem) return NS_ERROR_UNEXPECTED;
+
+        // build a list of nodes in the range
+        nsCOMPtr range( do_QueryInterface(currentItem) );
+        nsCOMPtr arrayOfNodes;
+        nsTrivialFunctor functor;
+        nsDOMSubtreeIterator iter;
+        res = iter.Init(range);
+        if (NS_FAILED(res)) return res;
+        res = iter.MakeList(functor, address_of(arrayOfNodes));
+        if (NS_FAILED(res)) return res;
     
-    // check endopints for possible text deletion.
-    // we can assume that if text node is found, we can
-    // delete to end or to begining as appropriate,
-    // since the case where both sel endpoints in same
-    // text node was already handled (we wouldn't be here)
-    if ( mHTMLEditor->IsTextNode(startNode) )
-    {
-      // delete to last character
-      nsCOMPtrnodeAsText;
-      PRUint32 len;
-      nodeAsText = do_QueryInterface(startNode);
-      nodeAsText->GetLength(&len);
-      if (len > (PRUint32)startOffset)
-      {
-        res = mHTMLEditor->DeleteText(nodeAsText,startOffset,len-startOffset);
-        if (NS_FAILED(res)) return res;
+        // now that we have the list, delete non table elements
+        PRUint32 listCount;
+        PRUint32 j;
+        nsCOMPtr somenode;
+        nsCOMPtr isupports;
+
+        arrayOfNodes->Count(&listCount);
+        for (j = 0; j < listCount; j++)
+        {
+          isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
+          somenode = do_QueryInterface(isupports);
+          res = DeleteNonTableElements(somenode);
+          arrayOfNodes->RemoveElementAt(0);
+        }
       }
-    }
-    if ( mHTMLEditor->IsTextNode(endNode) )
-    {
-      // delete to first character
-      nsCOMPtrnodeAsText;
-      nodeAsText = do_QueryInterface(endNode);
-      if (endOffset)
+      
+      // check endopints for possible text deletion.
+      // we can assume that if text node is found, we can
+      // delete to end or to begining as appropriate,
+      // since the case where both sel endpoints in same
+      // text node was already handled (we wouldn't be here)
+      if ( mHTMLEditor->IsTextNode(startNode) )
       {
-        res = mHTMLEditor->DeleteText(nodeAsText,0,endOffset);
-        if (NS_FAILED(res)) return res;
+        // delete to last character
+        nsCOMPtrnodeAsText;
+        PRUint32 len;
+        nodeAsText = do_QueryInterface(startNode);
+        nodeAsText->GetLength(&len);
+        if (len > (PRUint32)startOffset)
+        {
+          res = mHTMLEditor->DeleteText(nodeAsText,startOffset,len-startOffset);
+          if (NS_FAILED(res)) return res;
+        }
+      }
+      if ( mHTMLEditor->IsTextNode(endNode) )
+      {
+        // delete to first character
+        nsCOMPtrnodeAsText;
+        nodeAsText = do_QueryInterface(endNode);
+        if (endOffset)
+        {
+          res = mHTMLEditor->DeleteText(nodeAsText,0,endOffset);
+          if (NS_FAILED(res)) return res;
+        }
       }
     }
     if (aAction == nsIEditor::eNext)
     {
-      res = aSelection->Collapse(endNode,0);
+      res = aSelection->Collapse(endNode,endOffset);
     }
     else
     {
@@ -2100,6 +2117,8 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
     if (NS_FAILED(res)) return res;
     res = mHTMLEditor->CreateNode(itemType, theList, 0, getter_AddRefs(theListItem));
     if (NS_FAILED(res)) return res;
+    // remember our new block for postprocessing
+    mNewBlock = theListItem;
     // put selection in new list item
     res = aSelection->Collapse(theListItem,0);
     selectionResetter.Abort();  // to prevent selection reseter from overriding us.
@@ -2254,6 +2273,8 @@ nsHTMLEditRules::WillMakeList(nsISelection *aSelection,
       if (NS_FAILED(res)) return res;
       res = mHTMLEditor->CreateNode(*aListType, curParent, offset, getter_AddRefs(curList));
       if (NS_FAILED(res)) return res;
+      // remember our new block for postprocessing
+      mNewBlock = curList;
       // curList is now the correct thing to put curNode in
       prevListItem = 0;
     }
@@ -2431,6 +2452,8 @@ nsHTMLEditRules::WillMakeBasicBlock(nsISelection *aSelection,
     if (NS_FAILED(res)) return res;
     res = mHTMLEditor->CreateNode(*aBlockType, parent, offset, getter_AddRefs(theBlock));
     if (NS_FAILED(res)) return res;
+    // remember our new block for postprocessing
+    mNewBlock = theBlock;
     // delete anything that was in the list of nodes
     nsCOMPtr isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
     nsCOMPtr curNode;
@@ -2530,6 +2553,8 @@ nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *
     if (NS_FAILED(res)) return res;
     res = mHTMLEditor->CreateNode(quoteType, parent, offset, getter_AddRefs(theBlock));
     if (NS_FAILED(res)) return res;
+    // remember our new block for postprocessing
+    mNewBlock = theBlock;
     // delete anything that was in the list of nodes
     nsCOMPtr isupports = dont_AddRef(arrayOfNodes->ElementAt(0));
     nsCOMPtr curNode;
@@ -2587,6 +2612,8 @@ nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *
         res = mHTMLEditor->CreateNode(listTag, curParent, offset, getter_AddRefs(curList));
         if (NS_FAILED(res)) return res;
         // curList is now the correct thing to put curNode in
+        // remember our new block for postprocessing
+        mNewBlock = curList;
       }
       // tuck the node into the end of the active list
       PRUint32 listLen;
@@ -2607,6 +2634,8 @@ nsHTMLEditRules::WillIndent(nsISelection *aSelection, PRBool *aCancel, PRBool *
         if (NS_FAILED(res)) return res;
         res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curQuote));
         if (NS_FAILED(res)) return res;
+        // remember our new block for postprocessing
+        mNewBlock = curQuote;
         
 /* !!!!!!!!!!!!!!!  TURNED OFF PER BUG 33213 !!!!!!!!!!!!!!!!!!!!
         // set style to not have unwanted vertical margins
@@ -3134,6 +3163,8 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
     }
     res = mHTMLEditor->CreateNode(divType, parent, offset, getter_AddRefs(theDiv));
     if (NS_FAILED(res)) return res;
+    // remember our new block for postprocessing
+    mNewBlock = theDiv;
     // set up the alignment on the div
     nsCOMPtr divElem = do_QueryInterface(theDiv);
     nsAutoString attr; attr.AssignWithConversion("align");
@@ -3203,6 +3234,8 @@ nsHTMLEditRules::WillAlign(nsISelection *aSelection,
       if (NS_FAILED(res)) return res;
       res = mHTMLEditor->CreateNode(divType, curParent, offset, getter_AddRefs(curDiv));
       if (NS_FAILED(res)) return res;
+      // remember our new block for postprocessing
+      mNewBlock = curDiv;
       // set up the alignment on the div
       nsCOMPtr divElem = do_QueryInterface(curDiv);
       nsAutoString attr; attr.AssignWithConversion("align");
@@ -4918,6 +4951,9 @@ nsHTMLEditRules::MakeBlockquote(nsISupportsArray *arrayOfNodes)
       if (NS_FAILED(res)) return res;
       res = mHTMLEditor->CreateNode(quoteType, curParent, offset, getter_AddRefs(curBlock));
       if (NS_FAILED(res)) return res;
+      // remember our new block for postprocessing
+      mNewBlock = curBlock;
+      // note: doesn't matter if we set mNewBlock multiple times.
     }
       
     PRUint32 blockLen;
@@ -5179,6 +5215,9 @@ nsHTMLEditRules::ApplyBlockStyle(nsISupportsArray *arrayOfNodes, const nsAReadab
         if (NS_FAILED(res)) return res;
         res = mHTMLEditor->CreateNode(*aBlockTag, curParent, offset, getter_AddRefs(curBlock));
         if (NS_FAILED(res)) return res;
+        // remember our new block for postprocessing
+        mNewBlock = curBlock;
+        // note: doesn't matter if we set mNewBlock multiple times.
       }
       
       // if curNode is a Break, replace it with a return if we are going to 
@@ -5397,6 +5436,111 @@ nsHTMLEditRules::AdjustWhitespace(nsISelection *aSelection)
   return nsWSRunObject(mHTMLEditor, selNode, selOffset).AdjustWhitespace();
 }
 
+nsresult 
+nsHTMLEditRules::PinSelectionToNewBlock(nsISelection *aSelection)
+{
+  if (!aSelection) return NS_ERROR_NULL_POINTER;
+  PRBool bCollapsed;
+  nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
+  if (NS_FAILED(res)) return res;
+  if (!bCollapsed) return res;
+
+  // get the (collapsed) selection location
+  nsCOMPtr selNode, temp;
+  PRInt32 selOffset;
+  res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
+  if (NS_FAILED(res)) return res;
+  temp = selNode;
+  
+  // use ranges and mRangeHelper to compare sel point to new block
+  nsCOMPtr range = do_CreateInstance(kRangeCID);
+  res = range->SetStart(selNode, selOffset);
+  if (NS_FAILED(res)) return res;
+  res = range->SetEnd(selNode, selOffset);
+  if (NS_FAILED(res)) return res;
+  nsCOMPtr block (do_QueryInterface(mNewBlock));
+  if (!block) return NS_ERROR_NO_INTERFACE;
+  PRBool nodeBefore, nodeAfter;
+  res = mHTMLEditor->mRangeHelper->CompareNodeToRange(block, range, &nodeBefore, &nodeAfter);
+  if (NS_FAILED(res)) return res;
+  
+  if (nodeBefore && nodeAfter)
+    return NS_OK;  // selection is inside block
+  else if (nodeBefore)
+  {
+    // selection is after block.  put at end of block.
+    nsCOMPtr tmp = mNewBlock;
+    mHTMLEditor->GetLastEditableChild(mNewBlock, address_of(tmp));
+    PRUint32 endPoint;
+    if (mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp))
+    {
+      res = nsEditor::GetLengthOfDOMNode(tmp, endPoint);
+      if (NS_FAILED(res)) return res;
+    }
+    else
+    {
+      nsCOMPtr tmp2;
+      res = nsEditor::GetNodeLocation(tmp, address_of(tmp2), (PRInt32*)&endPoint);
+      if (NS_FAILED(res)) return res;
+      tmp = tmp2;
+      endPoint++;  // want to be after this node
+    }
+    return aSelection->Collapse(tmp, (PRInt32)endPoint);
+  }
+  else
+  {
+    // selection is before block.  put at start of block.
+    nsCOMPtr tmp = mNewBlock;
+    mHTMLEditor->GetFirstEditableChild(mNewBlock, address_of(tmp));
+    PRInt32 offset;
+    if (!(mHTMLEditor->IsTextNode(tmp) || mHTMLEditor->IsContainer(tmp)))
+    {
+      nsCOMPtr tmp2;
+      res = nsEditor::GetNodeLocation(tmp, address_of(tmp2), &offset);
+      if (NS_FAILED(res)) return res;
+      tmp = tmp2;
+    }
+    return aSelection->Collapse(tmp, 0);
+  }
+}
+
+nsresult 
+nsHTMLEditRules::CheckInterlinePosition(nsISelection *aSelection)
+{
+  if (!aSelection) return NS_ERROR_NULL_POINTER;
+  nsCOMPtr selection(aSelection);
+  nsCOMPtr selPriv(do_QueryInterface(selection));
+
+  // if the selection isn't collapsed, do nothing.
+  PRBool bCollapsed;
+  nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
+  if (NS_FAILED(res)) return res;
+  if (!bCollapsed) return res;
+
+  // get the (collapsed) selection location
+  nsCOMPtr selNode, node;
+  PRInt32 selOffset;
+  res = mHTMLEditor->GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
+  if (NS_FAILED(res)) return res;
+  
+  // are we after a block?  If so try set caret to following content
+  mHTMLEditor->GetPriorHTMLSibling(selNode, selOffset, address_of(node));
+  if (node && IsBlockNode(node))
+  {
+    selPriv->SetInterlinePosition(PR_TRUE);
+    return NS_OK;
+  }
+
+  // are we before a block?  If so try set caret to prior content
+  mHTMLEditor->GetNextHTMLSibling(selNode, selOffset, address_of(node));
+  if (node && IsBlockNode(node))
+  {
+    selPriv->SetInterlinePosition(PR_FALSE);
+    return NS_OK;
+  }
+  return NS_OK;
+}
+
 nsresult 
 nsHTMLEditRules::AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aAction)
 {
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.h b/mozilla/editor/libeditor/html/nsHTMLEditRules.h
index 6738407d515..e9b9c791926 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditRules.h
+++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.h
@@ -179,6 +179,8 @@ protected:
   nsresult RemoveListStructure(nsIDOMNode *aList);
   nsresult AdjustSpecialBreaks(PRBool aSafeToAskFrames = PR_FALSE);
   nsresult AdjustWhitespace(nsISelection *aSelection);
+  nsresult PinSelectionToNewBlock(nsISelection *aSelection);
+  nsresult CheckInterlinePosition(nsISelection *aSelection);
   nsresult AdjustSelection(nsISelection *aSelection, nsIEditor::EDirection aAction);
   nsresult FindNearSelectableNode(nsIDOMNode *aSelNode, 
                                   PRInt32 aSelOffset, 
@@ -202,6 +204,7 @@ protected:
   PRBool                  mReturnInEmptyLIKillsList;
   nsCOMPtr   mUtilRange;
   PRUint32                mJoinOffset;  // need to remember an int across willJoin/didJoin...
+  nsCOMPtr    mNewBlock;
 
 };