michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/dom/Selection.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsEditorUtils.h" michael@0: #include "nsError.h" michael@0: #include "nsIClipboardDragDropHookList.h" michael@0: // hooks michael@0: #include "nsIClipboardDragDropHooks.h" michael@0: #include "nsIContent.h" michael@0: #include "nsIContentIterator.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDocShell.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsINode.h" michael@0: #include "nsISimpleEnumerator.h" michael@0: michael@0: class nsIDOMRange; michael@0: class nsISupports; michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::dom; michael@0: michael@0: /****************************************************************************** michael@0: * nsAutoSelectionReset michael@0: *****************************************************************************/ michael@0: michael@0: nsAutoSelectionReset::nsAutoSelectionReset(Selection* aSel, nsEditor* aEd) michael@0: : mSel(nullptr), mEd(nullptr) michael@0: { michael@0: if (!aSel || !aEd) return; // not much we can do, bail. michael@0: if (aEd->ArePreservingSelection()) return; // we already have initted mSavedSel, so this must be nested call. michael@0: mSel = aSel; michael@0: mEd = aEd; michael@0: if (mSel) michael@0: { michael@0: mEd->PreserveSelectionAcrossActions(mSel); michael@0: } michael@0: } michael@0: michael@0: nsAutoSelectionReset::~nsAutoSelectionReset() michael@0: { michael@0: NS_ASSERTION(!mSel || mEd, "mEd should be non-null when mSel is"); michael@0: if (mSel && mEd->ArePreservingSelection()) // mSel will be null if this was nested call michael@0: { michael@0: mEd->RestorePreservedSelection(mSel); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsAutoSelectionReset::Abort() michael@0: { michael@0: NS_ASSERTION(!mSel || mEd, "mEd should be non-null when mSel is"); michael@0: if (mSel) michael@0: mEd->StopPreservingSelection(); michael@0: } michael@0: michael@0: michael@0: /****************************************************************************** michael@0: * some helper classes for iterating the dom tree michael@0: *****************************************************************************/ michael@0: michael@0: nsDOMIterator::nsDOMIterator() : michael@0: mIter(nullptr) michael@0: { michael@0: } michael@0: michael@0: nsDOMIterator::~nsDOMIterator() michael@0: { michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMIterator::Init(nsIDOMRange* aRange) michael@0: { michael@0: nsresult res; michael@0: mIter = do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res); michael@0: NS_ENSURE_SUCCESS(res, res); michael@0: NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE); michael@0: return mIter->Init(aRange); michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMIterator::Init(nsIDOMNode* aNode) michael@0: { michael@0: nsresult res; michael@0: mIter = do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res); michael@0: NS_ENSURE_SUCCESS(res, res); michael@0: NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE); michael@0: nsCOMPtr content = do_QueryInterface(aNode); michael@0: return mIter->Init(content); michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMIterator::AppendList(nsBoolDomIterFunctor& functor, michael@0: nsCOMArray& arrayOfNodes) const michael@0: { michael@0: nsCOMPtr node; michael@0: michael@0: // iterate through dom and build list michael@0: while (!mIter->IsDone()) michael@0: { michael@0: node = do_QueryInterface(mIter->GetCurrentNode()); michael@0: NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); michael@0: michael@0: if (functor(node)) michael@0: { michael@0: arrayOfNodes.AppendObject(node); michael@0: } michael@0: mIter->Next(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsDOMSubtreeIterator::nsDOMSubtreeIterator() michael@0: { michael@0: } michael@0: michael@0: nsDOMSubtreeIterator::~nsDOMSubtreeIterator() michael@0: { michael@0: } michael@0: michael@0: nsresult michael@0: nsDOMSubtreeIterator::Init(nsIDOMRange* aRange) michael@0: { michael@0: nsresult res; michael@0: mIter = do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res); michael@0: NS_ENSURE_SUCCESS(res, res); michael@0: NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE); michael@0: return mIter->Init(aRange); michael@0: } michael@0: michael@0: /****************************************************************************** michael@0: * some general purpose editor utils michael@0: *****************************************************************************/ michael@0: michael@0: bool michael@0: nsEditorUtils::IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t *aOffset) michael@0: { michael@0: NS_ENSURE_TRUE(aNode || aParent, false); michael@0: if (aNode == aParent) return false; michael@0: michael@0: nsCOMPtr parent, node = do_QueryInterface(aNode); michael@0: nsresult res; michael@0: michael@0: do michael@0: { michael@0: res = node->GetParentNode(getter_AddRefs(parent)); michael@0: NS_ENSURE_SUCCESS(res, false); michael@0: if (parent == aParent) michael@0: { michael@0: if (aOffset) michael@0: { michael@0: nsCOMPtr pCon(do_QueryInterface(parent)); michael@0: nsCOMPtr cCon(do_QueryInterface(node)); michael@0: if (pCon) michael@0: { michael@0: *aOffset = pCon->IndexOf(cCon); michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: node = parent; michael@0: } while (parent); michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsEditorUtils::IsLeafNode(nsIDOMNode *aNode) michael@0: { michael@0: bool hasChildren = false; michael@0: if (aNode) michael@0: aNode->HasChildNodes(&hasChildren); michael@0: return !hasChildren; michael@0: } michael@0: michael@0: /****************************************************************************** michael@0: * utility methods for drag/drop/copy/paste hooks michael@0: *****************************************************************************/ michael@0: michael@0: nsresult michael@0: nsEditorHookUtils::GetHookEnumeratorFromDocument(nsIDOMDocument *aDoc, michael@0: nsISimpleEnumerator **aResult) michael@0: { michael@0: nsCOMPtr doc = do_QueryInterface(aDoc); michael@0: NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr docShell = doc->GetDocShell(); michael@0: nsCOMPtr hookObj = do_GetInterface(docShell); michael@0: NS_ENSURE_TRUE(hookObj, NS_ERROR_FAILURE); michael@0: michael@0: return hookObj->GetHookEnumerator(aResult); michael@0: } michael@0: michael@0: bool michael@0: nsEditorHookUtils::DoInsertionHook(nsIDOMDocument *aDoc, nsIDOMEvent *aDropEvent, michael@0: nsITransferable *aTrans) michael@0: { michael@0: nsCOMPtr enumerator; michael@0: GetHookEnumeratorFromDocument(aDoc, getter_AddRefs(enumerator)); michael@0: NS_ENSURE_TRUE(enumerator, true); michael@0: michael@0: bool hasMoreHooks = false; michael@0: while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks)) && hasMoreHooks) michael@0: { michael@0: nsCOMPtr isupp; michael@0: if (NS_FAILED(enumerator->GetNext(getter_AddRefs(isupp)))) michael@0: break; michael@0: michael@0: nsCOMPtr override = do_QueryInterface(isupp); michael@0: if (override) michael@0: { michael@0: bool doInsert = true; michael@0: #ifdef DEBUG michael@0: nsresult hookResult = michael@0: #endif michael@0: override->OnPasteOrDrop(aDropEvent, aTrans, &doInsert); michael@0: NS_ASSERTION(NS_SUCCEEDED(hookResult), "hook failure in OnPasteOrDrop"); michael@0: NS_ENSURE_TRUE(doInsert, false); michael@0: } michael@0: } michael@0: michael@0: return true; michael@0: }