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

This commit is contained in:
William Chen 2012-11-01 11:18:08 -07:00
Родитель c4b46247ca
Коммит a9e43bd562
24 изменённых файлов: 579 добавлений и 1 удалений

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

@ -474,6 +474,7 @@ user_pref("app.update.staging.enabled", false);
user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
user_pref("dom.w3c_touch_events.enabled", 1);
user_pref("dom.undo_manager.enabled", true);
user_pref("dom.webcomponents.enabled", true);
// Set a future policy version to avoid the telemetry prompt.
user_pref("toolkit.telemetry.prompted", 999);
user_pref("toolkit.telemetry.notifiedOptOut", 999);

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

@ -92,6 +92,7 @@ class DocumentFragment;
class DocumentType;
class DOMImplementation;
class Element;
struct ElementRegistrationOptions;
class GlobalObject;
class HTMLBodyElement;
class Link;
@ -1910,6 +1911,10 @@ public:
{
return GetRootElement();
}
virtual JSObject*
Register(JSContext* aCx, const nsAString& aName,
const mozilla::dom::ElementRegistrationOptions& aOptions,
mozilla::ErrorResult& rv) = 0;
already_AddRefed<nsContentList>
GetElementsByTagName(const nsAString& aTagName)
{

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

@ -34,6 +34,7 @@
#include "nsIDocShellTreeItem.h"
#include "nsIScriptRuntime.h"
#include "nsCOMArray.h"
#include "nsDOMClassInfo.h"
#include "nsGUIEvent.h"
#include "nsAsyncDOMEvent.h"
@ -138,10 +139,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
@ -171,8 +174,10 @@
#include "mozilla/dom/Comment.h"
#include "nsTextNode.h"
#include "mozilla/dom/Link.h"
#include "mozilla/dom/HTMLElementBinding.h"
#include "nsXULAppAPI.h"
#include "nsDOMTouchEvent.h"
#include "DictionaryHelpers.h"
#include "mozilla/Preferences.h"
@ -183,6 +188,7 @@
#include "nsIAppsService.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/DocumentFragment.h"
#include "mozilla/dom/WebComponentsBinding.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/NodeFilterBinding.h"
#include "mozilla/dom/UndoManager.h"
@ -1372,6 +1378,13 @@ nsDocument::~nsDocument()
mInDestructor = true;
mInUnlinkOrDeletion = true;
mCustomPrototypes.Clear();
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();
@ -1478,6 +1491,7 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIInlineEventHandlers)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocumentRegister)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver)
NS_OFFSET_AND_INTERFACE_TABLE_END
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
@ -1716,7 +1730,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
@ -1781,6 +1813,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
tmp->mIdentifierMap.Clear();
tmp->mCustomPrototypes.Clear();
if (tmp->mAnimationController) {
tmp->mAnimationController->Unlink();
}
@ -1805,6 +1839,7 @@ nsDocument::Init()
mIdentifierMap.Init();
mStyledLinks.Init();
mRadioGroups.Init();
mCustomPrototypes.Init();
// Force initialization.
nsINode::nsSlots* slots = Slots();
@ -1841,6 +1876,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;
}
@ -1961,6 +2005,8 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
mInUnlinkOrDeletion = oldVal;
mCachedRootElement = nullptr;
mCustomPrototypes.Clear();
// Reset our stylesheets
ResetStylesheetsToURI(aURI);
@ -4845,6 +4891,205 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
return attribute.forget();
}
static JSBool
CustomElementConstructor(JSContext *aCx, unsigned aArgc, JS::Value* aVp)
{
JS::Value calleeVal = JS_CALLEE(aCx, aVp);
JSObject* global = JS_GetGlobalForObject(aCx, &calleeVal.toObject());
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, calleeVal));
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, newElement, &v);
NS_ENSURE_SUCCESS(rv, false);
JS_SET_RVAL(aCx, aVp, v);
return true;
}
bool
nsDocument::RegisterEnabled()
{
static bool sPrefValue =
Preferences::GetBool("dom.webcomponents.enabled", false);
return sPrefValue;
}
NS_IMETHODIMP
nsDocument::Register(const nsAString& aName, const JS::Value& aOptions,
JSContext* aCx, uint8_t aOptionalArgc,
jsval* aConstructor /* out param */)
{
ElementRegistrationOptions options;
if (aOptionalArgc > 0) {
JSAutoCompartment ac(aCx, GetWrapper());
NS_ENSURE_TRUE(JS_WrapValue(aCx, const_cast<JS::Value*>(&aOptions)),
NS_ERROR_UNEXPECTED);
NS_ENSURE_TRUE(options.Init(aCx, nullptr, aOptions),
NS_ERROR_UNEXPECTED);
}
ErrorResult rv;
JSObject* object = Register(aCx, aName, options, rv);
if (rv.Failed()) {
return rv.ErrorCode();
}
NS_ENSURE_TRUE(object, NS_ERROR_UNEXPECTED);
*aConstructor = OBJECT_TO_JSVAL(object);
return NS_OK;
}
JSObject*
nsDocument::Register(JSContext* aCx, const nsAString& aName,
const ElementRegistrationOptions& aOptions,
ErrorResult& rv)
{
nsAutoString lcName;
nsContentUtils::ASCIIToLower(aName, lcName);
if (!StringBeginsWith(lcName, NS_LITERAL_STRING("x-"))) {
rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
return nullptr;
}
if (NS_FAILED(nsContentUtils::CheckQName(lcName, false))) {
rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
return nullptr;
}
nsIScriptGlobalObject* sgo = GetScopeObject();
if (!sgo) {
rv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
JSObject* global = sgo->GetGlobalJSObject();
JSAutoCompartment ac(aCx, global);
JSObject* htmlProto = HTMLElementBinding::GetProtoObject(aCx, global);
if (!htmlProto) {
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
JSObject* protoObject;
if (!aOptions.mPrototype) {
protoObject = JS_NewObject(aCx, NULL, htmlProto, NULL);
if (!protoObject) {
rv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
} else {
// If a prototype is provided, we must check to ensure that it inherits
// from HTMLElement.
protoObject = aOptions.mPrototype;
if (!JS_WrapObject(aCx, &protoObject)) {
rv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
// Check the proto chain for HTMLElement prototype.
JSObject* protoProto;
if (!JS_GetPrototype(aCx, protoObject, &protoProto)) {
rv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
while (protoProto) {
if (protoProto == htmlProto) {
break;
}
if (!JS_GetPrototype(aCx, protoProto, &protoProto)) {
rv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
}
if (!protoProto) {
rv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
return nullptr;
}
}
// 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++) {
nsCOMPtr<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));
if (rv.Failed()) {
return nullptr;
}
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.");
parentNode->ReplaceChild(*newNode, *oldNode, rv);
if (rv.Failed()) {
return nullptr;
}
// Dispatch elementreplaced to replaced elements.
nsCOMPtr<nsIDOMEvent> event;
rv = CreateEvent(NS_LITERAL_STRING("elementreplace"), getter_AddRefs(event));
if (rv.Failed()) {
return nullptr;
}
if (aOptions.mLifecycle.mCreated) {
// Don't abort the upgrade algorithm if the callback throws an
// exception.
ErrorResult dummy;
aOptions.mLifecycle.mCreated->Call(newElement.get(), dummy);
}
nsCOMPtr<nsIDOMElementReplaceEvent> ptEvent = do_QueryInterface(event);
MOZ_ASSERT(ptEvent);
rv = ptEvent->InitElementReplaceEvent(NS_LITERAL_STRING("elementreplace"),
false, false, newElement);
if (rv.Failed()) {
return nullptr;
}
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);
return constructorObject;
}
NS_IMETHODIMP
nsDocument::GetElementsByTagName(const nsAString& aTagname,
nsIDOMNodeList** aReturn)
@ -7427,6 +7672,8 @@ nsDocument::Destroy()
// tearing down all those frame trees right now is the right thing to do.
mExternalResourceMap.Shutdown();
mCustomPrototypes.Clear();
// XXX We really should let cycle collection do this, but that currently still
// leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
nsContentUtils::ReleaseWrapper(static_cast<nsINode*>(this), this);

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

@ -62,6 +62,7 @@
#include "nsIProgressEventSink.h"
#include "nsISecurityEventSink.h"
#include "nsIChannelEventSink.h"
#include "nsIDocumentRegister.h"
#include "imgIRequest.h"
#include "mozilla/dom/DOMImplementation.h"
#include "nsIDOMTouchEvent.h"
@ -480,6 +481,7 @@ class nsDocument : public nsIDocument,
public nsStubMutationObserver,
public nsIDOMDocumentTouch,
public nsIInlineEventHandlers,
public nsIDocumentRegister,
public nsIObserver
{
public:
@ -779,6 +781,9 @@ public:
// nsIInlineEventHandlers
NS_DECL_NSIINLINEEVENTHANDLERS
// nsIDocumentRegister
NS_DECL_NSIDOCUMENTREGISTER
// nsIObserver
NS_DECL_NSIOBSERVER
@ -1013,9 +1018,22 @@ public:
virtual nsIDOMNode* AsDOMNode() { return this; }
JSObject* GetCustomPrototype(const nsAString& aElementName)
{
JSObject* prototype = nullptr;
mCustomPrototypes.Get(aElementName, &prototype);
return prototype;
}
static bool RegisterEnabled();
// WebIDL bits
virtual mozilla::dom::DOMImplementation*
GetImplementation(mozilla::ErrorResult& rv);
virtual JSObject*
Register(JSContext* aCx, const nsAString& aName,
const mozilla::dom::ElementRegistrationOptions& aOptions,
mozilla::ErrorResult& rv);
virtual nsIDOMStyleSheetList* StyleSheets();
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet);
virtual void GetLastStyleSheetSet(nsString& aSheetSet);
@ -1184,6 +1202,10 @@ protected:
// non-null when this document is in fullscreen mode.
nsWeakPtr mFullscreenRoot;
// Hashtable for custom element prototypes in web components.
// Custom prototypes are in the document's compartment.
nsDataHashtable<nsStringHashKey, JSObject*> mCustomPrototypes;
nsRefPtr<nsEventListenerManager> mListenerManager;
nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;

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

@ -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

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

@ -54,6 +54,7 @@ MOCHITEST_CHROME_FILES = \
test_domparsing.xul \
test_bug814638.xul \
host_bug814638.xul \
test_document_register.xul \
frame_bug814638.xul \
$(NULL)

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

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
-->
<window title="Mozilla Bug 549682"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129"
target="_blank">Mozilla Bug 783129</a>
<iframe onload="startTests()" id="fooframe" src="http://example.com"></iframe>
</body>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
/** Test for Bug 783129 **/
SimpleTest.waitForExplicitFinish();
function startTests() {
var c = $("fooframe").contentDocument.register("x-foo");
var elem = new c();
is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
var anotherElem = $("fooframe").contentDocument.createElement("x-foo");
is(anotherElem.tagName, "X-FOO", "createElement should create an x-foo element.");
SimpleTest.finish();
}
]]></script>
</window>

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

@ -866,6 +866,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);

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

@ -3,6 +3,7 @@
* 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 "nsDocument.h"
#include "HTMLUnknownElement.h"
#include "mozilla/dom/HTMLElementBinding.h"
@ -18,7 +19,19 @@ JSObject*
HTMLUnknownElement::WrapNode(JSContext *aCx, JSObject *aScope,
bool *aTriedToWrap)
{
return HTMLUnknownElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
JSObject* obj =
HTMLUnknownElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
if (obj && Substring(NodeName(), 0, 2).LowerCaseEqualsLiteral("x-")) {
// If we have a registered x-tag then we fix the prototype.
JSAutoCompartment ac(aCx, obj);
nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
JSObject* prototype = document->GetCustomPrototype(LocalName());
if (prototype) {
NS_ENSURE_TRUE(JS_WrapObject(aCx, &prototype), nullptr);
NS_ENSURE_TRUE(JS_SetPrototype(aCx, obj, prototype), nullptr);
}
}
return obj;
}
// QueryInterface implementation for HTMLUnknownElement

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

@ -2044,6 +2044,8 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDocumentRegister,
nsDocument::RegisterEnabled())
DOM_CLASSINFO_DOCUMENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END

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

@ -29,6 +29,7 @@ SDK_XPIDLSRCS = \
nsIDOMNodeList.idl \
nsIDOMProcessingInstruction.idl \
nsIDOMText.idl \
nsIDocumentRegister.idl \
$(NULL)
XPIDLSRCS = \
nsIDOMDOMStringList.idl \

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

@ -0,0 +1,16 @@
/* -*- 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 "nsISupports.idl"
[scriptable, uuid(e35935bd-ebae-4e0d-93bf-efa93ab14c05)]
interface nsIDocumentRegister : nsISupports
{
[optional_argc,
implicit_jscontext] jsval register(in DOMString name,
[optional] in jsval options)
raises(DOMException);
};

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

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

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

@ -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(19a31767-54bf-4044-8769-cd172e37eca2)]
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;
};

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

@ -64,6 +64,7 @@ var interfaceNamesInGlobalScope =
"HTMLOptionElement",
"Pkcs11",
"NotifyAudioAvailableEvent",
"ElementReplaceEvent",
"Array",
"SVGZoomAndPan",
"XULPopupElement",

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

@ -21,6 +21,7 @@ DIRS += [
'storageevent',
'pointerlock',
'webapps',
'webcomponents',
]
#needs IPC support, also tests do not run successfully in Firefox for now

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

@ -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

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

@ -0,0 +1,5 @@
# vim: set filetype=python:
# 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/.

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

@ -0,0 +1,90 @@
<!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() {
// Create a prototype that inheits from HTMLElement.
var customProto = {};
customProto.__proto__ = HTMLElement.prototype;
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.");
// Check that custom elements registered without a prototype inherit from HTMLElement.
document.register("x-bye");
var byeElement = document.createElement("x-bye");
ok(byeElement.__proto__.__proto__, HTMLElement.prototype, "Element registered without prototype should inherit from HTMLElement.");
// Check that element registration with a prototype that does not inherit from HTMLElement results in exception.
try {
document.register("x-foo", { "prototype": {} });
ok(false, "Prototype that does not inherit from HTMLElement should throw exception");
} catch (ex) {
ok(true, "Prototype that does not inherit from HTMLElement should throw exception");
}
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>

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

@ -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>

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

@ -228,6 +228,12 @@ partial interface Document {
void mozExitPointerLock ();
};
//http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-document-register
partial interface Document {
[Throws, Pref="dom.webcomponents.enabled"]
object register(DOMString name, optional ElementRegistrationOptions options);
};
// http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface
partial interface Document {
readonly attribute boolean hidden;

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

@ -0,0 +1,24 @@
/* 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/.
*
* The origin of this IDL file is
* http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface DocumentFragment;
callback LifecycleCreatedCallback = void();
dictionary LifecycleCallbacks {
LifecycleCreatedCallback? created = null;
};
dictionary ElementRegistrationOptions {
object? prototype = null;
LifecycleCallbacks lifecycle;
};

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

@ -217,6 +217,7 @@ webidl_files = \
TreeWalker.webidl \
URL.webidl \
ValidityState.webidl \
WebComponents.webidl \
WebSocket.webidl \
UndoManager.webidl \
URLUtils.webidl \

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

@ -39,6 +39,7 @@ simple_events = [
'MozVoicemailEvent',
'USSDReceivedEvent',
#endif
'ElementReplaceEvent',
'MozSmsEvent',
'DeviceStorageChangeEvent',
'PopupBlockedEvent',