Bug 783129 - Implementation of document.register without shadow DOM support. r=mrbkap, bent

This commit is contained in:
William Chen 2012-11-01 11:18:08 -07:00
parent 35b1d04204
commit de026650c9
16 changed files with 548 additions and 3 deletions

View File

@ -61,6 +61,7 @@
#include "nsTreeWalker.h"
#include "nsIServiceManager.h"
#include "nsDOMClassInfo.h"
#include "nsContentCID.h"
#include "nsError.h"
@ -135,10 +136,12 @@
#include "nsIPrompt.h"
#include "nsIPropertyBag2.h"
#include "nsIDOMPageTransitionEvent.h"
#include "nsJSUtils.h"
#include "nsFrameLoader.h"
#include "nsEscape.h"
#include "nsObjectLoadingContent.h"
#include "nsHtml5TreeOpExecutor.h"
#include "nsIDOMElementReplaceEvent.h"
#ifdef MOZ_MEDIA
#include "nsHTMLMediaElement.h"
#endif // MOZ_MEDIA
@ -168,6 +171,7 @@
#include "mozilla/dom/Link.h"
#include "nsXULAppAPI.h"
#include "nsDOMTouchEvent.h"
#include "DictionaryHelpers.h"
#include "mozilla/Preferences.h"
@ -189,6 +193,8 @@ nsWeakPtr nsDocument::sFullScreenDoc = nullptr;
// which requested DOM full-screen mode.
nsWeakPtr nsDocument::sFullScreenRootDoc = nullptr;
nsIDOMElement* nsDocument::sCurrentUpgradeElement = nullptr;
#ifdef PR_LOGGING
static PRLogModuleInfo* gDocumentLeakPRLog;
static PRLogModuleInfo* gCspPRLog;
@ -1369,6 +1375,11 @@ nsDocument::~nsDocument()
mInDestructor = true;
mInUnlinkOrDeletion = true;
nsISupports* supports;
QueryInterface(NS_GET_IID(nsCycleCollectionISupports), reinterpret_cast<void**>(&supports));
NS_ASSERTION(supports, "Failed to QI to nsCycleCollectionISupports?!");
nsContentUtils::DropJSObjects(supports);
// Clear mObservers to keep it in sync with the mutationobserver list
mObservers.Clear();
@ -1694,7 +1705,25 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
struct CustomPrototypeTraceArgs {
TraceCallback callback;
void* closure;
};
static PLDHashOperator
CustomPrototypeTrace(const nsAString& aName, JSObject* aObject, void *aArg)
{
CustomPrototypeTraceArgs* traceArgs = static_cast<CustomPrototypeTraceArgs*>(aArg);
MOZ_ASSERT(aObject, "Protocol object value must not be null");
traceArgs->callback(aObject, "mCustomPrototypes entry", traceArgs->closure);
return PL_DHASH_NEXT;
}
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument)
CustomPrototypeTraceArgs customPrototypeArgs = { aCallback, aClosure };
tmp->mCustomPrototypes.EnumerateRead(CustomPrototypeTrace, &customPrototypeArgs);
nsINode::Trace(tmp, aCallback, aClosure);
NS_IMPL_CYCLE_COLLECTION_TRACE_END
@ -1758,6 +1787,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
tmp->mIdentifierMap.Clear();
tmp->mCustomPrototypes.Clear();
if (tmp->mAnimationController) {
tmp->mAnimationController->Unlink();
}
@ -1782,6 +1813,7 @@ nsDocument::Init()
mIdentifierMap.Init();
mStyledLinks.Init();
mRadioGroups.Init();
mCustomPrototypes.Init();
// Force initialization.
nsINode::nsSlots* slots = Slots();
@ -1818,6 +1850,15 @@ nsDocument::Init()
mImageTracker.Init();
mPlugins.Init();
nsXPCOMCycleCollectionParticipant* participant;
CallQueryInterface(this, &participant);
NS_ASSERTION(participant, "Failed to QI to nsXPCOMCycleCollectionParticipant!");
nsISupports* thisSupports;
QueryInterface(NS_GET_IID(nsCycleCollectionISupports), reinterpret_cast<void**>(&thisSupports));
NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
nsContentUtils::HoldJSObjects(thisSupports, participant);
return NS_OK;
}
@ -4582,6 +4623,218 @@ nsDocument::GetElementsByTagName(const nsAString& aTagname,
return NS_OK;
}
static JSBool
CustomElementConstructor(JSContext *aCx, unsigned aArgc, JS::Value* aVp)
{
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
JSObject* global = JS_GetGlobalForObject(aCx, &args.callee());
nsCOMPtr<nsPIDOMWindow> window = do_QueryWrapper(aCx, global);
MOZ_ASSERT(window, "Should have a non-null window");
nsIDocument* document = window->GetDoc();
// Function name is the type of the custom element.
JSString* jsFunName = JS_GetFunctionId(JS_ValueToFunction(aCx,
args.calleev()));
nsDependentJSString elemName;
if (!elemName.init(aCx, jsFunName)) {
return false;
}
nsCOMPtr<nsIContent> newElement;
nsresult rv = document->CreateElem(elemName, nullptr, kNameSpaceID_XHTML,
getter_AddRefs(newElement));
JS::Value v;
rv = nsContentUtils::WrapNative(aCx, global, newElement,
(nsWrapperCache*) nullptr, &v);
NS_ENSURE_SUCCESS(rv, false);
JS_SET_RVAL(aCx, aVp, v);
return true;
}
static nsresult
GetPrototypeFromClassInfoId(JSContext* aCx, JSObject* aScope,
nsDOMClassInfoID aClassInfoId,
JSObject** aPrototype)
{
nsIXPConnect* xpc = nsContentUtils::XPConnect();
nsIClassInfo* classInfo = NS_GetDOMClassInfoInstance(aClassInfoId);
NS_ENSURE_TRUE(classInfo, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = xpc->GetWrappedNativePrototype(aCx, aScope, classInfo,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
JSObject* interface;
rv = holder->GetJSObject(&interface);
NS_ENSURE_SUCCESS(rv, rv);
*aPrototype = interface;
return NS_OK;
}
NS_IMETHODIMP
nsDocument::Register(const nsAString& aName, const JS::Value& aOptions,
JSContext* aCx, uint8_t aArgc,
jsval* aConstructor /* out param */)
{
nsAutoString lcName;
nsContentUtils::ASCIIToLower(aName, lcName);
NS_ENSURE_TRUE(StringBeginsWith(lcName, NS_LITERAL_STRING("x-")),
NS_ERROR_DOM_INVALID_CHARACTER_ERR);
nsresult rv = nsContentUtils::CheckQName(lcName, false);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INVALID_CHARACTER_ERR);
DocumentRegisterOptions options;
nsCOMPtr<nsILifecycleCallback> lifecycleCallback;
if (aArgc > 0) {
rv = options.Init(aCx, &aOptions);
NS_ENSURE_SUCCESS(rv, rv);
if (options.lifecycle) {
JS::Value callbacksValue;
rv = options.lifecycle->GetAsJSVal(&callbacksValue);
NS_ENSURE_SUCCESS(rv, rv);
LifecycleCallbacks callbacks;
rv = callbacks.Init(aCx, &callbacksValue);
NS_ENSURE_SUCCESS(rv, rv);
lifecycleCallback = callbacks.created;
}
}
// TODO(wchen): Templates are not currently supported. Bug 818976.
if (options.customTemplate) {
return NS_ERROR_NOT_IMPLEMENTED;
}
nsIScriptGlobalObject* sgo = GetScopeObject();
NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
JSObject* global = sgo->GetGlobalJSObject();
JSObject* protoObject;
if (!options.prototype) {
// If a prototype is not provided, we use the interface prototype for
// HTMLSpanElement.
rv = GetPrototypeFromClassInfoId(aCx, global,
eDOMClassInfo_HTMLSpanElement_id,
&protoObject);
NS_ENSURE_SUCCESS(rv, rv);
} else {
JS::Value customProto;
rv = options.prototype->GetAsJSVal(&customProto);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(!customProto.isPrimitive(), NS_ERROR_TYPE_ERR);
protoObject = &customProto.toObject();
// If a prototype is provided, we must check to ensure that it inherits
// from HTMLElement.
JSObject* htmlProto;
rv = GetPrototypeFromClassInfoId(aCx, global,
eDOMClassInfo_HTMLElement_id,
&htmlProto);
NS_ENSURE_SUCCESS(rv, rv);
// Check the proto chain for HTMLElement prototype.
JSObject* protoProto;
NS_ENSURE_TRUE(JS_GetPrototype(aCx, protoObject, &protoProto),
NS_ERROR_UNEXPECTED);
while (protoProto) {
if (protoProto == htmlProto) {
break;
}
NS_ENSURE_TRUE(JS_GetPrototype(aCx, protoProto, &protoProto),
NS_ERROR_UNEXPECTED);
}
NS_ENSURE_TRUE(protoProto, NS_ERROR_DOM_TYPE_MISMATCH_ERR);
}
// Associate the prototype with the custom element.
mCustomPrototypes.Put(lcName, protoObject);
// Do element upgrade.
nsRefPtr<nsContentList> list = GetElementsByTagName(lcName);
for (int32_t i = 0; i < list->Length(false); i++) {
nsINode* oldNode = list->Item(i, false);
// TODO(wchen): Perform upgrade on Shadow DOM when implemented.
// Bug 806506.
nsCOMPtr<nsINode> newNode;
rv = nsNodeUtils::Clone(oldNode, true, getter_AddRefs(newNode));
NS_ENSURE_SUCCESS(rv, rv);
nsINode* parentNode = oldNode->GetParentNode();
MOZ_ASSERT(parentNode, "Node obtained by GetElementsByTagName.");
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newNode);
MOZ_ASSERT(newElement, "Cloned of node obtained by GetElementsByTagName.");
ErrorResult error;
parentNode->ReplaceChild(*newNode, *oldNode, error);
rv = error.ErrorCode();
NS_ENSURE_SUCCESS(rv, rv);
// Dispatch elementreplaced to replaced elements.
nsCOMPtr<nsIDOMEvent> event;
rv = CreateEvent(NS_LITERAL_STRING("elementreplace"), getter_AddRefs(event));
NS_ENSURE_SUCCESS(rv, rv);
if (lifecycleCallback) {
// Update static member used for "this" translation
// when calling callback.
sCurrentUpgradeElement = newElement.get();
lifecycleCallback->Created(nullptr);
sCurrentUpgradeElement = nullptr;
}
nsCOMPtr<nsIDOMElementReplaceEvent> ptEvent = do_QueryInterface(event);
MOZ_ASSERT(ptEvent);
rv = ptEvent->InitElementReplaceEvent(NS_LITERAL_STRING("elementreplace"),
false, false, newElement);
NS_ENSURE_SUCCESS(rv, rv);
event->SetTrusted(true);
event->SetTarget(oldNode);
nsEventDispatcher::DispatchDOMEvent(oldNode, nullptr, event,
nullptr, nullptr);
}
nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
NS_LITERAL_STRING("elementupgrade"),
true, true);
// Create constructor to return. Store the name of the custom element as the
// name of the function.
JSFunction* constructor = JS_NewFunction(aCx, CustomElementConstructor, 0,
JSFUN_CONSTRUCTOR, nullptr,
NS_ConvertUTF16toUTF8(lcName).get());
JSObject* constructorObject = JS_GetFunctionObject(constructor);
JS::Value protoVal = OBJECT_TO_JSVAL(protoObject);
NS_ENSURE_TRUE(JS_SetProperty(aCx, constructorObject, "prototype",
&protoVal), NS_ERROR_UNEXPECTED);
JS::Value constructorVal = OBJECT_TO_JSVAL(constructorObject);
NS_ENSURE_TRUE(JS_SetProperty(aCx, protoObject, "constructor",
&constructorVal), NS_ERROR_UNEXPECTED);
// Return the constructor.
*aConstructor = OBJECT_TO_JSVAL(constructorObject);
return NS_OK;
}
already_AddRefed<nsContentList>
nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
const nsAString& aLocalName)

View File

@ -1005,6 +1005,18 @@ public:
// DocSizeOfIncludingThis is inherited from nsIDocument.
virtual nsIDOMNode* AsDOMNode() { return this; }
static nsIDOMElement* CurrentUpgradeElement()
{
return sCurrentUpgradeElement;
}
JSObject* GetCustomPrototype(const nsAString& aElementName)
{
JSObject* prototype = nullptr;
mCustomPrototypes.Get(aElementName, &prototype);
return prototype;
}
protected:
friend class nsNodeUtils;
@ -1162,6 +1174,14 @@ protected:
// pop one off this stack, restoring the previous full-screen state
nsTArray<nsWeakPtr> mFullScreenStack;
// Weak reference to the current upgraded element in document.register.
// This member is used for function |this| translation when calling a
// callback interface in document.register.
static nsIDOMElement* sCurrentUpgradeElement;
// Hashtable for custom element prototypes in web components.
nsDataHashtable<nsStringHashKey, JSObject*> mCustomPrototypes;
nsRefPtr<nsEventListenerManager> mListenerManager;
nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;

View File

@ -156,6 +156,16 @@ public:
nullptr, aNodesWithProperties, nullptr, aResult);
}
/**
* Clones aNode, its attributes and, if aDeep is true, its descendant nodes
*/
static nsresult Clone(nsINode *aNode, bool aDeep, nsINode **aResult)
{
nsCOMArray<nsINode> dummyNodeWithProperties;
return CloneAndAdopt(aNode, true, aDeep, nullptr, nullptr, nullptr,
dummyNodeWithProperties, aNode->GetParent(), aResult);
}
/**
* Walks aNode, its attributes and descendant nodes. If aNewNodeInfoManager is
* not null, it is used to create new nodeinfos for the nodes. Also reparents

View File

@ -816,6 +816,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
if (aEventType.LowerCaseEqualsLiteral("commandevent") ||
aEventType.LowerCaseEqualsLiteral("commandevents"))
return NS_NewDOMCommandEvent(aDOMEvent, aPresContext, nullptr);
if (aEventType.LowerCaseEqualsLiteral("elementreplace"))
return NS_NewDOMElementReplaceEvent(aDOMEvent, aPresContext, nullptr);
if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") ||
aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
return NS_NewDOMDataContainerEvent(aDOMEvent, aPresContext, nullptr);

View File

@ -2360,6 +2360,9 @@ nsDOMClassInfo::Init()
nsCOMPtr<nsIXPCFunctionThisTranslator> elt = new nsEventListenerThisTranslator();
sXPConnect->SetFunctionThisTranslator(NS_GET_IID(nsIDOMEventListener), elt);
nsCOMPtr<nsIXPCFunctionThisTranslator> lct = new nsLifecycleCallbacksThisTranslator();
sXPConnect->SetFunctionThisTranslator(NS_GET_IID(nsILifecycleCallback), lct);
nsCOMPtr<nsIScriptSecurityManager> sm =
do_GetService("@mozilla.org/scriptsecuritymanager;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
@ -7941,6 +7944,13 @@ nsElementSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
}
#endif
nsAutoString elementName;
nsContentUtils::ASCIIToLower(element->NodeName(), elementName);
if (StringBeginsWith(elementName, NS_LITERAL_STRING("x-"))) {
// Don't allow slim wrappers for custom elements.
return rv == NS_SUCCESS_ALLOW_SLIM_WRAPPERS ? NS_OK : rv;
}
nsIDocument *doc = element->HasFlag(NODE_FORCE_XBL_BINDINGS) ?
element->OwnerDoc() :
element->GetCurrentDoc();
@ -7986,6 +7996,17 @@ nsElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
#endif
// If we have a registered x-tag then we fix the prototype.
nsAutoString elementName;
nsContentUtils::ASCIIToLower(element->NodeName(), elementName);
if (StringBeginsWith(elementName, NS_LITERAL_STRING("x-"))) {
nsDocument* document = static_cast<nsDocument*>(element->OwnerDoc());
JSObject* prototype = document->GetCustomPrototype(elementName);
if (prototype) {
return JS_SetPrototype(cx, obj, prototype) ? NS_OK : NS_ERROR_UNEXPECTED;
}
}
nsIDocument* doc;
if (element->HasFlag(NODE_FORCE_XBL_BINDINGS)) {
doc = element->OwnerDoc();
@ -10197,6 +10218,24 @@ nsEventListenerThisTranslator::TranslateThis(nsISupports *aInitialThis,
return NS_OK;
}
NS_INTERFACE_MAP_BEGIN(nsLifecycleCallbacksThisTranslator)
NS_INTERFACE_MAP_ENTRY(nsIXPCFunctionThisTranslator)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(nsLifecycleCallbacksThisTranslator)
NS_IMPL_RELEASE(nsLifecycleCallbacksThisTranslator)
NS_IMETHODIMP
nsLifecycleCallbacksThisTranslator::TranslateThis(nsISupports *aInitialThis,
nsISupports **_retval)
{
NS_IF_ADDREF(*_retval = nsDocument::CurrentUpgradeElement());
return NS_OK;
}
NS_IMETHODIMP
nsDOMConstructorSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj)

View File

@ -1208,6 +1208,24 @@ public:
NS_DECL_NSIXPCFUNCTIONTHISTRANSLATOR
};
class nsLifecycleCallbacksThisTranslator : public nsIXPCFunctionThisTranslator
{
public:
nsLifecycleCallbacksThisTranslator()
{
}
virtual ~nsLifecycleCallbacksThisTranslator()
{
}
// nsISupports
NS_DECL_ISUPPORTS
// nsIXPCFunctionThisTranslator
NS_DECL_NSIXPCFUNCTIONTHISTRANSLATOR
};
class nsDOMConstructorSH : public nsDOMGenericSH
{
protected:

View File

@ -27,7 +27,7 @@ interface nsIDOMLocation;
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
[scriptable, uuid(31ce7ae7-15d5-4fc8-912b-ae0e23e93146)]
[scriptable, uuid(6f3aac2e-ae11-487a-9eb0-0e12c66b3b21)]
interface nsIDOMDocument : nsIDOMNode
{
readonly attribute nsIDOMDocumentType doctype;
@ -47,6 +47,11 @@ interface nsIDOMDocument : nsIDOMNode
raises(DOMException);
nsIDOMNodeList getElementsByTagName(in DOMString tagname);
[optional_argc,
implicit_jscontext] jsval register(in DOMString name,
[optional] in jsval options)
raises(DOMException);
// Introduced in DOM Level 2:
[optional_argc] nsIDOMNode importNode(in nsIDOMNode importedNode,
[optional] in boolean deep)
@ -396,3 +401,24 @@ interface nsIDOMDocument : nsIDOMNode
*/
readonly attribute DOMString compatMode;
};
/**
* Interface for lifecycle callbacks in document.register.
*/
[scriptable, function, uuid(bfcd6299-081e-45d8-99f6-cb06fe2e70de)]
interface nsILifecycleCallback : nsISupports
{
void created(in nsIDOMElement dummy);
};
dictionary LifecycleCallbacks {
nsILifecycleCallback created;
};
dictionary DocumentRegisterOptions {
nsIVariant prototype;
nsIDOMDocumentFragment customTemplate;
nsIVariant lifecycle;
};

View File

@ -47,6 +47,7 @@ XPIDLSRCS = \
nsIDOMUserProximityEvent.idl \
nsIDOMDeviceOrientationEvent.idl \
nsIDOMDeviceMotionEvent.idl \
nsIDOMElementReplaceEvent.idl \
nsIDOMScrollAreaEvent.idl \
nsIDOMTransitionEvent.idl \
nsIDOMAnimationEvent.idl \

View File

@ -0,0 +1,24 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIDOMEvent.idl"
interface nsIDOMElement;
[scriptable, builtinclass, uuid(f57f7c46-d420-4f32-a61b-0eb585d30ee1)]
interface nsIDOMElementReplaceEvent : nsIDOMEvent
{
readonly attribute nsIDOMElement upgrade;
void initElementReplaceEvent(in DOMString typeArg,
in boolean canBubbleArg,
in boolean canCancelArg,
in nsIDOMElement upgrade);
};
dictionary ElementReplaceEventInit : EventInit
{
nsIDOMElement upgrade;
};

View File

@ -27,6 +27,7 @@ DIRS += \
storageevent \
pointerlock \
webapps \
webcomponents \
$(NULL)
#needs IPC support, also tests do not run successfully in Firefox for now

View File

@ -528,7 +528,8 @@ var interfaceNamesInGlobalScope =
"RTCPeerConnection",
"LocalMediaStream",
"CSSConditionRule",
"CSSGroupingRule"
"CSSGroupingRule",
"ElementReplaceEvent"
]
for (var i in SpecialPowers.Components.interfaces) {

View File

@ -0,0 +1,18 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DEPTH = @DEPTH@
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = @relativesrcdir@
include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES = \
test_document_register.html \
test_document_register_lifecycle.html \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,79 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
-->
<head>
<title>Test for document.register using custom prototype</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script>
var gElementUpgraded = false;
var gElementReplaced = false;
function elementUpgrade() {
gElementUpgraded = true;
// Check for prototype on upgraded element.
var documentElement = document.getElementById("grabme");
ok(documentElement.hello, "Upgraded element should inherit 'hello' method from prototype.");
documentElement.hello();
var customChild = document.getElementById("kid");
ok(customChild, "Upgrade should preserve children.");
ok(customChild.parentNode == documentElement, "Parent should be updated to new custom element.");
// Try creating new element and checking for prototype.
var constructedElement = document.createElement("x-hello");
ok(constructedElement.hello, "Created element should inherit 'hello' method from prototype.");
constructedElement.hello();
}
function elementReplace(e) {
gElementReplaced = true;
ok(e.upgrade != e.target, "Upgraded element should be different from the target.");
ok(e.upgrade.firstElementChild.id == "kid", "Upgrade element should have a child.");
ok(e.target.firstElementChild.id == "kid", "Replacement element should have a child.");
}
function startTest() {
var HtmlProto = function() {};
HtmlProto.prototype = HTMLElement.prototype;
// Create a prototype that inheits from HTMLElement.
var customProto = new HtmlProto();
customProto.hello = function() {
ok(true, "Custom element should use provided prototype.");
};
var oldElem = document.getElementById("grabme");
oldElem.addEventListener("elementreplace", elementReplace);
document.addEventListener("elementupgrade", elementUpgrade);
var elementConstructor = document.register("x-hello", { prototype: customProto });
// Try creating new element and checking for prototype.
var constructedElement = new elementConstructor();
ok(constructedElement.hello, "Created element should inherit 'hello' method from prototype.");
constructedElement.hello();
ok(!oldElem.hello, "Element obtained prior to registration should not have inherited prototype.");
ok(gElementUpgraded && gElementReplaced, "Upgrade and replace events should have been fired.");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
<x-hello id="grabme">
<div id="kid"></div>
</x-hello>
</body>
</html>

View File

@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
-->
<head>
<title>Test for document.register lifecycle callback</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script>
var gLifecycleCallbackCalled = false;
var lifecycleCallbacks = {
created: function() {
is(this.getAttribute("id"), "grabme", "|this| value should be the upgrade element");
gLifecycleCallbackCalled = true;
}
};
function startTest() {
var HtmlProto = function() {};
HtmlProto.prototype = HTMLElement.prototype;
// Create a prototype that inheits from HTMLElement.
var customProto = new HtmlProto();
customProto.hello = function() {
ok(true, "Custom element should use provided prototype.");
};
var elementConstructor = document.register("x-hello", { prototype: customProto, lifecycle: lifecycleCallbacks });
ok(gLifecycleCallbackCalled, "Lifecycle callback should be called.");
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="startTest()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
<x-hello id="grabme">
<div id="kid"></div>
</x-hello>
</body>
</html>

View File

@ -14,6 +14,8 @@ dictionaries = [
[ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ],
[ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ],
[ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ],
[ 'DocumentRegisterOptions', 'nsIDOMDocument.idl' ],
[ 'LifecycleCallbacks', 'nsIDOMDocument.idl' ],
[ 'CameraSize', 'nsIDOMCameraManager.idl' ],
[ 'CameraRegion', 'nsIDOMCameraManager.idl' ],
[ 'CameraPosition', 'nsIDOMCameraManager.idl' ],
@ -34,5 +36,6 @@ special_includes = [
# name of the type to not include using #include "typename.h"
exclude_automatic_type_include = [
'nsISupports',
'mozIDOMApplication'
'mozIDOMApplication',
'nsILifecycleCallback'
]

View File

@ -32,6 +32,7 @@ simple_events = [
'MozWifiConnectionInfoEvent',
'MozCellBroadcastEvent',
#endif
'ElementReplaceEvent',
'DeviceStorageChangeEvent',
'PopupBlockedEvent'
]