1999-03-10 22:53:26 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
1999-11-06 06:43:54 +03:00
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
1999-03-10 22:53:26 +03:00
|
|
|
*
|
1999-11-06 06:43:54 +03:00
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
1999-03-10 22:53:26 +03:00
|
|
|
*
|
1999-11-06 06:43:54 +03:00
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape
|
1999-03-10 22:53:26 +03:00
|
|
|
* Communications Corporation. Portions created by Netscape are
|
1999-11-06 06:43:54 +03:00
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
1999-03-10 22:53:26 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "nsTextEditRules.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-05-05 08:05:19 +04:00
|
|
|
#include "nsEditor.h"
|
2000-01-26 03:57:37 +03:00
|
|
|
#include "nsHTMLEditUtils.h"
|
1999-08-09 05:37:50 +04:00
|
|
|
|
1999-03-10 22:53:26 +03:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsIDOMNode.h"
|
|
|
|
#include "nsIDOMElement.h"
|
|
|
|
#include "nsIDOMNodeList.h"
|
|
|
|
#include "nsIDOMSelection.h"
|
|
|
|
#include "nsIDOMRange.h"
|
1999-03-12 05:28:24 +03:00
|
|
|
#include "nsIDOMCharacterData.h"
|
1999-03-13 07:53:21 +03:00
|
|
|
#include "nsIContent.h"
|
1999-06-25 03:36:56 +04:00
|
|
|
#include "nsIContentIterator.h"
|
|
|
|
#include "nsIEnumerator.h"
|
|
|
|
#include "nsLayoutCID.h"
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
#include "nsIEditProperty.h"
|
1999-12-07 11:30:19 +03:00
|
|
|
#include "nsEditorUtils.h"
|
2000-01-13 13:17:35 +03:00
|
|
|
#include "EditTxn.h"
|
2000-03-29 16:53:23 +04:00
|
|
|
#include "TypeInState.h"
|
1999-03-10 22:53:26 +03:00
|
|
|
|
2000-01-13 13:17:35 +03:00
|
|
|
static NS_DEFINE_CID(kContentIteratorCID, NS_CONTENTITERATOR_CID);
|
|
|
|
static NS_DEFINE_IID(kRangeCID, NS_RANGE_CID);
|
1999-03-15 03:57:32 +03:00
|
|
|
|
1999-12-07 11:30:19 +03:00
|
|
|
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
#define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
|
1999-08-09 05:37:50 +04:00
|
|
|
if ((mFlags & nsIHTMLEditor::eEditorReadonlyMask) || (mFlags & nsIHTMLEditor::eEditorDisabledMask)) \
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
{ \
|
|
|
|
*aCancel = PR_TRUE; \
|
|
|
|
return NS_OK; \
|
|
|
|
};
|
1999-03-13 07:53:21 +03:00
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
NS_NewTextEditRules(nsIEditRules** aInstancePtrResult)
|
|
|
|
{
|
|
|
|
nsTextEditRules * rules = new nsTextEditRules();
|
|
|
|
if (rules)
|
|
|
|
return rules->QueryInterface(NS_GET_IID(nsIEditRules), (void**) aInstancePtrResult);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-04-05 21:21:59 +04:00
|
|
|
/********************************************************
|
1999-03-29 12:02:05 +04:00
|
|
|
* Constructor/Destructor
|
1999-04-05 21:21:59 +04:00
|
|
|
********************************************************/
|
1999-03-29 12:02:05 +04:00
|
|
|
|
1999-08-09 22:39:49 +04:00
|
|
|
nsTextEditRules::nsTextEditRules()
|
1999-08-09 05:37:50 +04:00
|
|
|
: mEditor(nsnull)
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
, mPasswordText()
|
|
|
|
, mBogusNode(nsnull)
|
|
|
|
, mBody(nsnull)
|
2000-08-29 02:15:03 +04:00
|
|
|
, mFlags(0) // initialized to 0 ("no flags set"). Real initial value is given in Init()
|
1999-12-07 11:30:19 +03:00
|
|
|
, mActionNesting(0)
|
|
|
|
, mLockRulesSniffing(PR_FALSE)
|
2000-02-25 07:39:30 +03:00
|
|
|
, mTheAction(0)
|
1999-03-10 22:53:26 +03:00
|
|
|
{
|
2000-03-24 03:26:47 +03:00
|
|
|
NS_INIT_REFCNT();
|
1999-03-10 22:53:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsTextEditRules::~nsTextEditRules()
|
|
|
|
{
|
1999-03-12 05:28:24 +03:00
|
|
|
// do NOT delete mEditor here. We do not hold a ref count to mEditor. mEditor owns our lifespan.
|
1999-03-10 22:53:26 +03:00
|
|
|
}
|
|
|
|
|
2000-03-24 03:26:47 +03:00
|
|
|
/********************************************************
|
|
|
|
* XPCOM Cruft
|
|
|
|
********************************************************/
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsTextEditRules)
|
|
|
|
NS_IMPL_RELEASE(nsTextEditRules)
|
|
|
|
NS_IMPL_QUERY_INTERFACE1(nsTextEditRules, nsIEditRules)
|
|
|
|
|
1999-03-29 12:02:05 +04:00
|
|
|
|
1999-04-05 21:21:59 +04:00
|
|
|
/********************************************************
|
1999-03-29 12:02:05 +04:00
|
|
|
* Public methods
|
1999-04-05 21:21:59 +04:00
|
|
|
********************************************************/
|
1999-03-29 12:02:05 +04:00
|
|
|
|
1999-03-10 22:53:26 +03:00
|
|
|
NS_IMETHODIMP
|
1999-08-09 22:39:49 +04:00
|
|
|
nsTextEditRules::Init(nsHTMLEditor *aEditor, PRUint32 aFlags)
|
1999-03-10 22:53:26 +03:00
|
|
|
{
|
|
|
|
if (!aEditor) { return NS_ERROR_NULL_POINTER; }
|
1999-08-09 05:37:50 +04:00
|
|
|
|
|
|
|
mEditor = aEditor; // we hold a non-refcounted reference back to our editor
|
1999-08-09 22:39:49 +04:00
|
|
|
// call SetFlags only aftet mEditor has been initialized!
|
|
|
|
SetFlags(aFlags);
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
nsCOMPtr<nsIDOMSelection> selection;
|
|
|
|
mEditor->GetSelection(getter_AddRefs(selection));
|
|
|
|
NS_ASSERTION(selection, "editor cannot get selection");
|
2000-01-13 13:17:35 +03:00
|
|
|
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
// remember our root node
|
2000-01-13 13:17:35 +03:00
|
|
|
nsCOMPtr<nsIDOMElement> bodyElement;
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
nsresult res = mEditor->GetRootElement(getter_AddRefs(bodyElement));
|
2000-01-13 13:17:35 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bodyElement) return NS_ERROR_NULL_POINTER;
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
mBody = do_QueryInterface(bodyElement);
|
|
|
|
if (!mBody) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// put in a magic br if needed
|
|
|
|
res = CreateBogusNodeIfNeeded(selection); // this method handles null selection, which should never happen anyway
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// create a range that is the entire body contents
|
2000-01-13 13:17:35 +03:00
|
|
|
nsCOMPtr<nsIDOMRange> wholeDoc;
|
|
|
|
res = nsComponentManager::CreateInstance(kRangeCID, nsnull, NS_GET_IID(nsIDOMRange),
|
|
|
|
getter_AddRefs(wholeDoc));
|
|
|
|
if (NS_FAILED(res)) return res;
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
wholeDoc->SetStart(mBody,0);
|
2000-05-04 12:33:48 +04:00
|
|
|
nsCOMPtr<nsIDOMNodeList> list;
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
res = mBody->GetChildNodes(getter_AddRefs(list));
|
2000-05-04 12:33:48 +04:00
|
|
|
if (NS_FAILED(res) || !list) return res?res:NS_ERROR_FAILURE;
|
|
|
|
PRUint32 listCount;
|
|
|
|
res = list->GetLength(&listCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
res = wholeDoc->SetEnd(mBody,listCount);
|
2000-01-13 13:17:35 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// replace newlines in that range with breaks
|
|
|
|
res = ReplaceNewlines(wholeDoc);
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsTextEditRules::GetFlags(PRUint32 *aFlags)
|
|
|
|
{
|
|
|
|
if (!aFlags) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
*aFlags = mFlags;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsTextEditRules::SetFlags(PRUint32 aFlags)
|
|
|
|
{
|
1999-07-25 09:34:02 +04:00
|
|
|
if (mFlags == aFlags) return NS_OK;
|
|
|
|
|
|
|
|
// XXX - this won't work if body element already has
|
|
|
|
// a style attribute on it, don't know why.
|
|
|
|
// SetFlags() is really meant to only be called once
|
|
|
|
// and at editor init time.
|
1999-08-09 05:37:50 +04:00
|
|
|
if (aFlags & nsIHTMLEditor::eEditorPlaintextMask)
|
1999-07-25 09:34:02 +04:00
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
if (!(mFlags & nsIHTMLEditor::eEditorPlaintextMask))
|
1999-07-25 09:34:02 +04:00
|
|
|
{
|
2000-02-05 02:39:31 +03:00
|
|
|
// Call the editor's SetBodyWrapWidth(), which will
|
|
|
|
// set the styles appropriately for plaintext:
|
|
|
|
mEditor->SetBodyWrapWidth(72);
|
1999-07-25 09:34:02 +04:00
|
|
|
}
|
|
|
|
}
|
2000-02-07 05:48:36 +03:00
|
|
|
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
mFlags = aFlags;
|
1999-03-10 22:53:26 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-12-07 11:30:19 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsTextEditRules::BeforeEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|
|
|
{
|
|
|
|
if (mLockRulesSniffing) return NS_OK;
|
|
|
|
|
|
|
|
nsAutoLockRulesSniffing lockIt(this);
|
|
|
|
|
2000-02-25 07:39:30 +03:00
|
|
|
if (!mActionNesting)
|
|
|
|
{
|
|
|
|
// let rules remember the top level action
|
|
|
|
mTheAction = action;
|
|
|
|
}
|
1999-12-07 11:30:19 +03:00
|
|
|
mActionNesting++;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-03-24 03:26:47 +03:00
|
|
|
nsTextEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
1999-12-07 11:30:19 +03:00
|
|
|
{
|
|
|
|
if (mLockRulesSniffing) return NS_OK;
|
|
|
|
|
|
|
|
nsAutoLockRulesSniffing lockIt(this);
|
|
|
|
|
|
|
|
NS_PRECONDITION(mActionNesting>0, "bad action nesting!");
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
if (!--mActionNesting)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMSelection>selection;
|
|
|
|
res = mEditor->GetSelection(getter_AddRefs(selection));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// detect empty doc
|
|
|
|
res = CreateBogusNodeIfNeeded(selection);
|
2000-05-08 11:50:57 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// create moz-br and adjust selection if needed
|
|
|
|
res = AdjustSelection(selection, aDirection);
|
1999-12-07 11:30:19 +03:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-04-05 21:21:59 +04:00
|
|
|
NS_IMETHODIMP
|
1999-04-12 16:01:32 +04:00
|
|
|
nsTextEditRules::WillDoAction(nsIDOMSelection *aSelection,
|
1999-10-06 23:34:09 +04:00
|
|
|
nsRulesInfo *aInfo,
|
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-03-29 12:02:05 +04:00
|
|
|
{
|
1999-07-25 22:14:44 +04:00
|
|
|
// null selection is legal
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aInfo || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-10-28 02:56:36 +04:00
|
|
|
#if defined(DEBUG_ftang)
|
|
|
|
printf("nsTextEditRules::WillDoAction action= %d", aInfo->action);
|
|
|
|
#endif
|
1999-06-08 10:04:51 +04:00
|
|
|
|
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-04-12 16:01:32 +04:00
|
|
|
|
|
|
|
// my kingdom for dynamic cast
|
|
|
|
nsTextRulesInfo *info = NS_STATIC_CAST(nsTextRulesInfo*, aInfo);
|
1999-04-05 21:21:59 +04:00
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
switch (info->action)
|
1999-04-05 21:21:59 +04:00
|
|
|
{
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
case kInsertBreak:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillInsertBreak(aSelection, aCancel, aHandled);
|
1999-04-05 21:21:59 +04:00
|
|
|
case kInsertText:
|
1999-11-03 03:07:37 +03:00
|
|
|
case kInsertTextIME:
|
2000-02-07 04:42:14 +03:00
|
|
|
return WillInsertText(info->action,
|
|
|
|
aSelection,
|
1999-10-06 23:34:09 +04:00
|
|
|
aCancel,
|
|
|
|
aHandled,
|
1999-04-12 16:01:32 +04:00
|
|
|
info->inString,
|
|
|
|
info->outString,
|
1999-06-08 10:04:51 +04:00
|
|
|
info->maxLength);
|
1999-04-05 21:21:59 +04:00
|
|
|
case kDeleteSelection:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillDeleteSelection(aSelection, info->collapsedAction, aCancel, aHandled);
|
1999-04-05 21:21:59 +04:00
|
|
|
case kUndo:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillUndo(aSelection, aCancel, aHandled);
|
1999-04-05 21:21:59 +04:00
|
|
|
case kRedo:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillRedo(aSelection, aCancel, aHandled);
|
1999-06-08 10:04:51 +04:00
|
|
|
case kSetTextProperty:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillSetTextProperty(aSelection, aCancel, aHandled);
|
1999-06-08 10:04:51 +04:00
|
|
|
case kRemoveTextProperty:
|
1999-10-06 23:34:09 +04:00
|
|
|
return WillRemoveTextProperty(aSelection, aCancel, aHandled);
|
1999-06-25 03:36:56 +04:00
|
|
|
case kOutputText:
|
|
|
|
return WillOutputText(aSelection,
|
1999-09-09 23:39:36 +04:00
|
|
|
info->outputFormat,
|
|
|
|
info->outString,
|
1999-10-06 23:34:09 +04:00
|
|
|
aCancel,
|
|
|
|
aHandled);
|
2000-01-12 05:58:57 +03:00
|
|
|
case kInsertElement: // i had thought this would be html rules only. but we put pre elements
|
|
|
|
// into plaintext mail when doing quoting for reply! doh!
|
|
|
|
return WillInsert(aSelection, aCancel);
|
1999-04-05 21:21:59 +04:00
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
1999-03-29 12:02:05 +04:00
|
|
|
}
|
1999-04-05 21:21:59 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-12 16:01:32 +04:00
|
|
|
nsTextEditRules::DidDoAction(nsIDOMSelection *aSelection,
|
|
|
|
nsRulesInfo *aInfo, nsresult aResult)
|
1999-03-29 12:02:05 +04:00
|
|
|
{
|
2000-01-05 15:24:10 +03:00
|
|
|
// dont let any txns in here move the selection around behind our back.
|
|
|
|
// Note that this won't prevent explicit selection setting from working.
|
|
|
|
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
if (!aSelection || !aInfo)
|
1999-04-05 21:21:59 +04:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
// my kingdom for dynamic cast
|
|
|
|
nsTextRulesInfo *info = NS_STATIC_CAST(nsTextRulesInfo*, aInfo);
|
|
|
|
|
|
|
|
switch (info->action)
|
1999-04-05 21:21:59 +04:00
|
|
|
{
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
case kInsertBreak:
|
|
|
|
return DidInsertBreak(aSelection, aResult);
|
1999-04-05 21:21:59 +04:00
|
|
|
case kInsertText:
|
1999-11-03 03:07:37 +03:00
|
|
|
case kInsertTextIME:
|
1999-04-05 21:21:59 +04:00
|
|
|
return DidInsertText(aSelection, aResult);
|
|
|
|
case kDeleteSelection:
|
1999-06-25 03:36:56 +04:00
|
|
|
return DidDeleteSelection(aSelection, info->collapsedAction, aResult);
|
1999-04-05 21:21:59 +04:00
|
|
|
case kUndo:
|
|
|
|
return DidUndo(aSelection, aResult);
|
|
|
|
case kRedo:
|
|
|
|
return DidRedo(aSelection, aResult);
|
1999-06-08 10:04:51 +04:00
|
|
|
case kSetTextProperty:
|
|
|
|
return DidSetTextProperty(aSelection, aResult);
|
|
|
|
case kRemoveTextProperty:
|
|
|
|
return DidRemoveTextProperty(aSelection, aResult);
|
1999-06-25 03:36:56 +04:00
|
|
|
case kOutputText:
|
|
|
|
return DidOutputText(aSelection, aResult);
|
1999-04-05 21:21:59 +04:00
|
|
|
}
|
1999-10-20 18:15:25 +04:00
|
|
|
// Don't fail on transactions we don't handle here!
|
|
|
|
return NS_OK;
|
1999-03-29 12:02:05 +04:00
|
|
|
}
|
1999-09-09 03:32:04 +04:00
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsTextEditRules::DocumentIsEmpty(PRBool *aDocumentIsEmpty)
|
|
|
|
{
|
|
|
|
if (!aDocumentIsEmpty)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
1999-04-05 21:21:59 +04:00
|
|
|
|
1999-09-09 03:32:04 +04:00
|
|
|
*aDocumentIsEmpty = (mBogusNode.get() != nsnull);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-04-05 21:21:59 +04:00
|
|
|
|
|
|
|
/********************************************************
|
|
|
|
* Protected methods
|
|
|
|
********************************************************/
|
|
|
|
|
1999-03-12 05:28:24 +03:00
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-03-13 07:53:21 +03:00
|
|
|
nsTextEditRules::WillInsert(nsIDOMSelection *aSelection, PRBool *aCancel)
|
|
|
|
{
|
1999-08-09 05:37:50 +04:00
|
|
|
if (!aSelection || !aCancel)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
|
|
|
|
1999-03-13 07:53:21 +03:00
|
|
|
// initialize out param
|
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
|
|
|
|
// check for the magic content node and delete it if it exists
|
1999-03-15 03:57:32 +03:00
|
|
|
if (mBogusNode)
|
1999-03-13 07:53:21 +03:00
|
|
|
{
|
1999-03-15 03:57:32 +03:00
|
|
|
mEditor->DeleteNode(mBogusNode);
|
|
|
|
mBogusNode = do_QueryInterface(nsnull);
|
1999-03-13 07:53:21 +03:00
|
|
|
}
|
|
|
|
|
1999-11-29 11:28:46 +03:00
|
|
|
// this next only works for collapsed selections right now,
|
|
|
|
// because selection is a pain to work with when not collapsed.
|
|
|
|
// (no good way to extend start or end of selection)
|
|
|
|
PRBool bCollapsed;
|
|
|
|
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed) return NS_OK;
|
|
|
|
|
|
|
|
// if we are after a mozBR in the same block, then move selection
|
|
|
|
// to be before it
|
|
|
|
nsCOMPtr<nsIDOMNode> selNode, priorNode;
|
|
|
|
PRInt32 selOffset;
|
|
|
|
// get the (collapsed) selection location
|
|
|
|
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-10 13:13:58 +03:00
|
|
|
// get prior node
|
2000-03-29 16:53:23 +04:00
|
|
|
res = mEditor->GetPriorHTMLNode(selNode, selOffset, &priorNode);
|
2000-01-26 03:57:37 +03:00
|
|
|
if (NS_SUCCEEDED(res) && priorNode && nsHTMLEditUtils::IsMozBR(priorNode))
|
1999-11-29 11:28:46 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> block1, block2;
|
|
|
|
if (mEditor->IsBlockNode(selNode)) block1 = selNode;
|
|
|
|
else block1 = mEditor->GetBlockNodeParent(selNode);
|
|
|
|
block2 = mEditor->GetBlockNodeParent(priorNode);
|
|
|
|
|
|
|
|
if (block1 != block2) return NS_OK;
|
|
|
|
|
|
|
|
// if we are here then the selection is right after a mozBR
|
|
|
|
// that is in the same block as the selection. We need to move
|
|
|
|
// the selection start to be before the mozBR.
|
|
|
|
res = nsEditor::GetNodeLocation(priorNode, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
1999-03-13 07:53:21 +03:00
|
|
|
}
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-03-13 07:53:21 +03:00
|
|
|
nsTextEditRules::DidInsert(nsIDOMSelection *aSelection, nsresult aResult)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-11-13 03:26:45 +03:00
|
|
|
nsresult
|
|
|
|
nsTextEditRules::GetTopEnclosingPre(nsIDOMNode *aNode,
|
|
|
|
nsIDOMNode** aOutPreNode)
|
|
|
|
{
|
|
|
|
// check parms
|
|
|
|
if (!aNode || !aOutPreNode)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
*aOutPreNode = 0;
|
|
|
|
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
nsCOMPtr<nsIDOMNode> node, parentNode;
|
|
|
|
node = do_QueryInterface(aNode);
|
|
|
|
|
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
nsAutoString tag;
|
|
|
|
nsEditor::GetTagString(node, tag);
|
2000-04-18 11:52:02 +04:00
|
|
|
if (tag.EqualsWithConversion("pre", PR_TRUE))
|
1999-11-13 03:26:45 +03:00
|
|
|
*aOutPreNode = node;
|
2000-04-18 11:52:02 +04:00
|
|
|
else if (tag.EqualsWithConversion("body", PR_TRUE))
|
1999-11-13 03:26:45 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
res = node->GetParentNode(getter_AddRefs(parentNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
node = parentNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IF_ADDREF(*aOutPreNode);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-06-22 09:39:54 +04:00
|
|
|
nsresult
|
1999-10-06 23:34:09 +04:00
|
|
|
nsTextEditRules::WillInsertBreak(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-08-09 05:37:50 +04:00
|
|
|
if (mFlags & nsIHTMLEditor::eEditorSingleLineMask) {
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
}
|
1999-11-29 11:28:46 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
|
|
|
|
// if the selection isn't collapsed, delete it.
|
|
|
|
PRBool bCollapsed;
|
|
|
|
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed)
|
|
|
|
{
|
1999-12-07 11:30:19 +03:00
|
|
|
res = mEditor->DeleteSelection(nsIEditor::eNone);
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// initialize out param
|
|
|
|
// we want to ignore result of WillInsert()
|
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
|
1999-11-13 03:26:45 +03:00
|
|
|
// Mail rule: split any <pre> tags in the way,
|
|
|
|
// since they're probably quoted text.
|
|
|
|
// For now, do this for all plaintext since mail is our main customer
|
|
|
|
// and we don't currently set eEditorMailMask for plaintext mail.
|
2000-02-25 07:39:30 +03:00
|
|
|
if (mTheAction != nsHTMLEditor::kOpInsertQuotation) // && mFlags & nsIHTMLEditor::eEditorMailMask)
|
1999-11-13 03:26:45 +03:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> preNode, selNode;
|
|
|
|
PRInt32 selOffset, newOffset;
|
|
|
|
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// If any of the following fail, then just proceed with the
|
|
|
|
// normal break insertion without worrying about the error
|
|
|
|
res = GetTopEnclosingPre(selNode, getter_AddRefs(preNode));
|
|
|
|
if (NS_SUCCEEDED(res) && preNode)
|
|
|
|
{
|
2000-02-25 07:39:30 +03:00
|
|
|
// Only split quote nodes: see if it has the attribute _moz_quote
|
|
|
|
nsCOMPtr<nsIDOMElement> preElement (do_QueryInterface(preNode));
|
|
|
|
if (preElement)
|
1999-11-13 03:26:45 +03:00
|
|
|
{
|
2000-04-18 11:52:02 +04:00
|
|
|
nsString mozQuote; mozQuote.AssignWithConversion("_moz_quote");
|
2000-02-25 07:39:30 +03:00
|
|
|
nsString mozQuoteVal;
|
|
|
|
PRBool isMozQuote = PR_FALSE;
|
|
|
|
if (NS_SUCCEEDED(mEditor->GetAttributeValue(preElement, mozQuote,
|
|
|
|
mozQuoteVal, isMozQuote))
|
|
|
|
&& isMozQuote)
|
|
|
|
{
|
|
|
|
printf("It's a moz quote -- splitting\n");
|
2000-05-03 05:34:34 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> outLeftNode;
|
|
|
|
nsCOMPtr<nsIDOMNode> outRightNode;
|
2000-08-26 08:03:50 +04:00
|
|
|
res = mEditor->SplitNodeDeep(preNode, selNode, selOffset, &newOffset, PR_TRUE, &outLeftNode, &outRightNode);
|
2000-02-25 07:39:30 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-05-03 05:34:34 +04:00
|
|
|
PRBool bIsEmptyNode;
|
2000-05-06 01:57:58 +04:00
|
|
|
|
|
|
|
// rememeber parent of selNode now, since we might delete selNode below
|
|
|
|
res = preNode->GetParentNode(getter_AddRefs(selNode));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
2000-05-03 05:34:34 +04:00
|
|
|
if (outLeftNode)
|
|
|
|
{
|
2000-06-22 09:39:54 +04:00
|
|
|
res = mEditor->IsEmptyNode(outLeftNode, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
2000-05-03 05:34:34 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bIsEmptyNode) mEditor->DeleteNode(outLeftNode);
|
|
|
|
}
|
|
|
|
if (outRightNode)
|
|
|
|
{
|
2000-05-06 01:57:58 +04:00
|
|
|
// HACK alert: consume a br if there is one at front of node
|
2000-05-03 05:34:34 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> firstNode;
|
|
|
|
res = mEditor->GetFirstEditableNode(outRightNode, &firstNode);
|
|
|
|
if (firstNode && nsHTMLEditUtils::IsBreak(firstNode))
|
|
|
|
{
|
|
|
|
mEditor->DeleteNode(firstNode);
|
|
|
|
}
|
|
|
|
|
2000-06-22 09:39:54 +04:00
|
|
|
res = mEditor->IsEmptyNode(outRightNode, &bIsEmptyNode, PR_TRUE, PR_FALSE);
|
2000-05-03 05:34:34 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bIsEmptyNode) mEditor->DeleteNode(outRightNode);
|
|
|
|
}
|
2000-02-25 07:39:30 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
|
|
|
// last ePrevious param causes selection to be set before the break
|
|
|
|
res = mEditor->CreateBR(selNode, newOffset, &brNode, nsIEditor::ePrevious);
|
2000-05-03 05:34:34 +04:00
|
|
|
*aHandled = PR_TRUE;
|
2000-02-25 07:39:30 +03:00
|
|
|
}
|
1999-11-13 03:26:45 +03:00
|
|
|
}
|
|
|
|
}
|
1999-11-29 11:28:46 +03:00
|
|
|
}
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsTextEditRules::DidInsertBreak(nsIDOMSelection *aSelection, nsresult aResult)
|
|
|
|
{
|
1999-12-07 11:30:19 +03:00
|
|
|
// we only need to execute the stuff below if we are a plaintext editor.
|
|
|
|
// html editors have a different mechanism for putting in mozBR's
|
|
|
|
// (because there are a bunch more placesyou have to worry about it in html)
|
|
|
|
if (!nsIHTMLEditor::eEditorPlaintextMask & mFlags) return NS_OK;
|
|
|
|
|
1999-11-29 11:28:46 +03:00
|
|
|
// if we are at the end of the document, we need to insert
|
|
|
|
// a special mozBR following the normal br, and then set the
|
2000-05-07 05:33:42 +04:00
|
|
|
// selection to stick to the mozBR.
|
1999-11-29 11:28:46 +03:00
|
|
|
PRInt32 selOffset;
|
|
|
|
nsCOMPtr<nsIDOMNode> nearNode, selNode;
|
|
|
|
nsresult res;
|
|
|
|
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-03-29 16:53:23 +04:00
|
|
|
res = mEditor->GetPriorHTMLNode(selNode, selOffset, &nearNode);
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-01-26 03:57:37 +03:00
|
|
|
if (nearNode && nsHTMLEditUtils::IsBreak(nearNode) && !nsHTMLEditUtils::IsMozBR(nearNode))
|
1999-11-29 11:28:46 +03:00
|
|
|
{
|
|
|
|
PRBool bIsLast;
|
2000-03-29 16:53:23 +04:00
|
|
|
res = mEditor->IsLastEditableChild(nearNode, &bIsLast);
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (bIsLast)
|
|
|
|
{
|
|
|
|
// need to insert special moz BR. Why? Because if we don't
|
|
|
|
// the user will see no new line for the break. Also, things
|
|
|
|
// like table cells won't grow in height.
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
|
|
|
res = CreateMozBR(selNode, selOffset, &brNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = nsEditor::GetNodeLocation(brNode, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-05-07 05:33:42 +04:00
|
|
|
aSelection->SetHint(PR_TRUE);
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
2000-06-29 13:23:41 +04:00
|
|
|
// mEditor->DumpContentTree();
|
1999-11-29 11:28:46 +03:00
|
|
|
return res;
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
}
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
2000-02-07 04:42:14 +03:00
|
|
|
nsTextEditRules::WillInsertText(PRInt32 aAction,
|
|
|
|
nsIDOMSelection *aSelection,
|
2000-03-29 16:53:23 +04:00
|
|
|
PRBool *aCancel,
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool *aHandled,
|
2000-03-29 16:53:23 +04:00
|
|
|
const nsString *inString,
|
|
|
|
nsString *outString,
|
1999-07-15 23:13:46 +04:00
|
|
|
PRInt32 aMaxLength)
|
2000-03-29 16:53:23 +04:00
|
|
|
{
|
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
1999-06-08 10:04:51 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
if (inString->IsEmpty() && (aAction != kInsertTextIME))
|
2000-02-07 04:42:14 +03:00
|
|
|
{
|
|
|
|
// HACK: this is a fix for bug 19395
|
|
|
|
// I can't outlaw all empty insertions
|
|
|
|
// because IME transaction depend on them
|
|
|
|
// There is more work to do to make the
|
|
|
|
// world safe for IME.
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
*aHandled = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
|
|
|
|
// initialize out param
|
1999-10-06 23:34:09 +04:00
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
*aHandled = PR_TRUE;
|
2000-03-29 16:53:23 +04:00
|
|
|
nsresult res;
|
|
|
|
nsCOMPtr<nsIDOMNode> selNode;
|
|
|
|
PRInt32 selOffset;
|
2000-03-29 17:45:08 +04:00
|
|
|
PRInt32 start=0; PRInt32 end=0;
|
|
|
|
|
|
|
|
// handle docs with a max length
|
2000-03-29 18:04:26 +04:00
|
|
|
// NOTE, this function copies inString into outString for us.
|
2000-03-29 17:45:08 +04:00
|
|
|
res = TruncateInsertionIfNeeded(aSelection, inString, outString, aMaxLength);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// handle password field docs
|
|
|
|
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
|
|
|
{
|
|
|
|
res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
|
|
|
|
NS_ASSERTION((NS_SUCCEEDED(res)), "getTextSelectionOffsets failed!");
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-02-07 05:48:36 +03:00
|
|
|
|
1999-11-29 11:28:46 +03:00
|
|
|
// if the selection isn't collapsed, delete it.
|
|
|
|
PRBool bCollapsed;
|
|
|
|
res = aSelection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed)
|
|
|
|
{
|
1999-12-07 11:30:19 +03:00
|
|
|
res = mEditor->DeleteSelection(nsIEditor::eNone);
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = WillInsert(aSelection, aCancel);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// initialize out param
|
|
|
|
// we want to ignore result of WillInsert()
|
|
|
|
*aCancel = PR_FALSE;
|
|
|
|
|
2000-03-29 17:45:08 +04:00
|
|
|
// handle password field data
|
|
|
|
// this has the side effect of changing all the characters in aOutString
|
|
|
|
// to the replacement character
|
|
|
|
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
|
|
|
{
|
|
|
|
res = EchoInsertionToPWBuff(start, end, outString);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
2000-08-29 02:15:03 +04:00
|
|
|
#ifdef REPLACE_LINEBREAK_WITH_SPACES
|
|
|
|
// Commented out per bug 23485
|
2000-03-29 17:45:08 +04:00
|
|
|
// if we're a single line control, pretreat the input string to remove returns
|
|
|
|
// this is unnecessary if we use <BR>'s for breaks in "plain text", because
|
|
|
|
// InsertBreak() checks the string. But we don't currently do that, so we need this
|
|
|
|
// fixes bug 21032
|
|
|
|
// *** there's some debate about whether we should replace CRLF with spaces, or
|
|
|
|
// truncate the string at the first CRLF. Here, we replace with spaces.
|
2000-03-31 02:57:19 +04:00
|
|
|
if (nsIHTMLEditor::eEditorSingleLineMask & mFlags)
|
2000-03-29 17:45:08 +04:00
|
|
|
{
|
|
|
|
outString->ReplaceChar(CRLF, ' ');
|
|
|
|
}
|
2000-08-29 02:15:03 +04:00
|
|
|
#endif /* REPLACE_LINEBREAK_WITH_SPACES */
|
2000-03-29 17:45:08 +04:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
// get the (collapsed) selection location
|
|
|
|
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
2000-02-07 04:42:14 +03:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
// dont put text in places that cant have it
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString textTag; textTag.AssignWithConversion("__moz_text");
|
2000-03-29 16:53:23 +04:00
|
|
|
if (!mEditor->IsTextNode(selNode) && !mEditor->CanContainTag(selNode, textTag))
|
|
|
|
return NS_ERROR_FAILURE;
|
2000-01-15 17:29:29 +03:00
|
|
|
|
2000-03-29 16:53:23 +04:00
|
|
|
// we need to get the doc
|
|
|
|
nsCOMPtr<nsIDOMDocument>doc;
|
|
|
|
res = mEditor->GetDocument(getter_AddRefs(doc));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!doc) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
if (aAction == kInsertTextIME)
|
2000-02-07 04:42:14 +03:00
|
|
|
{
|
2000-04-14 01:50:19 +04:00
|
|
|
res = mEditor->InsertTextImpl(*outString, &selNode, &selOffset, doc);
|
2000-01-15 17:29:29 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
else // aAction == kInsertText
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
// find where we are
|
|
|
|
nsCOMPtr<nsIDOMNode> curNode = selNode;
|
|
|
|
PRInt32 curOffset = selOffset;
|
|
|
|
|
|
|
|
// is our text going to be PREformatted?
|
|
|
|
// We remember this so that we know how to handle tabs.
|
|
|
|
PRBool isPRE;
|
|
|
|
res = mEditor->IsPreformatted(selNode, &isPRE);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// dont spaz my selection in subtransactions
|
|
|
|
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
|
|
|
nsSubsumeStr subStr;
|
2000-03-29 18:04:26 +04:00
|
|
|
const PRUnichar *unicodeBuf = outString->GetUnicode();
|
2000-03-29 16:53:23 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> unused;
|
|
|
|
PRInt32 pos = 0;
|
|
|
|
|
|
|
|
// for efficiency, break out the pre case seperately. This is because
|
|
|
|
// its a lot cheaper to search the input string for only newlines than
|
|
|
|
// it is to search for both tabs and newlines.
|
|
|
|
if (isPRE)
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
char newlineChar = '\n';
|
2000-06-22 09:39:54 +04:00
|
|
|
while (unicodeBuf && (pos != -1) && ((PRUint32)pos < outString->Length()))
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
PRInt32 oldPos = pos;
|
|
|
|
PRInt32 subStrLen;
|
2000-03-29 18:04:26 +04:00
|
|
|
pos = outString->FindChar(newlineChar, PR_FALSE, oldPos);
|
2000-03-29 16:53:23 +04:00
|
|
|
|
|
|
|
if (pos != -1)
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
subStrLen = pos - oldPos;
|
|
|
|
// if first char is newline, then use just it
|
|
|
|
if (subStrLen == 0)
|
|
|
|
subStrLen = 1;
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-03-29 18:04:26 +04:00
|
|
|
subStrLen = outString->Length() - oldPos;
|
|
|
|
pos = outString->Length();
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
|
|
|
|
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
|
|
|
|
|
|
|
// is it a return?
|
2000-04-18 11:52:02 +04:00
|
|
|
if (subStr.EqualsWithConversion("\n"))
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
{
|
2000-08-29 02:15:03 +04:00
|
|
|
if (nsIHTMLEditor::eEditorSingleLineMask & mFlags)
|
|
|
|
res = mEditor->InsertTextImpl(subStr, &curNode, &curOffset, doc);
|
|
|
|
else
|
|
|
|
res = mEditor->CreateBRImpl(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
2000-03-29 16:53:23 +04:00
|
|
|
pos++;
|
1999-04-05 00:10:39 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
else
|
1999-04-05 00:10:39 +04:00
|
|
|
{
|
2000-04-14 01:50:19 +04:00
|
|
|
res = mEditor->InsertTextImpl(subStr, &curNode, &curOffset, doc);
|
1999-04-05 00:10:39 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char specialChars[] = {'\t','\n',0};
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString tabString; tabString.AssignWithConversion(" ");
|
2000-06-22 09:39:54 +04:00
|
|
|
while (unicodeBuf && (pos != -1) && ((PRUint32)pos < outString->Length()))
|
2000-03-29 16:53:23 +04:00
|
|
|
{
|
|
|
|
PRInt32 oldPos = pos;
|
|
|
|
PRInt32 subStrLen;
|
2000-03-29 18:04:26 +04:00
|
|
|
pos = outString->FindCharInSet(specialChars, oldPos);
|
2000-03-29 16:53:23 +04:00
|
|
|
|
|
|
|
if (pos != -1)
|
1999-04-05 00:10:39 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
subStrLen = pos - oldPos;
|
|
|
|
// if first char is newline, then use just it
|
|
|
|
if (subStrLen == 0)
|
|
|
|
subStrLen = 1;
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
else
|
1999-04-16 22:29:12 +04:00
|
|
|
{
|
2000-03-29 18:04:26 +04:00
|
|
|
subStrLen = outString->Length() - oldPos;
|
|
|
|
pos = outString->Length();
|
1999-04-20 21:49:34 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
|
|
|
|
subStr.Subsume((PRUnichar*)&unicodeBuf[oldPos], PR_FALSE, subStrLen);
|
|
|
|
|
|
|
|
// is it a tab?
|
2000-04-18 11:52:02 +04:00
|
|
|
if (subStr.EqualsWithConversion("\t"))
|
1999-04-20 21:49:34 +04:00
|
|
|
{
|
2000-04-14 01:50:19 +04:00
|
|
|
res = mEditor->InsertTextImpl(tabString, &curNode, &curOffset, doc);
|
2000-03-29 16:53:23 +04:00
|
|
|
pos++;
|
1999-04-20 21:49:34 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
// is it a return?
|
2000-04-18 11:52:02 +04:00
|
|
|
else if (subStr.EqualsWithConversion("\n"))
|
1999-04-20 21:49:34 +04:00
|
|
|
{
|
2000-04-14 01:50:19 +04:00
|
|
|
res = mEditor->CreateBRImpl(&curNode, &curOffset, &unused, nsIEditor::eNone);
|
2000-03-29 16:53:23 +04:00
|
|
|
pos++;
|
1999-04-16 22:29:12 +04:00
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
else
|
|
|
|
{
|
2000-04-14 01:50:19 +04:00
|
|
|
res = mEditor->InsertTextImpl(subStr, &curNode, &curOffset, doc);
|
2000-03-29 16:53:23 +04:00
|
|
|
}
|
|
|
|
if (NS_FAILED(res)) return res;
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
}
|
|
|
|
}
|
2000-03-29 16:53:23 +04:00
|
|
|
if (curNode) aSelection->Collapse(curNode, curOffset);
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
}
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
}
|
|
|
|
|
1999-04-20 21:49:34 +04:00
|
|
|
nsresult
|
2000-03-29 16:53:23 +04:00
|
|
|
nsTextEditRules::DidInsertText(nsIDOMSelection *aSelection,
|
|
|
|
nsresult aResult)
|
1999-04-20 21:49:34 +04:00
|
|
|
{
|
2000-03-29 16:53:23 +04:00
|
|
|
return DidInsert(aSelection, aResult);
|
1999-04-20 21:49:34 +04:00
|
|
|
}
|
|
|
|
|
1999-04-05 00:10:39 +04:00
|
|
|
|
As a reminder, we decided to do this based strictly content. Some support for style-based text properties is written, but not used
anywhere any more.
* Cleaned up split and join undo/redo.
* Added TypeInState, a data struct that remembers things about text properties for collapsed selections, so you can type
* Ctrl-B with an insertion point and the next character will be bold.
* Added all the logic to handle inline vs. block elements when setting text properties.
* Added some support for italic and underline as well. Adding these things is pretty easy now. Ctrl-B, Ctrl-I, Ctrl-U for testing bold, italic, underline.
* Added all the logic to make sure we only add style tags where they're needed, so you should never get the same style tag nested within itself, except as needed for block elements.
* Added methods for testing a node to see if a particular style is set. This isn't 100% done yet, but with very little work we could have toolbar buttons that respond to selection changed notification that show the state of bold, italic, underline, etc. in real time. Supports tri-state: whole selection is bold, some of selection is bold, none of selection is bold, ...
* Fully undoable and redoable.
* Added some debug printfs to transactions and editors. all controlled by a gNoisy static in each module. helps me track down undo/redo problems. if the output bugs people enough, I'll shut it off and re-enable it in my local tree.
Noticably missing: make un-bold, make un-italic, etc. This is coming soon.
1999-04-01 21:58:07 +04:00
|
|
|
|
1999-06-08 10:04:51 +04:00
|
|
|
nsresult
|
1999-10-06 23:34:09 +04:00
|
|
|
nsTextEditRules::WillSetTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
1999-06-08 10:04:51 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled)
|
|
|
|
{ return NS_ERROR_NULL_POINTER; }
|
1999-08-24 12:56:51 +04:00
|
|
|
nsresult res = NS_OK;
|
1999-06-08 10:04:51 +04:00
|
|
|
|
|
|
|
// XXX: should probably return a success value other than NS_OK that means "not allowed"
|
1999-08-09 05:37:50 +04:00
|
|
|
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
|
1999-06-08 10:04:51 +04:00
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
}
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
1999-06-08 10:04:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsTextEditRules::DidSetTextProperty(nsIDOMSelection *aSelection, nsresult aResult)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
1999-10-06 23:34:09 +04:00
|
|
|
nsTextEditRules::WillRemoveTextProperty(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
1999-06-08 10:04:51 +04:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled)
|
|
|
|
{ return NS_ERROR_NULL_POINTER; }
|
1999-08-24 12:56:51 +04:00
|
|
|
nsresult res = NS_OK;
|
1999-06-08 10:04:51 +04:00
|
|
|
|
|
|
|
// XXX: should probably return a success value other than NS_OK that means "not allowed"
|
1999-08-09 05:37:50 +04:00
|
|
|
if (nsIHTMLEditor::eEditorPlaintextMask & mFlags) {
|
1999-06-08 10:04:51 +04:00
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
}
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
1999-06-08 10:04:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsTextEditRules::DidRemoveTextProperty(nsIDOMSelection *aSelection, nsresult aResult)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-06-25 03:36:56 +04:00
|
|
|
nsTextEditRules::WillDeleteSelection(nsIDOMSelection *aSelection,
|
1999-12-07 11:30:19 +03:00
|
|
|
nsIEditor::EDirection aCollapsedAction,
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-03-10 22:53:26 +03:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
|
|
|
|
1999-03-12 05:28:24 +03:00
|
|
|
// initialize out param
|
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-03-13 07:53:21 +03:00
|
|
|
|
|
|
|
// if there is only bogus content, cancel the operation
|
1999-03-15 03:57:32 +03:00
|
|
|
if (mBogusNode) {
|
|
|
|
*aCancel = PR_TRUE;
|
|
|
|
return NS_OK;
|
1999-03-13 07:53:21 +03:00
|
|
|
}
|
1999-08-09 05:37:50 +04:00
|
|
|
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
1999-06-25 03:36:56 +04:00
|
|
|
{
|
|
|
|
// manage the password buffer
|
|
|
|
PRInt32 start, end;
|
1999-06-28 17:36:38 +04:00
|
|
|
mEditor->GetTextSelectionOffsets(aSelection, start, end);
|
1999-06-25 03:36:56 +04:00
|
|
|
if (end==start)
|
|
|
|
{ // collapsed selection
|
1999-12-07 11:30:19 +03:00
|
|
|
if (nsIEditor::ePrevious==aCollapsedAction && 0<start) { // del back
|
1999-06-25 03:36:56 +04:00
|
|
|
mPasswordText.Cut(start-1, 1);
|
|
|
|
}
|
1999-12-07 11:30:19 +03:00
|
|
|
else if (nsIEditor::eNext==aCollapsedAction) { // del forward
|
1999-06-25 03:36:56 +04:00
|
|
|
mPasswordText.Cut(start, 1);
|
|
|
|
}
|
|
|
|
// otherwise nothing to do for this collapsed selection
|
|
|
|
}
|
|
|
|
else { // extended selection
|
|
|
|
mPasswordText.Cut(start, end-start);
|
|
|
|
}
|
|
|
|
|
1999-09-03 12:31:33 +04:00
|
|
|
#ifdef DEBUG_buster
|
1999-06-25 03:36:56 +04:00
|
|
|
char *password = mPasswordText.ToNewCString();
|
|
|
|
printf("mPasswordText is %s\n", password);
|
1999-09-06 10:22:51 +04:00
|
|
|
nsCRT::free(password);
|
1999-09-03 12:31:33 +04:00
|
|
|
#endif
|
1999-06-25 03:36:56 +04:00
|
|
|
}
|
1999-03-12 05:28:24 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the document is empty, insert a bogus text node with a
|
1999-03-16 19:38:09 +03:00
|
|
|
// if we ended up with consecutive text nodes, merge them
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-06-25 03:36:56 +04:00
|
|
|
nsTextEditRules::DidDeleteSelection(nsIDOMSelection *aSelection,
|
1999-12-07 11:30:19 +03:00
|
|
|
nsIEditor::EDirection aCollapsedAction,
|
1999-06-25 03:36:56 +04:00
|
|
|
nsresult aResult)
|
1999-03-12 05:28:24 +03:00
|
|
|
{
|
1999-08-24 12:56:51 +04:00
|
|
|
nsresult res = aResult; // if aResult is an error, we just return it
|
1999-03-12 05:28:24 +03:00
|
|
|
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
|
|
|
|
PRBool isCollapsed;
|
1999-07-18 06:27:19 +04:00
|
|
|
aSelection->GetIsCollapsed(&isCollapsed);
|
1999-03-12 05:28:24 +03:00
|
|
|
NS_ASSERTION(PR_TRUE==isCollapsed, "selection not collapsed after delete selection.");
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_SUCCEEDED(res)) // only do this work if DeleteSelection completed successfully
|
1999-03-12 05:28:24 +03:00
|
|
|
{
|
1999-03-16 19:38:09 +03:00
|
|
|
// if we don't have an empty document, check the selection to see if any collapsing is necessary
|
|
|
|
if (!mBogusNode)
|
|
|
|
{
|
1999-11-17 14:30:39 +03:00
|
|
|
// get the node that contains the selection point
|
1999-03-16 19:38:09 +03:00
|
|
|
nsCOMPtr<nsIDOMNode>anchor;
|
|
|
|
PRInt32 offset;
|
1999-12-07 11:30:19 +03:00
|
|
|
res = aSelection->GetAnchorNode(getter_AddRefs(anchor));
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-19 17:30:48 +04:00
|
|
|
if (!anchor) return NS_ERROR_NULL_POINTER;
|
1999-08-24 12:56:51 +04:00
|
|
|
res = aSelection->GetAnchorOffset(&offset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
1999-11-17 14:30:39 +03:00
|
|
|
// selectedNode is either the anchor itself,
|
|
|
|
// or if anchor has children, it's the referenced child node
|
2000-05-07 05:33:42 +04:00
|
|
|
// XXX ----------------------------------------------- XXX
|
|
|
|
// I believe this s wrong. Assuming anchor and focus
|
|
|
|
// alwas correspond to selection endpoints, it is possible
|
|
|
|
// for the first node after the selectin start point to not
|
|
|
|
// be selected. As an example consider a selection that
|
|
|
|
// starts right before a <ul>, and ends after the first character
|
|
|
|
// in the text of the first list item. Really all that is
|
|
|
|
// selected is one letter of text, not the <ul>
|
1999-11-17 14:30:39 +03:00
|
|
|
nsCOMPtr<nsIDOMNode> selectedNode = do_QueryInterface(anchor);
|
|
|
|
PRBool hasChildren=PR_FALSE;
|
|
|
|
anchor->HasChildNodes(&hasChildren);
|
|
|
|
if (PR_TRUE==hasChildren)
|
|
|
|
{ // if anchor has children, set selectedNode to the child pointed at
|
|
|
|
nsCOMPtr<nsIDOMNodeList> anchorChildren;
|
|
|
|
res = anchor->GetChildNodes(getter_AddRefs(anchorChildren));
|
|
|
|
if ((NS_SUCCEEDED(res)) && anchorChildren) {
|
|
|
|
res = anchorChildren->Item(offset, getter_AddRefs(selectedNode));
|
|
|
|
}
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
1999-11-17 14:30:39 +03:00
|
|
|
|
2000-05-07 05:33:42 +04:00
|
|
|
if ((NS_SUCCEEDED(res)) && selectedNode && !DeleteEmptyTextNode(selectedNode))
|
1999-03-16 19:38:09 +03:00
|
|
|
{
|
1999-08-19 17:30:48 +04:00
|
|
|
nsCOMPtr<nsIDOMCharacterData>selectedNodeAsText;
|
|
|
|
selectedNodeAsText = do_QueryInterface(selectedNode);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (selectedNodeAsText && mEditor->IsEditable(selectedNode))
|
1999-03-16 19:38:09 +03:00
|
|
|
{
|
1999-08-19 17:30:48 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> siblingNode;
|
|
|
|
selectedNode->GetPreviousSibling(getter_AddRefs(siblingNode));
|
2000-05-07 05:33:42 +04:00
|
|
|
if (siblingNode && !DeleteEmptyTextNode(siblingNode))
|
1999-03-16 19:38:09 +03:00
|
|
|
{
|
1999-08-19 17:30:48 +04:00
|
|
|
nsCOMPtr<nsIDOMCharacterData>siblingNodeAsText;
|
|
|
|
siblingNodeAsText = do_QueryInterface(siblingNode);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (siblingNodeAsText && mEditor->IsEditable(siblingNode))
|
1999-03-16 19:38:09 +03:00
|
|
|
{
|
1999-08-19 17:30:48 +04:00
|
|
|
PRUint32 siblingLength; // the length of siblingNode before the join
|
|
|
|
siblingNodeAsText->GetLength(&siblingLength);
|
|
|
|
nsCOMPtr<nsIDOMNode> parentNode;
|
1999-08-24 12:56:51 +04:00
|
|
|
res = selectedNode->GetParentNode(getter_AddRefs(parentNode));
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!parentNode) return NS_ERROR_NULL_POINTER;
|
1999-08-24 12:56:51 +04:00
|
|
|
res = mEditor->JoinNodes(siblingNode, selectedNode, parentNode);
|
1999-08-19 17:30:48 +04:00
|
|
|
// selectedNode will remain after the join, siblingNode is removed
|
1999-03-16 19:38:09 +03:00
|
|
|
}
|
1999-08-19 17:30:48 +04:00
|
|
|
}
|
|
|
|
selectedNode->GetNextSibling(getter_AddRefs(siblingNode));
|
2000-05-07 05:33:42 +04:00
|
|
|
if (siblingNode && !DeleteEmptyTextNode(siblingNode))
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>siblingNodeAsText;
|
|
|
|
siblingNodeAsText = do_QueryInterface(siblingNode);
|
2000-01-10 13:13:58 +03:00
|
|
|
if (siblingNodeAsText && mEditor->IsEditable(siblingNode))
|
1999-03-16 19:38:09 +03:00
|
|
|
{
|
1999-08-19 17:30:48 +04:00
|
|
|
PRUint32 selectedNodeLength; // the length of siblingNode before the join
|
|
|
|
selectedNodeAsText->GetLength(&selectedNodeLength);
|
|
|
|
nsCOMPtr<nsIDOMNode> parentNode;
|
1999-08-24 12:56:51 +04:00
|
|
|
res = selectedNode->GetParentNode(getter_AddRefs(parentNode));
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!parentNode) return NS_ERROR_NULL_POINTER;
|
1999-08-19 17:30:48 +04:00
|
|
|
|
1999-08-24 12:56:51 +04:00
|
|
|
res = mEditor->JoinNodes(selectedNode, siblingNode, parentNode);
|
1999-12-07 11:30:19 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-08-19 17:30:48 +04:00
|
|
|
// selectedNode will remain after the join, siblingNode is removed
|
1999-03-16 19:38:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-03-10 22:53:26 +03:00
|
|
|
}
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
1999-03-10 22:53:26 +03:00
|
|
|
}
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-10-06 23:34:09 +04:00
|
|
|
nsTextEditRules::WillUndo(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
1999-03-15 08:08:30 +03:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
1999-03-15 08:08:30 +03:00
|
|
|
// initialize out param
|
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-03-15 08:08:30 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-08-24 12:56:51 +04:00
|
|
|
/* the idea here is to see if the magic empty node has suddenly reappeared as the res of the undo.
|
1999-03-15 08:08:30 +03:00
|
|
|
* if it has, set our state so we remember it.
|
|
|
|
* There is a tradeoff between doing here and at redo, or doing it everywhere else that might care.
|
|
|
|
* Since undo and redo are relatively rare, it makes sense to take the (small) performance hit here.
|
|
|
|
*/
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-03-15 08:08:30 +03:00
|
|
|
nsTextEditRules:: DidUndo(nsIDOMSelection *aSelection, nsresult aResult)
|
|
|
|
{
|
1999-08-24 12:56:51 +04:00
|
|
|
nsresult res = aResult; // if aResult is an error, we return it.
|
1999-03-15 08:08:30 +03:00
|
|
|
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_SUCCEEDED(res))
|
1999-03-15 08:08:30 +03:00
|
|
|
{
|
|
|
|
if (mBogusNode) {
|
|
|
|
mBogusNode = do_QueryInterface(nsnull);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-09-20 05:31:44 +04:00
|
|
|
nsCOMPtr<nsIDOMElement> theBody;
|
2000-05-07 05:33:42 +04:00
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
2000-05-04 12:33:48 +04:00
|
|
|
res = mEditor->GetRootElement(getter_AddRefs(theBody));
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-20 05:31:44 +04:00
|
|
|
if (!theBody) return NS_ERROR_FAILURE;
|
2000-05-07 05:33:42 +04:00
|
|
|
res = mEditor->GetLeftmostChild(theBody,getter_AddRefs(node));
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
2000-05-07 05:33:42 +04:00
|
|
|
if (!node) return NS_ERROR_NULL_POINTER;
|
|
|
|
if (mEditor->IsMozEditorBogusNode(node))
|
|
|
|
mBogusNode = do_QueryInterface(node);
|
1999-03-15 08:08:30 +03:00
|
|
|
}
|
|
|
|
}
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
1999-03-15 08:08:30 +03:00
|
|
|
}
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-10-06 23:34:09 +04:00
|
|
|
nsTextEditRules::WillRedo(nsIDOMSelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
1999-03-15 08:08:30 +03:00
|
|
|
{
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
1999-03-15 08:08:30 +03:00
|
|
|
// initialize out param
|
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-03-15 08:08:30 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-04-12 16:01:32 +04:00
|
|
|
nsresult
|
1999-03-15 08:08:30 +03:00
|
|
|
nsTextEditRules::DidRedo(nsIDOMSelection *aSelection, nsresult aResult)
|
|
|
|
{
|
1999-08-24 12:56:51 +04:00
|
|
|
nsresult res = aResult; // if aResult is an error, we return it.
|
1999-03-15 08:08:30 +03:00
|
|
|
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_SUCCEEDED(res))
|
1999-03-15 08:08:30 +03:00
|
|
|
{
|
|
|
|
if (mBogusNode) {
|
|
|
|
mBogusNode = do_QueryInterface(nsnull);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-09-20 05:31:44 +04:00
|
|
|
nsCOMPtr<nsIDOMElement> theBody;
|
2000-05-04 12:33:48 +04:00
|
|
|
res = mEditor->GetRootElement(getter_AddRefs(theBody));
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-20 05:31:44 +04:00
|
|
|
if (!theBody) return NS_ERROR_FAILURE;
|
|
|
|
|
2000-04-18 11:52:02 +04:00
|
|
|
nsAutoString tagName; tagName.AssignWithConversion("div");
|
1999-09-20 05:31:44 +04:00
|
|
|
nsCOMPtr<nsIDOMNodeList> nodeList;
|
|
|
|
res = theBody->GetElementsByTagName(tagName, getter_AddRefs(nodeList));
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
1999-09-20 05:31:44 +04:00
|
|
|
if (nodeList)
|
1999-03-15 08:08:30 +03:00
|
|
|
{
|
1999-09-22 02:32:39 +04:00
|
|
|
PRUint32 len;
|
1999-09-20 05:31:44 +04:00
|
|
|
nodeList->GetLength(&len);
|
|
|
|
|
|
|
|
if (len != 1) return NS_OK; // only in the case of one div could there be the bogus node
|
|
|
|
nsCOMPtr<nsIDOMNode>node;
|
|
|
|
nodeList->Item(0, getter_AddRefs(node));
|
|
|
|
if (!node) return NS_ERROR_NULL_POINTER;
|
2000-01-19 02:45:35 +03:00
|
|
|
if (mEditor->IsMozEditorBogusNode(node))
|
|
|
|
mBogusNode = do_QueryInterface(node);
|
1999-03-15 08:08:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
1999-03-15 08:08:30 +03:00
|
|
|
}
|
|
|
|
|
1999-06-25 03:36:56 +04:00
|
|
|
nsresult
|
|
|
|
nsTextEditRules::WillOutputText(nsIDOMSelection *aSelection,
|
1999-09-09 23:39:36 +04:00
|
|
|
const nsString *aOutputFormat,
|
|
|
|
nsString *aOutString,
|
1999-10-06 23:34:09 +04:00
|
|
|
PRBool *aCancel,
|
|
|
|
PRBool *aHandled)
|
1999-06-25 03:36:56 +04:00
|
|
|
{
|
|
|
|
// null selection ok
|
1999-10-06 23:34:09 +04:00
|
|
|
if (!aOutString || !aOutputFormat || !aCancel || !aHandled)
|
|
|
|
{ return NS_ERROR_NULL_POINTER; }
|
1999-06-25 03:36:56 +04:00
|
|
|
|
|
|
|
// initialize out param
|
|
|
|
*aCancel = PR_FALSE;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_FALSE;
|
1999-09-09 23:39:36 +04:00
|
|
|
|
2000-04-18 11:52:02 +04:00
|
|
|
if (PR_TRUE == aOutputFormat->EqualsWithConversion("text/plain"))
|
1999-09-09 23:39:36 +04:00
|
|
|
{ // only use these rules for plain text output
|
|
|
|
if (mFlags & nsIHTMLEditor::eEditorPasswordMask)
|
|
|
|
{
|
|
|
|
*aOutString = mPasswordText;
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
1999-09-09 23:39:36 +04:00
|
|
|
}
|
|
|
|
else if (mBogusNode)
|
|
|
|
{ // this means there's no content, so output null string
|
2000-04-18 11:52:02 +04:00
|
|
|
aOutString->SetLength(0);
|
1999-10-06 23:34:09 +04:00
|
|
|
*aHandled = PR_TRUE;
|
1999-09-09 23:39:36 +04:00
|
|
|
}
|
1999-08-24 17:48:08 +04:00
|
|
|
}
|
1999-06-25 03:36:56 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsTextEditRules::DidOutputText(nsIDOMSelection *aSelection, nsresult aResult)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-03-10 22:53:26 +03:00
|
|
|
|
2000-01-13 13:17:35 +03:00
|
|
|
nsresult
|
|
|
|
nsTextEditRules::ReplaceNewlines(nsIDOMRange *aRange)
|
|
|
|
{
|
|
|
|
if (!aRange) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// convert any newlines in editable, preformatted text nodes
|
|
|
|
// into normal breaks. this is because layout wont give us a place
|
|
|
|
// to put the cursor on empty lines otherwise.
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContentIterator> iter;
|
|
|
|
nsCOMPtr<nsISupports> isupports;
|
|
|
|
PRUint32 nodeCount,j;
|
|
|
|
nsCOMPtr<nsISupportsArray> arrayOfNodes;
|
|
|
|
|
|
|
|
// make an isupportsArray to hold a list of nodes
|
|
|
|
nsresult res = NS_NewISupportsArray(getter_AddRefs(arrayOfNodes));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// need an iterator
|
|
|
|
res = nsComponentManager::CreateInstance(kContentIteratorCID,
|
|
|
|
nsnull,
|
|
|
|
NS_GET_IID(nsIContentIterator),
|
|
|
|
getter_AddRefs(iter));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = iter->Init(aRange);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// gather up a list of editable preformatted text nodes
|
|
|
|
while (NS_ENUMERATOR_FALSE == iter->IsDone())
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
res = iter->CurrentNode(getter_AddRefs(content));
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
node = do_QueryInterface(content);
|
|
|
|
if (!node) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
if (mEditor->IsTextNode(node) && mEditor->IsEditable(node))
|
|
|
|
{
|
|
|
|
PRBool isPRE;
|
|
|
|
res = mEditor->IsPreformatted(node, &isPRE);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (isPRE)
|
|
|
|
{
|
|
|
|
isupports = do_QueryInterface(node);
|
|
|
|
arrayOfNodes->AppendElement(isupports);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res = iter->Next();
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// replace newlines with breaks. have to do this left to right,
|
|
|
|
// since inserting the break can split the text node, and the
|
|
|
|
// original node becomes the righthand node.
|
|
|
|
char newlineChar[] = {'\n',0};
|
|
|
|
res = arrayOfNodes->Count(&nodeCount);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
for (j = 0; j < nodeCount; j++)
|
|
|
|
{
|
|
|
|
isupports = (dont_AddRef)(arrayOfNodes->ElementAt(0));
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode, theNode( do_QueryInterface(isupports) );
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> textNode( do_QueryInterface(theNode) );
|
|
|
|
arrayOfNodes->RemoveElementAt(0);
|
|
|
|
// find the newline
|
|
|
|
PRInt32 offset;
|
|
|
|
nsAutoString tempString;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
textNode->GetData(tempString);
|
|
|
|
offset = tempString.FindCharInSet(newlineChar);
|
|
|
|
if (offset == -1) break; // done with this node
|
|
|
|
|
|
|
|
// delete the newline
|
|
|
|
EditTxn *txn;
|
|
|
|
// note 1: we are not telling edit listeners about these because they don't care
|
|
|
|
// note 2: we are not wrapping these in a placeholder because we know they already are,
|
|
|
|
// or, failing that, undo is disabled
|
|
|
|
res = mEditor->CreateTxnForDeleteText(textNode, offset, 1, (DeleteTextTxn**)&txn);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!txn) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
res = mEditor->Do(txn);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// The transaction system (if any) has taken ownwership of txn
|
|
|
|
NS_IF_RELEASE(txn);
|
|
|
|
|
|
|
|
// insert a break
|
|
|
|
res = mEditor->CreateBR(textNode, offset, &brNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
} while (1); // break used to exit while loop
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
nsresult
|
|
|
|
nsTextEditRules::CreateBogusNodeIfNeeded(nsIDOMSelection *aSelection)
|
|
|
|
{
|
|
|
|
if (!aSelection) { return NS_ERROR_NULL_POINTER; }
|
1999-07-01 22:42:28 +04:00
|
|
|
if (!mEditor) { return NS_ERROR_NULL_POINTER; }
|
1999-09-20 05:31:44 +04:00
|
|
|
if (mBogusNode) return NS_OK; // let's not create more than one, ok?
|
1999-12-07 11:30:19 +03:00
|
|
|
|
|
|
|
// tell rules system to not do any post-processing
|
|
|
|
nsAutoRules beginRulesSniffing(mEditor, nsEditor::kOpIgnore, nsIEditor::eNone);
|
1999-09-20 05:31:44 +04:00
|
|
|
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
if (!mBody) return NS_ERROR_NULL_POINTER;
|
1999-08-19 17:30:48 +04:00
|
|
|
|
|
|
|
// now we've got the body tag.
|
|
|
|
// iterate the body tag, looking for editable content
|
|
|
|
// if no editable content is found, insert the bogus node
|
|
|
|
PRBool needsBogusContent=PR_TRUE;
|
|
|
|
nsCOMPtr<nsIDOMNode>bodyChild;
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
nsresult res = mBody->GetFirstChild(getter_AddRefs(bodyChild));
|
1999-08-24 12:56:51 +04:00
|
|
|
while ((NS_SUCCEEDED(res)) && bodyChild)
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
2000-01-19 02:45:35 +03:00
|
|
|
if (mEditor->IsMozEditorBogusNode(bodyChild) || mEditor->IsEditable(bodyChild))
|
1999-08-19 17:30:48 +04:00
|
|
|
{
|
|
|
|
needsBogusContent = PR_FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIDOMNode>temp;
|
|
|
|
bodyChild->GetNextSibling(getter_AddRefs(temp));
|
|
|
|
bodyChild = do_QueryInterface(temp);
|
|
|
|
}
|
2000-01-19 02:45:35 +03:00
|
|
|
if (needsBogusContent)
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
{
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
// create a br
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc;
|
|
|
|
res = mEditor->GetDocument(getter_AddRefs(domDoc));
|
|
|
|
nsCOMPtr<nsIDOMElement>brElement;
|
2000-07-14 03:15:41 +04:00
|
|
|
nsCOMPtr<nsIContent> newContent;
|
|
|
|
|
2000-06-07 05:18:12 +04:00
|
|
|
nsString qualifiedTag;
|
2000-07-14 03:15:41 +04:00
|
|
|
qualifiedTag.AssignWithConversion("br");
|
|
|
|
|
2000-07-14 22:38:24 +04:00
|
|
|
res = mEditor->CreateHTMLContent(qualifiedTag, getter_AddRefs(newContent));
|
2000-07-14 03:15:41 +04:00
|
|
|
brElement = do_QueryInterface(newContent);
|
1999-08-24 12:56:51 +04:00
|
|
|
if (NS_FAILED(res)) return res;
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
|
|
|
|
// set mBogusNode to be the newly created <br>
|
|
|
|
mBogusNode = do_QueryInterface(brElement);
|
1999-11-03 00:35:21 +03:00
|
|
|
if (!mBogusNode) return NS_ERROR_NULL_POINTER;
|
1999-08-19 17:30:48 +04:00
|
|
|
|
1999-11-03 00:35:21 +03:00
|
|
|
// give it a special attribute
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
brElement->SetAttribute( NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeAttr),
|
|
|
|
NS_ConvertASCIItoUCS2(nsEditor::kMOZEditorBogusNodeValue) );
|
1999-12-05 03:29:34 +03:00
|
|
|
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
// put the node in the document
|
|
|
|
res = mEditor->InsertNode(mBogusNode,mBody,0);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
1999-12-05 03:29:34 +03:00
|
|
|
// set selection
|
fixes:
14753, 29843, 39864, 40141,
40139, 36679, 39542, 34729,
34855, 37216, 39292, 26447
r=sfraser,cmanske,fm; a=beppe
2000-05-25 03:00:24 +04:00
|
|
|
aSelection->Collapse(mBody,0);
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
}
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsTextEditRules::TruncateInsertionIfNeeded(nsIDOMSelection *aSelection,
|
|
|
|
const nsString *aInString,
|
|
|
|
nsString *aOutString,
|
|
|
|
PRInt32 aMaxLength)
|
|
|
|
{
|
|
|
|
if (!aSelection || !aInString || !aOutString) {return NS_ERROR_NULL_POINTER;}
|
|
|
|
|
|
|
|
nsresult res = NS_OK;
|
|
|
|
*aOutString = *aInString;
|
|
|
|
|
|
|
|
if ((-1 != aMaxLength) && (mFlags & nsIHTMLEditor::eEditorPlaintextMask))
|
|
|
|
{
|
|
|
|
// Get the current text length.
|
|
|
|
// Get the length of inString.
|
1999-12-07 11:30:19 +03:00
|
|
|
// Get the length of the selection.
|
|
|
|
// If selection is collapsed, it is length 0.
|
|
|
|
// Subtract the length of the selection from the len(doc)
|
|
|
|
// since we'll delete the selection on insert.
|
|
|
|
// This is resultingDocLength.
|
1999-08-24 12:56:51 +04:00
|
|
|
// If (resultingDocLength) is at or over max, cancel the insert
|
|
|
|
// If (resultingDocLength) + (length of input) > max,
|
1999-12-07 11:30:19 +03:00
|
|
|
// set aOutString to subset of inString so length = max
|
1999-08-24 12:56:51 +04:00
|
|
|
PRInt32 docLength;
|
|
|
|
res = mEditor->GetDocumentLength(&docLength);
|
|
|
|
if (NS_FAILED(res)) { return res; }
|
|
|
|
PRInt32 start, end;
|
|
|
|
res = mEditor->GetTextSelectionOffsets(aSelection, start, end);
|
|
|
|
if (NS_FAILED(res)) { return res; }
|
|
|
|
PRInt32 selectionLength = end-start;
|
|
|
|
if (selectionLength<0) { selectionLength *= (-1); }
|
|
|
|
PRInt32 resultingDocLength = docLength - selectionLength;
|
|
|
|
if (resultingDocLength >= aMaxLength)
|
|
|
|
{
|
2000-04-18 11:52:02 +04:00
|
|
|
aOutString->SetLength(0);
|
1999-08-24 12:56:51 +04:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PRInt32 inCount = aOutString->Length();
|
|
|
|
if ((inCount+resultingDocLength) > aMaxLength)
|
|
|
|
{
|
|
|
|
aOutString->Truncate(aMaxLength-resultingDocLength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
Preparation for ender-based text control
* added focus listener. Doesn't do much yet, but when focus notifications start appearing, we'll be ready for them. The code is in
place to hide selection when we lose focus and paint selection when we get focus. That's probably not quite right, but it's a start.
We will need to be able to determine the distinction between losing focus to another control within our app, and losing focus to
another app.
* added support for disabled and readonly states in the editor. This is accomplished by having flags set by the client, and letting the
rules system deal with those flags. The flags I added are:
TEXT_EDITOR_FLAG_PLAINTEXT 0x01 // only plain text editing is allowed
TEXT_EDITOR_FLAG_SINGLELINE 0x02 // enter key and CR-LF handled specially
TEXT_EDITOR_FLAG_PASSWORD 0x04 // text is not entered into content, only a representative character
TEXT_EDITOR_FLAG_READONLY 0x08 // editing events are disabled. Editor may still accept focus.
TEXT_EDITOR_FLAG_DISALBED 0x10 // all events are disabled (like scrolling). Editor will not accept focus.
* added WillInsertBreak/DidInsertBreak into text rules, so flags could be checked. This gets us readonly, disabled, and single line
behavior.
* cleaned up the code that allocates, registers, and destroys event listeners. Thanks to Kin and Simon for cleaning up the
ownership model on the listeners, it was a big help.
* added support for a max text length. You can now tell the text editor, be no bigger than n characters.
1999-05-29 01:24:18 +04:00
|
|
|
}
|
1999-07-01 17:42:03 +04:00
|
|
|
|
1999-08-24 12:56:51 +04:00
|
|
|
|
|
|
|
nsresult
|
2000-02-07 05:48:36 +03:00
|
|
|
nsTextEditRules::EchoInsertionToPWBuff(PRInt32 aStart, PRInt32 aEnd, nsString *aOutString)
|
1999-08-24 12:56:51 +04:00
|
|
|
{
|
2000-02-07 05:48:36 +03:00
|
|
|
if (!aOutString) {return NS_ERROR_NULL_POINTER;}
|
1999-08-24 12:56:51 +04:00
|
|
|
|
|
|
|
// manage the password buffer
|
2000-02-07 05:48:36 +03:00
|
|
|
mPasswordText.Insert(*aOutString, aStart);
|
1999-08-24 12:56:51 +04:00
|
|
|
|
|
|
|
// change the output to '*' only
|
|
|
|
PRInt32 length = aOutString->Length();
|
|
|
|
PRInt32 i;
|
2000-04-18 11:52:02 +04:00
|
|
|
aOutString->SetLength(0);
|
1999-08-24 12:56:51 +04:00
|
|
|
for (i=0; i<length; i++)
|
2000-04-18 11:52:02 +04:00
|
|
|
aOutString->AppendWithConversion('*');
|
1999-08-24 12:56:51 +04:00
|
|
|
|
2000-02-07 05:48:36 +03:00
|
|
|
return NS_OK;
|
1999-08-24 12:56:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-29 11:28:46 +03:00
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// CreateMozBR: put a BR node with moz attribute at {aNode, aOffset}
|
|
|
|
//
|
|
|
|
nsresult
|
|
|
|
nsTextEditRules::CreateMozBR(nsIDOMNode *inParent, PRInt32 inOffset, nsCOMPtr<nsIDOMNode> *outBRNode)
|
|
|
|
{
|
|
|
|
if (!inParent || !outBRNode) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
nsresult res = mEditor->CreateBR(inParent, inOffset, outBRNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// give it special moz attr
|
|
|
|
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(*outBRNode);
|
|
|
|
if (brElem)
|
|
|
|
{
|
2000-04-18 11:52:02 +04:00
|
|
|
res = mEditor->SetAttribute(brElem, NS_ConvertASCIItoUCS2("type"), NS_ConvertASCIItoUCS2("_moz"));
|
1999-11-29 11:28:46 +03:00
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2000-05-07 05:33:42 +04:00
|
|
|
PRBool
|
|
|
|
nsTextEditRules::DeleteEmptyTextNode(nsIDOMNode *aNode)
|
|
|
|
{
|
|
|
|
if (aNode)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMCharacterData>nodeAsText;
|
|
|
|
nodeAsText = do_QueryInterface(aNode);
|
|
|
|
if (nodeAsText)
|
|
|
|
{
|
|
|
|
PRUint32 len;
|
|
|
|
nodeAsText->GetLength(&len);
|
|
|
|
if (!len)
|
|
|
|
{
|
|
|
|
mEditor->DeleteNode(aNode);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
2000-05-08 11:50:57 +04:00
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsTextEditRules::AdjustSelection(nsIDOMSelection *aSelection, nsIEditor::EDirection aDirection)
|
|
|
|
{
|
|
|
|
if (!aSelection) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
// if the selection isn't collapsed, do nothing.
|
|
|
|
PRBool bCollapsed;
|
|
|
|
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!bCollapsed) return res;
|
|
|
|
|
|
|
|
// get the (collapsed) selection location
|
|
|
|
nsCOMPtr<nsIDOMNode> selNode, temp;
|
|
|
|
PRInt32 selOffset;
|
|
|
|
res = mEditor->GetStartNodeAndOffset(aSelection, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
temp = selNode;
|
|
|
|
|
|
|
|
// are we in an editable node?
|
|
|
|
while (!mEditor->IsEditable(selNode))
|
|
|
|
{
|
|
|
|
// scan up the tree until we find an editable place to be
|
|
|
|
res = nsEditor::GetNodeLocation(temp, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
if (!selNode) return NS_ERROR_FAILURE;
|
|
|
|
temp = selNode;
|
|
|
|
}
|
|
|
|
|
|
|
|
// are we in a text node?
|
|
|
|
nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(selNode);
|
|
|
|
if (textNode)
|
|
|
|
return NS_OK; // we LIKE it when we are in a text node. that RULZ
|
|
|
|
|
|
|
|
// do we need to insert a special mozBR? We do if we are:
|
|
|
|
// 1) after a block element AND
|
|
|
|
// 2) at the end of the body OR before another block
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> priorNode, nextNode;
|
|
|
|
res = mEditor->GetPriorHTMLSibling(selNode, selOffset, &priorNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = mEditor->GetNextHTMLSibling(selNode, selOffset, &nextNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
|
|
|
|
// is priorNode a block?
|
|
|
|
if (priorNode && mEditor->IsBlockNode(priorNode))
|
|
|
|
{
|
|
|
|
if (!nextNode || mEditor->IsBlockNode(nextNode))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMNode> brNode;
|
|
|
|
res = CreateMozBR(selNode, selOffset, &brNode);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
res = nsEditor::GetNodeLocation(brNode, &selNode, &selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
// selection stays *before* moz-br, sticking to it
|
|
|
|
aSelection->SetHint(PR_TRUE);
|
|
|
|
res = aSelection->Collapse(selNode,selOffset);
|
|
|
|
if (NS_FAILED(res)) return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|