Bug 613662 - Implement insertAdjacentHTML. r=bzbarsky.

This commit is contained in:
Henri Sivonen 2011-08-01 10:48:28 +03:00
Родитель 783a7d246e
Коммит 3aa0ce16e6
3 изменённых файлов: 138 добавлений и 14 удалений

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

@ -721,6 +721,26 @@ nsGenericHTMLElement::GetInnerHTML(nsAString& aInnerHTML)
return rv; 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<nsCOMPtr<nsIContent>, 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 nsresult
nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML) nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
{ {
@ -755,19 +775,7 @@ nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
eCompatibility_NavQuirks, eCompatibility_NavQuirks,
PR_TRUE); PR_TRUE);
// HTML5 parser has notified, but not fired mutation events. // HTML5 parser has notified, but not fired mutation events.
// Fire mutation events. Optimize for the case when there are no listeners FireMutationEventsForDirectParsing(doc, this, oldChildCount);
PRInt32 newChildCount = GetChildCount();
if (newChildCount && nsContentUtils::
HasMutationListeners(doc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
nsAutoTArray<nsCOMPtr<nsIContent>, 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);
}
} else { } else {
rv = nsContentUtils::CreateContextualFragment(this, aInnerHTML, rv = nsContentUtils::CreateContextualFragment(this, aInnerHTML,
PR_TRUE, PR_TRUE,
@ -781,6 +789,104 @@ nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
return rv; 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<nsIContent> 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<nsIDOMDocumentFragment> df;
nsresult rv = nsContentUtils::CreateContextualFragment(destination,
aText,
PR_TRUE,
getter_AddRefs(df));
nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
NS_ENSURE_SUCCESS(rv, rv);
switch (position) {
case eBeforeBegin:
destination->InsertBefore(fragment, this, &rv);
break;
case eAfterBegin:
static_cast<nsINode*>(this)->InsertBefore(fragment, GetFirstChild(), &rv);
break;
case eBeforeEnd:
static_cast<nsINode*>(this)->AppendChild(fragment, &rv);
break;
case eAfterEnd:
destination->InsertBefore(fragment, GetNextSibling(), &rv);
break;
default:
NS_NOTREACHED("Bad position.");
break;
}
return rv;
}
nsresult nsresult
nsGenericHTMLElement::ScrollIntoView(PRBool aTop, PRUint8 optional_argc) nsGenericHTMLElement::ScrollIntoView(PRBool aTop, PRUint8 optional_argc)
{ {

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

@ -135,6 +135,8 @@ public:
nsresult GetOffsetParent(nsIDOMElement** aOffsetParent); nsresult GetOffsetParent(nsIDOMElement** aOffsetParent);
virtual nsresult GetInnerHTML(nsAString& aInnerHTML); virtual nsresult GetInnerHTML(nsAString& aInnerHTML);
virtual nsresult SetInnerHTML(const nsAString& aInnerHTML); virtual nsresult SetInnerHTML(const nsAString& aInnerHTML);
virtual nsresult InsertAdjacentHTML(const nsAString& aPosition,
const nsAString& aText);
nsresult ScrollIntoView(PRBool aTop, PRUint8 optional_argc); nsresult ScrollIntoView(PRBool aTop, PRUint8 optional_argc);
// Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetHidden(), // Declare Focus(), Blur(), GetTabIndex(), SetTabIndex(), GetHidden(),
// SetHidden(), GetSpellcheck(), SetSpellcheck(), and GetDraggable() such that // SetHidden(), GetSpellcheck(), SetSpellcheck(), and GetDraggable() such that
@ -571,6 +573,18 @@ protected:
} }
private: 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); void RegUnRegAccessKey(PRBool aDoReg);
protected: protected:

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

@ -40,7 +40,7 @@
interface nsIDOMDOMStringMap; interface nsIDOMDOMStringMap;
[scriptable, uuid(cf76761d-2d93-4e88-aaf1-b637878bad65)] [scriptable, uuid(4012e9a9-f6fb-48b3-9a80-b096c1dcb5ba)]
interface nsIDOMNSHTMLElement : nsISupports interface nsIDOMNSHTMLElement : nsISupports
{ {
readonly attribute long offsetTop; readonly attribute long offsetTop;
@ -65,6 +65,10 @@ interface nsIDOMNSHTMLElement : nsISupports
// for WHAT-WG drag and drop // for WHAT-WG drag and drop
attribute boolean draggable; attribute boolean draggable;
void insertAdjacentHTML(in DOMString position,
in DOMString text)
raises(DOMException);
[optional_argc] void scrollIntoView([optional] in boolean top); [optional_argc] void scrollIntoView([optional] in boolean top);
attribute boolean spellcheck; attribute boolean spellcheck;