diff --git a/editor/base/nsEditorEventListeners.cpp b/editor/base/nsEditorEventListeners.cpp index a8a714674bf53fe359902862ad17accbd11f3f8a..6b9e2fa4bf6fe227a21c5ee9da2107a32b9b4a7f 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 b73d4c4af65589585321823be79ce29c0dad637d..bb0593b037b1ed2db0c649701b09057c42919195 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 70fccbf0231a4480ca90fdc3b26b6b10fbd1d5d4..a1915de5a32e36c67ab1faf3d234ce891f442620 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 b3b07f87d1ec06fc3a80d429a373cd71e525c52b..91a8cc798e58d2691d079449d45d68a6bdd6ba83 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 4529148c5d8011e1d3115d95576bc488dd7aa50e..f4341227d6c5f786e13e63bf668a67bb65fa4bd9 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 b73d4c4af65589585321823be79ce29c0dad637d..bb0593b037b1ed2db0c649701b09057c42919195 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 70fccbf0231a4480ca90fdc3b26b6b10fbd1d5d4..a1915de5a32e36c67ab1faf3d234ce891f442620 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 a8a714674bf53fe359902862ad17accbd11f3f8a..6b9e2fa4bf6fe227a21c5ee9da2107a32b9b4a7f 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 50b6e582f3279731b3da7e9af528f63fa9213d05..1c1b09a4385ba8c521568b3204591a97795bc8db 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.