Fix for bug 335856 (Can't easily put caret in this designmode iframe testcase (caret doesn't show up)), also fixes bug 393568 (blocking1.9+) and bug 386872. r/sr=jst.

This commit is contained in:
peterv@propagandism.org 2007-10-03 05:16:50 -07:00
parent 4a67feba15
commit f6c6606714
5 changed files with 85 additions and 35 deletions

View File

@ -217,7 +217,8 @@ nsEditor::~nsEditor()
NS_IF_RELEASE(mViewManager); NS_IF_RELEASE(mViewManager);
} }
NS_IMPL_ISUPPORTS4(nsEditor, nsIEditor, nsIEditorIMESupport, nsISupportsWeakReference, nsIPhonetic) NS_IMPL_ISUPPORTS5(nsEditor, nsIEditor, nsIEditorIMESupport,
nsISupportsWeakReference, nsIPhonetic, nsIMutationObserver)
#ifdef XP_MAC #ifdef XP_MAC
#pragma mark - #pragma mark -
@ -244,6 +245,9 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIPresShell* aPresShell, nsIContent *aRoot
if (aRoot) if (aRoot)
mRootElement = do_QueryInterface(aRoot); mRootElement = do_QueryInterface(aRoot);
nsCOMPtr<nsINode> document = do_QueryInterface(aDoc);
document->AddMutationObserver(this);
// Set up the DTD // Set up the DTD
// XXX - in the long run we want to get this from the document, but there // XXX - in the long run we want to get this from the document, but there
// is no way to do that right now. So we leave it null here and set // is no way to do that right now. So we leave it null here and set
@ -519,6 +523,10 @@ nsEditor::PreDestroy()
// tell our listeners that the doc is going away // tell our listeners that the doc is going away
NotifyDocumentListeners(eDocumentToBeDestroyed); NotifyDocumentListeners(eDocumentToBeDestroyed);
nsCOMPtr<nsINode> document = do_QueryReferent(mDocWeak);
if (document)
document->RemoveMutationObserver(this);
// Unregister event listeners // Unregister event listeners
RemoveEventListeners(); RemoveEventListeners();
mActionListeners.Clear(); mActionListeners.Clear();
@ -2280,6 +2288,45 @@ nsEditor::GetQueryCaretRect(nsQueryCaretRectEventReply* aReply)
/* Non-interface, public methods */ /* Non-interface, public methods */
void
nsEditor::ContentAppended(nsIDocument *aDocument, nsIContent* aContainer,
PRInt32 aNewIndexInContainer)
{
ContentInserted(aDocument, aContainer, nsnull, aNewIndexInContainer);
}
void
nsEditor::ContentInserted(nsIDocument *aDocument, nsIContent* aContainer,
nsIContent* aChild, PRInt32 aIndexInContainer)
{
// XXX If we need aChild then nsEditor::ContentAppended should start passing
// in the child.
if (!mRootElement)
{
// Need to remove the event listeners first because BeginningOfDocument
// could set a new root (and event target) and we won't be able to remove
// them from the old event target then.
RemoveEventListeners();
BeginningOfDocument();
InstallEventListeners();
SyncRealTimeSpell();
}
}
void
nsEditor::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer,
nsIContent* aChild, PRInt32 aIndexInContainer)
{
nsCOMPtr<nsIDOMHTMLElement> elem = do_QueryInterface(aChild);
if (elem == mRootElement)
{
RemoveEventListeners();
mRootElement = nsnull;
mEventTarget = nsnull;
InstallEventListeners();
}
}
NS_IMETHODIMP NS_IMETHODIMP
nsEditor::GetRootElement(nsIDOMElement **aRootElement) nsEditor::GetRootElement(nsIDOMElement **aRootElement)
{ {

View File

@ -64,6 +64,7 @@
#include "nsIEditorSpellCheck.h" #include "nsIEditorSpellCheck.h"
#include "nsIInlineSpellChecker.h" #include "nsIInlineSpellChecker.h"
#include "nsPIDOMEventTarget.h" #include "nsPIDOMEventTarget.h"
#include "nsStubMutationObserver.h"
class nsIDOMCharacterData; class nsIDOMCharacterData;
class nsIDOMRange; class nsIDOMRange;
@ -97,7 +98,8 @@ class nsIDOMEventTarget;
class nsEditor : public nsIEditor, class nsEditor : public nsIEditor,
public nsIEditorIMESupport, public nsIEditorIMESupport,
public nsSupportsWeakReference, public nsSupportsWeakReference,
public nsIPhonetic public nsIPhonetic,
public nsStubMutationObserver
{ {
public: public:
@ -151,6 +153,9 @@ public:
// nsIPhonetic // nsIPhonetic
NS_DECL_NSIPHONETIC NS_DECL_NSIPHONETIC
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
public: public:

View File

@ -1123,7 +1123,7 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
nsCOMPtr<nsISelectionController> selCon; nsCOMPtr<nsISelectionController> selCon;
mEditor->GetSelectionController(getter_AddRefs(selCon)); mEditor->GetSelectionController(getter_AddRefs(selCon));
if (selCon && editableRoot) if (selCon)
{ {
nsCOMPtr<nsISelection> selection; nsCOMPtr<nsISelection> selection;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
@ -1150,6 +1150,14 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
{ {
selectionPrivate->SetAncestorLimiter(editableRoot); selectionPrivate->SetAncestorLimiter(editableRoot);
} }
if (!editableRoot) {
PRInt32 rangeCount;
selection->GetRangeCount(&rangeCount);
if (rangeCount == 0) {
mEditor->BeginningOfDocument();
}
}
} }
} }

View File

@ -134,7 +134,7 @@ nsTextEditRules::Init(nsPlaintextEditor *aEditor, PRUint32 aFlags)
NS_ASSERTION(selection, "editor cannot get selection"); NS_ASSERTION(selection, "editor cannot get selection");
// Cache our body node, if available. // Cache our body node, if available.
GetBody(); nsIDOMNode *body = mEditor->GetRoot();
// Put in a magic br if needed. This method handles null selection, // Put in a magic br if needed. This method handles null selection,
// which should never happen anyway // which should never happen anyway
@ -148,15 +148,15 @@ nsTextEditRules::Init(nsPlaintextEditor *aEditor, PRUint32 aFlags)
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
} }
if (mBody) if (body)
{ {
// create a range that is the entire body contents // create a range that is the entire body contents
nsCOMPtr<nsIDOMRange> wholeDoc = nsCOMPtr<nsIDOMRange> wholeDoc =
do_CreateInstance("@mozilla.org/content/range;1"); do_CreateInstance("@mozilla.org/content/range;1");
if (!wholeDoc) return NS_ERROR_NULL_POINTER; if (!wholeDoc) return NS_ERROR_NULL_POINTER;
wholeDoc->SetStart(mBody,0); wholeDoc->SetStart(body,0);
nsCOMPtr<nsIDOMNodeList> list; nsCOMPtr<nsIDOMNodeList> list;
res = mBody->GetChildNodes(getter_AddRefs(list)); res = body->GetChildNodes(getter_AddRefs(list));
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!list) return NS_ERROR_FAILURE; if (!list) return NS_ERROR_FAILURE;
@ -164,7 +164,7 @@ nsTextEditRules::Init(nsPlaintextEditor *aEditor, PRUint32 aFlags)
res = list->GetLength(&listCount); res = list->GetLength(&listCount);
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
res = wholeDoc->SetEnd(mBody, listCount); res = wholeDoc->SetEnd(body, listCount);
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
// replace newlines in that range with breaks // replace newlines in that range with breaks
@ -992,9 +992,11 @@ nsTextEditRules::WillDeleteSelection(nsISelection *aSelection,
// make sure it is not last node in editfield. If it is, cancel deletion. // make sure it is not last node in editfield. If it is, cancel deletion.
if (nextNode && (aCollapsedAction == nsIEditor::eNext) && nsTextEditUtils::IsBreak(nextNode)) if (nextNode && (aCollapsedAction == nsIEditor::eNext) && nsTextEditUtils::IsBreak(nextNode))
{ {
if (!GetBody()) return NS_ERROR_NULL_POINTER; nsIDOMNode *body = mEditor->GetRoot();
if (!body)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> lastChild; nsCOMPtr<nsIDOMNode> lastChild;
res = mBody->GetLastChild(getter_AddRefs(lastChild)); res = body->GetLastChild(getter_AddRefs(lastChild));
if (lastChild == nextNode) if (lastChild == nextNode)
{ {
*aCancel = PR_TRUE; *aCancel = PR_TRUE;
@ -1251,9 +1253,11 @@ nsTextEditRules::CreateTrailingBRIfNeeded()
// but only if we aren't a single line edit field // but only if we aren't a single line edit field
if (mFlags & nsIPlaintextEditor::eEditorSingleLineMask) if (mFlags & nsIPlaintextEditor::eEditorSingleLineMask)
return NS_OK; return NS_OK;
if (!GetBody()) return NS_ERROR_NULL_POINTER; nsIDOMNode *body = mEditor->GetRoot();
if (!body)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMNode> lastChild; nsCOMPtr<nsIDOMNode> lastChild;
nsresult res = mBody->GetLastChild(getter_AddRefs(lastChild)); nsresult res = body->GetLastChild(getter_AddRefs(lastChild));
// assuming CreateBogusNodeIfNeeded() has been called first // assuming CreateBogusNodeIfNeeded() has been called first
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
if (!lastChild) return NS_ERROR_NULL_POINTER; if (!lastChild) return NS_ERROR_NULL_POINTER;
@ -1262,10 +1266,10 @@ nsTextEditRules::CreateTrailingBRIfNeeded()
{ {
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor); nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
PRUint32 rootLen; PRUint32 rootLen;
res = mEditor->GetLengthOfDOMNode(mBody, rootLen); res = mEditor->GetLengthOfDOMNode(body, rootLen);
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
nsCOMPtr<nsIDOMNode> unused; nsCOMPtr<nsIDOMNode> unused;
res = CreateMozBR(mBody, rootLen, address_of(unused)); res = CreateMozBR(body, rootLen, address_of(unused));
} }
return res; return res;
} }
@ -1279,8 +1283,9 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsISelection *aSelection)
// tell rules system to not do any post-processing // tell rules system to not do any post-processing
nsAutoRules beginRulesSniffing(mEditor, nsEditor::kOpIgnore, nsIEditor::eNone); nsAutoRules beginRulesSniffing(mEditor, nsEditor::kOpIgnore, nsIEditor::eNone);
if (!GetBody()) nsIDOMNode* body = mEditor->GetRoot();
if (!body)
{ {
// we don't even have a body yet, don't insert any bogus nodes at // we don't even have a body yet, don't insert any bogus nodes at
// this point. // this point.
@ -1293,11 +1298,11 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsISelection *aSelection)
// if no editable content is found, insert the bogus node // if no editable content is found, insert the bogus node
PRBool needsBogusContent=PR_TRUE; PRBool needsBogusContent=PR_TRUE;
nsCOMPtr<nsIDOMNode> bodyChild; nsCOMPtr<nsIDOMNode> bodyChild;
nsresult res = mBody->GetFirstChild(getter_AddRefs(bodyChild)); nsresult res = body->GetFirstChild(getter_AddRefs(bodyChild));
while ((NS_SUCCEEDED(res)) && bodyChild) while ((NS_SUCCEEDED(res)) && bodyChild)
{ {
if (mEditor->IsMozEditorBogusNode(bodyChild) || if (mEditor->IsMozEditorBogusNode(bodyChild) ||
!mEditor->IsEditable(mBody) || !mEditor->IsEditable(body) ||
mEditor->IsEditable(bodyChild)) mEditor->IsEditable(bodyChild))
{ {
needsBogusContent = PR_FALSE; needsBogusContent = PR_FALSE;
@ -1324,11 +1329,11 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsISelection *aSelection)
kMOZEditorBogusNodeValue ); kMOZEditorBogusNodeValue );
// put the node in the document // put the node in the document
res = mEditor->InsertNode(mBogusNode, mBody, 0); res = mEditor->InsertNode(mBogusNode, body, 0);
if (NS_FAILED(res)) return res; if (NS_FAILED(res)) return res;
// set selection // set selection
aSelection->Collapse(mBody, 0); aSelection->Collapse(body, 0);
} }
return res; return res;
} }
@ -1466,15 +1471,3 @@ nsTextEditRules::CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<ns
} }
return res; return res;
} }
nsIDOMNode *
nsTextEditRules::GetBody()
{
if (!mBody)
{
// remember our body node
mBody = mEditor->GetRoot();
}
return mBody;
}

View File

@ -197,15 +197,12 @@ protected:
nsIEditor::EDirection aAction, nsIEditor::EDirection aAction,
PRBool *aCancel); PRBool *aCancel);
nsIDOMNode *GetBody();
// data members // data members
nsPlaintextEditor *mEditor; // note that we do not refcount the editor nsPlaintextEditor *mEditor; // note that we do not refcount the editor
nsString mPasswordText; // a buffer we use to store the real value of password editors nsString mPasswordText; // a buffer we use to store the real value of password editors
nsString mPasswordIMEText; // a buffer we use to track the IME composition string nsString mPasswordIMEText; // a buffer we use to track the IME composition string
PRUint32 mPasswordIMEIndex; PRUint32 mPasswordIMEIndex;
nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc nsCOMPtr<nsIDOMNode> mBogusNode; // magic node acts as placeholder in empty doc
nsCOMPtr<nsIDOMNode> mBody; // cached root node
nsCOMPtr<nsIDOMNode> mCachedSelectionNode; // cached selected node nsCOMPtr<nsIDOMNode> mCachedSelectionNode; // cached selected node
PRInt32 mCachedSelectionOffset; // cached selected offset PRInt32 mCachedSelectionOffset; // cached selected offset
PRUint32 mFlags; PRUint32 mFlags;