From c6d23e3e18a22b3732864732540cfe1e46b2cd40 Mon Sep 17 00:00:00 2001 From: "buster%netscape.com" <buster%netscape.com> Date: Fri, 30 Apr 1999 22:40:18 +0000 Subject: [PATCH] with permission from chofmann: 1. fix for bug 5796, crash on exit. This was a bad, bad memory smudge on my part, easily fixed by doing the right ref counting in the right places. 2. some preliminary code for M6 block transformations has leaked into this checkin. It's safer than trying to re-code the fix above into a fresh tree. Unless you're making calls to do block transformations, you won't see any difference. --- editor/base/nsEditorEventListeners.cpp | 37 ++- editor/base/nsHTMLEditor.cpp | 265 +++++++++++++----- editor/base/nsHTMLEditor.h | 14 +- editor/base/nsTextEditor.cpp | 118 +++++++- editor/base/nsTextEditor.h | 13 +- editor/libeditor/html/nsHTMLEditor.cpp | 265 +++++++++++++----- editor/libeditor/html/nsHTMLEditor.h | 14 +- .../libeditor/text/nsEditorEventListeners.cpp | 37 ++- editor/public/nsIHTMLEditor.h | 21 +- 9 files changed, 588 insertions(+), 196 deletions(-) diff --git a/editor/base/nsEditorEventListeners.cpp b/editor/base/nsEditorEventListeners.cpp index a8a714674bf53..6b9e2fa4bf6fe 100644 --- a/editor/base/nsEditorEventListeners.cpp +++ b/editor/base/nsEditorEventListeners.cpp @@ -428,7 +428,6 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr // hard-coded ChangeTextAttributes test -- font color red case nsIDOMEvent::VK_1: - case nsIDOMEvent::VK_F: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -454,7 +453,6 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr // hard-coded ChangeTextAttributes test -- remove font color case nsIDOMEvent::VK_2: - case nsIDOMEvent::VK_R: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -553,9 +551,8 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr } break; - // hard-coded change structure test -- block H1 + // hard-coded change structure test -- transform block H1 case nsIDOMEvent::VK_7: - case nsIDOMEvent::VK_Q: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -567,15 +564,14 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr { nsAutoString tag; nsIEditProperty::h1->ToString(tag); - htmlEditor->AddBlockParent(tag); + htmlEditor->ReplaceBlockParent(tag); } } } break; - // hard-coded change structure test -- block blockquote (indent) + // hard-coded change structure test -- transform block H2 case nsIDOMEvent::VK_8: - case nsIDOMEvent::VK_W: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -586,8 +582,8 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr if (htmlEditor) { nsAutoString tag; - nsIEditProperty::blockquote->ToString(tag); - htmlEditor->AddBlockParent(tag); + nsIEditProperty::h2->ToString(tag); + htmlEditor->ReplaceBlockParent(tag); } } } @@ -595,7 +591,6 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr // hard-coded change structure test -- normal case nsIDOMEvent::VK_9: - case nsIDOMEvent::VK_E: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -610,9 +605,27 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr } break; + // hard-coded change structure test -- block blockquote (indent) + case nsIDOMEvent::VK_COMMA: + if (PR_TRUE==ctrlKey) + { + aProcessed=PR_TRUE; + if (mEditor) + { + nsCOMPtr<nsIHTMLEditor>htmlEditor; + htmlEditor = do_QueryInterface(mEditor); + if (htmlEditor) + { + nsAutoString tag; + nsIEditProperty::blockquote->ToString(tag); + htmlEditor->AddBlockParent(tag); + } + } + } + break; + // hard-coded change structure test -- un-BlockQuote - case nsIDOMEvent::VK_0: - case nsIDOMEvent::VK_G: + case nsIDOMEvent::VK_PERIOD: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; diff --git a/editor/base/nsHTMLEditor.cpp b/editor/base/nsHTMLEditor.cpp index b73d4c4af6558..bb0593b037b1e 100644 --- a/editor/base/nsHTMLEditor.cpp +++ b/editor/base/nsHTMLEditor.cpp @@ -35,6 +35,8 @@ #include "nsEditorCID.h" #include "nsLayoutCID.h" #include "nsIDOMRange.h" +#include "nsISupportsArray.h" +#include "nsVoidArray.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" @@ -360,10 +362,74 @@ nsHTMLEditor::CopyAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode) // Note: Table Editing methods are implemented in EditTable.cpp // +// get the paragraph style(s) for the selection NS_IMETHODIMP -nsHTMLEditor::AddBlockParent(nsString& aParentTag) +nsHTMLEditor::GetParagraphStyle(nsStringArray *aTagList) { + if (gNoisy) { printf("---------- nsHTMLEditor::GetParagraphStyle ----------\n"); } + if (!aTagList) { return NS_ERROR_NULL_POINTER; } + nsresult result; + nsCOMPtr<nsIDOMSelection>selection; + result = nsEditor::GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) + { + nsCOMPtr<nsIEnumerator> enumerator; + enumerator = do_QueryInterface(selection); + if (enumerator) + { + enumerator->First(); + nsISupports *currentItem; + result = enumerator->CurrentItem(¤tItem); + if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) + { + nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); + // scan the range for all the independent block content subranges + // and get the block parent of each + nsISupportsArray *subRanges; + result = NS_NewISupportsArray(&subRanges); + if ((NS_SUCCEEDED(result)) && subRanges) + { + result = GetBlockRanges(range, subRanges); + if (NS_SUCCEEDED(result)) + { + nsIDOMRange *subRange; + subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + while (subRange && (NS_SUCCEEDED(result))) + { + nsCOMPtr<nsIDOMNode>startParent; + result = subRange->GetStartParent(getter_AddRefs(startParent)); + if (NS_SUCCEEDED(result) && startParent) + { + nsCOMPtr<nsIDOMElement> blockParent; + result = GetBlockParent(startParent, getter_AddRefs(blockParent)); + if (NS_SUCCEEDED(result) && blockParent) + { + nsAutoString blockParentTag; + blockParent->GetTagName(blockParentTag); + if (-1==aTagList->IndexOf(blockParentTag)) { + aTagList->AppendString(blockParentTag); + } + } + } + NS_RELEASE(subRange); + subRanges->RemoveElementAt(0); + subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + } + } + NS_RELEASE(subRanges); + } + } + } + } + + return result; +} + +// use this when block parents are to be added regardless of current state +NS_IMETHODIMP +nsHTMLEditor::AddBlockParent(nsString& aParentTag) +{ if (gNoisy) { char *tag = aParentTag.ToNewCString(); @@ -388,58 +454,9 @@ nsHTMLEditor::AddBlockParent(nsString& aParentTag) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) { nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); - nsCOMPtr<nsIDOMNode>commonParent; - result = range->GetCommonParent(getter_AddRefs(commonParent)); - if ((NS_SUCCEEDED(result)) && commonParent) - { - PRInt32 startOffset, endOffset; - range->GetStartOffset(&startOffset); - range->GetEndOffset(&endOffset); - nsCOMPtr<nsIDOMNode> startParent; nsCOMPtr<nsIDOMNode> endParent; - range->GetStartParent(getter_AddRefs(startParent)); - range->GetEndParent(getter_AddRefs(endParent)); - if (startParent.get()==endParent.get()) - { // the range is entirely contained within a single node - result = ReParentContentOfNode(startParent, aParentTag); - } - else - { - nsCOMPtr<nsIDOMNode> startGrandParent; - startParent->GetParentNode(getter_AddRefs(startGrandParent)); - nsCOMPtr<nsIDOMNode> endGrandParent; - endParent->GetParentNode(getter_AddRefs(endGrandParent)); - if (NS_SUCCEEDED(result)) - { - PRBool canCollapse = PR_FALSE; - if (endGrandParent.get()==startGrandParent.get()) - { - result = IntermediateNodesAreInline(range, startParent, startOffset, - endParent, endOffset, - canCollapse); - } - if (NS_SUCCEEDED(result)) - { - if (PR_TRUE==canCollapse) - { // the range is between 2 nodes that have a common (immediate) grandparent, - // and any intermediate nodes are just inline style nodes - result = ReParentContentOfNode(startParent, aParentTag); - } - else - { // the range is between 2 nodes that have no simple relationship - result = ReParentContentOfRange(range, aParentTag); - } - } - } - } - if (NS_SUCCEEDED(result)) - { // compute a range for the selection - // don't want to actually do anything with selection, because - // we are still iterating through it. Just want to create and remember - // an nsIDOMRange, and later add the range to the selection after clearing it. - // XXX: I'm blocked here because nsIDOMSelection doesn't provide a mechanism - // for setting a compound selection yet. - } - } + // scan the range for all the independent block content subranges + // and apply the transformation to them + result = ReParentContentOfRange(range, aParentTag, eInsertParent); } } nsEditor::EndTransaction(); @@ -453,8 +470,74 @@ nsHTMLEditor::AddBlockParent(nsString& aParentTag) return result; } +// use this when a paragraph type is being transformed from one type to another NS_IMETHODIMP -nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag) +nsHTMLEditor::ReplaceBlockParent(nsString& aParentTag) +{ + + if (gNoisy) + { + char *tag = aParentTag.ToNewCString(); + printf("---------- nsHTMLEditor::ReplaceBlockParent %s ----------\n", tag); + delete [] tag; + } + + nsresult result=NS_ERROR_NOT_INITIALIZED; + nsCOMPtr<nsIDOMSelection>selection; + result = nsEditor::GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) + { + // set the block parent for all selected ranges + nsEditor::BeginTransaction(); + nsCOMPtr<nsIEnumerator> enumerator; + enumerator = do_QueryInterface(selection); + if (enumerator) + { + enumerator->First(); + nsISupports *currentItem; + result = enumerator->CurrentItem(¤tItem); + if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) + { + nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); + // scan the range for all the independent block content subranges + // and apply the transformation to them + result = ReParentContentOfRange(range, aParentTag, eReplaceParent); + } + } + nsEditor::EndTransaction(); + if (NS_SUCCEEDED(result)) + { // set the selection + // XXX: can't do anything until I can create ranges + } + } + if (gNoisy) {printf("Finished nsHTMLEditor::AddBlockParent with this content:\n"); DebugDumpContent(); } // DEBUG + + return result; +} + +void IsRootTag(nsString &aTag, PRBool &aIsTag) +{ + static nsAutoString bodyTag = "body"; + static nsAutoString tdTag = "td"; + static nsAutoString thTag = "th"; + static nsAutoString captionTag = "caption"; + if (PR_TRUE==aTag.EqualsIgnoreCase(bodyTag) || + PR_TRUE==aTag.EqualsIgnoreCase(tdTag) || + PR_TRUE==aTag.EqualsIgnoreCase(thTag) || + PR_TRUE==aTag.EqualsIgnoreCase(captionTag) ) + { + aIsTag = PR_TRUE; + } + else { + aIsTag = PR_FALSE; + } +} + + +NS_IMETHODIMP +nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, + nsString &aParentTag, + BlockTransformationType aTransformation) { if (!aNode) { return NS_ERROR_NULL_POINTER; } // find the current block parent, or just use aNode if it is a block node @@ -473,7 +556,7 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag) nodeIsBlock=PR_TRUE; } } - // if aNode is the block parent, then we're operating on one of its children + // if aNode is the block parent, then the node to reparent is one of its children if (PR_TRUE==nodeIsBlock) { result = aNode->QueryInterface(nsIDOMNode::GetIID(), getter_AddRefs(blockParentElement)); @@ -481,7 +564,7 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag) result = aNode->GetFirstChild(getter_AddRefs(nodeToReParent)); } } - else { + else { // we just need to get the block parent of aNode result = nsTextEditor::GetBlockParent(aNode, getter_AddRefs(blockParentElement)); } // at this point, we must have a good result, a node to reparent, and a block parent @@ -494,38 +577,44 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag) // we need to treat nodes directly inside the body differently nsAutoString parentTag; blockParentElement->GetTagName(parentTag); - nsAutoString bodyTag = "body"; - if (PR_TRUE==parentTag.EqualsIgnoreCase(bodyTag)) + PRBool isRoot; + IsRootTag(parentTag, isRoot); + if (PR_TRUE==isRoot) { - // if nodeToReParent is a text node, we have <BODY><TEXT>text. - // re-parent <TEXT> into a new <aTag> at the offset of <TEXT> in <BODY> + // if nodeToReParent is a text node, we have <ROOT>Text. + // re-parent Text into a new <aTag> at the offset of Text in <ROOT> + // so we end up with <ROOT><aTag>Text + // ignore aTransformation, replaces act like inserts nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(nodeToReParent); if (nodeAsText) { result = ReParentBlockContent(nodeToReParent, aParentTag, blockParentNode, parentTag, - getter_AddRefs(newParentNode)); + aTransformation, getter_AddRefs(newParentNode)); } else { // this is the case of an insertion point between 2 non-text objects + // XXX: how to you know it's an insertion point??? PRInt32 offsetInParent=0; result = nsIEditorSupport::GetChildOffset(nodeToReParent, blockParentNode, offsetInParent); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); // otherwise, just create the block parent at the selection result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, getter_AddRefs(newParentNode)); - // XXX: need to create a bogus text node inside this new block! + // XXX: need to move some of the children of blockParentNode into the newParentNode? + // XXX: need to create a bogus text node inside this new block? // that means, I need to generalize bogus node handling } } else - { - // for the selected block content, replace blockParentNode with a new node of the correct type - if (PR_FALSE==parentTag.EqualsIgnoreCase(aParentTag)) + { // the block parent is not a ROOT, + // for the selected block content, transform blockParentNode + if (((eReplaceParent==aTransformation) && (PR_FALSE==parentTag.EqualsIgnoreCase(aParentTag))) || + (eInsertParent==aTransformation)) { - if (gNoisy) { DebugDumpContent(); } // DEBUG + if (gNoisy) { DebugDumpContent(); } // DEBUG result = ReParentBlockContent(nodeToReParent, aParentTag, blockParentNode, parentTag, - getter_AddRefs(newParentNode)); - if (NS_SUCCEEDED(result) && newParentNode) + aTransformation, getter_AddRefs(newParentNode)); + if ((NS_SUCCEEDED(result)) && (newParentNode) && (eReplaceParent==aTransformation)) { PRBool hasChildren; blockParentNode->HasChildNodes(&hasChildren); @@ -554,6 +643,7 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, nsString &aParentTag, nsIDOMNode *aBlockParentNode, nsString &aBlockParentTag, + BlockTransformationType aTranformation, nsIDOMNode **aNewParentNode) { if (!aNode || !aBlockParentNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; } @@ -574,16 +664,13 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, } // now, previousAncestor is the node we are operating on nsCOMPtr<nsIDOMNode>leftNode, rightNode; - result = GetBlockDelimitedContent(aBlockParentNode, - previousAncestor, + result = GetBlockDelimitedContent(previousAncestor, getter_AddRefs(leftNode), getter_AddRefs(rightNode)); if ((NS_SUCCEEDED(result)) && leftNode && rightNode) { PRInt32 offsetInParent=0; - PRBool canContain; - CanContainBlock(aParentTag, aBlockParentTag, canContain); - if (PR_TRUE==canContain) + if (eInsertParent==aTranformation) { result = nsIEditorSupport::GetChildOffset(leftNode, aBlockParentNode, offsetInParent); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); @@ -644,10 +731,36 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, } NS_IMETHODIMP -nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, nsString &aParentTag) +nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, + nsString &aParentTag, + BlockTransformationType aTranformation) { - nsresult result=NS_ERROR_NOT_IMPLEMENTED; - printf("transformations over complex selections not implemented.\n"); + if (!aRange) { return NS_ERROR_NULL_POINTER; } + nsresult result; + nsISupportsArray *subRanges; + result = NS_NewISupportsArray(&subRanges); + if ((NS_SUCCEEDED(result)) && subRanges) + { + result = GetBlockRanges(aRange, subRanges); + if (NS_SUCCEEDED(result)) + { + nsIDOMRange *subRange; + subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + while (subRange && (NS_SUCCEEDED(result))) + { + nsCOMPtr<nsIDOMNode>startParent; + result = subRange->GetStartParent(getter_AddRefs(startParent)); + if (NS_SUCCEEDED(result) && startParent) + { + result = ReParentContentOfNode(startParent, aParentTag, aTranformation); + } + NS_RELEASE(subRange); + subRanges->RemoveElementAt(0); + subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + } + } + NS_RELEASE(subRanges); + } return result; } diff --git a/editor/base/nsHTMLEditor.h b/editor/base/nsHTMLEditor.h index 70fccbf0231a4..a1915de5a32e3 100644 --- a/editor/base/nsHTMLEditor.h +++ b/editor/base/nsHTMLEditor.h @@ -32,6 +32,9 @@ */ class nsHTMLEditor : public nsTextEditor, public nsIHTMLEditor { + + typedef enum {eNoOp=0, eReplaceParent=1, eInsertParent=2} BlockTransformationType; + public: // see nsIHTMLEditor for documentation @@ -96,7 +99,9 @@ public: // End of methods implemented in nsEditor //============================================================= // HTML Editing methods + NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList); NS_IMETHOD AddBlockParent(nsString& aParentTag); + NS_IMETHOD ReplaceBlockParent(nsString& aParentTag); NS_IMETHOD RemoveBlockParent(); NS_IMETHOD RemoveParent(const nsString &aParentTag); @@ -138,15 +143,20 @@ protected: virtual void InitRules(); - NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag); + NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode, + nsString &aParentTag, + BlockTransformationType aTranformation); NS_IMETHOD ReParentBlockContent(nsIDOMNode *aNode, nsString &aParentTag, nsIDOMNode *aBlockParentNode, nsString &aBlockParentTag, + BlockTransformationType aTranformation, nsIDOMNode **aNewParentNode); - NS_IMETHOD ReParentContentOfRange(nsIDOMRange *aRange, nsString &aParentTag); + NS_IMETHOD ReParentContentOfRange(nsIDOMRange *aRange, + nsString &aParentTag, + BlockTransformationType aTranformation); NS_IMETHOD CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRBool &aCanContain); diff --git a/editor/base/nsTextEditor.cpp b/editor/base/nsTextEditor.cpp index b3b07f87d1ec0..91a8cc798e58d 100644 --- a/editor/base/nsTextEditor.cpp +++ b/editor/base/nsTextEditor.cpp @@ -187,6 +187,7 @@ nsTextEditor::~nsTextEditor() if (mRules) { delete mRules; } + NS_IF_RELEASE(mTypeInState); nsEditProperty::InstanceShutdown(); } @@ -228,12 +229,18 @@ NS_IMETHODIMP nsTextEditor::Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell) result = nsEditor::Init(aDoc, aPresShell); if (NS_OK != result) { return result; } + // init the type-in state + mTypeInState = new TypeInState(); + if (!mTypeInState) {return NS_ERROR_NULL_POINTER;} + NS_ADDREF(mTypeInState); + nsCOMPtr<nsIDOMSelection>selection; result = nsEditor::GetSelection(getter_AddRefs(selection)); if (NS_OK != result) { return result; } - if (selection) { + if (selection) + { nsCOMPtr<nsIDOMSelectionListener>listener; - listener = do_QueryInterface(&mTypeInState); + listener = do_QueryInterface(mTypeInState); if (listener) { selection->AddSelectionListener(listener); } @@ -331,7 +338,7 @@ NS_IMETHODIMP nsTextEditor::SetTextProperty(nsIAtom *aProperty, if (PR_TRUE==isCollapsed) { // manipulating text attributes on a collapsed selection only sets state for the next text insertion - SetTypeInStateForProperty(mTypeInState, aProperty, aAttribute, aValue); + SetTypeInStateForProperty(*mTypeInState, aProperty, aAttribute, aValue); } else { @@ -646,7 +653,7 @@ NS_IMETHODIMP nsTextEditor::RemoveTextProperty(nsIAtom *aProperty, const nsStrin if (PR_TRUE==isCollapsed) { // manipulating text attributes on a collapsed selection only sets state for the next text insertion - SetTypeInStateForProperty(mTypeInState, aProperty, aAttribute, nsnull); + SetTypeInStateForProperty(*mTypeInState, aProperty, aAttribute, nsnull); } else { @@ -787,7 +794,7 @@ NS_IMETHODIMP nsTextEditor::InsertText(const nsString& aStringToInsert) ruleInfo.placeTxn = &placeholderTxn; ruleInfo.inString = &aStringToInsert; ruleInfo.outString = &resultString; - ruleInfo.typeInState = mTypeInState; + ruleInfo.typeInState = *mTypeInState; nsresult result = mRules->WillDoAction(selection, &ruleInfo, &cancel); if ((PR_FALSE==cancel) && (NS_SUCCEEDED(result))) @@ -1379,13 +1386,12 @@ nsTextEditor::GetBlockParent(nsIDOMNode *aNode, nsIDOMElement **aBlockParent) co } NS_IMETHODIMP -nsTextEditor::GetBlockDelimitedContent(nsIDOMNode *aParent, - nsIDOMNode *aChild, +nsTextEditor::GetBlockDelimitedContent(nsIDOMNode *aChild, nsIDOMNode **aLeftNode, nsIDOMNode **aRightNode) const { nsresult result = NS_OK; - if (!aParent || !aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;} + if (!aChild || !aLeftNode || !aRightNode) {return NS_ERROR_NULL_POINTER;} *aLeftNode = aChild; *aRightNode = aChild; @@ -1429,6 +1435,94 @@ nsTextEditor::GetBlockDelimitedContent(nsIDOMNode *aParent, return result; } +NS_IMETHODIMP +nsTextEditor::GetBlockRanges(nsIDOMRange *aRange, nsISupportsArray *aSubRanges) const +{ + if (!aRange || !aSubRanges) {return NS_ERROR_NULL_POINTER;} + + nsresult result; + nsCOMPtr<nsIContentIterator>iter; + result = nsComponentManager::CreateInstance(kCContentIteratorCID, nsnull, + kIContentIteratorIID, getter_AddRefs(iter)); + if ((NS_SUCCEEDED(result)) && iter) + { + nsCOMPtr<nsIDOMRange> lastRange; + iter->Init(aRange); + nsCOMPtr<nsIContent> currentContent; + iter->CurrentNode(getter_AddRefs(currentContent)); + while (NS_COMFALSE == iter->IsDone()) + { + nsCOMPtr<nsIDOMNode>currentNode = do_QueryInterface(currentContent); + if (currentNode) + { + PRBool isInlineOrText; + result = IsNodeInline(currentNode, isInlineOrText); + if (PR_FALSE==isInlineOrText) + { + PRUint16 nodeType; + currentNode->GetNodeType(&nodeType); + if (nsIDOMNode::TEXT_NODE == nodeType) { + isInlineOrText = PR_TRUE; + } + } + if (PR_TRUE==isInlineOrText) + { + nsCOMPtr<nsIDOMNode>leftNode; + nsCOMPtr<nsIDOMNode>rightNode; + result = GetBlockDelimitedContent(currentNode, + getter_AddRefs(leftNode), + getter_AddRefs(rightNode)); + if (gNoisy) {printf("currentNode %p has block content (%p,%p)\n", currentNode.get(), leftNode.get(), rightNode.get());} + if ((NS_SUCCEEDED(result)) && leftNode && rightNode) + { + // add range to the list if it doesn't overlap with the previous range + PRBool addRange=PR_TRUE; + if (lastRange) + { + nsCOMPtr<nsIDOMNode> lastStartNode; + nsCOMPtr<nsIDOMElement> blockParentOfLastStartNode; + lastRange->GetStartParent(getter_AddRefs(lastStartNode)); + result = GetBlockParent(lastStartNode, getter_AddRefs(blockParentOfLastStartNode)); + if ((NS_SUCCEEDED(result)) && blockParentOfLastStartNode) + { + if (gNoisy) {printf("lastStartNode %p has block parent %p\n", lastStartNode.get(), blockParentOfLastStartNode.get());} + nsCOMPtr<nsIDOMElement> blockParentOfLeftNode; + result = GetBlockParent(leftNode, getter_AddRefs(blockParentOfLeftNode)); + if ((NS_SUCCEEDED(result)) && blockParentOfLeftNode) + { + if (gNoisy) {printf("leftNode %p has block parent %p\n", leftNode.get(), blockParentOfLeftNode.get());} + if (blockParentOfLastStartNode==blockParentOfLeftNode) { + addRange = PR_FALSE; + } + } + } + } + if (PR_TRUE==addRange) + { + if (gNoisy) {printf("adding range, setting lastRange with start node %p\n", leftNode.get());} + nsCOMPtr<nsIDOMRange> range; + result = nsComponentManager::CreateInstance(kCRangeCID, nsnull, + kIDOMRangeIID, getter_AddRefs(range)); + if ((NS_SUCCEEDED(result)) && range) + { // initialize the range + range->SetStart(leftNode, 0); + range->SetEnd(rightNode, 0); + aSubRanges->AppendElement(range); + lastRange = do_QueryInterface(range); + } + } + } + } + } + /* do not check result here, and especially do not return the result code. + * we rely on iter->IsDone to tell us when the iteration is complete + */ + iter->Next(); + iter->CurrentNode(getter_AddRefs(currentContent)); + } + } + return result; +} NS_IMETHODIMP nsTextEditor::IntermediateNodesAreInline(nsIDOMRange *aRange, @@ -2236,6 +2330,14 @@ nsTextEditor::RemoveTextPropertiesForNodeWithDifferentParents(nsIDOMNode *aStar return result; } +TypeInState * nsTextEditor::GetTypeInState() +{ + if (mTypeInState) { + NS_ADDREF(mTypeInState); + } + return mTypeInState; +} + NS_IMETHODIMP nsTextEditor::SetTypeInStateForProperty(TypeInState &aTypeInState, nsIAtom *aPropName, diff --git a/editor/base/nsTextEditor.h b/editor/base/nsTextEditor.h index 4529148c5d801..f4341227d6c5f 100644 --- a/editor/base/nsTextEditor.h +++ b/editor/base/nsTextEditor.h @@ -151,8 +151,11 @@ protected: */ NS_IMETHOD GetBlockParent(nsIDOMNode *aNode, nsIDOMElement **aBlockParent) const; - NS_IMETHOD GetBlockDelimitedContent(nsIDOMNode *aParent, nsIDOMNode *aChild, - nsIDOMNode **aLeftNode, nsIDOMNode **aRightNode) const; + NS_IMETHOD GetBlockDelimitedContent(nsIDOMNode *aChild, + nsIDOMNode **aLeftNode, + nsIDOMNode **aRightNode) const; + + NS_IMETHOD GetBlockRanges(nsIDOMRange *aRange, nsISupportsArray *aSubRanges) const; /** returns PR_TRUE in out-param aResult if all nodes between (aStartNode, aStartOffset) * and (aEndNode, aEndOffset) are inline as defined by HTML DTD. @@ -265,13 +268,13 @@ protected: const nsString *aAttribute, const nsString *aValue); - TypeInState GetTypeInState() { return mTypeInState;} + TypeInState *GetTypeInState(); // Data members protected: - TypeInState mTypeInState; // xxx - isn't it wrong to have xpcom classes as members? shouldn't it be a pointer? - nsTextEditRules* mRules; + TypeInState *mTypeInState; + nsTextEditRules *mRules; nsCOMPtr<nsIDOMEventListener> mKeyListenerP; nsCOMPtr<nsIDOMEventListener> mMouseListenerP; nsCOMPtr<nsIDOMEventListener> mTextListenerP; diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index b73d4c4af6558..bb0593b037b1e 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -35,6 +35,8 @@ #include "nsEditorCID.h" #include "nsLayoutCID.h" #include "nsIDOMRange.h" +#include "nsISupportsArray.h" +#include "nsVoidArray.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" @@ -360,10 +362,74 @@ nsHTMLEditor::CopyAttributes(nsIDOMNode *aDestNode, nsIDOMNode *aSourceNode) // Note: Table Editing methods are implemented in EditTable.cpp // +// get the paragraph style(s) for the selection NS_IMETHODIMP -nsHTMLEditor::AddBlockParent(nsString& aParentTag) +nsHTMLEditor::GetParagraphStyle(nsStringArray *aTagList) { + if (gNoisy) { printf("---------- nsHTMLEditor::GetParagraphStyle ----------\n"); } + if (!aTagList) { return NS_ERROR_NULL_POINTER; } + nsresult result; + nsCOMPtr<nsIDOMSelection>selection; + result = nsEditor::GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) + { + nsCOMPtr<nsIEnumerator> enumerator; + enumerator = do_QueryInterface(selection); + if (enumerator) + { + enumerator->First(); + nsISupports *currentItem; + result = enumerator->CurrentItem(¤tItem); + if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) + { + nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); + // scan the range for all the independent block content subranges + // and get the block parent of each + nsISupportsArray *subRanges; + result = NS_NewISupportsArray(&subRanges); + if ((NS_SUCCEEDED(result)) && subRanges) + { + result = GetBlockRanges(range, subRanges); + if (NS_SUCCEEDED(result)) + { + nsIDOMRange *subRange; + subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + while (subRange && (NS_SUCCEEDED(result))) + { + nsCOMPtr<nsIDOMNode>startParent; + result = subRange->GetStartParent(getter_AddRefs(startParent)); + if (NS_SUCCEEDED(result) && startParent) + { + nsCOMPtr<nsIDOMElement> blockParent; + result = GetBlockParent(startParent, getter_AddRefs(blockParent)); + if (NS_SUCCEEDED(result) && blockParent) + { + nsAutoString blockParentTag; + blockParent->GetTagName(blockParentTag); + if (-1==aTagList->IndexOf(blockParentTag)) { + aTagList->AppendString(blockParentTag); + } + } + } + NS_RELEASE(subRange); + subRanges->RemoveElementAt(0); + subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + } + } + NS_RELEASE(subRanges); + } + } + } + } + + return result; +} + +// use this when block parents are to be added regardless of current state +NS_IMETHODIMP +nsHTMLEditor::AddBlockParent(nsString& aParentTag) +{ if (gNoisy) { char *tag = aParentTag.ToNewCString(); @@ -388,58 +454,9 @@ nsHTMLEditor::AddBlockParent(nsString& aParentTag) if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) { nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); - nsCOMPtr<nsIDOMNode>commonParent; - result = range->GetCommonParent(getter_AddRefs(commonParent)); - if ((NS_SUCCEEDED(result)) && commonParent) - { - PRInt32 startOffset, endOffset; - range->GetStartOffset(&startOffset); - range->GetEndOffset(&endOffset); - nsCOMPtr<nsIDOMNode> startParent; nsCOMPtr<nsIDOMNode> endParent; - range->GetStartParent(getter_AddRefs(startParent)); - range->GetEndParent(getter_AddRefs(endParent)); - if (startParent.get()==endParent.get()) - { // the range is entirely contained within a single node - result = ReParentContentOfNode(startParent, aParentTag); - } - else - { - nsCOMPtr<nsIDOMNode> startGrandParent; - startParent->GetParentNode(getter_AddRefs(startGrandParent)); - nsCOMPtr<nsIDOMNode> endGrandParent; - endParent->GetParentNode(getter_AddRefs(endGrandParent)); - if (NS_SUCCEEDED(result)) - { - PRBool canCollapse = PR_FALSE; - if (endGrandParent.get()==startGrandParent.get()) - { - result = IntermediateNodesAreInline(range, startParent, startOffset, - endParent, endOffset, - canCollapse); - } - if (NS_SUCCEEDED(result)) - { - if (PR_TRUE==canCollapse) - { // the range is between 2 nodes that have a common (immediate) grandparent, - // and any intermediate nodes are just inline style nodes - result = ReParentContentOfNode(startParent, aParentTag); - } - else - { // the range is between 2 nodes that have no simple relationship - result = ReParentContentOfRange(range, aParentTag); - } - } - } - } - if (NS_SUCCEEDED(result)) - { // compute a range for the selection - // don't want to actually do anything with selection, because - // we are still iterating through it. Just want to create and remember - // an nsIDOMRange, and later add the range to the selection after clearing it. - // XXX: I'm blocked here because nsIDOMSelection doesn't provide a mechanism - // for setting a compound selection yet. - } - } + // scan the range for all the independent block content subranges + // and apply the transformation to them + result = ReParentContentOfRange(range, aParentTag, eInsertParent); } } nsEditor::EndTransaction(); @@ -453,8 +470,74 @@ nsHTMLEditor::AddBlockParent(nsString& aParentTag) return result; } +// use this when a paragraph type is being transformed from one type to another NS_IMETHODIMP -nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag) +nsHTMLEditor::ReplaceBlockParent(nsString& aParentTag) +{ + + if (gNoisy) + { + char *tag = aParentTag.ToNewCString(); + printf("---------- nsHTMLEditor::ReplaceBlockParent %s ----------\n", tag); + delete [] tag; + } + + nsresult result=NS_ERROR_NOT_INITIALIZED; + nsCOMPtr<nsIDOMSelection>selection; + result = nsEditor::GetSelection(getter_AddRefs(selection)); + if ((NS_SUCCEEDED(result)) && selection) + { + // set the block parent for all selected ranges + nsEditor::BeginTransaction(); + nsCOMPtr<nsIEnumerator> enumerator; + enumerator = do_QueryInterface(selection); + if (enumerator) + { + enumerator->First(); + nsISupports *currentItem; + result = enumerator->CurrentItem(¤tItem); + if ((NS_SUCCEEDED(result)) && (nsnull!=currentItem)) + { + nsCOMPtr<nsIDOMRange> range( do_QueryInterface(currentItem) ); + // scan the range for all the independent block content subranges + // and apply the transformation to them + result = ReParentContentOfRange(range, aParentTag, eReplaceParent); + } + } + nsEditor::EndTransaction(); + if (NS_SUCCEEDED(result)) + { // set the selection + // XXX: can't do anything until I can create ranges + } + } + if (gNoisy) {printf("Finished nsHTMLEditor::AddBlockParent with this content:\n"); DebugDumpContent(); } // DEBUG + + return result; +} + +void IsRootTag(nsString &aTag, PRBool &aIsTag) +{ + static nsAutoString bodyTag = "body"; + static nsAutoString tdTag = "td"; + static nsAutoString thTag = "th"; + static nsAutoString captionTag = "caption"; + if (PR_TRUE==aTag.EqualsIgnoreCase(bodyTag) || + PR_TRUE==aTag.EqualsIgnoreCase(tdTag) || + PR_TRUE==aTag.EqualsIgnoreCase(thTag) || + PR_TRUE==aTag.EqualsIgnoreCase(captionTag) ) + { + aIsTag = PR_TRUE; + } + else { + aIsTag = PR_FALSE; + } +} + + +NS_IMETHODIMP +nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, + nsString &aParentTag, + BlockTransformationType aTransformation) { if (!aNode) { return NS_ERROR_NULL_POINTER; } // find the current block parent, or just use aNode if it is a block node @@ -473,7 +556,7 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag) nodeIsBlock=PR_TRUE; } } - // if aNode is the block parent, then we're operating on one of its children + // if aNode is the block parent, then the node to reparent is one of its children if (PR_TRUE==nodeIsBlock) { result = aNode->QueryInterface(nsIDOMNode::GetIID(), getter_AddRefs(blockParentElement)); @@ -481,7 +564,7 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag) result = aNode->GetFirstChild(getter_AddRefs(nodeToReParent)); } } - else { + else { // we just need to get the block parent of aNode result = nsTextEditor::GetBlockParent(aNode, getter_AddRefs(blockParentElement)); } // at this point, we must have a good result, a node to reparent, and a block parent @@ -494,38 +577,44 @@ nsHTMLEditor::ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag) // we need to treat nodes directly inside the body differently nsAutoString parentTag; blockParentElement->GetTagName(parentTag); - nsAutoString bodyTag = "body"; - if (PR_TRUE==parentTag.EqualsIgnoreCase(bodyTag)) + PRBool isRoot; + IsRootTag(parentTag, isRoot); + if (PR_TRUE==isRoot) { - // if nodeToReParent is a text node, we have <BODY><TEXT>text. - // re-parent <TEXT> into a new <aTag> at the offset of <TEXT> in <BODY> + // if nodeToReParent is a text node, we have <ROOT>Text. + // re-parent Text into a new <aTag> at the offset of Text in <ROOT> + // so we end up with <ROOT><aTag>Text + // ignore aTransformation, replaces act like inserts nsCOMPtr<nsIDOMCharacterData> nodeAsText = do_QueryInterface(nodeToReParent); if (nodeAsText) { result = ReParentBlockContent(nodeToReParent, aParentTag, blockParentNode, parentTag, - getter_AddRefs(newParentNode)); + aTransformation, getter_AddRefs(newParentNode)); } else { // this is the case of an insertion point between 2 non-text objects + // XXX: how to you know it's an insertion point??? PRInt32 offsetInParent=0; result = nsIEditorSupport::GetChildOffset(nodeToReParent, blockParentNode, offsetInParent); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); // otherwise, just create the block parent at the selection result = nsTextEditor::CreateNode(aParentTag, blockParentNode, offsetInParent, getter_AddRefs(newParentNode)); - // XXX: need to create a bogus text node inside this new block! + // XXX: need to move some of the children of blockParentNode into the newParentNode? + // XXX: need to create a bogus text node inside this new block? // that means, I need to generalize bogus node handling } } else - { - // for the selected block content, replace blockParentNode with a new node of the correct type - if (PR_FALSE==parentTag.EqualsIgnoreCase(aParentTag)) + { // the block parent is not a ROOT, + // for the selected block content, transform blockParentNode + if (((eReplaceParent==aTransformation) && (PR_FALSE==parentTag.EqualsIgnoreCase(aParentTag))) || + (eInsertParent==aTransformation)) { - if (gNoisy) { DebugDumpContent(); } // DEBUG + if (gNoisy) { DebugDumpContent(); } // DEBUG result = ReParentBlockContent(nodeToReParent, aParentTag, blockParentNode, parentTag, - getter_AddRefs(newParentNode)); - if (NS_SUCCEEDED(result) && newParentNode) + aTransformation, getter_AddRefs(newParentNode)); + if ((NS_SUCCEEDED(result)) && (newParentNode) && (eReplaceParent==aTransformation)) { PRBool hasChildren; blockParentNode->HasChildNodes(&hasChildren); @@ -554,6 +643,7 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, nsString &aParentTag, nsIDOMNode *aBlockParentNode, nsString &aBlockParentTag, + BlockTransformationType aTranformation, nsIDOMNode **aNewParentNode) { if (!aNode || !aBlockParentNode || !aNewParentNode) { return NS_ERROR_NULL_POINTER; } @@ -574,16 +664,13 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, } // now, previousAncestor is the node we are operating on nsCOMPtr<nsIDOMNode>leftNode, rightNode; - result = GetBlockDelimitedContent(aBlockParentNode, - previousAncestor, + result = GetBlockDelimitedContent(previousAncestor, getter_AddRefs(leftNode), getter_AddRefs(rightNode)); if ((NS_SUCCEEDED(result)) && leftNode && rightNode) { PRInt32 offsetInParent=0; - PRBool canContain; - CanContainBlock(aParentTag, aBlockParentTag, canContain); - if (PR_TRUE==canContain) + if (eInsertParent==aTranformation) { result = nsIEditorSupport::GetChildOffset(leftNode, aBlockParentNode, offsetInParent); NS_ASSERTION((NS_SUCCEEDED(result)), "bad result from GetChildOffset"); @@ -644,10 +731,36 @@ nsHTMLEditor::ReParentBlockContent(nsIDOMNode *aNode, } NS_IMETHODIMP -nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, nsString &aParentTag) +nsHTMLEditor::ReParentContentOfRange(nsIDOMRange *aRange, + nsString &aParentTag, + BlockTransformationType aTranformation) { - nsresult result=NS_ERROR_NOT_IMPLEMENTED; - printf("transformations over complex selections not implemented.\n"); + if (!aRange) { return NS_ERROR_NULL_POINTER; } + nsresult result; + nsISupportsArray *subRanges; + result = NS_NewISupportsArray(&subRanges); + if ((NS_SUCCEEDED(result)) && subRanges) + { + result = GetBlockRanges(aRange, subRanges); + if (NS_SUCCEEDED(result)) + { + nsIDOMRange *subRange; + subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + while (subRange && (NS_SUCCEEDED(result))) + { + nsCOMPtr<nsIDOMNode>startParent; + result = subRange->GetStartParent(getter_AddRefs(startParent)); + if (NS_SUCCEEDED(result) && startParent) + { + result = ReParentContentOfNode(startParent, aParentTag, aTranformation); + } + NS_RELEASE(subRange); + subRanges->RemoveElementAt(0); + subRange = (nsIDOMRange *)(subRanges->ElementAt(0)); + } + } + NS_RELEASE(subRanges); + } return result; } diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index 70fccbf0231a4..a1915de5a32e3 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -32,6 +32,9 @@ */ class nsHTMLEditor : public nsTextEditor, public nsIHTMLEditor { + + typedef enum {eNoOp=0, eReplaceParent=1, eInsertParent=2} BlockTransformationType; + public: // see nsIHTMLEditor for documentation @@ -96,7 +99,9 @@ public: // End of methods implemented in nsEditor //============================================================= // HTML Editing methods + NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList); NS_IMETHOD AddBlockParent(nsString& aParentTag); + NS_IMETHOD ReplaceBlockParent(nsString& aParentTag); NS_IMETHOD RemoveBlockParent(); NS_IMETHOD RemoveParent(const nsString &aParentTag); @@ -138,15 +143,20 @@ protected: virtual void InitRules(); - NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode, nsString &aParentTag); + NS_IMETHOD ReParentContentOfNode(nsIDOMNode *aNode, + nsString &aParentTag, + BlockTransformationType aTranformation); NS_IMETHOD ReParentBlockContent(nsIDOMNode *aNode, nsString &aParentTag, nsIDOMNode *aBlockParentNode, nsString &aBlockParentTag, + BlockTransformationType aTranformation, nsIDOMNode **aNewParentNode); - NS_IMETHOD ReParentContentOfRange(nsIDOMRange *aRange, nsString &aParentTag); + NS_IMETHOD ReParentContentOfRange(nsIDOMRange *aRange, + nsString &aParentTag, + BlockTransformationType aTranformation); NS_IMETHOD CanContainBlock(nsString &aBlockChild, nsString &aBlockParent, PRBool &aCanContain); diff --git a/editor/libeditor/text/nsEditorEventListeners.cpp b/editor/libeditor/text/nsEditorEventListeners.cpp index a8a714674bf53..6b9e2fa4bf6fe 100644 --- a/editor/libeditor/text/nsEditorEventListeners.cpp +++ b/editor/libeditor/text/nsEditorEventListeners.cpp @@ -428,7 +428,6 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr // hard-coded ChangeTextAttributes test -- font color red case nsIDOMEvent::VK_1: - case nsIDOMEvent::VK_F: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -454,7 +453,6 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr // hard-coded ChangeTextAttributes test -- remove font color case nsIDOMEvent::VK_2: - case nsIDOMEvent::VK_R: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -553,9 +551,8 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr } break; - // hard-coded change structure test -- block H1 + // hard-coded change structure test -- transform block H1 case nsIDOMEvent::VK_7: - case nsIDOMEvent::VK_Q: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -567,15 +564,14 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr { nsAutoString tag; nsIEditProperty::h1->ToString(tag); - htmlEditor->AddBlockParent(tag); + htmlEditor->ReplaceBlockParent(tag); } } } break; - // hard-coded change structure test -- block blockquote (indent) + // hard-coded change structure test -- transform block H2 case nsIDOMEvent::VK_8: - case nsIDOMEvent::VK_W: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -586,8 +582,8 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr if (htmlEditor) { nsAutoString tag; - nsIEditProperty::blockquote->ToString(tag); - htmlEditor->AddBlockParent(tag); + nsIEditProperty::h2->ToString(tag); + htmlEditor->ReplaceBlockParent(tag); } } } @@ -595,7 +591,6 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr // hard-coded change structure test -- normal case nsIDOMEvent::VK_9: - case nsIDOMEvent::VK_E: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; @@ -610,9 +605,27 @@ nsTextEditorKeyListener::ProcessShortCutKeys(nsIDOMEvent* aKeyEvent, PRBool& aPr } break; + // hard-coded change structure test -- block blockquote (indent) + case nsIDOMEvent::VK_COMMA: + if (PR_TRUE==ctrlKey) + { + aProcessed=PR_TRUE; + if (mEditor) + { + nsCOMPtr<nsIHTMLEditor>htmlEditor; + htmlEditor = do_QueryInterface(mEditor); + if (htmlEditor) + { + nsAutoString tag; + nsIEditProperty::blockquote->ToString(tag); + htmlEditor->AddBlockParent(tag); + } + } + } + break; + // hard-coded change structure test -- un-BlockQuote - case nsIDOMEvent::VK_0: - case nsIDOMEvent::VK_G: + case nsIDOMEvent::VK_PERIOD: if (PR_TRUE==ctrlKey) { aProcessed=PR_TRUE; diff --git a/editor/public/nsIHTMLEditor.h b/editor/public/nsIHTMLEditor.h index 50b6e582f3279..1c1b09a4385ba 100644 --- a/editor/public/nsIHTMLEditor.h +++ b/editor/public/nsIHTMLEditor.h @@ -31,6 +31,7 @@ class nsIEditorCallback; class nsISupportsArray; +class nsStringArray; class nsIAtom; class nsIInputStream; class nsIOutputStream; @@ -98,14 +99,28 @@ public: * trigger off of ContentChanged notifications. */ + NS_IMETHOD GetParagraphStyle(nsStringArray *aTagList)=0; + /** Add a block parent node around the selected content. - * If the selected content already has a block parent that is not a sub-document, - * that block parent is changed to the type given by aParentTag. - * Otherwise, the new block parent is nested in the closest sub-document. + * Only legal nestings are allowed. + * An example of use is for indenting using blockquote nodes. + * * @param aParentTag The tag from which the new parent is created. */ NS_IMETHOD AddBlockParent(nsString& aParentTag)=0; + /** Replace the block parent node around the selected content with a new block + * parent node of type aParentTag. + * Only legal replacements are allowed. + * An example of use are is transforming H1 to LI ("paragraph type transformations"). + * For containing block transformations (transforming UL to OL, for example), + * the caller should RemoveParent("UL"), set the selection appropriately, + * and call AddBlockParent("OL"). + * + * @param aParentTag The tag from which the new parent is created. + */ + NS_IMETHOD ReplaceBlockParent(nsString& aParentTag)=0; + /** remove block parent of type aTagToRemove from the selection. * if aTagToRemove is null, the nearest enclosing block that * is <B>not</B> a sub-document is removed. -- GitLab