Fix for bug 237964 (Allow editable areas in browser (contentEditable)). r/sr=sicking.

This commit is contained in:
peterv@propagandism.org 2007-06-27 19:48:16 -07:00
Родитель 638ec56dce
Коммит 02b7a30529
53 изменённых файлов: 1324 добавлений и 266 удалений

Просмотреть файл

@ -63,9 +63,8 @@ class nsIDocShell;
// IID for the nsIContent interface
#define NS_ICONTENT_IID \
{ 0xb6408b0, 0x20c6, 0x4d60, \
{ 0xb7, 0x2f, 0x90, 0xb7, 0x7a, 0x9d, 0xb9, 0xb6 } }
{ 0x36b375cb, 0xf01e, 0x4c18, \
{ 0xbf, 0x9e, 0xba, 0xad, 0x77, 0x1d, 0xce, 0x22 } }
// hack to make egcs / gcc 2.95.2 happy
class nsIContent_base : public nsINode {
@ -715,11 +714,8 @@ public:
*/
// XXXbz this is PRInt32 because all the ESM content state APIs use
// PRInt32. We should really use PRUint32 instead.
virtual PRInt32 IntrinsicState() const
{
return 0;
}
virtual PRInt32 IntrinsicState() const;
/* The default script type (language) ID for this content.
All content must support fetching the default script language.
*/
@ -790,6 +786,12 @@ public:
*/
virtual nsIAtom *GetClassAttributeName() const = 0;
/**
* Should be called when the node can become editable or when it can stop
* being editable (for example when its contentEditable attribute changes,
* when it is moved into an editable parent, ...).
*/
virtual void UpdateEditableState();
#ifdef DEBUG
/**

Просмотреть файл

@ -89,11 +89,13 @@ class nsNodeSupportsWeakRefTearoff;
// Whether a binding manager may have a pointer to this
#define NODE_MAY_BE_IN_BINDING_MNGR 0x00000080U
#define NODE_IS_EDITABLE 0x00000100U
// Four bits for the script-type ID
#define NODE_SCRIPT_TYPE_OFFSET 8
#define NODE_SCRIPT_TYPE_OFFSET 9
// Remaining bits are node type specific.
#define NODE_TYPE_SPECIFIC_BITS_OFFSET 0x0c
#define NODE_TYPE_SPECIFIC_BITS_OFFSET 0x0d
// Useful macro for getting a node given an nsIContent and an nsIDocument
// Returns the first argument cast to nsINode if it is non-null, otherwise
@ -105,8 +107,8 @@ class nsNodeSupportsWeakRefTearoff;
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0x22ab1440, 0xa6ee, 0x4da7, \
{ 0xbc, 0x3b, 0x94, 0x2e, 0x56, 0x0d, 0xdc, 0xe0 } }
{ 0xd3e63f80, 0x9e98, 0x47d7, \
{ 0xac, 0x8d, 0xad, 0x6f, 0x20, 0x6c, 0xe7, 0xc6 } }
// hack to make egcs / gcc 2.95.2 happy
class nsINode_base : public nsPIDOMEventTarget {
@ -596,6 +598,16 @@ public:
*flags &= ~aFlagsToUnset;
}
void SetEditableFlag(PRBool aEditable)
{
if (aEditable) {
SetFlags(NODE_IS_EDITABLE);
}
else {
UnsetFlags(NODE_IS_EDITABLE);
}
}
protected:
// Override this function to create a custom slots class.

Просмотреть файл

@ -41,6 +41,7 @@
interface nsIDOMRange;
interface nsISelectionListener;
interface nsIContent;
%{C++
class nsFrameSelection;
@ -54,7 +55,7 @@ struct nsPoint;
[ptr] native nsIPresShell(nsIPresShell);
[ref] native nsPointRef(nsPoint);
[scriptable, uuid(3225CA54-D7E1-4FF5-8EE9-091B0BFCDA1F)]
[scriptable, uuid(b416c692-eeb8-4186-addd-c444e81b68e5)]
interface nsISelectionPrivate : nsISupports
{
const short ENDOFPRECEDINGLINE=0;
@ -115,5 +116,7 @@ interface nsISelectionPrivate : nsISupports
* Returnes a reference to the frame selection associated with this selection
*/
[noscript] nsFrameSelection getFrameSelection();
[noscript] void setAncestorLimiter(in nsIContent aContent);
};

Просмотреть файл

@ -598,6 +598,8 @@ nsGenericDOMDataNode::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsNodeUtils::ParentChainChanged(this);
UpdateEditableState();
NS_POSTCONDITION(aDocument == GetCurrentDoc(), "Bound to wrong document");
NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
NS_POSTCONDITION(aBindingParent == GetBindingParent(),

Просмотреть файл

@ -300,6 +300,28 @@ nsIContent::SetNativeAnonymous(PRBool aAnonymous)
}
}
PRInt32
nsIContent::IntrinsicState() const
{
PRBool editable = HasFlag(NODE_IS_EDITABLE);
if (!editable) {
nsIDocument *doc = GetCurrentDoc();
if (doc) {
editable = doc->HasFlag(NODE_IS_EDITABLE);
}
}
return editable ? NS_EVENT_STATE_MOZ_READWRITE : NS_EVENT_STATE_MOZ_READONLY;
}
void
nsIContent::UpdateEditableState()
{
nsIContent *parent = GetParent();
SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE));
}
//----------------------------------------------------------------------
nsChildContentList::~nsChildContentList()
@ -2002,6 +2024,8 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
}
}
UpdateEditableState();
// Now recurse into our kids
PRUint32 i;
// Don't call GetChildCount() here since that'll make XUL generate

Просмотреть файл

@ -208,6 +208,7 @@ GK_ATOM(commandupdater, "commandupdater")
GK_ATOM(comment, "comment")
GK_ATOM(compact, "compact")
GK_ATOM(concat, "concat")
GK_ATOM(contenteditable, "contenteditable")
GK_ATOM(conditions, "conditions")
GK_ATOM(constructor, "constructor")
GK_ATOM(container, "container")
@ -410,6 +411,7 @@ GK_ATOM(indent, "indent")
GK_ATOM(index, "index")
GK_ATOM(infer, "infer")
GK_ATOM(infinity, "infinity")
GK_ATOM(inherit, "inherit")
GK_ATOM(inherits, "inherits")
GK_ATOM(inheritstyle, "inheritstyle")
GK_ATOM(input, "input")

Просмотреть файл

@ -239,7 +239,9 @@ nsTextNode::List(FILE* out, PRInt32 aIndent) const
PRInt32 index;
for (index = aIndent; --index >= 0; ) fputs(" ", out);
fprintf(out, "Text@%p refcount=%d<", this, mRefCnt.get());
fprintf(out, "Text@%p", this);
fprintf(out, " intrinsicstate=[%08x]", IntrinsicState());
fprintf(out, " refcount=%d<", mRefCnt.get());
nsAutoString tmp;
ToCString(tmp, 0, mText.GetLength());

Просмотреть файл

@ -1102,18 +1102,12 @@ nsGenericHTMLElement::GetSpellcheck(PRBool* aSpellcheck)
return NS_OK; // Not spellchecked by default
}
// Is this the actual body of the current document?
if (IsCurrentBodyElement()) {
// Is designMode on?
nsCOMPtr<nsIDOMNSHTMLDocument> nsHTMLDocument =
do_QueryInterface(GetCurrentDoc());
if (!nsHTMLDocument) {
return PR_FALSE;
nsCOMPtr<nsIHTMLDocument> doc = do_QueryInterface(GetCurrentDoc());
if (doc) {
*aSpellcheck = doc->IsEditingOn();
}
nsAutoString designMode;
nsHTMLDocument->GetDesignMode(designMode);
*aSpellcheck = designMode.EqualsLiteral("on");
return NS_OK;
}
@ -1164,6 +1158,20 @@ nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc)
return aDoc && aDoc->GetCompatibilityMode() == eCompatibility_NavQuirks;
}
void
nsGenericHTMLElement::UpdateEditableState()
{
// XXX Should we do this only when in a document?
ContentEditableTristate value = GetContentEditableValue();
if (value != eInherit) {
SetEditableFlag(value);
return;
}
nsGenericElement::UpdateEditableState();
}
nsresult
nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
@ -1174,6 +1182,14 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
aCompileEventHandlers);
NS_ENSURE_SUCCESS(rv, rv);
if (aDocument && HasFlag(NODE_IS_EDITABLE) &&
GetContentEditableValue() == eTrue) {
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(aDocument);
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, +1);
}
}
// XXXbz if we already have a style attr parsed, this won't do
// anything... need to fix that.
ReparseStyleAttribute();
@ -1190,6 +1206,19 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
return rv;
}
void
nsGenericHTMLElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
{
if (GetContentEditableValue() == eTrue) {
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(GetCurrentDoc());
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, -1);
}
}
nsGenericElement::UnbindFromTree(aDeep, aNullParent);
}
already_AddRefed<nsIDOMHTMLFormElement>
nsGenericHTMLElement::FindForm(nsIForm* aCurrentForm)
{
@ -1398,18 +1427,50 @@ nsGenericHTMLElement::GetEventListenerManagerForAttr(nsIEventListenerManager** a
aDefer);
}
nsresult
nsGenericHTMLElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify)
{
PRBool contentEditable = aNameSpaceID == kNameSpaceID_None &&
aName == nsGkAtoms::contenteditable;
PRInt32 change;
if (contentEditable) {
change = GetContentEditableValue() == eTrue ? -1 : 0;
}
nsresult rv = nsGenericElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
aNotify);
NS_ENSURE_SUCCESS(rv, rv);
if (contentEditable) {
if (aValue.IsEmpty() || aValue.LowerCaseEqualsLiteral("true")) {
change += 1;
}
ChangeEditableState(change);
}
return NS_OK;
}
nsresult
nsGenericHTMLElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
PRBool aNotify)
{
// Check for event handlers
if (aNameSpaceID == kNameSpaceID_None &&
nsContentUtils::IsEventAttributeName(aAttribute, EventNameType_HTML)) {
nsCOMPtr<nsIEventListenerManager> manager;
GetListenerManager(PR_FALSE, getter_AddRefs(manager));
if (aNameSpaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::contenteditable) {
ChangeEditableState(GetContentEditableValue() == eTrue ? -1 : 0);
}
else if (nsContentUtils::IsEventAttributeName(aAttribute,
EventNameType_HTML)) {
nsCOMPtr<nsIEventListenerManager> manager;
GetListenerManager(PR_FALSE, getter_AddRefs(manager));
if (manager) {
manager->RemoveScriptEventListener(aAttribute);
if (manager) {
manager->RemoveScriptEventListener(aAttribute);
}
}
}
@ -1580,6 +1641,11 @@ nsGenericHTMLElement::ParseAttribute(PRInt32 aNamespaceID,
aResult.ParseAtom(aValue);
return PR_TRUE;
}
if (aAttribute == nsGkAtoms::contenteditable) {
aResult.ParseAtom(aValue);
return PR_TRUE;
}
}
return nsGenericElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
@ -2021,6 +2087,24 @@ void
nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
nsRuleData* aData)
{
if (aData->mSID == eStyleStruct_UserInterface) {
nsRuleDataUserInterface *ui = aData->mUserInterfaceData;
if (ui->mUserModify.GetUnit() == eCSSUnit_Null) {
const nsAttrValue* value =
aAttributes->GetAttr(nsGkAtoms::contenteditable);
if (value) {
if (value->Equals(nsGkAtoms::_empty, eCaseMatters) ||
value->Equals(nsGkAtoms::_true, eIgnoreCase)) {
ui->mUserModify.SetIntValue(NS_STYLE_USER_MODIFY_READ_WRITE,
eCSSUnit_Enumerated);
}
else {
ui->mUserModify.SetIntValue(NS_STYLE_USER_MODIFY_READ_ONLY,
eCSSUnit_Enumerated);
}
}
}
}
if (aData->mSID == eStyleStruct_Visibility) {
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::lang);
if (value && value->Type() == nsAttrValue::eString) {
@ -2030,10 +2114,34 @@ nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttribu
}
}
void
nsGenericHTMLFormElement::UpdateEditableFormControlState()
{
ContentEditableTristate value = GetContentEditableValue();
if (value != eInherit) {
SetEditableFlag(value);
return;
}
nsIContent *parent = GetParent();
PRBool editable = parent && parent->HasFlag(NODE_IS_EDITABLE);
if (!editable) {
// If not contentEditable we still need to check the readonly attribute.
PRBool roState;
GetBoolAttr(nsGkAtoms::readonly, &roState);
editable = !roState;
}
SetEditableFlag(editable);
}
/* static */ const nsGenericHTMLElement::MappedAttributeEntry
nsGenericHTMLElement::sCommonAttributeMap[] = {
{ &nsGkAtoms::contenteditable },
{ &nsGkAtoms::lang },
{ nsnull }
};
@ -2528,6 +2636,47 @@ nsGenericHTMLElement::GetURIListAttr(nsIAtom* aAttr, nsAString& aResult)
return NS_OK;
}
nsresult
nsGenericHTMLElement::GetContentEditable(nsAString& aContentEditable)
{
ContentEditableTristate value = GetContentEditableValue();
if (value == eTrue) {
aContentEditable.AssignLiteral("true");
}
else if (value == eFalse) {
aContentEditable.AssignLiteral("false");
}
else {
aContentEditable.AssignLiteral("inherit");
}
return NS_OK;
}
nsresult
nsGenericHTMLElement::SetContentEditable(const nsAString& aContentEditable)
{
nsString contentEditable;
ToLowerCase(aContentEditable, contentEditable);
if (contentEditable.EqualsLiteral("inherit")) {
UnsetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, PR_TRUE);
return NS_OK;
}
if (!contentEditable.EqualsLiteral("true") &&
!contentEditable.EqualsLiteral("false")) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
SetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, contentEditable,
PR_TRUE);
return NS_OK;
}
//----------------------------------------------------------------------
NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsGenericHTMLFrameElement, TabIndex, tabindex, 0)
@ -3153,10 +3302,19 @@ nsGenericHTMLElement::IsFocusable(PRInt32 *aTabIndex)
PRInt32 tabIndex = 0; // Default value for non HTML elements with -moz-user-focus
GetTabIndex(&tabIndex);
// Just check for disabled attribute on all HTML elements
PRBool disabled = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
if (disabled) {
tabIndex = -1;
PRBool disabled;
if (IsEditableRoot()) {
disabled = PR_FALSE;
if (!HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
tabIndex = 0;
}
}
else {
// Just check for disabled attribute on all HTML elements
disabled = HasAttr(kNameSpaceID_None, nsGkAtoms::disabled);
if (disabled) {
tabIndex = -1;
}
}
if (aTabIndex) {
@ -3768,3 +3926,93 @@ nsGenericHTMLElement::RecompileScriptEventListeners()
AddScriptEventListener(attr, value, PR_TRUE);
}
}
PRBool
nsGenericHTMLElement::IsEditableRoot() const
{
nsIDocument *document = GetCurrentDoc();
if (!document) {
return PR_FALSE;
}
if (document->HasFlag(NODE_IS_EDITABLE)) {
return this == document->GetRootContent();
}
if (!HasFlag(NODE_IS_EDITABLE)) {
return PR_FALSE;
}
nsIContent *parent = GetParent();
return !parent || !parent->HasFlag(NODE_IS_EDITABLE);
}
nsIContent*
nsGenericHTMLElement::FindEditableRoot()
{
nsIDocument *document = GetCurrentDoc();
if (!document) {
return nsnull;
}
if (document->HasFlag(NODE_IS_EDITABLE)) {
return document->GetRootContent();
}
if (!HasFlag(NODE_IS_EDITABLE)) {
return nsnull;
}
nsIContent *parent, *content = this;
while ((parent = content->GetParent()) && parent->HasFlag(NODE_IS_EDITABLE)) {
content = parent;
}
return content;
}
static void
MakeContentDescendantsEditable(nsIContent *aContent, nsIDocument *aDocument)
{
PRInt32 stateBefore = aContent->IntrinsicState();
aContent->UpdateEditableState();
if (aDocument && stateBefore != aContent->IntrinsicState()) {
aDocument->ContentStatesChanged(aContent, nsnull,
NS_EVENT_STATE_MOZ_READONLY |
NS_EVENT_STATE_MOZ_READWRITE);
}
PRUint32 i, n = aContent->GetChildCount();
for (i = 0; i < n; ++i) {
nsIContent *child = aContent->GetChildAt(i);
if (!child->HasAttr(kNameSpaceID_None, nsGkAtoms::contenteditable)) {
MakeContentDescendantsEditable(child, aDocument);
}
}
}
void
nsGenericHTMLElement::ChangeEditableState(PRInt32 aChange)
{
nsIDocument* document = GetCurrentDoc();
if (!document) {
return;
}
if (aChange != 0) {
nsCOMPtr<nsIHTMLDocument> htmlDocument =
do_QueryInterface(document);
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, aChange);
}
}
if (document->HasFlag(NODE_IS_EDITABLE)) {
document = nsnull;
}
MakeContentDescendantsEditable(this, document);
}

Просмотреть файл

@ -44,6 +44,7 @@
#include "nsIFormControl.h"
#include "nsIDOMNSHTMLFrameElement.h"
#include "nsFrameLoader.h"
#include "nsGkAtoms.h"
class nsIDOMAttr;
class nsIDOMEventListener;
@ -165,6 +166,8 @@ public:
NS_IMETHOD SetTabIndex(PRInt32 aTabIndex);
NS_IMETHOD GetSpellcheck(PRBool* aSpellcheck);
NS_IMETHOD SetSpellcheck(PRBool aSpellcheck);
nsresult GetContentEditable(nsAString &aContentEditable);
nsresult SetContentEditable(const nsAString &aContentEditable);
/**
* Get the frame's offset information for offsetTop/Left/Width/Height.
@ -196,6 +199,16 @@ public:
virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsIContent* aBindingParent,
PRBool aCompileEventHandlers);
virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
PRBool aNullParent = PR_TRUE);
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString& aValue, PRBool aNotify)
{
return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
}
virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
nsIAtom* aPrefix, const nsAString& aValue,
PRBool aNotify);
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
PRBool aNotify);
virtual PRBool IsNodeOfType(PRUint32 aFlags) const;
@ -225,6 +238,8 @@ public:
}
virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
virtual void UpdateEditableState();
virtual const nsAttrValue* GetClasses() const;
virtual nsIAtom *GetIDAttributeName() const;
virtual nsIAtom *GetClassAttributeName() const;
@ -768,6 +783,50 @@ protected:
* spellchecking.
*/
static void SyncEditorsOnSubtree(nsIContent* content);
enum ContentEditableTristate {
eInherit = -1,
eFalse = 0,
eTrue = 1
};
/**
* Returns eTrue if the element has a contentEditable attribute and its value
* is "true" or an empty string. Returns eFalse if the element has a
* contentEditable attribute and its value is "false". Otherwise returns
* eInherit.
*/
NS_HIDDEN_(ContentEditableTristate) GetContentEditableValue() const
{
static const nsIContent::AttrValuesArray values[] =
{ &nsGkAtoms::_false, &nsGkAtoms::_true, &nsGkAtoms::_empty, nsnull };
PRInt32 value = FindAttrValueIn(kNameSpaceID_None,
nsGkAtoms::contenteditable, values,
eIgnoreCase);
return value > 0 ? eTrue : (value == 0 ? eFalse : eInherit);
}
private:
/**
* Returns whether this element is an editable root. An editable root is
* defined as an element that is editable and whose parent is either a
* non-editable element or an editable document (so if the whole document is
* editable, then there is only one editable root, namely the
* documentElement).
*/
PRBool IsEditableRoot() const;
/**
* Returns the first node amongst this node and its ancestors that is an
* editable root.
*
* @see IsEditableRoot for a definition of an editable root.
*/
nsIContent* FindEditableRoot();
void ChangeEditableState(PRInt32 aChange);
};
@ -817,6 +876,7 @@ public:
virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
PRBool aNotify);
virtual PRUint32 GetDesiredIMEState();
virtual PRInt32 IntrinsicState() const;
protected:
/**
@ -838,7 +898,7 @@ protected:
*/
PRBool CanBeDisabled() const;
virtual PRInt32 IntrinsicState() const;
void UpdateEditableFormControlState();
void SetFocusAndScrollIntoView(nsPresContext* aPresContext);

Просмотреть файл

@ -238,6 +238,11 @@ public:
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
virtual void UpdateEditableState()
{
return UpdateEditableFormControlState();
}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLInputElement,
nsGenericHTMLFormElement)
@ -601,6 +606,21 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
NS_EVENT_STATE_LOADING);
}
}
// If readonly is changed for text and password we need to handle
// :read-only / :read-write
if (aNotify && aName == nsGkAtoms::readonly &&
(mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD)) {
UpdateEditableState();
nsIDocument* document = GetCurrentDoc();
if (document) {
mozAutoDocUpdate upd(document, UPDATE_CONTENT_STATE, PR_TRUE);
document->ContentStatesChanged(this, nsnull,
NS_EVENT_STATE_MOZ_READONLY |
NS_EVENT_STATE_MOZ_READWRITE);
}
}
}
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,

Просмотреть файл

@ -165,6 +165,11 @@ public:
nsIContent* aChild,
PRInt32 aIndexInContainer);
virtual void UpdateEditableState()
{
return UpdateEditableFormControlState();
}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTextAreaElement,
nsGenericHTMLFormElement)
@ -202,6 +207,9 @@ protected:
* parent; we should only respond to the change if aContent is non-anonymous.
*/
void ContentChanged(nsIContent* aContent);
virtual nsresult AfterSetAttr(PRInt32 aNamespaceID, nsIAtom *aName,
const nsAString* aValue, PRBool aNotify);
};
@ -990,3 +998,23 @@ nsHTMLTextAreaElement::ContentChanged(nsIContent* aContent)
Reset();
}
}
nsresult
nsHTMLTextAreaElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString* aValue, PRBool aNotify)
{
if (aNotify && aNameSpaceID == kNameSpaceID_None &&
aName == nsGkAtoms::readonly) {
UpdateEditableState();
nsIDocument* document = GetCurrentDoc();
if (document) {
mozAutoDocUpdate upd(document, UPDATE_CONTENT_STATE, PR_TRUE);
document->ContentStatesChanged(this, nsnull,
NS_EVENT_STATE_MOZ_READONLY |
NS_EVENT_STATE_MOZ_READWRITE);
}
}
return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue,
aNotify);
}

Просмотреть файл

@ -76,6 +76,7 @@ REQUIRES = xpcom \
composer \
editor \
plugin \
txtsvc \
$(NULL)
CPPSRCS = \

Просмотреть файл

@ -125,6 +125,7 @@
#include "nsIMutableArray.h"
#include "nsArrayUtils.h"
#include "nsIEffectiveTLDService.h"
#include "nsIEventStateManager.h"
#include "nsIPrompt.h"
//AHMED 12-2
@ -133,6 +134,11 @@
#include "nsIEditingSession.h"
#include "nsIEditor.h"
#include "nsNodeInfoManager.h"
#include "nsIEditor.h"
#include "nsIEditorDocShell.h"
#include "nsIEditorStyleSheets.h"
#include "nsIInlineSpellChecker.h"
#include "nsRange.h"
#define NS_MAX_DOCUMENT_WRITE_DEPTH 20
@ -1204,8 +1210,13 @@ nsHTMLDocument::EndLoad()
mWriteState == eDocumentClosed, "EndLoad called early");
mWriteState = eNotWriting;
PRBool turnOnEditing =
mParser && (HasFlag(NODE_IS_EDITABLE) || mContentEditableCount > 0);
// Note: nsDocument::EndLoad nulls out mParser.
nsDocument::EndLoad();
if (turnOnEditing) {
EditingStateChanged();
}
}
NS_IMETHODIMP
@ -2207,14 +2218,14 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
mRootContent = root;
}
if (mEditingIsOn) {
if (IsEditingOn()) {
// Reset() blows away all event listeners in the document, and our
// editor relies heavily on those. Midas is turned on, to make it
// work, re-initialize it to give it a chance to add its event
// listeners again.
SetDesignMode(NS_LITERAL_STRING("off"));
SetDesignMode(NS_LITERAL_STRING("on"));
TurnEditingOff();
EditingStateChanged();
}
// Zap the old title -- otherwise it would hang around until document.close()
@ -3717,7 +3728,7 @@ nsHTMLDocument::GenerateParserKey(void)
NS_IMETHODIMP
nsHTMLDocument::GetDesignMode(nsAString & aDesignMode)
{
if (mEditingIsOn) {
if (HasFlag(NODE_IS_EDITABLE)) {
aDesignMode.AssignLiteral("on");
}
else {
@ -3726,9 +3737,152 @@ nsHTMLDocument::GetDesignMode(nsAString & aDesignMode)
return NS_OK;
}
NS_IMETHODIMP
nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode)
nsresult
nsHTMLDocument::ChangeContentEditableCount(nsIContent *aElement,
PRInt32 aChange)
{
NS_ASSERTION(mContentEditableCount + aChange >= 0,
"Trying to decrement too much.");
mContentEditableCount += aChange;
if (mParser) {
return NS_OK;
}
EditingState oldState = mEditingState;
nsresult rv = EditingStateChanged();
NS_ENSURE_SUCCESS(rv, rv);
if (oldState == mEditingState && mEditingState == eContentEditable) {
// We just changed the contentEditable state of a node, we need to reset
// the spellchecking state of that node.
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(aElement);
if (node) {
nsPIDOMWindow *window = GetWindow();
if (!window)
return NS_ERROR_FAILURE;
nsIDocShell *docshell = window->GetDocShell();
if (!docshell)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIEditorDocShell> editorDocShell =
do_QueryInterface(docshell, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIEditor> editor;
rv = editorDocShell->GetEditor(getter_AddRefs(editor));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMRange> range;
rv = NS_NewRange(getter_AddRefs(range));
NS_ENSURE_SUCCESS(rv, rv);
rv = range->SelectNode(node);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIInlineSpellChecker> spellChecker;
rv = editor->GetInlineSpellChecker(PR_FALSE,
getter_AddRefs(spellChecker));
NS_ENSURE_SUCCESS(rv, rv);
if (spellChecker) {
rv = spellChecker->SpellCheckRange(range);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
return NS_OK;
}
static void
NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument,
PRBool aEditable)
{
PRUint32 i, n = aNode->GetChildCount();
for (i = 0; i < n; ++i) {
nsIContent *child = aNode->GetChildAt(i);
if (child->HasFlag(NODE_IS_EDITABLE) != aEditable) {
aDocument->ContentStatesChanged(child, nsnull,
NS_EVENT_STATE_MOZ_READONLY |
NS_EVENT_STATE_MOZ_READWRITE);
}
NotifyEditableStateChange(child, aDocument, aEditable);
}
}
nsresult
nsHTMLDocument::TurnEditingOff()
{
NS_ASSERTION(mEditingState != eOff, "Editing is already off.");
nsPIDOMWindow *window = GetWindow();
if (!window)
return NS_ERROR_FAILURE;
nsIDocShell *docshell = window->GetDocShell();
if (!docshell)
return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr<nsIEditorDocShell> editorDocShell =
do_QueryInterface(docshell, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIEditor> editor;
rv = editorDocShell->GetEditor(getter_AddRefs(editor));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// turn editing off
rv = editSession->TearDownEditorOnWindow(window, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIEditorStyleSheets> editorss = do_QueryInterface(editor, &rv);
NS_ENSURE_SUCCESS(rv, rv);
if (!HasFlag(NODE_IS_EDITABLE)) {
editorss->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource:/res/contenteditable.css"));
editorss->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource:/res/designmode.css"));
rv = docshell->SetAllowJavascript(mScriptsEnabled);
NS_ENSURE_SUCCESS(rv, rv);
rv = docshell->SetAllowPlugins(mPluginsEnabled);
NS_ENSURE_SUCCESS(rv, rv);
}
mEditingState = eOff;
return NS_OK;
}
nsresult
nsHTMLDocument::EditingStateChanged()
{
if (mEditingState == eSettingUp) {
// XXX We shouldn't recurse.
return NS_OK;
}
PRBool designMode = HasFlag(NODE_IS_EDITABLE);
EditingState newState = designMode ? eDesignMode :
(mContentEditableCount > 0 ? eContentEditable : eOff);
if (mEditingState == newState) {
// No changes in editing mode.
return NS_OK;
}
if (newState == eOff) {
// Editing is being turned off.
return TurnEditingOff();
}
// get editing session
nsPIDOMWindow *window = GetWindow();
if (!window)
@ -3738,6 +3892,128 @@ nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode)
if (!docshell)
return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell, &rv);
NS_ENSURE_SUCCESS(rv, rv);
PRBool makeWindowEditable = (mEditingState == eOff);
if (makeWindowEditable) {
// Editing is being turned on (through designMode or contentEditable)
// Turn on editor.
// XXX This can cause flushing which can change the editing state, so make
// sure to avoid recursing.
EditingState oldState = mEditingState;
mEditingState = eSettingUp;
rv = editSession->MakeWindowEditable(window, "html", PR_FALSE, PR_FALSE,
PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
mEditingState = oldState;
}
// XXX Need to call TearDownEditorOnWindow for all failures.
nsCOMPtr<nsIEditorDocShell> editorDocShell =
do_QueryInterface(docshell, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIEditor> editor;
rv = editorDocShell->GetEditor(getter_AddRefs(editor));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIEditorStyleSheets> editorss = do_QueryInterface(editor, &rv);
NS_ENSURE_SUCCESS(rv, rv);
editorss->AddOverrideStyleSheet(NS_LITERAL_STRING("resource:/res/contenteditable.css"));
// Should we update the editable state of all the nodes in the document? We
// need to do this when the designMode value changes, as that overrides
// specific states on the elements.
PRBool updateState;
PRBool spellRecheckAll = PR_FALSE;
if (designMode) {
// designMode is being turned on (overrides contentEditable).
editorss->AddOverrideStyleSheet(NS_LITERAL_STRING("resource:/res/designmode.css"));
// Store scripting and plugins state.
PRBool tmp;
rv = docshell->GetAllowJavascript(&tmp);
NS_ENSURE_SUCCESS(rv, rv);
mScriptsEnabled = tmp;
rv = docshell->GetAllowPlugins(&tmp);
NS_ENSURE_SUCCESS(rv, rv);
mPluginsEnabled = tmp;
updateState = PR_TRUE;
spellRecheckAll = mEditingState == eContentEditable;
}
else if (mEditingState == eDesignMode) {
// designMode is being turned off (contentEditable is still on).
editorss->RemoveOverrideStyleSheet(NS_LITERAL_STRING("resource:/res/designmode.css"));
rv = docshell->SetAllowJavascript(mScriptsEnabled);
NS_ENSURE_SUCCESS(rv, rv);
rv = docshell->SetAllowPlugins(mPluginsEnabled);
NS_ENSURE_SUCCESS(rv, rv);
updateState = PR_TRUE;
}
else {
// contentEditable is being turned on (and designMode is off).
updateState = PR_FALSE;
}
mEditingState = newState;
if (makeWindowEditable) {
// Set the editor to not insert br's on return when in p
// elements by default.
// XXX Do we only want to do this for designMode?
PRBool unused;
rv = ExecCommand(NS_LITERAL_STRING("insertBrOnReturn"), PR_FALSE,
NS_LITERAL_STRING("false"), &unused);
if (NS_FAILED(rv)) {
// Editor setup failed. Editing is not on after all.
// XXX Should we reset the editable flag on nodes?
editSession->TearDownEditorOnWindow(window, PR_TRUE);
mEditingState = eOff;
return rv;
}
}
if (updateState) {
mozAutoDocUpdate upd(this, UPDATE_CONTENT_STATE, PR_TRUE);
NotifyEditableStateChange(this, this, !designMode);
}
// Resync the editor's spellcheck state.
if (spellRecheckAll) {
nsCOMPtr<nsISelectionController> selcon;
nsresult rv = editor->GetSelectionController(getter_AddRefs(selcon));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISelection> spellCheckSelection;
rv = selcon->GetSelection(nsISelectionController::SELECTION_SPELLCHECK,
getter_AddRefs(spellCheckSelection));
if (NS_SUCCEEDED(rv)) {
spellCheckSelection->RemoveAllRanges();
}
}
editor->SyncRealTimeSpell();
return NS_OK;
}
NS_IMETHODIMP
nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode)
{
nsresult rv = NS_OK;
if (!nsContentUtils::IsCallerTrustedForWrite()) {
@ -3751,53 +4027,14 @@ nsHTMLDocument::SetDesignMode(const nsAString & aDesignMode)
}
}
nsCOMPtr<nsIEditingSession> editSession = do_GetInterface(docshell);
if (!editSession)
return NS_ERROR_FAILURE;
PRBool editableMode = HasFlag(NODE_IS_EDITABLE);
if (aDesignMode.LowerCaseEqualsASCII(editableMode ? "off" : "on")) {
SetEditableFlag(!editableMode);
if (aDesignMode.LowerCaseEqualsLiteral("on") && !mEditingIsOn) {
rv = editSession->MakeWindowEditable(window, "html", PR_FALSE);
if (NS_SUCCEEDED(rv)) {
// now that we've successfully created the editor, we can
// reset our flag
mEditingIsOn = PR_TRUE;
// Set the editor to not insert br's on return when in p
// elements by default.
PRBool unused;
rv = ExecCommand(NS_LITERAL_STRING("insertBrOnReturn"), PR_FALSE,
NS_LITERAL_STRING("false"), &unused);
if (NS_FAILED(rv)) {
// Editor setup failed. Editing is is not on after all.
editSession->TearDownEditorOnWindow(window);
mEditingIsOn = PR_FALSE;
} else {
// Resync the editor's spellcheck state, since when the editor was
// created it asked us whether designMode was on, and we told it no.
// Note that reporting "yes" (by setting mEditingIsOn true before
// calling MakeWindowEditable()) exposed several crash bugs (see bugs
// 348497, 348981).
nsCOMPtr<nsIEditor> editor;
rv = editSession->GetEditorForWindow(window, getter_AddRefs(editor));
if (NS_SUCCEEDED(rv)) {
editor->SyncRealTimeSpell();
}
}
}
} else if (aDesignMode.LowerCaseEqualsLiteral("off") && mEditingIsOn) {
// turn editing off
rv = editSession->TearDownEditorOnWindow(window);
if (NS_SUCCEEDED(rv)) {
mEditingIsOn = PR_FALSE;
}
return EditingStateChanged();
}
return rv;
return NS_OK;
}
nsresult
@ -3982,19 +4219,21 @@ nsHTMLDocument::ConvertToMidasInternalCommand(const nsAString & inCommandID,
NS_ConvertUTF16toUTF8 convertedParam(inParam);
// check to see if we need to convert the parameter
PRUint32 j;
for (j = 0; j < MidasParamCount; ++j) {
if (convertedParam.Equals(gMidasParamTable[j].incomingParamString,
nsCaseInsensitiveCStringComparator())) {
outParam.Assign(gMidasParamTable[j].internalParamString);
break;
if (outCommandID.EqualsLiteral("cmd_paragraphState")) {
PRUint32 j;
for (j = 0; j < MidasParamCount; ++j) {
if (convertedParam.Equals(gMidasParamTable[j].incomingParamString,
nsCaseInsensitiveCStringComparator())) {
outParam.Assign(gMidasParamTable[j].internalParamString);
break;
}
}
}
// if we didn't convert the parameter, just
// pass through the parameter that was passed to us
if (j == MidasParamCount)
return j != MidasParamCount;
}
else {
outParam.Assign(convertedParam);
}
}
}
} // end else for useNewParam (do convert existing param)
@ -4069,12 +4308,12 @@ nsHTMLDocument::ExecCommand(const nsAString & commandID,
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
if (!IsEditingOn())
return NS_ERROR_FAILURE;
// if they are requesting UI from us, let's fail since we have no UI
if (doShowUI)
return NS_ERROR_NOT_IMPLEMENTED;
return NS_OK;
nsresult rv = NS_OK;
@ -4105,7 +4344,7 @@ nsHTMLDocument::ExecCommand(const nsAString & commandID,
PRBool isBool, boolVal;
if (!ConvertToMidasInternalCommand(commandID, value,
cmdToDispatch, paramStr, isBool, boolVal))
return NS_ERROR_NOT_IMPLEMENTED;
return NS_OK;
if (!isBool && paramStr.IsEmpty()) {
rv = cmdMgr->DoCommand(cmdToDispatch.get(), nsnull, window);
@ -4144,7 +4383,7 @@ nsHTMLDocument::ExecCommandShowHelp(const nsAString & commandID,
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
if (!IsEditingOn())
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_IMPLEMENTED;
@ -4159,7 +4398,7 @@ nsHTMLDocument::QueryCommandEnabled(const nsAString & commandID,
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
if (!IsEditingOn())
return NS_ERROR_FAILURE;
// get command manager and dispatch command to our window if it's acceptable
@ -4190,7 +4429,7 @@ nsHTMLDocument::QueryCommandIndeterm(const nsAString & commandID,
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
if (!IsEditingOn())
return NS_ERROR_FAILURE;
// get command manager and dispatch command to our window if it's acceptable
@ -4232,7 +4471,7 @@ nsHTMLDocument::QueryCommandState(const nsAString & commandID, PRBool *_retval)
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
if (!IsEditingOn())
return NS_ERROR_FAILURE;
// get command manager and dispatch command to our window if it's acceptable
@ -4294,7 +4533,7 @@ nsHTMLDocument::QueryCommandSupported(const nsAString & commandID,
*_retval = PR_FALSE;
// if editing is not on, bail
if (!mEditingIsOn)
if (!IsEditingOn())
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_IMPLEMENTED;
@ -4308,7 +4547,7 @@ nsHTMLDocument::QueryCommandText(const nsAString & commandID,
_retval.SetLength(0);
// if editing is not on, bail
if (!mEditingIsOn)
if (!IsEditingOn())
return NS_ERROR_FAILURE;
return NS_ERROR_NOT_IMPLEMENTED;
@ -4322,7 +4561,7 @@ nsHTMLDocument::QueryCommandValue(const nsAString & commandID,
_retval.SetLength(0);
// if editing is not on, bail
if (!mEditingIsOn)
if (!IsEditingOn())
return NS_ERROR_FAILURE;
// get command manager and dispatch command to our window if it's acceptable

Просмотреть файл

@ -59,6 +59,8 @@
#include "nsICommandManager.h"
class nsIEditor;
class nsIEditorDocShell;
class nsIParser;
class nsIURI;
class nsIMarkupDocumentViewer;
@ -207,6 +209,13 @@ public:
nsIContent** aResult);
#endif
nsresult ChangeContentEditableCount(nsIContent *aElement, PRInt32 aChange);
virtual PRBool IsEditingOn()
{
return mEditingState != eOff;
}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLDocument, nsDocument)
protected:
@ -365,7 +374,20 @@ protected:
PRBool& isBoolean,
PRBool& boolValue);
nsCOMPtr<nsICommandManager> mMidasCommandManager;
PRBool mEditingIsOn;
nsresult TurnEditingOff();
nsresult EditingStateChanged();
PRUint32 mContentEditableCount;
enum EditingState {
eSettingUp = -1,
eOff = 0,
eDesignMode,
eContentEditable
};
EditingState mEditingState;
PRPackedBool mScriptsEnabled;
PRPackedBool mPluginsEnabled;
nsresult DoClipboardSecurityCheck(PRBool aPaste);
static jsval sCutCopyInternal_id;

Просмотреть файл

@ -55,8 +55,8 @@ class nsIDOMHTMLBodyElement;
class nsIScriptElement;
#define NS_IHTMLDOCUMENT_IID \
{ 0xcfe72003, 0xcc90, 0x4624, \
{ 0xb4, 0x1b, 0xc3, 0x14, 0x1d, 0x31, 0x7a, 0x71 } }
{ 0xf6aa3582, 0x67c3, 0x4f42, \
{ 0xb6, 0xee, 0x89, 0x19, 0x24, 0x5c, 0x15, 0x89 } }
/**
@ -127,6 +127,23 @@ public:
* the document that are of type nsIContent::eHTML_FORM_CONTROL).
*/
virtual nsContentList* GetFormControls() = 0;
/**
* Should be called when an element's editable changes as a result of
* changing its contentEditable attribute/property.
*
* @param aElement the element for which the contentEditable
* attribute/property was changed
* @param aChange +1 if the contentEditable attribute/property was changed to
* true, -1 if it was changed to false
*/
virtual nsresult ChangeContentEditableCount(nsIContent *aElement,
PRInt32 aChange) = 0;
/**
* Returns whether the document is editable.
*/
virtual PRBool IsEditingOn() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIHTMLDocument, NS_IHTMLDOCUMENT_IID)

Просмотреть файл

@ -1040,6 +1040,15 @@ nsXULElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
HideWindowChrome(aValue && NS_LITERAL_STRING("true").Equals(*aValue));
}
// handle :read-only/:read-write
nsIDocument *document = GetCurrentDoc();
if (aName == nsGkAtoms::readonly && document) {
mozAutoDocUpdate upd(document, UPDATE_CONTENT_STATE, PR_TRUE);
document->ContentStatesChanged(this, nsnull,
NS_EVENT_STATE_MOZ_READONLY |
NS_EVENT_STATE_MOZ_READWRITE);
}
// XXX need to check if they're changing an event handler: if
// so, then we need to unhook the old one. Or something.
}
@ -2098,6 +2107,22 @@ nsXULElement::AddPopupListener(nsIAtom* aName)
return NS_OK;
}
PRInt32
nsXULElement::IntrinsicState() const
{
PRInt32 state = nsGenericElement::IntrinsicState();
const nsIAtom* tag = Tag();
if (GetNameSpaceID() == kNameSpaceID_XUL &&
(tag == nsGkAtoms::textbox || tag == nsGkAtoms::textarea) &&
!HasAttr(kNameSpaceID_None, nsGkAtoms::readonly)) {
state |= NS_EVENT_STATE_MOZ_READWRITE;
state &= ~NS_EVENT_STATE_MOZ_READONLY;
}
return state;
}
//----------------------------------------------------------------------
nsGenericElement::nsAttrInfo

Просмотреть файл

@ -558,6 +558,7 @@ public:
NS_DECL_NSIDOMXULELEMENT
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
virtual PRInt32 IntrinsicState() const;
nsresult GetStyle(nsIDOMCSSStyleDeclaration** aStyle);

Просмотреть файл

@ -73,7 +73,7 @@ nsDocShellEditorData::~nsDocShellEditorData()
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(mDocShell);
// This will eventually call nsDocShellEditorData::SetEditor(nsnull)
// which will call mEditorPreDestroy() and delete the editor
mEditingSession->TearDownEditorOnWindow(domWindow);
mEditingSession->TearDownEditorOnWindow(domWindow, PR_TRUE);
}
else if (mEditor) // Should never have this w/o nsEditingSession!
{
@ -104,7 +104,8 @@ nsDocShellEditorData::MakeEditable(PRBool inWaitForUriLoad /*, PRBool inEditable
mEditor = nsnull;
}
mMakeEditable = PR_TRUE;
if (inWaitForUriLoad)
mMakeEditable = PR_TRUE;
return NS_OK;
}
@ -191,6 +192,8 @@ nsDocShellEditorData::SetEditor(nsIEditor *inEditor)
}
mEditor = inEditor; // owning addref
if (!mEditor)
mMakeEditable = PR_FALSE;
}
return NS_OK;

Просмотреть файл

@ -772,7 +772,11 @@ nsWebShell::OnLinkClick(nsIContent* aContent,
if (mFiredUnloadEvent) {
return NS_OK;
}
if (aContent->HasFlag(NODE_IS_EDITABLE)) {
return NS_OK;
}
nsCOMPtr<nsIRunnable> ev =
new OnLinkClickEvent(this, aContent, aURI, aTargetSpec,
aPostDataStream, aHeadersDataStream);
@ -800,6 +804,10 @@ nsWebShell::OnLinkClickSync(nsIContent *aContent,
return NS_OK;
}
if (aContent->HasFlag(NODE_IS_EDITABLE)) {
return NS_OK;
}
{
// defer to an external protocol handler if necessary...
nsCOMPtr<nsIExternalProtocolService> extProtService = do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
@ -895,6 +903,10 @@ nsWebShell::OnOverLink(nsIContent* aContent,
nsIURI* aURI,
const PRUnichar* aTargetSpec)
{
if (aContent->HasFlag(NODE_IS_EDITABLE)) {
return NS_OK;
}
nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
nsresult rv = NS_ERROR_FAILURE;

Просмотреть файл

@ -38,7 +38,7 @@
#include "domstubs.idl"
[scriptable, uuid(b0a29b0a-ce2b-4cdf-b98a-4c7ed994d6e2)]
[scriptable, uuid(eac0a4ee-2e4f-403c-9b77-5cf32cfb42f7)]
interface nsIDOMNSHTMLElement : nsISupports
{
readonly attribute long offsetTop;
@ -60,6 +60,8 @@ interface nsIDOMNSHTMLElement : nsISupports
attribute long tabIndex;
attribute DOMString contentEditable;
void blur();
void focus();

Просмотреть файл

@ -43,7 +43,7 @@
interface nsIEditor;
[scriptable, uuid(d39fd2b4-3978-45d2-a4be-ba448171b61b)]
[scriptable, uuid(aee80d50-2065-4411-834d-0cadfb649a19)]
interface nsIEditingSession : nsISupports
{
@ -68,8 +68,16 @@ interface nsIEditingSession : nsISupports
* Make this window editable
* @param aWindow nsIDOMWindow, the window the embedder needs to make editable
* @param aEditorType string, "html" "htmlsimple" "text" "textsimple"
* @param aMakeWholeDocumentEditable if PR_TRUE make the whole document in
* aWindow editable, otherwise it's the
* embedder who should make the document
* (or part of it) editable.
* @param aInteractive if PR_FALSE turn off scripting and plugins
*/
void makeWindowEditable(in nsIDOMWindow window, in string aEditorType, in boolean doAfterUriLoad);
void makeWindowEditable(in nsIDOMWindow window, in string aEditorType,
in boolean doAfterUriLoad,
in boolean aMakeWholeDocumentEditable,
in boolean aInteractive);
/**
* Test whether a specific window has had its editable flag set; it may have an editor
@ -93,7 +101,7 @@ interface nsIEditingSession : nsISupports
/**
* Destroy editor and related support objects
*/
void tearDownEditorOnWindow(in nsIDOMWindow window);
void tearDownEditorOnWindow(in nsIDOMWindow window, in boolean aStopEditing);
void setEditorOnControllers(in nsIDOMWindow aWindow,
in nsIEditor aEditor);

Просмотреть файл

@ -95,6 +95,7 @@
nsEditingSession::nsEditingSession()
: mDoneSetup(PR_FALSE)
, mCanCreateEditor(PR_FALSE)
, mInteractive(PR_FALSE)
, mScriptsEnabled(PR_TRUE)
, mPluginsEnabled(PR_TRUE)
, mProgressListenerRegistered(PR_FALSE)
@ -128,14 +129,18 @@ NS_IMPL_ISUPPORTS3(nsEditingSession, nsIEditingSession, nsIWebProgressListener,
aEditorType string, "html" "htmlsimple" "text" "textsimple"
void makeWindowEditable(in nsIDOMWindow aWindow, in string aEditorType,
in boolean aDoAfterUriLoad);
in boolean aDoAfterUriLoad,
in boolean aMakeWholeDocumentEditable,
in boolean aInteractive);
----------------------------------------------------------------------------*/
#define DEFAULT_EDITOR_TYPE "html"
NS_IMETHODIMP
nsEditingSession::MakeWindowEditable(nsIDOMWindow *aWindow,
const char *aEditorType,
PRBool aDoAfterUriLoad)
PRBool aDoAfterUriLoad,
PRBool aMakeWholeDocumentEditable,
PRBool aInteractive)
{
mEditorType.Truncate();
mEditorFlags = 0;
@ -146,27 +151,42 @@ nsEditingSession::MakeWindowEditable(nsIDOMWindow *aWindow,
if (!docShell) return NS_ERROR_FAILURE;
nsresult rv;
// Disable JavaScript in this document:
PRBool tmp;
rv = docShell->GetAllowJavascript(&tmp);
NS_ENSURE_SUCCESS(rv, rv);
if (aMakeWholeDocumentEditable) {
nsCOMPtr<nsIDOMDocument> domDoc;
rv = aWindow->GetDocument(getter_AddRefs(domDoc));
NS_ENSURE_SUCCESS(rv, rv);
mScriptsEnabled = tmp;
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = docShell->SetAllowJavascript(PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
doc->SetEditableFlag(PR_TRUE);
}
// Disable plugins in this document:
rv = docShell->GetAllowPlugins(&tmp);
NS_ENSURE_SUCCESS(rv, rv);
mInteractive = aInteractive;
mPluginsEnabled = tmp;
if (!mInteractive) {
// Disable JavaScript in this document:
PRBool tmp;
rv = docShell->GetAllowJavascript(&tmp);
NS_ENSURE_SUCCESS(rv, rv);
rv = docShell->SetAllowPlugins(PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
mScriptsEnabled = tmp;
rv = docShell->SetAllowJavascript(PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
// Disable plugins in this document:
rv = docShell->GetAllowPlugins(&tmp);
NS_ENSURE_SUCCESS(rv, rv);
mPluginsEnabled = tmp;
rv = docShell->SetAllowPlugins(PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
}
// Always remove existing editor
TearDownEditorOnWindow(aWindow);
TearDownEditorOnWindow(aWindow, PR_FALSE);
// Tells embedder that startup is in progress
mEditorStatus = eEditorCreationInProgress;
@ -215,7 +235,7 @@ nsEditingSession::MakeWindowEditable(nsIDOMWindow *aWindow,
// Since this is used only when editing an existing page,
// it IS ok to destroy current editor
if (NS_FAILED(rv))
TearDownEditorOnWindow(aWindow);
TearDownEditorOnWindow(aWindow, PR_FALSE);
}
return rv;
}
@ -361,6 +381,10 @@ nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
needHTMLController = PR_TRUE;
}
if (mInteractive) {
mEditorFlags |= nsIPlaintextEditor::eEditorAllowInteraction;
}
// make the UI state maintainer
nsComposerCommandsUpdater *stateMaintainer;
NS_NEWXPCOM(stateMaintainer, nsComposerCommandsUpdater);
@ -390,13 +414,15 @@ nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
if (!docShell) return NS_ERROR_FAILURE;
// Disable animation of images in this document:
nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
if (!utils) return NS_ERROR_FAILURE;
if (!mInteractive) {
// Disable animation of images in this document:
nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
if (!utils) return NS_ERROR_FAILURE;
rv = utils->GetImageAnimationMode(&mImageAnimationMode);
if (NS_FAILED(rv)) return rv;
utils->SetImageAnimationMode(imgIContainer::kDontAnimMode);
rv = utils->GetImageAnimationMode(&mImageAnimationMode);
if (NS_FAILED(rv)) return rv;
utils->SetImageAnimationMode(imgIContainer::kDontAnimMode);
}
// create and set editor
nsCOMPtr<nsIEditorDocShell> editorDocShell = do_QueryInterface(docShell, &rv);
@ -480,10 +506,12 @@ nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
TearDownEditorOnWindow
void tearDownEditorOnWindow (in nsIDOMWindow aWindow);
void tearDownEditorOnWindow (in nsIDOMWindow aWindow,
in boolean aStopEditing);
----------------------------------------------------------------------------*/
NS_IMETHODIMP
nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow,
PRBool aStopEditing)
{
if (!mDoneSetup)
return NS_OK;
@ -501,23 +529,7 @@ nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
mDoneSetup = PR_FALSE;
nsCOMPtr<nsIDOMDocument> dom_doc;
aWindow->GetDocument(getter_AddRefs(dom_doc));
nsCOMPtr<nsIDOMNSHTMLDocument> html_doc(do_QueryInterface(dom_doc));
PRBool isMidas = PR_FALSE;
if (html_doc) {
nsAutoString designMode;
html_doc->GetDesignMode(designMode);
isMidas = designMode.EqualsLiteral("on");
}
if (isMidas) {
// We're tearing down a midas editor, unregister callbacks since
// we're all done editing here.
if (aStopEditing) {
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
if (webProgress) {
webProgress->RemoveProgressListener(this);
@ -622,7 +634,7 @@ nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
mHTMLCommandControllerId = 0;
}
if (isMidas) {
if (aStopEditing && !mInteractive) {
// Make things the way they were before we started editing.
if (mScriptsEnabled) {
docShell->SetAllowJavascript(PR_TRUE);
@ -972,7 +984,7 @@ nsEditingSession::StartDocumentLoad(nsIWebProgress *aWebProgress,
aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
if (domWindow)
{
TearDownEditorOnWindow(domWindow);
TearDownEditorOnWindow(domWindow, PR_FALSE);
}
if (aIsToBeMadeEditable)
@ -1042,27 +1054,45 @@ nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress,
if (makeEditable)
{
mCanCreateEditor = PR_FALSE;
rv = SetupEditorOnWindow(domWindow);
// do we already have an editor here?
nsCOMPtr<nsIEditor> editor;
rv = editorDocShell->GetEditor(getter_AddRefs(editor));
if (NS_FAILED(rv))
return rv;
if (!editor)
{
// If we had an error, setup timer to load a blank page later
if (mLoadBlankDocTimer)
mCanCreateEditor = PR_FALSE;
rv = SetupEditorOnWindow(domWindow);
if (NS_FAILED(rv))
{
// Must cancel previous timer?
mLoadBlankDocTimer->Cancel();
mLoadBlankDocTimer = NULL;
}
// If we had an error, setup timer to load a blank page later
if (mLoadBlankDocTimer)
{
// Must cancel previous timer?
mLoadBlankDocTimer->Cancel();
mLoadBlankDocTimer = NULL;
}
mLoadBlankDocTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_FAILED(rv)) return rv;
mLoadBlankDocTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_FAILED(rv)) return rv;
mEditorStatus = eEditorCreationInProgress;
mLoadBlankDocTimer->InitWithFuncCallback(
nsEditingSession::TimerCallback,
(void*)docShell,
10, nsITimer::TYPE_ONE_SHOT);
mEditorStatus = eEditorCreationInProgress;
mLoadBlankDocTimer->InitWithFuncCallback(
nsEditingSession::TimerCallback,
(void*)docShell,
10, nsITimer::TYPE_ONE_SHOT);
}
}
// XXX This should move somewhere else!
nsCOMPtr<nsIDOMDocument> domDoc;
rv = domWindow->GetDocument(getter_AddRefs(domDoc));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc, &rv);
NS_ENSURE_SUCCESS(rv, rv);
doc->SetEditableFlag(PR_TRUE);
}
}
return rv;
@ -1144,7 +1174,7 @@ nsEditingSession::EndPageLoad(nsIWebProgress *aWebProgress,
#if 0
// Shouldn't we do this when we want to edit sub-frames?
return MakeWindowEditable(domWindow, "html", PR_FALSE);
return MakeWindowEditable(domWindow, "html", PR_FALSE, mInteractive);
#else
return NS_OK;
#endif

Просмотреть файл

@ -129,6 +129,8 @@ protected:
// before creating an editor
PRPackedBool mCanCreateEditor;
PRPackedBool mInteractive;
// True if scripts were enabled before the editor turned scripts
// off, otherwise false.
PRPackedBool mScriptsEnabled;

Просмотреть файл

@ -35,6 +35,10 @@
*
* ***** END LICENSE BLOCK ***** */
*|* {
-moz-user-modify: read-write;
}
/* Styles to alter look of things in the Editor content window
* that should NOT be removed when we display in completely WYSIWYG
* "Browser Preview" mode.

Просмотреть файл

@ -18,10 +18,12 @@ GetContentDOMWindow call.&nbsp; Then simply call
nsIWebBrowser-&gt;do_GetInterface on the nsIWebBrowser to retrieve the
nsIEditingSession from it.&nbsp; From there you call
editingSession-&gt;MakeWindowEditable(domWindow, editortype,
PR_TRUE);&nbsp;&nbsp;&nbsp; The first parameter is the nsIDOMWindow you
just retrieved, the second is the editor type you want to create and the
PR_TRUE, PR_FALSE);&nbsp;&nbsp;&nbsp; The first parameter is the nsIDOMWindow
you just retrieved, the second is the editor type you want to create and the
third is whether you want the window editable immediately or when the
document is done loading.&nbsp; In calling this method the editor is
document is done loading, the fourth is whether you want the editor to make
the whole document editable, the fifth is whether you want to turn of
scripts, plugins, ...&nbsp; In calling this method the editor is
created underneath and the event listeners etc. are all prepared.<br>
</p>
<p><i>&nbsp;&nbsp;&nbsp; nsCOMPtr&lt;nsIDOMWindow&gt; domWindow;<br>
@ -36,7 +38,8 @@ editingSession;<br>
nsIWebBrowser-&gt;do_GetInterface(getter_AddRefs(editingSession));<br>
&nbsp;&nbsp;&nbsp; if (editingSession)<br>
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
editingSession-&gt;MakeWindowEditable(domWindow, "html", PR_TRUE);</i></p>
editingSession-&gt;MakeWindowEditable(domWindow, "html", PR_TRUE,
PR_FALSE, PR_TRUE, PR_FALSE);</i></p>
<p>The valid editor types are:<br>
</p>
<ul>

Просмотреть файл

@ -62,7 +62,7 @@ typedef short EDirection;
[ptr] native nsIPresShellPtr(nsIPresShell);
[scriptable, uuid(470e18e4-2e82-48de-8850-7474cdbbd97d)]
[scriptable, uuid(dc81f464-89dd-47bf-bf21-10df3b65b956)]
interface nsIEditor : nsISupports
{
@ -562,4 +562,7 @@ interface nsIEditor : nsISupports
/* Run unit tests. Noop in optimized builds */
void debugUnitTests(out long outNumTests, out long outNumTestsFailed);
/* checks if a node is read-only or not */
[notxpcom] boolean isModifiableNode(in nsIDOMNode aNode);
};

Просмотреть файл

@ -39,34 +39,23 @@
interface nsIDOMKeyEvent;
[scriptable, uuid(28dbb4d0-5fea-43f4-aca7-344fc2ecc4f9)]
[scriptable, uuid(35d74f2b-3d03-43c5-8ace-9d90c3e31244)]
interface nsIPlaintextEditor : nsISupports
{
/* the bits in an editor behavior mask. */
const short eEditorPlaintextBit = 0; /* only plain text entry is allowed via events */
const short eEditorSingleLineBit = 1; /* enter key and CR-LF handled specially */
const short eEditorPasswordBit = 2; /* text is not entered into content, only a representative character */
const short eEditorReadonlyBit = 3; /* editing events are disabled. Editor may still accept focus. */
const short eEditorDisabledBit = 4; /* all events are disabled (like scrolling). Editor will not accept focus. */
const short eEditorFilterInputBit = 5; /* text input is limited to certain character types, use mFilter */
const short eEditorMailBit = 6; /* use mail-compose editting rules */
const short eEditorUseAsyncUpdatesBit = 7; /* prevent immediate reflows and view refreshes */
const short eEditorEnableWrapHackBit = 8; /* allow the editor to set font: monospace on the root node */
const short eEditorWidgetBit = 9; /* bit for widgets */
const short eEditorNoCSSBit = 10; /* this HTML editor should not create css styles */
const long eEditorPlaintextMask = 1;
const long eEditorSingleLineMask = 2;
const long eEditorPasswordMask = 4;
const long eEditorReadonlyMask = 8;
const long eEditorDisabledMask = 16;
const long eEditorFilterInputMask = 32;
const long eEditorMailMask = 64;
const long eEditorUseAsyncUpdatesMask = 128;
const long eEditorEnableWrapHackMask = 256;
const long eEditorWidgetMask = 512;
const long eEditorNoCSSMask = 1024;
// XXX Why aren't these in nsIEditor?
const long eEditorPlaintextMask = 0x0001; /* only plain text entry is allowed via events */
const long eEditorSingleLineMask = 0x0002; /* enter key and CR-LF handled specially */
const long eEditorPasswordMask = 0x0004; /* text is not entered into content, only a representative character */
const long eEditorReadonlyMask = 0x0008; /* editing events are disabled. Editor may still accept focus. */
const long eEditorDisabledMask = 0x0010; /* all events are disabled (like scrolling). Editor will not accept focus. */
const long eEditorFilterInputMask = 0x0020; /* text input is limited to certain character types, use mFilter */
const long eEditorMailMask = 0x0040; /* use mail-compose editing rules */
const long eEditorUseAsyncUpdatesMask = 0x0080; /* prevent immediate reflows and view refreshes */
const long eEditorEnableWrapHackMask = 0x0100; /* allow the editor to set font: monospace on the root node */
const long eEditorWidgetMask = 0x0200; /* bit for widgets */
const long eEditorNoCSSMask = 0x0400; /* this HTML editor should not create css styles */
const long eEditorAllowInteraction = 0x0800; /* */
/*
* The valid values for newlines handling.

Просмотреть файл

@ -58,11 +58,21 @@ DeleteElementTxn::DeleteElementTxn()
{
}
NS_IMETHODIMP DeleteElementTxn::Init(nsIDOMNode *aElement,
NS_IMETHODIMP DeleteElementTxn::Init(nsIEditor *aEditor,
nsIDOMNode *aElement,
nsRangeUpdater *aRangeUpdater)
{
if (!aElement) return NS_ERROR_NULL_POINTER;
if (!aEditor || !aElement) return NS_ERROR_NULL_POINTER;
mEditor = aEditor;
mElement = do_QueryInterface(aElement);
nsresult result = mElement->GetParentNode(getter_AddRefs(mParent));
if (NS_FAILED(result)) { return result; }
// do nothing if the parent is read-only
if (mParent && !mEditor->IsModifiableNode(mParent)) {
return NS_ERROR_FAILURE;
}
mRangeUpdater = aRangeUpdater;
return NS_OK;
}
@ -76,8 +86,6 @@ NS_IMETHODIMP DeleteElementTxn::DoTransaction(void)
if (!mElement) return NS_ERROR_NOT_INITIALIZED;
nsresult result = mElement->GetParentNode(getter_AddRefs(mParent));
if (NS_FAILED(result)) { return result; }
if (!mParent) { return NS_OK; } // this is a no-op, there's no parent to delete mElement from
#ifdef NS_DEBUG
@ -105,7 +113,7 @@ NS_IMETHODIMP DeleteElementTxn::DoTransaction(void)
#endif
// remember which child mElement was (by remembering which child was next)
result = mElement->GetNextSibling(getter_AddRefs(mRefNode)); // can return null mRefNode
nsresult result = mElement->GetNextSibling(getter_AddRefs(mRefNode)); // can return null mRefNode
// give range updater a chance. SelAdjDeleteNode() needs to be called *before*
// we do the action, unlike some of the other nsRangeStore update methods.

Просмотреть файл

@ -41,6 +41,7 @@
#include "EditTxn.h"
#include "nsIDOMNode.h"
#include "nsIEditor.h"
#include "nsCOMPtr.h"
#define DELETE_ELEMENT_TXN_CID \
@ -62,7 +63,7 @@ public:
/** initialize the transaction.
* @param aElement the node to delete
*/
NS_IMETHOD Init(nsIDOMNode *aElement, nsRangeUpdater *aRangeUpdater);
NS_IMETHOD Init(nsIEditor *aEditor, nsIDOMNode *aElement, nsRangeUpdater *aRangeUpdater);
private:
DeleteElementTxn();
@ -83,6 +84,9 @@ protected:
/** next sibling to remember for undo/redo purposes */
nsCOMPtr<nsIDOMNode> mRefNode;
/** the editor for this transaction */
nsIEditor* mEditor;
/** range updater object */
nsRangeUpdater *mRangeUpdater;

Просмотреть файл

@ -88,6 +88,17 @@ NS_IMETHODIMP DeleteRangeTxn::Init(nsIEditor *aEditor,
result = aRange->GetCommonAncestorContainer(getter_AddRefs(mCommonParent));
NS_ASSERTION((NS_SUCCEEDED(result)), "GetCommonParent failed.");
if (!mEditor->IsModifiableNode(mStartParent)) {
return NS_ERROR_FAILURE;
}
if (mStartParent!=mEndParent &&
(!mEditor->IsModifiableNode(mEndParent) ||
!mEditor->IsModifiableNode(mCommonParent)))
{
return NS_ERROR_FAILURE;
}
#ifdef NS_DEBUG
{
PRUint32 count;
@ -236,8 +247,9 @@ DeleteRangeTxn::CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
numToDel = 1;
else
numToDel = aEndOffset-aStartOffset;
txn->Init(mEditor, textNode, aStartOffset, numToDel, mRangeUpdater);
AppendChild(txn);
result = txn->Init(mEditor, textNode, aStartOffset, numToDel, mRangeUpdater);
if (NS_SUCCEEDED(result))
AppendChild(txn);
NS_RELEASE(txn);
}
else
@ -265,8 +277,9 @@ DeleteRangeTxn::CreateTxnsToDeleteBetween(nsIDOMNode *aStartParent,
if (NS_FAILED(result)) return result;
if (!txn) return NS_ERROR_NULL_POINTER;
txn->Init(child, mRangeUpdater);
AppendChild(txn);
result = txn->Init(mEditor, child, mRangeUpdater);
if (NS_SUCCEEDED(result))
AppendChild(txn);
NS_RELEASE(txn);
}
}
@ -302,8 +315,9 @@ NS_IMETHODIMP DeleteRangeTxn::CreateTxnsToDeleteContent(nsIDOMNode *aParent,
if (NS_FAILED(result)) return result;
if (!txn) return NS_ERROR_NULL_POINTER;
txn->Init(mEditor, textNode, start, numToDelete, mRangeUpdater);
AppendChild(txn);
result = txn->Init(mEditor, textNode, start, numToDelete, mRangeUpdater);
if (NS_SUCCEEDED(result))
AppendChild(txn);
NS_RELEASE(txn);
}
}
@ -319,7 +333,7 @@ NS_IMETHODIMP DeleteRangeTxn::CreateTxnsToDeleteNodesBetween()
nsresult result = iter->Init(mRange);
if (NS_FAILED(result)) return result;
while (!iter->IsDone())
while (!iter->IsDone() && NS_SUCCEEDED(result))
{
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(iter->GetCurrentNode());
if (!node)
@ -330,8 +344,9 @@ NS_IMETHODIMP DeleteRangeTxn::CreateTxnsToDeleteNodesBetween()
if (NS_FAILED(result)) return result;
if (!txn) return NS_ERROR_NULL_POINTER;
txn->Init(node, mRangeUpdater);
AppendChild(txn);
result = txn->Init(mEditor, node, mRangeUpdater);
if (NS_SUCCEEDED(result))
AppendChild(txn);
NS_RELEASE(txn);
iter->Next();
}

Просмотреть файл

@ -65,6 +65,11 @@ NS_IMETHODIMP DeleteTextTxn::Init(nsIEditor *aEditor,
mEditor = aEditor;
mElement = do_QueryInterface(aElement);
// do nothing if the node is read-only
if (!mEditor->IsModifiableNode(mElement)) {
return NS_ERROR_FAILURE;
}
mOffset = aOffset;
mNumCharsToDelete = aNumCharsToDelete;
NS_ASSERTION(0!=aNumCharsToDelete, "bad arg, numCharsToDelete");

Просмотреть файл

@ -57,6 +57,12 @@ NS_IMETHODIMP JoinElementTxn::Init(nsEditor *aEditor,
if (!aEditor || !aLeftNode || !aRightNode) { return NS_ERROR_NULL_POINTER; }
mEditor = aEditor;
mLeftNode = do_QueryInterface(aLeftNode);
nsCOMPtr<nsIDOMNode>leftParent;
nsresult result = mLeftNode->GetParentNode(getter_AddRefs(leftParent));
if (NS_FAILED(result)) return result;
if (!mEditor->IsModifiableNode(leftParent)) {
return NS_ERROR_FAILURE;
}
mRightNode = do_QueryInterface(aRightNode);
mOffset=0;
return NS_OK;

Просмотреть файл

@ -166,6 +166,7 @@ EDITOR_ATOM(cssWhitespace, "white-space")
EDITOR_ATOM(cssWidth, "width")
EDITOR_ATOM(cssZIndex, "z-index")
EDITOR_ATOM(cssMozUserModify, "-moz-user-modify")
EDITOR_ATOM(cssMozUserSelect, "-moz-user-select")
EDITOR_ATOM(mozdirty, "_moz_dirty")

Просмотреть файл

@ -3777,8 +3777,8 @@ nsEditor::IsEditable(nsIDOMNode *aNode)
GetPresShell(getter_AddRefs(shell));
if (!shell) return PR_FALSE;
if (IsMozEditorBogusNode(aNode)) return PR_FALSE;
if (IsMozEditorBogusNode(aNode) || !IsModifiableNode(aNode)) return PR_FALSE;
// see if it has a frame. If so, we'll edit it.
// special case for textnodes: frame must have width.
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
@ -4734,7 +4734,7 @@ NS_IMETHODIMP nsEditor::CreateTxnForDeleteElement(nsIDOMNode * aElement,
{
result = TransactionFactory::GetNewTransaction(DeleteElementTxn::GetCID(), (EditTxn **)aTxn);
if (NS_SUCCEEDED(result)) {
result = (*aTxn)->Init(aElement, &mRangeUpdater);
result = (*aTxn)->Init(this, aElement, &mRangeUpdater);
}
}
return result;
@ -5355,3 +5355,9 @@ nsEditor::DumpNode(nsIDOMNode *aNode, PRInt32 indent)
}
}
#endif
PRBool
nsEditor::IsModifiableNode(nsIDOMNode *aNode)
{
return PR_TRUE;
}

Просмотреть файл

@ -585,6 +585,51 @@ nsHTMLEditRules::WillDoAction(nsISelection *aSelection,
// my kingdom for dynamic cast
nsTextRulesInfo *info = NS_STATIC_CAST(nsTextRulesInfo*, aInfo);
// Deal with actions for which we don't need to check whether the selection is
// editable.
if (info->action == kOutputText) {
return nsTextEditRules::WillDoAction(aSelection, aInfo, aCancel, aHandled);
}
nsCOMPtr<nsIDOMRange> domRange;
nsresult rv = aSelection->GetRangeAt(0, getter_AddRefs(domRange));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> selStartNode;
rv = domRange->GetStartContainer(getter_AddRefs(selStartNode));
NS_ENSURE_SUCCESS(rv, rv);
if (!mHTMLEditor->IsModifiableNode(selStartNode))
{
*aCancel = PR_TRUE;
return NS_OK;
}
nsCOMPtr<nsIDOMNode> selEndNode;
rv = domRange->GetEndContainer(getter_AddRefs(selEndNode));
NS_ENSURE_SUCCESS(rv, rv);
if (selStartNode != selEndNode)
{
if (!mHTMLEditor->IsModifiableNode(selEndNode))
{
*aCancel = PR_TRUE;
return NS_OK;
}
nsCOMPtr<nsIRange> range = do_QueryInterface(domRange);
nsCOMPtr<nsIDOMNode> ancestor =
do_QueryInterface(range->GetCommonAncestor());
if (!mHTMLEditor->IsModifiableNode(ancestor))
{
*aCancel = PR_TRUE;
return NS_OK;
}
}
switch (info->action)
{
@ -1569,6 +1614,13 @@ nsHTMLEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBo
if (!blockParent) return NS_ERROR_FAILURE;
// do nothing if the node is read-only
if (!mHTMLEditor->IsModifiableNode(blockParent))
{
*aCancel = PR_TRUE;
return NS_OK;
}
// if block is empty, populate with br.
// (for example, imagine a div that contains the word "text". the user selects
// "text" and types return. "text" is deleted leaving an empty block. we want

Просмотреть файл

@ -130,6 +130,7 @@
#include "nsIView.h"
#include "nsIWidget.h"
#include "nsIParserService.h"
#include "nsIEventStateManager.h"
// Some utilities to handle annoying overloading of "A" tag for link and named anchor
static char hrefText[] = "href";
@ -302,7 +303,7 @@ nsHTMLEditor::Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell,
// disable links
nsPresContext *context = aPresShell->GetPresContext();
if (!context) return NS_ERROR_NULL_POINTER;
if (!(mFlags & eEditorPlaintextMask)) {
if (!(mFlags & (eEditorPlaintextMask | eEditorAllowInteraction))) {
mLinkHandler = context->GetLinkHandler();
context->SetLinkHandler(nsnull);
@ -317,8 +318,10 @@ nsHTMLEditor::Init(nsIDOMDocument *aDoc, nsIPresShell *aPresShell,
mSelectionListenerP = new ResizerSelectionListener(this);
if (!mSelectionListenerP) {return NS_ERROR_NULL_POINTER;}
// ignore any errors from this in case the file is missing
AddOverrideStyleSheet(NS_LITERAL_STRING("resource:/res/EditorOverride.css"));
if (!(mFlags & eEditorAllowInteraction)) {
// ignore any errors from this in case the file is missing
AddOverrideStyleSheet(NS_LITERAL_STRING("resource:/res/EditorOverride.css"));
}
nsCOMPtr<nsISelection>selection;
result = GetSelection(getter_AddRefs(selection));
@ -3884,6 +3887,11 @@ nsHTMLEditor::GetEmbeddedObjects(nsISupportsArray** aNodeList)
NS_IMETHODIMP nsHTMLEditor::DeleteNode(nsIDOMNode * aNode)
{
// do nothing if the node is read-only
if (!IsModifiableNode(aNode)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMNode> selectAllNode = FindUserSelectAllNode(aNode);
if (selectAllNode)
@ -3897,6 +3905,11 @@ NS_IMETHODIMP nsHTMLEditor::DeleteText(nsIDOMCharacterData *aTextNode,
PRUint32 aOffset,
PRUint32 aLength)
{
// do nothing if the node is read-only
if (!IsModifiableNode(aTextNode)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMNode> selectAllNode = FindUserSelectAllNode(aTextNode);
if (selectAllNode)
@ -3906,6 +3919,18 @@ NS_IMETHODIMP nsHTMLEditor::DeleteText(nsIDOMCharacterData *aTextNode,
return nsEditor::DeleteText(aTextNode, aOffset, aLength);
}
NS_IMETHODIMP nsHTMLEditor::InsertTextImpl(const nsAString& aStringToInsert,
nsCOMPtr<nsIDOMNode> *aInOutNode,
PRInt32 *aInOutOffset,
nsIDOMDocument *aDoc)
{
// do nothing if the node is read-only
if (!IsModifiableNode(*aInOutNode)) {
return NS_ERROR_FAILURE;
}
return nsEditor::InsertTextImpl(aStringToInsert, aInOutNode, aInOutOffset, aDoc);
}
#ifdef XP_MAC
#pragma mark -
@ -3947,6 +3972,14 @@ nsCOMPtr<nsIDOMNode> nsHTMLEditor::FindUserSelectAllNode(nsIDOMNode *aNode)
return resultNode;
}
NS_IMETHODIMP_(PRBool)
nsHTMLEditor::IsModifiableNode(nsIDOMNode *aNode)
{
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
return !content || !(content->IntrinsicState() & NS_EVENT_STATE_MOZ_READONLY);
}
static nsresult SetSelectionAroundHeadChildren(nsCOMPtr<nsISelection> aSelection, nsWeakPtr aDocWeak)
{
nsresult res = NS_OK;
@ -4204,6 +4237,54 @@ nsHTMLEditor::SelectEntireDocument(nsISelection *aSelection)
return nsEditor::SelectEntireDocument(aSelection);
}
static nsIContent*
FindEditableRoot(nsIContent *aContent)
{
nsIDocument *document = aContent->GetCurrentDoc();
if (!document || document->HasFlag(NODE_IS_EDITABLE) ||
!aContent->HasFlag(NODE_IS_EDITABLE)) {
return nsnull;
}
nsIContent *parent, *content = aContent;
while ((parent = content->GetParent()) && parent->HasFlag(NODE_IS_EDITABLE)) {
content = parent;
}
return content;
}
NS_IMETHODIMP
nsHTMLEditor::SelectAll()
{
ForceCompositionEnd();
nsresult rv;
nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISelection> selection;
rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> anchorNode;
rv = selection->GetAnchorNode(getter_AddRefs(anchorNode));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIContent> anchorContent = do_QueryInterface(anchorNode, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsIContent *rootContent = FindEditableRoot(anchorContent);
if (!rootContent) {
return SelectEntireDocument(selection);
}
nsCOMPtr<nsIDOMNode> rootElement = do_QueryInterface(rootContent, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return selection->SelectAllChildren(rootElement);
}
#ifdef XP_MAC

Просмотреть файл

@ -363,6 +363,13 @@ public:
NS_IMETHODIMP DeleteText(nsIDOMCharacterData *aTextNode,
PRUint32 aOffset,
PRUint32 aLength);
NS_IMETHOD InsertTextImpl(const nsAString& aStringToInsert,
nsCOMPtr<nsIDOMNode> *aInOutNode,
PRInt32 *aInOutOffset,
nsIDOMDocument *aDoc);
NS_IMETHOD_(PRBool) IsModifiableNode(nsIDOMNode *aNode);
NS_IMETHOD SelectAll();
/* ------------ nsICSSLoaderObserver -------------- */
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aWasAlternate,

Просмотреть файл

@ -68,6 +68,7 @@
#include "nsEditorUtils.h"
#include "nsIDOMEventTarget.h"
#include "nsIEventStateManager.h"
#include "nsISelectionPrivate.h"
//#define DEBUG_IME
@ -223,7 +224,8 @@ nsTextEditorKeyListener::KeyPress(nsIDOMEvent* aKeyEvent)
case nsIDOMKeyEvent::DOM_VK_TAB:
if ((flags & nsIPlaintextEditor::eEditorSingleLineMask) ||
(flags & nsIPlaintextEditor::eEditorPasswordMask) ||
(flags & nsIPlaintextEditor::eEditorWidgetMask))
(flags & nsIPlaintextEditor::eEditorWidgetMask) ||
(flags & nsIPlaintextEditor::eEditorAllowInteraction))
return NS_OK; // let it be used for focus switching
if (isAnyModifierKeyButShift)
@ -1032,6 +1034,30 @@ IsTargetFocused(nsIDOMEventTarget* aTarget)
return (focusedContent == content);
}
static nsIContent*
FindEditableRoot(nsIContent *aContent)
{
nsIDocument *document = aContent->GetCurrentDoc();
if (!document) {
return nsnull;
}
if (document->HasFlag(NODE_IS_EDITABLE)) {
return document->GetRootContent();
}
if (!aContent->HasFlag(NODE_IS_EDITABLE)) {
return nsnull;
}
nsIContent *parent, *content = aContent;
while ((parent = content->GetParent()) && parent->HasFlag(NODE_IS_EDITABLE)) {
content = parent;
}
return content;
}
nsresult
nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
{
@ -1059,18 +1085,38 @@ nsTextEditorFocusListener::Focus(nsIDOMEvent* aEvent)
mEditor->GetFlags(&flags);
if (! (flags & nsIPlaintextEditor::eEditorDisabledMask))
{ // only enable caret and selection if the editor is not disabled
nsCOMPtr<nsIEditor>editor = do_QueryInterface(mEditor);
if (editor)
nsCOMPtr<nsIContent> content = do_QueryInterface(target);
nsIContent *editableRoot = content ? FindEditableRoot(content) : nsnull;
nsCOMPtr<nsISelectionController> selCon;
mEditor->GetSelectionController(getter_AddRefs(selCon));
nsCOMPtr<nsIPresShell> presShell = do_QueryInterface(selCon);
if (selCon && editableRoot)
{
nsCOMPtr<nsISelectionController>selCon;
editor->GetSelectionController(getter_AddRefs(selCon));
if (selCon)
nsCOMPtr<nsISelection> selection;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
if (presShell && selection) {
nsCOMPtr<nsICaret> caret;
presShell->GetCaret(getter_AddRefs(caret));
if (caret) {
caret->SetCaretDOMSelection(selection);
}
}
const PRBool kIsReadonly = (flags & nsIPlaintextEditor::eEditorReadonlyMask) != 0;
selCon->SetCaretReadOnly(kIsReadonly);
selCon->SetCaretEnabled(PR_TRUE);
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsISelectionPrivate> selectionPrivate =
do_QueryInterface(selection);
if (selectionPrivate)
{
const PRBool kIsReadonly = (flags & nsIPlaintextEditor::eEditorReadonlyMask) != 0;
selCon->SetCaretReadOnly(kIsReadonly);
selCon->SetCaretEnabled(PR_TRUE);
selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
selectionPrivate->SetAncestorLimiter(editableRoot);
}
}
}
@ -1105,6 +1151,16 @@ nsTextEditorFocusListener::Blur(nsIDOMEvent* aEvent)
editor->GetSelectionController(getter_AddRefs(selCon));
if (selCon)
{
nsCOMPtr<nsISelection> selection;
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection));
nsCOMPtr<nsISelectionPrivate> selectionPrivate =
do_QueryInterface(selection);
if (selectionPrivate) {
selectionPrivate->SetAncestorLimiter(nsnull);
}
selCon->SetCaretEnabled(PR_FALSE);
PRUint32 flags;

Просмотреть файл

@ -1296,7 +1296,9 @@ nsTextEditRules::CreateBogusNodeIfNeeded(nsISelection *aSelection)
nsresult res = mBody->GetFirstChild(getter_AddRefs(bodyChild));
while ((NS_SUCCEEDED(res)) && bodyChild)
{
if (mEditor->IsMozEditorBogusNode(bodyChild) || mEditor->IsEditable(bodyChild))
if (mEditor->IsMozEditorBogusNode(bodyChild) ||
!mEditor->IsEditable(mBody) ||
mEditor->IsEditable(bodyChild))
{
needsBogusContent = PR_FALSE;
break;

Просмотреть файл

@ -54,6 +54,7 @@ const kDisplayModeTabIDS = ["NormalModeButton", "TagModeButton", "SourceModeButt
const kNormalStyleSheet = "chrome://editor/content/EditorContent.css";
const kAllTagsStyleSheet = "chrome://editor/content/EditorAllTags.css";
const kParagraphMarksStyleSheet = "chrome://editor/content/EditorParagraphMarks.css";
const kContentEditableStyleSheet = "resource:/res/contenteditable.css";
const kTextMimeType = "text/plain";
const kHTMLMimeType = "text/html";
@ -399,6 +400,10 @@ var gEditorDocumentObserver =
// and extra styles for showing anchors, table borders, smileys, etc
editor.addOverrideStyleSheet(kNormalStyleSheet);
// remove contenteditable stylesheets if they were applied by the
// editingSession
editor.removeOverrideStyleSheet(kContentEditableStyleSheet);
} catch (e) {}
// Things for just the Web Composer application

Просмотреть файл

@ -1291,7 +1291,8 @@ HRESULT CMozillaBrowser::SetEditorMode(BOOL bEnabled)
if (NS_FAILED(rv))
return E_FAIL;
rv = mEditingSession->MakeWindowEditable(domWindow, "html", PR_FALSE);
rv = mEditingSession->MakeWindowEditable(domWindow, "html", PR_FALSE,
PR_FALSE);
return S_OK;
}

Просмотреть файл

@ -101,7 +101,8 @@ void CnsIEditSession::MakeWinEditTest(PRBool afterUriLoad, PRInt16 displayMode)
editingSession = GetEditSessionObject();
domWindow = GetTheDOMWindow(qaWebBrowser);
if (editingSession) {
rv= editingSession->MakeWindowEditable(domWindow, "text", afterUriLoad);
rv= editingSession->MakeWindowEditable(domWindow, "text", afterUriLoad,
PR_TRUE, PR_FALSE);
RvTestResult(rv, "MakeWindowEditable() test", displayMode);
if (displayMode == 1)
RvTestResultDlg(rv, "MakeWindowEditable() test");
@ -171,7 +172,7 @@ void CnsIEditSession::TearEditorWinTest(PRInt16 displayMode)
editingSession = GetEditSessionObject();
domWindow = GetTheDOMWindow(qaWebBrowser);
if (editingSession) {
rv = editingSession->TearDownEditorOnWindow(domWindow);
rv = editingSession->TearDownEditorOnWindow(domWindow, PR_FALSE);
RvTestResult(rv, "TearDownEditorOnWindow() test", displayMode);
if (displayMode == 1)
RvTestResultDlg(rv, "TearDownEditorOnWindow() test");

Просмотреть файл

@ -84,7 +84,7 @@ void EditorFrame::MakeEditable()
nsCOMPtr<nsIEditingSession> editingSession = do_GetInterface(mWebBrowser);
if (!editingSession)
return;// NS_ERROR_FAILURE;
editingSession->MakeWindowEditable(domWindow, NULL, PR_TRUE);
editingSession->MakeWindowEditable(domWindow, NULL, PR_TRUE, PR_FALSE);
}
nsresult EditorFrame::DoCommand(const char *aCommand, nsICommandParams *aCommandParams)

Просмотреть файл

@ -93,6 +93,8 @@
#include "nsString.h"
#include "nsThreadUtils.h"
#include "nsUnicharUtils.h"
#include "nsIContent.h"
#include "nsIEventStateManager.h"
// Set to spew messages to the console about what is happening.
//#define DEBUG_INLINESPELL
@ -1108,6 +1110,11 @@ mozInlineSpellChecker::SkipSpellCheckForNode(nsIEditor* aEditor,
parent = nextParent;
}
}
else {
// XXX Do we really want this for all read-write content?
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
*checkSpelling = content->IntrinsicState() & NS_EVENT_STATE_MOZ_READWRITE;
}
return NS_OK;
}

Просмотреть файл

@ -584,14 +584,10 @@ nsCaret::DrawAtPositionWithHint(nsIDOMNode* aNode,
&theFrame, &theFrameOffset);
if (NS_FAILED(rv) || !theFrame)
return PR_FALSE;
// now we have a frame, check whether it's appropriate to show the caret here
const nsStyleUserInterface* userinterface = theFrame->GetStyleUserInterface();
if (
#ifdef SUPPORT_USER_MODIFY
// editable content still defaults to NS_STYLE_USER_MODIFY_READ_ONLY at present. See bug 15284
(userinterface->mUserModify == NS_STYLE_USER_MODIFY_READ_ONLY) ||
#endif
if ((userinterface->mUserModify == NS_STYLE_USER_MODIFY_READ_ONLY) ||
(userinterface->mUserInput == NS_STYLE_USER_INPUT_NONE) ||
(userinterface->mUserInput == NS_STYLE_USER_INPUT_DISABLED))
{

Просмотреть файл

@ -5737,17 +5737,6 @@ nsIFrame::IsFocusable(PRInt32 *aTabIndex, PRBool aWithMouse)
const nsStyleVisibility* vis = GetStyleVisibility();
if (vis->mVisible != NS_STYLE_VISIBILITY_COLLAPSE &&
vis->mVisible != NS_STYLE_VISIBILITY_HIDDEN) {
if (mContent->IsNodeOfType(nsINode::eHTML)) {
nsCOMPtr<nsISupports> container(PresContext()->GetContainer());
nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(container));
if (editorDocShell) {
PRBool isEditable;
editorDocShell->GetEditable(&isEditable);
if (isEditable) {
return NS_OK; // Editor content is not focusable
}
}
}
const nsStyleUserInterface* ui = GetStyleUserInterface();
if (ui->mUserFocus != NS_STYLE_USER_FOCUS_IGNORE &&
ui->mUserFocus != NS_STYLE_USER_FOCUS_NONE) {

Просмотреть файл

@ -457,6 +457,9 @@ public:
*/
nsIContent* GetLimiter() { return mLimiter; }
nsIContent* GetAncestorLimiter() { return mAncestorLimiter; }
void SetAncestorLimiter(nsIContent *aLimiter);
/** This will tell the frame selection that a double click has been pressed
* so it can track abort future drags if inside the same selection
* @aDoubleDown has the double click down happened
@ -631,6 +634,8 @@ private:
PRInt32 mBatching;
nsIContent *mLimiter; //limit selection navigation to a child of this node.
nsIContent *mAncestorLimiter; // Limit selection navigation to a descendant of
// this node.
nsIPresShell *mShell;
PRInt16 mSelectionChangeReason; // reason for notifications of selection changing

Просмотреть файл

@ -664,12 +664,22 @@ IsValidSelectionPoint(nsFrameSelection *aFrameSel, nsIContent *aContent)
return PR_FALSE;
if (aFrameSel)
{
nsCOMPtr<nsIContent> tLimiter = aFrameSel->GetLimiter();
if (tLimiter && tLimiter != aContent)
nsIContent *limiter = aFrameSel->GetLimiter();
if (limiter)
{
if (tLimiter != aContent->GetParent()) //if newfocus == the limiter. that's ok. but if not there and not parent bad
if (limiter != aContent && limiter != aContent->GetParent()) //if newfocus == the limiter. that's ok. but if not there and not parent bad
return PR_FALSE; //not in the right content. tLimiter said so
}
limiter = aFrameSel->GetAncestorLimiter();
if (limiter)
{
nsIContent *content = aContent;
while (content && content != limiter)
{
content = content->GetParent();
}
return content != nsnull;
}
}
return PR_TRUE;
}
@ -825,6 +835,7 @@ nsFrameSelection::nsFrameSelection()
mChangesDuringBatching = PR_FALSE;
mNotifyFrames = PR_TRUE;
mLimiter = nsnull; //no default limiter.
mAncestorLimiter = nsnull;
mMouseDoubleDownState = PR_FALSE;
@ -2220,8 +2231,10 @@ nsFrameSelection::HandleClick(nsIContent *aNewFocus,
InvalidateDesiredX();
if (!aContinueSelection)
if (!aContinueSelection) {
mMaintainRange = nsnull;
mAncestorLimiter = nsnull;
}
mHint = HINT(aHint);
// Don't take focus when dragging off of a table
@ -2786,6 +2799,9 @@ nsFrameSelection::SelectAll()
{
rootContent = mLimiter;//addrefit
}
else if (mAncestorLimiter) {
rootContent = mAncestorLimiter;
}
else
{
nsIDocument *doc = mShell->GetDocument();
@ -2797,7 +2813,7 @@ nsFrameSelection::SelectAll()
}
PRInt32 numChildren = rootContent->GetChildCount();
PostReason(nsISelectionListener::NO_REASON);
return TakeFocus(mLimiter, 0, numChildren, PR_FALSE, PR_FALSE);
return TakeFocus(rootContent, 0, numChildren, PR_FALSE, PR_FALSE);
}
//////////END FRAMESELECTION
@ -3823,6 +3839,23 @@ nsFrameSelection::CreateAndAddRange(nsIDOMNode *aParentNode, PRInt32 aOffset)
// End of Table Selection
void
nsFrameSelection::SetAncestorLimiter(nsIContent *aLimiter)
{
if (mAncestorLimiter != aLimiter) {
mAncestorLimiter = aLimiter;
PRInt8 index =
GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
if (!IsValidSelectionPoint(this, mDomSelections[index]->FetchFocusNode())) {
ClearNormalSelection();
if (mAncestorLimiter) {
PostReason(nsISelectionListener::NO_REASON);
TakeFocus(mAncestorLimiter, 0, 0, PR_FALSE, PR_FALSE);
}
}
}
}
//END nsFrameSelection methods
@ -5291,6 +5324,13 @@ nsTypedSelection::GetFrameSelection(nsFrameSelection **aFrameSelection) {
return NS_OK;
}
NS_IMETHODIMP
nsTypedSelection::SetAncestorLimiter(nsIContent *aContent)
{
mFrameSelection->SetAncestorLimiter(aContent);
return NS_OK;
}
nsresult
nsTypedSelection::StartAutoScrollTimer(nsPresContext *aPresContext,
nsIView *aView,

Просмотреть файл

@ -178,6 +178,8 @@ _FILES = \
viewsource.css \
arrow.gif \
arrowd.gif \
contenteditable.css \
designmode.css \
$(NULL)
GARBAGE += $(addprefix $(DIST)/bin/res/,$(_FILES))

Просмотреть файл

@ -134,6 +134,11 @@ input > .anonymous-div {
ime-mode: inherit;
}
input:-moz-read-write,
textarea:-moz-read-write {
-moz-user-modify: read-write !important;
}
select {
margin: 0;
border-color: ThreeDFace;

Просмотреть файл

@ -64,7 +64,7 @@ find-menu appears in editor element which has had makeEditable() called but desi
var webnav = gBrowser.webNavigation;
var edsession = webnav.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIEditingSession);
edsession.makeWindowEditable(gBrowser.contentWindow, "html", false);
edsession.makeWindowEditable(gBrowser.contentWindow, "html", false, true, false);
gBrowser.contentWindow.focus();
enterStringIntoEditor("'");
enterStringIntoEditor("/");

Просмотреть файл

@ -66,7 +66,7 @@
<parameter name="waitForUrlLoad"/>
<body>
<![CDATA[
this.editingSession.makeWindowEditable(this.contentWindow, editortype, waitForUrlLoad);
this.editingSession.makeWindowEditable(this.contentWindow, editortype, waitForUrlLoad, true, false);
this.setAttribute("editortype", editortype);
this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)

Просмотреть файл

@ -66,7 +66,7 @@
<parameter name="waitForUrlLoad"/>
<body>
<![CDATA[
this.editingSession.makeWindowEditable(this.contentWindow, editortype, waitForUrlLoad);
this.editingSession.makeWindowEditable(this.contentWindow, editortype, waitForUrlLoad, true, false);
this.setAttribute("editortype", editortype);
this.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)