diff --git a/mozilla/content/base/public/nsIContent.h b/mozilla/content/base/public/nsIContent.h
index f80e02af8fe..105be819376 100644
--- a/mozilla/content/base/public/nsIContent.h
+++ b/mozilla/content/base/public/nsIContent.h
@@ -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
/**
diff --git a/mozilla/content/base/public/nsINode.h b/mozilla/content/base/public/nsINode.h
index 74eb33e3dfc..d06e9e259ea 100644
--- a/mozilla/content/base/public/nsINode.h
+++ b/mozilla/content/base/public/nsINode.h
@@ -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.
diff --git a/mozilla/content/base/public/nsISelectionPrivate.idl b/mozilla/content/base/public/nsISelectionPrivate.idl
index d6a9e96c498..178a91de928 100644
--- a/mozilla/content/base/public/nsISelectionPrivate.idl
+++ b/mozilla/content/base/public/nsISelectionPrivate.idl
@@ -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);
};
diff --git a/mozilla/content/base/src/nsGenericDOMDataNode.cpp b/mozilla/content/base/src/nsGenericDOMDataNode.cpp
index 9741254b74c..ecb45429c14 100644
--- a/mozilla/content/base/src/nsGenericDOMDataNode.cpp
+++ b/mozilla/content/base/src/nsGenericDOMDataNode.cpp
@@ -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(),
diff --git a/mozilla/content/base/src/nsGenericElement.cpp b/mozilla/content/base/src/nsGenericElement.cpp
index 53a2f247824..aa97723f193 100644
--- a/mozilla/content/base/src/nsGenericElement.cpp
+++ b/mozilla/content/base/src/nsGenericElement.cpp
@@ -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
diff --git a/mozilla/content/base/src/nsGkAtomList.h b/mozilla/content/base/src/nsGkAtomList.h
index ba19825839f..b5a007b54af 100755
--- a/mozilla/content/base/src/nsGkAtomList.h
+++ b/mozilla/content/base/src/nsGkAtomList.h
@@ -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")
diff --git a/mozilla/content/base/src/nsTextNode.cpp b/mozilla/content/base/src/nsTextNode.cpp
index c622bd6a69b..53f97542d6c 100644
--- a/mozilla/content/base/src/nsTextNode.cpp
+++ b/mozilla/content/base/src/nsTextNode.cpp
@@ -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());
diff --git a/mozilla/content/html/content/src/nsGenericHTMLElement.cpp b/mozilla/content/html/content/src/nsGenericHTMLElement.cpp
index 21a7f9fe51c..bd35f2f2649 100644
--- a/mozilla/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/mozilla/content/html/content/src/nsGenericHTMLElement.cpp
@@ -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 nsHTMLDocument =
- do_QueryInterface(GetCurrentDoc());
- if (!nsHTMLDocument) {
- return PR_FALSE;
+ nsCOMPtr 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 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 htmlDocument = do_QueryInterface(GetCurrentDoc());
+ if (htmlDocument) {
+ htmlDocument->ChangeContentEditableCount(this, -1);
+ }
+ }
+
+ nsGenericElement::UnbindFromTree(aDeep, aNullParent);
+}
+
already_AddRefed
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 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 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 htmlDocument =
+ do_QueryInterface(document);
+ if (htmlDocument) {
+ htmlDocument->ChangeContentEditableCount(this, aChange);
+ }
+ }
+
+ if (document->HasFlag(NODE_IS_EDITABLE)) {
+ document = nsnull;
+ }
+
+ MakeContentDescendantsEditable(this, document);
+}
diff --git a/mozilla/content/html/content/src/nsGenericHTMLElement.h b/mozilla/content/html/content/src/nsGenericHTMLElement.h
index c7fa8fc3d9e..e0519d1de0c 100644
--- a/mozilla/content/html/content/src/nsGenericHTMLElement.h
+++ b/mozilla/content/html/content/src/nsGenericHTMLElement.h
@@ -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);
diff --git a/mozilla/content/html/content/src/nsHTMLInputElement.cpp b/mozilla/content/html/content/src/nsHTMLInputElement.cpp
index 517714bbd51..b839bcfa9bd 100644
--- a/mozilla/content/html/content/src/nsHTMLInputElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLInputElement.cpp
@@ -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,
diff --git a/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp b/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp
index cebf913870a..8cb6e900a12 100644
--- a/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp
+++ b/mozilla/content/html/content/src/nsHTMLTextAreaElement.cpp
@@ -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);
+}
diff --git a/mozilla/content/html/document/src/Makefile.in b/mozilla/content/html/document/src/Makefile.in
index 7dc7c7b1b58..23ac37343a3 100644
--- a/mozilla/content/html/document/src/Makefile.in
+++ b/mozilla/content/html/document/src/Makefile.in
@@ -76,6 +76,7 @@ REQUIRES = xpcom \
composer \
editor \
plugin \
+ txtsvc \
$(NULL)
CPPSRCS = \
diff --git a/mozilla/content/html/document/src/nsHTMLDocument.cpp b/mozilla/content/html/document/src/nsHTMLDocument.cpp
index 08f25b3ff8f..172490993fe 100644
--- a/mozilla/content/html/document/src/nsHTMLDocument.cpp
+++ b/mozilla/content/html/document/src/nsHTMLDocument.cpp
@@ -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 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 editorDocShell =
+ do_QueryInterface(docshell, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr editor;
+ rv = editorDocShell->GetEditor(getter_AddRefs(editor));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr range;
+ rv = NS_NewRange(getter_AddRefs(range));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = range->SelectNode(node);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr 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 editorDocShell =
+ do_QueryInterface(docshell, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr editor;
+ rv = editorDocShell->GetEditor(getter_AddRefs(editor));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr 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 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 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 editorDocShell =
+ do_QueryInterface(docshell, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr editor;
+ rv = editorDocShell->GetEditor(getter_AddRefs(editor));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr 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 selcon;
+ nsresult rv = editor->GetSelectionController(getter_AddRefs(selcon));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr 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 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 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
diff --git a/mozilla/content/html/document/src/nsHTMLDocument.h b/mozilla/content/html/document/src/nsHTMLDocument.h
index a419601af1b..d4ead1465de 100644
--- a/mozilla/content/html/document/src/nsHTMLDocument.h
+++ b/mozilla/content/html/document/src/nsHTMLDocument.h
@@ -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 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;
diff --git a/mozilla/content/html/document/src/nsIHTMLDocument.h b/mozilla/content/html/document/src/nsIHTMLDocument.h
index 6f01e2c3112..b4e2279eee1 100644
--- a/mozilla/content/html/document/src/nsIHTMLDocument.h
+++ b/mozilla/content/html/document/src/nsIHTMLDocument.h
@@ -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)
diff --git a/mozilla/content/xul/content/src/nsXULElement.cpp b/mozilla/content/xul/content/src/nsXULElement.cpp
index be735fd7173..b3748bab53f 100644
--- a/mozilla/content/xul/content/src/nsXULElement.cpp
+++ b/mozilla/content/xul/content/src/nsXULElement.cpp
@@ -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
diff --git a/mozilla/content/xul/content/src/nsXULElement.h b/mozilla/content/xul/content/src/nsXULElement.h
index 6468d00fa9f..4fc777e14d5 100644
--- a/mozilla/content/xul/content/src/nsXULElement.h
+++ b/mozilla/content/xul/content/src/nsXULElement.h
@@ -558,6 +558,7 @@ public:
NS_DECL_NSIDOMXULELEMENT
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
+ virtual PRInt32 IntrinsicState() const;
nsresult GetStyle(nsIDOMCSSStyleDeclaration** aStyle);
diff --git a/mozilla/docshell/base/nsDocShellEditorData.cpp b/mozilla/docshell/base/nsDocShellEditorData.cpp
index 2480a2d8170..90c8b410369 100644
--- a/mozilla/docshell/base/nsDocShellEditorData.cpp
+++ b/mozilla/docshell/base/nsDocShellEditorData.cpp
@@ -73,7 +73,7 @@ nsDocShellEditorData::~nsDocShellEditorData()
nsCOMPtr 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;
diff --git a/mozilla/docshell/base/nsWebShell.cpp b/mozilla/docshell/base/nsWebShell.cpp
index 14ffba20e3d..3000869df18 100644
--- a/mozilla/docshell/base/nsWebShell.cpp
+++ b/mozilla/docshell/base/nsWebShell.cpp
@@ -772,7 +772,11 @@ nsWebShell::OnLinkClick(nsIContent* aContent,
if (mFiredUnloadEvent) {
return NS_OK;
}
-
+
+ if (aContent->HasFlag(NODE_IS_EDITABLE)) {
+ return NS_OK;
+ }
+
nsCOMPtr 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 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 browserChrome2 = do_GetInterface(mTreeOwner);
nsresult rv = NS_ERROR_FAILURE;
diff --git a/mozilla/dom/public/idl/html/nsIDOMNSHTMLElement.idl b/mozilla/dom/public/idl/html/nsIDOMNSHTMLElement.idl
index b978b4d59c8..59cae2ed339 100644
--- a/mozilla/dom/public/idl/html/nsIDOMNSHTMLElement.idl
+++ b/mozilla/dom/public/idl/html/nsIDOMNSHTMLElement.idl
@@ -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();
diff --git a/mozilla/editor/composer/public/nsIEditingSession.idl b/mozilla/editor/composer/public/nsIEditingSession.idl
index 8f2635f16f6..5714bbf0ccf 100644
--- a/mozilla/editor/composer/public/nsIEditingSession.idl
+++ b/mozilla/editor/composer/public/nsIEditingSession.idl
@@ -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);
diff --git a/mozilla/editor/composer/src/nsEditingSession.cpp b/mozilla/editor/composer/src/nsEditingSession.cpp
index 24cd54abc99..966fbfa4835 100644
--- a/mozilla/editor/composer/src/nsEditingSession.cpp
+++ b/mozilla/editor/composer/src/nsEditingSession.cpp
@@ -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 domDoc;
+ rv = aWindow->GetDocument(getter_AddRefs(domDoc));
+ NS_ENSURE_SUCCESS(rv, rv);
- mScriptsEnabled = tmp;
+ nsCOMPtr 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 utils(do_GetInterface(aWindow));
- if (!utils) return NS_ERROR_FAILURE;
+ if (!mInteractive) {
+ // Disable animation of images in this document:
+ nsCOMPtr 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 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 dom_doc;
- aWindow->GetDocument(getter_AddRefs(dom_doc));
-
- nsCOMPtr 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 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 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 domDoc;
+ rv = domWindow->GetDocument(getter_AddRefs(domDoc));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr 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
diff --git a/mozilla/editor/composer/src/nsEditingSession.h b/mozilla/editor/composer/src/nsEditingSession.h
index f8bec766f80..5929ade09b4 100644
--- a/mozilla/editor/composer/src/nsEditingSession.h
+++ b/mozilla/editor/composer/src/nsEditingSession.h
@@ -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;
diff --git a/mozilla/editor/composer/src/res/EditorOverride.css b/mozilla/editor/composer/src/res/EditorOverride.css
index f2b137e6dea..5b43ca9a14c 100644
--- a/mozilla/editor/composer/src/res/EditorOverride.css
+++ b/mozilla/editor/composer/src/res/EditorOverride.css
@@ -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.
diff --git a/mozilla/editor/docs/Editor_Embedding_Guide.html b/mozilla/editor/docs/Editor_Embedding_Guide.html
index 696579ea80c..3c076f3f9dd 100644
--- a/mozilla/editor/docs/Editor_Embedding_Guide.html
+++ b/mozilla/editor/docs/Editor_Embedding_Guide.html
@@ -18,10 +18,12 @@ GetContentDOMWindow call. Then simply call
nsIWebBrowser->do_GetInterface on the nsIWebBrowser to retrieve the
nsIEditingSession from it. From there you call
editingSession->MakeWindowEditable(domWindow, editortype,
-PR_TRUE); 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); 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. 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, ... In calling this method the editor is
created underneath and the event listeners etc. are all prepared.
nsCOMPtr<nsIDOMWindow> domWindow;
@@ -36,7 +38,8 @@ editingSession;
nsIWebBrowser->do_GetInterface(getter_AddRefs(editingSession));
if (editingSession)
-editingSession->MakeWindowEditable(domWindow, "html", PR_TRUE);
+editingSession->MakeWindowEditable(domWindow, "html", PR_TRUE,
+PR_FALSE, PR_TRUE, PR_FALSE);
The valid editor types are:
diff --git a/mozilla/editor/idl/nsIEditor.idl b/mozilla/editor/idl/nsIEditor.idl
index 8760f3959db..ea7b634a94f 100644
--- a/mozilla/editor/idl/nsIEditor.idl
+++ b/mozilla/editor/idl/nsIEditor.idl
@@ -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);
};
diff --git a/mozilla/editor/idl/nsIPlaintextEditor.idl b/mozilla/editor/idl/nsIPlaintextEditor.idl
index 12f5dbe41f2..8a3669f73e4 100644
--- a/mozilla/editor/idl/nsIPlaintextEditor.idl
+++ b/mozilla/editor/idl/nsIPlaintextEditor.idl
@@ -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.
diff --git a/mozilla/editor/libeditor/base/DeleteElementTxn.cpp b/mozilla/editor/libeditor/base/DeleteElementTxn.cpp
index 9ea120068a6..3b9cb5c91a7 100644
--- a/mozilla/editor/libeditor/base/DeleteElementTxn.cpp
+++ b/mozilla/editor/libeditor/base/DeleteElementTxn.cpp
@@ -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.
diff --git a/mozilla/editor/libeditor/base/DeleteElementTxn.h b/mozilla/editor/libeditor/base/DeleteElementTxn.h
index 14610eef383..0337856d5ee 100644
--- a/mozilla/editor/libeditor/base/DeleteElementTxn.h
+++ b/mozilla/editor/libeditor/base/DeleteElementTxn.h
@@ -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 mRefNode;
+ /** the editor for this transaction */
+ nsIEditor* mEditor;
+
/** range updater object */
nsRangeUpdater *mRangeUpdater;
diff --git a/mozilla/editor/libeditor/base/DeleteRangeTxn.cpp b/mozilla/editor/libeditor/base/DeleteRangeTxn.cpp
index abbdbe73ce1..d3dae9d2bd4 100644
--- a/mozilla/editor/libeditor/base/DeleteRangeTxn.cpp
+++ b/mozilla/editor/libeditor/base/DeleteRangeTxn.cpp
@@ -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 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();
}
diff --git a/mozilla/editor/libeditor/base/DeleteTextTxn.cpp b/mozilla/editor/libeditor/base/DeleteTextTxn.cpp
index e5e3f84fbb1..fd7c412b919 100644
--- a/mozilla/editor/libeditor/base/DeleteTextTxn.cpp
+++ b/mozilla/editor/libeditor/base/DeleteTextTxn.cpp
@@ -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");
diff --git a/mozilla/editor/libeditor/base/JoinElementTxn.cpp b/mozilla/editor/libeditor/base/JoinElementTxn.cpp
index e0d631777af..2c0ebbc9450 100644
--- a/mozilla/editor/libeditor/base/JoinElementTxn.cpp
+++ b/mozilla/editor/libeditor/base/JoinElementTxn.cpp
@@ -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);
+ nsCOMPtrleftParent;
+ 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;
diff --git a/mozilla/editor/libeditor/base/nsEditPropertyAtomList.h b/mozilla/editor/libeditor/base/nsEditPropertyAtomList.h
index 5890943749b..ac8ef52c1ce 100644
--- a/mozilla/editor/libeditor/base/nsEditPropertyAtomList.h
+++ b/mozilla/editor/libeditor/base/nsEditPropertyAtomList.h
@@ -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")
diff --git a/mozilla/editor/libeditor/base/nsEditor.cpp b/mozilla/editor/libeditor/base/nsEditor.cpp
index 8194e75e838..adbd4dc0bf8 100644
--- a/mozilla/editor/libeditor/base/nsEditor.cpp
+++ b/mozilla/editor/libeditor/base/nsEditor.cpp
@@ -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 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;
+}
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
index ce0e3910f54..3fc1a0f0054 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLEditRules.cpp
@@ -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 domRange;
+ nsresult rv = aSelection->GetRangeAt(0, getter_AddRefs(domRange));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr selStartNode;
+ rv = domRange->GetStartContainer(getter_AddRefs(selStartNode));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (!mHTMLEditor->IsModifiableNode(selStartNode))
+ {
+ *aCancel = PR_TRUE;
+
+ return NS_OK;
+ }
+
+ nsCOMPtr 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 range = do_QueryInterface(domRange);
+ nsCOMPtr 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
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
index a78bdf4700e..111851b9de7 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/mozilla/editor/libeditor/html/nsHTMLEditor.cpp
@@ -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"));
+ }
nsCOMPtrselection;
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 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 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 *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 nsHTMLEditor::FindUserSelectAllNode(nsIDOMNode *aNode)
return resultNode;
}
+NS_IMETHODIMP_(PRBool)
+nsHTMLEditor::IsModifiableNode(nsIDOMNode *aNode)
+{
+ nsCOMPtr content = do_QueryInterface(aNode);
+
+ return !content || !(content->IntrinsicState() & NS_EVENT_STATE_MOZ_READONLY);
+}
+
static nsresult SetSelectionAroundHeadChildren(nsCOMPtr 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 selCon = do_QueryReferent(mSelConWeak, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr selection;
+ rv = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
+ getter_AddRefs(selection));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr anchorNode;
+ rv = selection->GetAnchorNode(getter_AddRefs(anchorNode));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr anchorContent = do_QueryInterface(anchorNode, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsIContent *rootContent = FindEditableRoot(anchorContent);
+ if (!rootContent) {
+ return SelectEntireDocument(selection);
+ }
+
+ nsCOMPtr rootElement = do_QueryInterface(rootContent, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return selection->SelectAllChildren(rootElement);
+}
#ifdef XP_MAC
diff --git a/mozilla/editor/libeditor/html/nsHTMLEditor.h b/mozilla/editor/libeditor/html/nsHTMLEditor.h
index dfa5b3e5982..b860cbce778 100644
--- a/mozilla/editor/libeditor/html/nsHTMLEditor.h
+++ b/mozilla/editor/libeditor/html/nsHTMLEditor.h
@@ -363,6 +363,13 @@ public:
NS_IMETHODIMP DeleteText(nsIDOMCharacterData *aTextNode,
PRUint32 aOffset,
PRUint32 aLength);
+ NS_IMETHOD InsertTextImpl(const nsAString& aStringToInsert,
+ nsCOMPtr *aInOutNode,
+ PRInt32 *aInOutOffset,
+ nsIDOMDocument *aDoc);
+ NS_IMETHOD_(PRBool) IsModifiableNode(nsIDOMNode *aNode);
+
+ NS_IMETHOD SelectAll();
/* ------------ nsICSSLoaderObserver -------------- */
NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aWasAlternate,
diff --git a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp
index 90f46a5ebbb..1c1461c8d37 100644
--- a/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp
+++ b/mozilla/editor/libeditor/text/nsEditorEventListeners.cpp
@@ -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
- nsCOMPtreditor = do_QueryInterface(mEditor);
- if (editor)
+ nsCOMPtr content = do_QueryInterface(target);
+
+ nsIContent *editableRoot = content ? FindEditableRoot(content) : nsnull;
+
+ nsCOMPtr selCon;
+ mEditor->GetSelectionController(getter_AddRefs(selCon));
+ nsCOMPtr presShell = do_QueryInterface(selCon);
+ if (selCon && editableRoot)
{
- nsCOMPtrselCon;
- editor->GetSelectionController(getter_AddRefs(selCon));
- if (selCon)
+ nsCOMPtr selection;
+ selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
+ getter_AddRefs(selection));
+
+ if (presShell && selection) {
+ nsCOMPtr 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 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 selection;
+ selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
+ getter_AddRefs(selection));
+
+ nsCOMPtr selectionPrivate =
+ do_QueryInterface(selection);
+ if (selectionPrivate) {
+ selectionPrivate->SetAncestorLimiter(nsnull);
+ }
+
selCon->SetCaretEnabled(PR_FALSE);
PRUint32 flags;
diff --git a/mozilla/editor/libeditor/text/nsTextEditRules.cpp b/mozilla/editor/libeditor/text/nsTextEditRules.cpp
index a825412fc74..81f0c5fbcdf 100644
--- a/mozilla/editor/libeditor/text/nsTextEditRules.cpp
+++ b/mozilla/editor/libeditor/text/nsTextEditRules.cpp
@@ -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;
diff --git a/mozilla/editor/ui/composer/content/editor.js b/mozilla/editor/ui/composer/content/editor.js
index d59464f7edb..c3f21522e3e 100644
--- a/mozilla/editor/ui/composer/content/editor.js
+++ b/mozilla/editor/ui/composer/content/editor.js
@@ -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
diff --git a/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp b/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp
index d8aa5790f11..05fc80d4877 100644
--- a/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp
+++ b/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp
@@ -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;
}
diff --git a/mozilla/embedding/qa/testembed/nsIEditSession.cpp b/mozilla/embedding/qa/testembed/nsIEditSession.cpp
index 14eafb50a53..0c4fdbfb548 100644
--- a/mozilla/embedding/qa/testembed/nsIEditSession.cpp
+++ b/mozilla/embedding/qa/testembed/nsIEditSession.cpp
@@ -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");
diff --git a/mozilla/embedding/tests/wxEmbed/EditorFrame.cpp b/mozilla/embedding/tests/wxEmbed/EditorFrame.cpp
index e16832d8b8e..7ef3dfb3a96 100644
--- a/mozilla/embedding/tests/wxEmbed/EditorFrame.cpp
+++ b/mozilla/embedding/tests/wxEmbed/EditorFrame.cpp
@@ -84,7 +84,7 @@ void EditorFrame::MakeEditable()
nsCOMPtr 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)
diff --git a/mozilla/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/mozilla/extensions/spellcheck/src/mozInlineSpellChecker.cpp
index 27848fcbb54..0fb1a12b268 100644
--- a/mozilla/extensions/spellcheck/src/mozInlineSpellChecker.cpp
+++ b/mozilla/extensions/spellcheck/src/mozInlineSpellChecker.cpp
@@ -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 content = do_QueryInterface(aNode);
+ *checkSpelling = content->IntrinsicState() & NS_EVENT_STATE_MOZ_READWRITE;
+ }
return NS_OK;
}
diff --git a/mozilla/layout/base/nsCaret.cpp b/mozilla/layout/base/nsCaret.cpp
index 4fe1931811a..dd105adbfe6 100644
--- a/mozilla/layout/base/nsCaret.cpp
+++ b/mozilla/layout/base/nsCaret.cpp
@@ -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))
{
diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp
index eb9150ef00a..a08b6f4d3ac 100644
--- a/mozilla/layout/generic/nsFrame.cpp
+++ b/mozilla/layout/generic/nsFrame.cpp
@@ -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 container(PresContext()->GetContainer());
- nsCOMPtr 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) {
diff --git a/mozilla/layout/generic/nsFrameSelection.h b/mozilla/layout/generic/nsFrameSelection.h
index c0d2b177191..919d677f249 100644
--- a/mozilla/layout/generic/nsFrameSelection.h
+++ b/mozilla/layout/generic/nsFrameSelection.h
@@ -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
diff --git a/mozilla/layout/generic/nsSelection.cpp b/mozilla/layout/generic/nsSelection.cpp
index 4aecd0a9978..f4163ff58ab 100644
--- a/mozilla/layout/generic/nsSelection.cpp
+++ b/mozilla/layout/generic/nsSelection.cpp
@@ -664,12 +664,22 @@ IsValidSelectionPoint(nsFrameSelection *aFrameSel, nsIContent *aContent)
return PR_FALSE;
if (aFrameSel)
{
- nsCOMPtr 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,
diff --git a/mozilla/layout/style/Makefile.in b/mozilla/layout/style/Makefile.in
index b73f2769fb4..1ef5f0d9886 100644
--- a/mozilla/layout/style/Makefile.in
+++ b/mozilla/layout/style/Makefile.in
@@ -178,6 +178,8 @@ _FILES = \
viewsource.css \
arrow.gif \
arrowd.gif \
+ contenteditable.css \
+ designmode.css \
$(NULL)
GARBAGE += $(addprefix $(DIST)/bin/res/,$(_FILES))
diff --git a/mozilla/layout/style/forms.css b/mozilla/layout/style/forms.css
index 595fff43eff..350ec1f1031 100644
--- a/mozilla/layout/style/forms.css
+++ b/mozilla/layout/style/forms.css
@@ -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;
diff --git a/mozilla/toolkit/content/tests/chrome/bug304188_window.xul b/mozilla/toolkit/content/tests/chrome/bug304188_window.xul
index 722536adca9..aecc27391ab 100755
--- a/mozilla/toolkit/content/tests/chrome/bug304188_window.xul
+++ b/mozilla/toolkit/content/tests/chrome/bug304188_window.xul
@@ -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("/");
diff --git a/mozilla/toolkit/content/widgets/editor.xml b/mozilla/toolkit/content/widgets/editor.xml
index 0ca18f16cfe..8cfc1fb509c 100644
--- a/mozilla/toolkit/content/widgets/editor.xml
+++ b/mozilla/toolkit/content/widgets/editor.xml
@@ -66,7 +66,7 @@