diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp
index 4f2dcfe12b51..ea705df3f085 100644
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -721,6 +721,26 @@ nsGenericHTMLElement::GetInnerHTML(nsAString& aInnerHTML)
return rv;
}
+void
+nsGenericHTMLElement::FireMutationEventsForDirectParsing(nsIDocument* aDoc,
+ nsIContent* aDest,
+ PRInt32 aOldChildCount)
+{
+ // Fire mutation events. Optimize for the case when there are no listeners
+ PRInt32 newChildCount = aDest->GetChildCount();
+ if (newChildCount && nsContentUtils::
+ HasMutationListeners(aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
+ nsAutoTArray, 50> childNodes;
+ NS_ASSERTION(newChildCount - aOldChildCount >= 0,
+ "What, some unexpected dom mutation has happened?");
+ childNodes.SetCapacity(newChildCount - aOldChildCount);
+ for (nsINode::ChildIterator iter(aDest); !iter.IsDone(); iter.Next()) {
+ childNodes.AppendElement(iter);
+ }
+ nsGenericElement::FireNodeInserted(aDoc, aDest, childNodes);
+ }
+}
+
nsresult
nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
{
@@ -755,19 +775,7 @@ nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
eCompatibility_NavQuirks,
PR_TRUE);
// HTML5 parser has notified, but not fired mutation events.
- // Fire mutation events. Optimize for the case when there are no listeners
- PRInt32 newChildCount = GetChildCount();
- if (newChildCount && nsContentUtils::
- HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
- nsAutoTArray, 50> childNodes;
- NS_ASSERTION(newChildCount - oldChildCount >= 0,
- "What, some unexpected dom mutation has happened?");
- childNodes.SetCapacity(newChildCount - oldChildCount);
- for (nsINode::ChildIterator iter(this); !iter.IsDone(); iter.Next()) {
- childNodes.AppendElement(iter);
- }
- nsGenericElement::FireNodeInserted(doc, this, childNodes);
- }
+ FireMutationEventsForDirectParsing(doc, this, oldChildCount);
} else {
rv = nsContentUtils::CreateContextualFragment(this, aInnerHTML,
PR_TRUE,
@@ -781,6 +789,104 @@ nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
return rv;
}
+enum nsAdjacentPosition {
+ eBeforeBegin,
+ eAfterBegin,
+ eBeforeEnd,
+ eAfterEnd
+};
+
+nsresult
+nsGenericHTMLElement::InsertAdjacentHTML(const nsAString& aPosition,
+ const nsAString& aText)
+{
+ nsAdjacentPosition position;
+ if (aPosition.LowerCaseEqualsLiteral("beforebegin")) {
+ position = eBeforeBegin;
+ } else if (aPosition.LowerCaseEqualsLiteral("afterbegin")) {
+ position = eAfterBegin;
+ } else if (aPosition.LowerCaseEqualsLiteral("beforeend")) {
+ position = eBeforeEnd;
+ } else if (aPosition.LowerCaseEqualsLiteral("afterend")) {
+ position = eAfterEnd;
+ } else {
+ return NS_ERROR_DOM_SYNTAX_ERR;
+ }
+
+ nsCOMPtr destination;
+ if (position == eBeforeBegin || position == eAfterEnd) {
+ destination = GetParent();
+ if (!destination) {
+ return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
+ }
+ } else {
+ destination = this;
+ }
+
+ nsIDocument* doc = GetOwnerDoc();
+ NS_ENSURE_STATE(doc);
+
+ // Needed when insertAdjacentHTML is used in combination with contenteditable
+ mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, PR_TRUE);
+
+ // Batch possible DOMSubtreeModified events.
+ mozAutoSubtreeModified subtree(doc, nsnull);
+
+ // Parse directly into destination if possible
+ if (doc->IsHTML() &&
+ (position == eBeforeEnd ||
+ (position == eAfterEnd && !GetNextSibling()) ||
+ (position == eAfterBegin && !GetFirstChild()))) {
+ PRInt32 oldChildCount = destination->GetChildCount();
+ PRInt32 contextNs = destination->GetNameSpaceID();
+ nsIAtom* contextLocal = destination->Tag();
+ if (contextLocal == nsGkAtoms::html && contextNs == kNameSpaceID_XHTML) {
+ // For compat with IE6 through IE9. Willful violation of HTML5 as of
+ // 2011-04-06. CreateContextualFragment does the same already.
+ // Spec bug: http://www.w3.org/Bugs/Public/show_bug.cgi?id=12434
+ contextLocal = nsGkAtoms::body;
+ }
+ nsContentUtils::ParseFragmentHTML(aText,
+ destination,
+ contextLocal,
+ contextNs,
+ doc->GetCompatibilityMode() ==
+ eCompatibility_NavQuirks,
+ PR_TRUE);
+ // HTML5 parser has notified, but not fired mutation events.
+ FireMutationEventsForDirectParsing(doc, destination, oldChildCount);
+ return NS_OK;
+ }
+
+ // couldn't parse directly
+ nsCOMPtr df;
+ nsresult rv = nsContentUtils::CreateContextualFragment(destination,
+ aText,
+ PR_TRUE,
+ getter_AddRefs(df));
+ nsCOMPtr fragment = do_QueryInterface(df);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ switch (position) {
+ case eBeforeBegin:
+ destination->InsertBefore(fragment, this, &rv);
+ break;
+ case eAfterBegin:
+ static_cast(this)->InsertBefore(fragment, GetFirstChild(), &rv);
+ break;
+ case eBeforeEnd:
+ static_cast(this)->AppendChild(fragment, &rv);
+ break;
+ case eAfterEnd:
+ destination->InsertBefore(fragment, GetNextSibling(), &rv);
+ break;
+ default:
+ NS_NOTREACHED("Bad position.");
+ break;
+ }
+ return rv;
+}
+
nsresult
nsGenericHTMLElement::ScrollIntoView(PRBool aTop, PRUint8 optional_argc)
{
diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h
index c4c5313a2fbd..af428736e755 100644
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -135,6 +135,8 @@ public:
nsresult GetOffsetParent(nsIDOMElement** aOffsetParent);
virtual nsresult GetInnerHTML(nsAString& aInnerHTML);
virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
+ virtual nsresult InsertAdjacentHTML(const nsAString& aPosition,
+ const nsAString& aText);
nsresult ScrollIntoView(PRBool aTop, PRUint8 optional_argc);
// Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetHidden(),
// SetHidden(), GetSpellcheck(), SetSpellcheck(), and GetDraggable() such that
@@ -571,6 +573,18 @@ protected:
}
private:
+ /**
+ * Fire mutation events for changes caused by parsing directly into a
+ * context node.
+ *
+ * @param aDoc the document of the node
+ * @param aDest the destination node that got stuff appended to it
+ * @param aOldChildCount the number of children the node had before parsing
+ */
+ void FireMutationEventsForDirectParsing(nsIDocument* aDoc,
+ nsIContent* aDest,
+ PRInt32 aOldChildCount);
+
void RegUnRegAccessKey(PRBool aDoReg);
protected:
diff --git a/dom/interfaces/html/nsIDOMNSHTMLElement.idl b/dom/interfaces/html/nsIDOMNSHTMLElement.idl
index 88dbedb3265a..0000b619d2ec 100644
--- a/dom/interfaces/html/nsIDOMNSHTMLElement.idl
+++ b/dom/interfaces/html/nsIDOMNSHTMLElement.idl
@@ -40,7 +40,7 @@
interface nsIDOMDOMStringMap;
-[scriptable, uuid(cf76761d-2d93-4e88-aaf1-b637878bad65)]
+[scriptable, uuid(4012e9a9-f6fb-48b3-9a80-b096c1dcb5ba)]
interface nsIDOMNSHTMLElement : nsISupports
{
readonly attribute long offsetTop;
@@ -65,6 +65,10 @@ interface nsIDOMNSHTMLElement : nsISupports
// for WHAT-WG drag and drop
attribute boolean draggable;
+ void insertAdjacentHTML(in DOMString position,
+ in DOMString text)
+ raises(DOMException);
+
[optional_argc] void scrollIntoView([optional] in boolean top);
attribute boolean spellcheck;