зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1416999 - Remove document.registerElement; r=smaug
MozReview-Commit-ID: HiX07Vbljhk --HG-- rename : dom/base/test/chrome/registerElement_ep.js => dom/base/test/chrome/custom_element_ep.js rename : dom/base/test/chrome/frame_registerElement_content.html => dom/base/test/chrome/frame_custom_element_content.html rename : dom/base/test/chrome/test_registerElement_content.xul => dom/base/test/chrome/test_custom_element_content.xul rename : dom/base/test/chrome/test_registerElement_ep.xul => dom/base/test/chrome/test_custom_element_ep.xul rename : dom/base/test/test_document_register.html => dom/base/test/test_custom_element.html rename : dom/tests/mochitest/webcomponents/test_document_register.html => dom/tests/mochitest/webcomponents/test_custom_element_define.html rename : dom/tests/mochitest/webcomponents/test_document_register_parser.html => dom/tests/mochitest/webcomponents/test_custom_element_define_parser.html rename : dom/tests/mochitest/webcomponents/test_template_custom_elements.html => dom/tests/mochitest/webcomponents/test_custom_element_template.html extra : rebase_source : cd2ebf166e8bd9c49910387c9136d7b83b51598d
This commit is contained in:
Родитель
0a16908b3d
Коммит
9f4324f41e
|
@ -407,19 +407,6 @@ CustomElementRegistry::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType
|
|||
reactionsStack->EnqueueCallbackReaction(aCustomElement, Move(callback));
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::GetCustomPrototype(nsAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> aPrototype)
|
||||
{
|
||||
mozilla::dom::CustomElementDefinition* definition =
|
||||
mCustomDefinitions.GetWeak(aAtom);
|
||||
if (definition) {
|
||||
aPrototype.set(definition->mPrototype);
|
||||
} else {
|
||||
aPrototype.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CustomElementRegistry::UpgradeCandidates(nsAtom* aKey,
|
||||
CustomElementDefinition* aDefinition,
|
||||
|
@ -620,9 +607,9 @@ CustomElementRegistry::Define(const nsAString& aName,
|
|||
*/
|
||||
JSAutoCompartment ac(cx, constructor);
|
||||
JS::Rooted<JS::Value> prototypev(cx);
|
||||
// The .prototype on the constructor passed from document.registerElement
|
||||
// is the "expando" of a wrapper. So we should get it from wrapper instead
|
||||
// instead of underlying object.
|
||||
// The .prototype on the constructor passed could be an "expando" of a
|
||||
// wrapper. So we should get it from wrapper instead of the underlying
|
||||
// object.
|
||||
if (!JS_GetProperty(cx, constructor, "prototype", &prototypev)) {
|
||||
aRv.StealExceptionFromJSContext(cx);
|
||||
return;
|
||||
|
|
|
@ -371,9 +371,6 @@ public:
|
|||
LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs,
|
||||
CustomElementDefinition* aDefinition);
|
||||
|
||||
void GetCustomPrototype(nsAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> aPrototype);
|
||||
|
||||
/**
|
||||
* Upgrade an element.
|
||||
* https://html.spec.whatwg.org/multipage/scripting.html#upgrades
|
||||
|
@ -382,8 +379,7 @@ public:
|
|||
|
||||
/**
|
||||
* Registers an unresolved custom element that is a candidate for
|
||||
* upgrade when the definition is registered via registerElement.
|
||||
* |aTypeName| is the name of the custom element type, if it is not
|
||||
* upgrade. |aTypeName| is the name of the custom element type, if it is not
|
||||
* provided, then element name is used. |aTypeName| should be provided
|
||||
* when registering a custom element that extends an existing
|
||||
* element. e.g. <button is="x-button">.
|
||||
|
@ -420,8 +416,8 @@ private:
|
|||
js::SystemAllocPolicy> ConstructorMap;
|
||||
|
||||
// Hashtable for custom element definitions in web components.
|
||||
// Custom prototypes are stored in the compartment where
|
||||
// registerElement was called.
|
||||
// Custom prototypes are stored in the compartment where definition was
|
||||
// defined.
|
||||
DefinitionMap mCustomDefinitions;
|
||||
|
||||
// Hashtable for looking up definitions by using constructor as key.
|
||||
|
|
|
@ -515,50 +515,11 @@ Element::GetBindingURL(nsIDocument *aDocument, css::URLValue **aResult)
|
|||
JSObject*
|
||||
Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
|
||||
JS::Rooted<JSObject*> customProto(aCx);
|
||||
|
||||
if (!givenProto) {
|
||||
// Custom element prototype swizzling.
|
||||
CustomElementData* data = GetCustomElementData();
|
||||
if (data) {
|
||||
// If this is a registered custom element then fix the prototype.
|
||||
nsContentUtils::GetCustomPrototype(OwnerDoc(), NodeInfo()->NamespaceID(),
|
||||
data->GetCustomElementType(), &customProto);
|
||||
if (customProto &&
|
||||
NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(customProto))) {
|
||||
// The custom element prototype could be in different compartment.
|
||||
if (!JS_WrapObject(aCx, &customProto)) {
|
||||
return nullptr;
|
||||
}
|
||||
// Just go ahead and create with the right proto up front. Set
|
||||
// customProto to null to flag that we don't need to do any post-facto
|
||||
// proto fixups here.
|
||||
givenProto = customProto;
|
||||
customProto = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, givenProto));
|
||||
JS::Rooted<JSObject*> obj(aCx, nsINode::WrapObject(aCx, aGivenProto));
|
||||
if (!obj) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (customProto) {
|
||||
// We want to set the custom prototype in the compartment where it was
|
||||
// registered. In the case that |obj| and |prototype| are in different
|
||||
// compartments, this will set the prototype on the |obj|'s wrapper and
|
||||
// thus only visible in the wrapper's compartment, since we know obj's
|
||||
// principal does not subsume customProto's in this case.
|
||||
JSAutoCompartment ac(aCx, customProto);
|
||||
JS::Rooted<JSObject*> wrappedObj(aCx, obj);
|
||||
if (!JS_WrapObject(aCx, &wrappedObj) ||
|
||||
!JS_SetPrototype(aCx, wrappedObj, customProto)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsIDocument* doc;
|
||||
if (HasFlag(NODE_FORCE_XBL_BINDINGS)) {
|
||||
doc = OwnerDoc();
|
||||
|
|
|
@ -10349,33 +10349,6 @@ nsContentUtils::EnqueueLifecycleCallback(nsIDocument::ElementCallbackType aType,
|
|||
aDefinition);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsContentUtils::GetCustomPrototype(nsIDocument* aDoc,
|
||||
int32_t aNamespaceID,
|
||||
nsAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> aPrototype)
|
||||
{
|
||||
MOZ_ASSERT(aDoc);
|
||||
|
||||
if ((aNamespaceID != kNameSpaceID_XHTML &&
|
||||
aNamespaceID != kNameSpaceID_XUL) ||
|
||||
!aDoc->GetDocShell()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window(aDoc->GetInnerWindow());
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<CustomElementRegistry> registry(window->CustomElements());
|
||||
if (!registry) {
|
||||
return;
|
||||
}
|
||||
|
||||
return registry->GetCustomPrototype(aAtom, aPrototype);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsContentUtils::AttemptLargeAllocationLoad(nsIHttpChannel* aChannel)
|
||||
{
|
||||
|
|
|
@ -700,7 +700,7 @@ public:
|
|||
|
||||
/**
|
||||
* Returns true if |aName| is a valid name to be registered via
|
||||
* document.registerElement.
|
||||
* customElements.define.
|
||||
*/
|
||||
static bool IsCustomElementName(nsAtom* aName);
|
||||
|
||||
|
@ -3059,11 +3059,6 @@ public:
|
|||
mozilla::dom::LifecycleAdoptedCallbackArgs* aAdoptedCallbackArgs = nullptr,
|
||||
mozilla::dom::CustomElementDefinition* aDefinition = nullptr);
|
||||
|
||||
static void GetCustomPrototype(nsIDocument* aDoc,
|
||||
int32_t aNamespaceID,
|
||||
nsAtom* aAtom,
|
||||
JS::MutableHandle<JSObject*> prototype);
|
||||
|
||||
static bool AttemptLargeAllocationLoad(nsIHttpChannel* aChannel);
|
||||
|
||||
/**
|
||||
|
|
|
@ -6015,31 +6015,6 @@ bool IsLowercaseASCII(const nsAString& aValue)
|
|||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::CustomElementRegistry>
|
||||
nsDocument::GetCustomElementRegistry()
|
||||
{
|
||||
nsAutoString contentType;
|
||||
GetContentType(contentType);
|
||||
if (!IsHTMLDocument() &&
|
||||
!contentType.EqualsLiteral("application/xhtml+xml")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window(
|
||||
do_QueryInterface(mScriptGlobalObject ? mScriptGlobalObject
|
||||
: GetScopeObject()));
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<CustomElementRegistry> registry = window->CustomElements();
|
||||
if (!registry) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return registry.forget();
|
||||
}
|
||||
|
||||
// We only support pseudo-elements with two colons in this function.
|
||||
static CSSPseudoElementType
|
||||
GetPseudoElementType(const nsString& aString, ErrorResult& aRv)
|
||||
|
@ -6358,116 +6333,6 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
|
|||
return attribute.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx,
|
||||
JS_GetGlobalForObject(aCx, &args.callee()));
|
||||
RefPtr<nsGlobalWindowInner> window;
|
||||
UNWRAP_OBJECT(Window, global, window);
|
||||
MOZ_ASSERT(window, "Should have a non-null window");
|
||||
|
||||
nsDocument* document = static_cast<nsDocument*>(window->GetDoc());
|
||||
|
||||
// Function name is the type of the custom element.
|
||||
JSString* jsFunName =
|
||||
JS_GetFunctionId(JS_ValueToFunction(aCx, args.calleev()));
|
||||
nsAutoJSString elemName;
|
||||
if (!elemName.init(aCx, jsFunName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<mozilla::dom::CustomElementRegistry> registry = window->CustomElements();
|
||||
if (!registry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<nsAtom> typeAtom(NS_Atomize(elemName));
|
||||
CustomElementDefinition* definition =
|
||||
registry->mCustomDefinitions.GetWeak(typeAtom);
|
||||
if (!definition) {
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<Element> element;
|
||||
|
||||
// We integrate with construction stack and do prototype swizzling here, so
|
||||
// that old upgrade behavior could also share the new upgrade steps.
|
||||
// And this old upgrade will be remove at some point (when everything is
|
||||
// switched to latest custom element spec).
|
||||
nsTArray<RefPtr<Element>>& constructionStack =
|
||||
definition->mConstructionStack;
|
||||
if (constructionStack.Length()) {
|
||||
element = constructionStack.LastElement();
|
||||
NS_ENSURE_TRUE(element != ALEADY_CONSTRUCTED_MARKER, false);
|
||||
|
||||
// Do prototype swizzling if dom reflector exists.
|
||||
JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
|
||||
if (reflector) {
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
JS::Rooted<JSObject*> prototype(aCx, definition->mPrototype);
|
||||
if (element->NodePrincipal()->SubsumesConsideringDomain(nsContentUtils::ObjectPrincipal(prototype))) {
|
||||
ac.emplace(aCx, reflector);
|
||||
if (!JS_WrapObject(aCx, &prototype) ||
|
||||
!JS_SetPrototype(aCx, reflector, prototype)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// We want to set the custom prototype in the compartment where it was
|
||||
// registered. We store the prototype from define() without unwrapped,
|
||||
// hence the prototype's compartment is the compartment where it was
|
||||
// registered.
|
||||
// In the case that |reflector| and |prototype| are in different
|
||||
// compartments, this will set the prototype on the |reflector|'s wrapper
|
||||
// and thus only visible in the wrapper's compartment, since we know
|
||||
// reflector's principal does not subsume prototype's in this case.
|
||||
ac.emplace(aCx, prototype);
|
||||
if (!JS_WrapObject(aCx, &reflector) ||
|
||||
!JS_SetPrototype(aCx, reflector, prototype)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap into current context.
|
||||
if (!JS_WrapObject(aCx, &reflector)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setObject(*reflector);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
RefPtr<mozilla::dom::NodeInfo> nodeInfo =
|
||||
document->NodeInfoManager()->GetNodeInfo(definition->mLocalName, nullptr,
|
||||
kNameSpaceID_XHTML,
|
||||
nsIDOMNode::ELEMENT_NODE);
|
||||
|
||||
int32_t tag = nsHTMLTags::CaseSensitiveAtomTagToId(definition->mLocalName);
|
||||
if (tag == eHTMLTag_userdefined &&
|
||||
nsContentUtils::IsCustomElementName(definition->mType)) {
|
||||
element = NS_NewHTMLElement(nodeInfo.forget(), NOT_FROM_PARSER);
|
||||
} else {
|
||||
element = ::CreateHTMLElement(tag, nodeInfo.forget(), NOT_FROM_PARSER);
|
||||
}
|
||||
|
||||
element->SetCustomElementData(
|
||||
new CustomElementData(definition->mType,
|
||||
CustomElementData::State::eCustom));
|
||||
|
||||
element->SetCustomElementDefinition(definition);
|
||||
|
||||
NS_ENSURE_TRUE(element, false);
|
||||
}
|
||||
|
||||
// The prototype setup happens in Element::WrapObject().
|
||||
nsresult rv = nsContentUtils::WrapNative(aCx, element, element, args.rval());
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::ScheduleSVGForPresAttrEvaluation(nsSVGElement* aSVG)
|
||||
{
|
||||
|
@ -6490,134 +6355,6 @@ nsDocument::ResolveScheduledSVGPresAttrs()
|
|||
mLazySVGPresElements.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType,
|
||||
const ElementRegistrationOptions& aOptions,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
RefPtr<CustomElementRegistry> registry(GetCustomElementRegistry());
|
||||
if (!registry) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
AutoCEReaction ceReaction(this->GetDocGroup()->CustomElementReactionsStack(),
|
||||
aCx);
|
||||
// Unconditionally convert TYPE to lowercase.
|
||||
nsAutoString lcType;
|
||||
nsContentUtils::ASCIIToLower(aType, lcType);
|
||||
|
||||
nsIGlobalObject* sgo = GetScopeObject();
|
||||
if (!sgo) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> global(aCx, sgo->GetGlobalJSObject());
|
||||
JS::Rooted<JSObject*> protoObject(aCx);
|
||||
|
||||
if (!aOptions.mPrototype) {
|
||||
JS::Rooted<JSObject*> htmlProto(aCx);
|
||||
htmlProto = HTMLElementBinding::GetProtoObjectHandle(aCx);
|
||||
if (!htmlProto) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
protoObject = JS_NewObjectWithGivenProto(aCx, nullptr, htmlProto);
|
||||
if (!protoObject) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
protoObject = aOptions.mPrototype;
|
||||
|
||||
// Get the unwrapped prototype to do some checks.
|
||||
JS::Rooted<JSObject*> protoObjectUnwrapped(aCx, js::CheckedUnwrap(protoObject));
|
||||
if (!protoObjectUnwrapped) {
|
||||
// If the caller's compartment does not have permission to access the
|
||||
// unwrapped prototype then throw.
|
||||
rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// If PROTOTYPE is already an interface prototype object for any interface
|
||||
// object or PROTOTYPE has a non-configurable property named constructor,
|
||||
// throw a NotSupportedError and stop.
|
||||
const js::Class* clasp = js::GetObjectClass(protoObjectUnwrapped);
|
||||
if (IsDOMIfaceAndProtoClass(clasp)) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::PropertyDescriptor> descRoot(aCx);
|
||||
JS::MutableHandle<JS::PropertyDescriptor> desc(&descRoot);
|
||||
// This check may go through a wrapper, but as we checked above
|
||||
// it should be transparent or an xray. This should be fine for now,
|
||||
// until the spec is sorted out.
|
||||
if (!JS_GetPropertyDescriptor(aCx, protoObject, "constructor", desc)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!desc.configurable()) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSFunction*> constructor(aCx);
|
||||
{
|
||||
// Go into the document's global compartment when creating the constructor
|
||||
// function because we want to get the correct document (where the
|
||||
// definition is registered) when it is called.
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
|
||||
// Create constructor to return. Store the name of the custom element as the
|
||||
// name of the function.
|
||||
constructor = JS_NewFunction(aCx, nsDocument::CustomElementConstructor, 0,
|
||||
JSFUN_CONSTRUCTOR,
|
||||
NS_ConvertUTF16toUTF8(lcType).get());
|
||||
if (!constructor) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> wrappedConstructor(aCx);
|
||||
wrappedConstructor = JS_GetFunctionObject(constructor);
|
||||
if (!JS_WrapObject(aCx, &wrappedConstructor)) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!JS_LinkConstructorAndPrototype(aCx, wrappedConstructor, protoObject)) {
|
||||
rv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
ElementDefinitionOptions options;
|
||||
if (!aOptions.mExtends.IsVoid()) {
|
||||
// Only convert NAME to lowercase in HTML documents.
|
||||
nsAutoString lcName;
|
||||
IsHTMLDocument() ? nsContentUtils::ASCIIToLower(aOptions.mExtends, lcName)
|
||||
: lcName.Assign(aOptions.mExtends);
|
||||
|
||||
options.mExtends.Construct(lcName);
|
||||
}
|
||||
|
||||
// Note: No calls that might run JS or trigger CC after this, or there's a
|
||||
// (vanishingly small) risk of our constructor being nulled before Define()
|
||||
// can access it.
|
||||
RefPtr<Function> functionConstructor =
|
||||
new Function(aCx, wrappedConstructor, sgo);
|
||||
|
||||
registry->Define(lcType, *functionConstructor, options, rv);
|
||||
|
||||
aRetval.set(wrappedConstructor);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetElementsByTagName(const nsAString& aTagname,
|
||||
nsIDOMNodeList** aReturn)
|
||||
|
|
|
@ -994,11 +994,6 @@ public:
|
|||
// WebIDL bits
|
||||
virtual mozilla::dom::DOMImplementation*
|
||||
GetImplementation(mozilla::ErrorResult& rv) override;
|
||||
virtual void
|
||||
RegisterElement(JSContext* aCx, const nsAString& aName,
|
||||
const mozilla::dom::ElementRegistrationOptions& aOptions,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
mozilla::ErrorResult& rv) override;
|
||||
virtual mozilla::dom::StyleSheetList* StyleSheets() override;
|
||||
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet) override;
|
||||
virtual void GetLastStyleSheetSet(nsString& aSheetSet) override;
|
||||
|
@ -1189,12 +1184,8 @@ protected:
|
|||
mozilla::Maybe<bool> mIsThirdParty;
|
||||
private:
|
||||
void UpdatePossiblyStaleDocumentState();
|
||||
static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
|
||||
|
||||
public:
|
||||
virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
|
||||
GetCustomElementRegistry() override;
|
||||
|
||||
RefPtr<mozilla::EventListenerManager> mListenerManager;
|
||||
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
|
||||
RefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
|
||||
|
|
|
@ -139,7 +139,6 @@ class DOMIntersectionObserver;
|
|||
class DOMStringList;
|
||||
class Element;
|
||||
struct ElementCreationOptions;
|
||||
struct ElementRegistrationOptions;
|
||||
class Event;
|
||||
class EventTarget;
|
||||
class FontFaceSet;
|
||||
|
@ -2861,14 +2860,6 @@ public:
|
|||
|
||||
nsIDocument* GetTopLevelContentDocument();
|
||||
|
||||
virtual void
|
||||
RegisterElement(JSContext* aCx, const nsAString& aName,
|
||||
const mozilla::dom::ElementRegistrationOptions& aOptions,
|
||||
JS::MutableHandle<JSObject*> aRetval,
|
||||
mozilla::ErrorResult& rv) = 0;
|
||||
virtual already_AddRefed<mozilla::dom::CustomElementRegistry>
|
||||
GetCustomElementRegistry() = 0;
|
||||
|
||||
already_AddRefed<nsContentList>
|
||||
GetElementsByTagName(const nsAString& aTagName)
|
||||
{
|
||||
|
|
|
@ -18,8 +18,8 @@ support-files =
|
|||
file_bug1209621.xul
|
||||
fileconstructor_file.png
|
||||
frame_bug814638.xul
|
||||
frame_registerElement_content.html
|
||||
registerElement_ep.js
|
||||
frame_custom_element_content.html
|
||||
custom_element_ep.js
|
||||
host_bug814638.xul
|
||||
window_nsITextInputProcessor.xul
|
||||
title_window.xul
|
||||
|
@ -64,8 +64,8 @@ support-files = ../file_bug357450.js
|
|||
[test_bug1346936.html]
|
||||
[test_cpows.xul]
|
||||
[test_getElementsWithGrid.html]
|
||||
[test_registerElement_content.xul]
|
||||
[test_registerElement_ep.xul]
|
||||
[test_custom_element_content.xul]
|
||||
[test_custom_element_ep.xul]
|
||||
[test_domparsing.xul]
|
||||
[test_fileconstructor.xul]
|
||||
[test_nsITextInputProcessor.xul]
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
class XFoo extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.magicNumber = 42;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
finishTest(this.magicNumber === 42);
|
||||
}
|
||||
};
|
||||
customElements.define("x-foo", XFoo);
|
||||
|
||||
document.firstChild.appendChild(document.createElement("x-foo"));
|
|
@ -1,8 +0,0 @@
|
|||
var proto = Object.create(HTMLElement.prototype);
|
||||
proto.magicNumber = 42;
|
||||
proto.connectedCallback = function() {
|
||||
finishTest(this.magicNumber === 42);
|
||||
};
|
||||
document.registerElement("x-foo", { prototype: proto });
|
||||
|
||||
document.firstChild.appendChild(document.createElement("x-foo"));
|
|
@ -14,7 +14,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
|||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130028"
|
||||
target="_blank">Mozilla Bug 1130028</a>
|
||||
<iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_registerElement_content.html"></iframe>
|
||||
<iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_custom_element_content.html"></iframe>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
|
@ -23,25 +23,29 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
|||
/** Test for Bug 1130028 **/
|
||||
var connectedCallbackCount = 0;
|
||||
|
||||
// Callback should be called only once by element created in content.
|
||||
function connectedCallbackCalled() {
|
||||
connectedCallbackCount++;
|
||||
is(connectedCallbackCount, 1, "Connected callback called, should be called once in test.");
|
||||
is(this.magicNumber, 42, "Callback should be able to see the custom prototype.");
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
var frame = $("frame");
|
||||
|
||||
var c = frame.contentDocument.registerElement("x-foo");
|
||||
var elem = new c();
|
||||
class XFoo extends frame.contentWindow.HTMLElement {};
|
||||
frame.contentWindow.customElements.define("x-foo", XFoo);
|
||||
var elem = new XFoo();
|
||||
is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
|
||||
|
||||
var proto = Object.create(frame.contentWindow.HTMLElement.prototype);
|
||||
proto.magicNumber = 42;
|
||||
proto.connectedCallback = connectedCallbackCalled;
|
||||
class XBar extends frame.contentWindow.HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.magicNumber = 42;
|
||||
}
|
||||
|
||||
frame.contentDocument.registerElement("x-bar", { prototype: proto });
|
||||
connectedCallback() {
|
||||
connectedCallbackCount++;
|
||||
// Callback should be called only once by element created in content.
|
||||
is(connectedCallbackCount, 1, "Connected callback called, should be called once in test.");
|
||||
is(this.magicNumber, 42, "Callback should be able to see the custom prototype.");
|
||||
}
|
||||
};
|
||||
|
||||
frame.contentWindow.customElements.define("x-bar", XBar);
|
||||
is(connectedCallbackCount, 1, "Connected callback should be called by element created in content.");
|
||||
|
||||
var element = frame.contentDocument.createElement("x-bar");
|
|
@ -14,7 +14,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
|||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1130028"
|
||||
target="_blank">Mozilla Bug 1130028</a>
|
||||
<iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_registerElement_content.html"></iframe>
|
||||
<iframe onload="startTests()" id="frame" src="http://example.com/chrome/dom/base/test/chrome/frame_custom_element_content.html"></iframe>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
|
@ -37,7 +37,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1130028
|
|||
// Create a sandbox with an extended principal then run a script that registers a custom element in the sandbox.
|
||||
var sandbox = Components.utils.Sandbox([frame.contentWindow], { sandboxPrototype: frame.contentWindow });
|
||||
sandbox.finishTest = finishTest;
|
||||
Services.scriptloader.loadSubScript("chrome://mochitests/content/chrome/dom/base/test/chrome/registerElement_ep.js", sandbox);
|
||||
Services.scriptloader.loadSubScript("chrome://mochitests/content/chrome/dom/base/test/chrome/custom_element_ep.js", sandbox);
|
||||
}
|
||||
|
||||
]]></script>
|
|
@ -635,7 +635,7 @@ skip-if = toolkit == 'android' #bug 904183
|
|||
[test_document.all_unqualified.html]
|
||||
[test_document_constructor.html]
|
||||
[test_document_importNode_document.html]
|
||||
[test_document_register.html]
|
||||
[test_custom_element.html]
|
||||
[test_domcursor.html]
|
||||
[test_domparser_null_char.html]
|
||||
[test_domparsing.html]
|
||||
|
|
|
@ -13,8 +13,10 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function startTests() {
|
||||
var c = document.getElementById("fooframe").contentDocument.registerElement("x-foo");
|
||||
var elem = new c();
|
||||
var frame = document.getElementById("fooframe");
|
||||
class XFoo extends frame.contentWindow.HTMLElement {};
|
||||
frame.contentWindow.customElements.define("x-foo", XFoo);
|
||||
var elem = new XFoo();
|
||||
is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
|
||||
|
||||
var anotherElem = $("fooframe").contentDocument.createElement("x-foo");
|
|
@ -570,7 +570,6 @@ support-files = file_cookiemanager.js
|
|||
[test_bug871161.html]
|
||||
support-files = file_bug871161-1.html file_bug871161-2.html
|
||||
[test_bug1013316.html]
|
||||
[test_bug1081037.html]
|
||||
[test_window_open_close.html]
|
||||
tags = openwindow
|
||||
[test_viewport_resize.html]
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1081037
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1081037</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1081037 **/
|
||||
|
||||
function shouldThrow(fun, msg, ex, todo) {
|
||||
try {
|
||||
fun();
|
||||
ok(todo, msg);
|
||||
} catch (e) {
|
||||
ok(new RegExp(ex).test(e), msg + " (thrown:" + e + ")")
|
||||
}
|
||||
}
|
||||
|
||||
var Foo = document.registerElement('x-foo', {
|
||||
prototype: {bar: 5}
|
||||
});
|
||||
|
||||
Foo.prototype.bar = 6;
|
||||
var foo = new Foo();
|
||||
is(foo.bar, 6, "prototype of the ctor returned from registerElement works");
|
||||
|
||||
var protoDesc = Object.getOwnPropertyDescriptor(Foo, "prototype");
|
||||
is(protoDesc.configurable, false, "proto should be non-configurable");
|
||||
is(protoDesc.enumerable, false, "proto should be non-enumerable");
|
||||
is(protoDesc.writable, false, "proto should be non-writable");
|
||||
|
||||
// TODO: FIXME!
|
||||
shouldThrow(function() {
|
||||
document.registerElement('x-foo2', {
|
||||
prototype: Foo.prototype
|
||||
});
|
||||
},
|
||||
"if proto is an interface prototype object, registerElement should throw",
|
||||
"not supported",
|
||||
/* todo = */ true);
|
||||
|
||||
var nonConfigReadonlyProto = Object.create(HTMLElement.prototype,
|
||||
{ constructor: { configurable: false, writable: false, value: 42 } });
|
||||
|
||||
shouldThrow(function() {
|
||||
document.registerElement('x-nonconfig-readonly', {
|
||||
prototype: nonConfigReadonlyProto
|
||||
});
|
||||
},
|
||||
"non-configurable and not-writable constructor property",
|
||||
"not supported");
|
||||
|
||||
|
||||
// this is not defined in current spec:
|
||||
var readonlyProto = Object.create(HTMLElement.prototype,
|
||||
{ constructor: { configurable: true, writable: false, value: 42 } });
|
||||
|
||||
var Readonly = document.registerElement('x-nonconfig-readonly', {
|
||||
prototype: readonlyProto
|
||||
});
|
||||
|
||||
is(Readonly.prototype, readonlyProto, "configurable readonly constructor property");
|
||||
|
||||
var handler = {
|
||||
getOwnPropertyDescriptor: function(target, name) {
|
||||
return name == "constructor" ? undefined : Object.getOwnPropertyDescriptor(target,name);
|
||||
},
|
||||
defineProperty: function(target, name, propertyDescriptor) {
|
||||
if (name == "constructor") {
|
||||
throw "spec this";
|
||||
}
|
||||
|
||||
return Object.defineProperty(target, name, propertyDescriptor);
|
||||
},
|
||||
has: function(target, name) {
|
||||
if (name == "constructor") {
|
||||
return false;
|
||||
}
|
||||
return name in target;
|
||||
}
|
||||
};
|
||||
var proxy = new Proxy({}, handler);
|
||||
|
||||
shouldThrow(function() {
|
||||
document.registerElement('x-proxymagic', {
|
||||
prototype: proxy
|
||||
});
|
||||
},
|
||||
"proxy magic",
|
||||
"spec this");
|
||||
|
||||
var getOwn = 0;
|
||||
var defineProp = 0;
|
||||
var handler2 = {
|
||||
getOwnPropertyDescriptor: function(target, name) {
|
||||
if (name == "constructor") {
|
||||
getOwn++;
|
||||
}
|
||||
return Object.getOwnPropertyDescriptor(target,name);
|
||||
},
|
||||
defineProperty: function(target, name, propertyDescriptor) {
|
||||
if (name == "constructor") {
|
||||
defineProp++;
|
||||
}
|
||||
return Object.defineProperty(target, name, propertyDescriptor);
|
||||
}
|
||||
};
|
||||
var proxy2 = new Proxy({}, handler2);
|
||||
|
||||
document.registerElement('x-proxymagic2', {
|
||||
prototype: proxy2
|
||||
});
|
||||
|
||||
is(getOwn, 1, "number of getOwnPropertyDescriptor calls from registerElement: " + getOwn);
|
||||
is(defineProp, 1, "number of defineProperty calls from registerElement: " + defineProp);
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081037">Mozilla Bug 1081037</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -16,7 +16,6 @@ support-files =
|
|||
htmlconstructor_autonomous_tests.js
|
||||
htmlconstructor_builtin_tests.js
|
||||
[test_custom_element_in_shadow.html]
|
||||
[test_custom_element_register_invalid_callbacks.html]
|
||||
[test_custom_element_throw_on_dynamic_markup_insertion.html]
|
||||
[test_custom_element_get.html]
|
||||
[test_custom_element_when_defined.html]
|
||||
|
@ -28,6 +27,9 @@ support-files =
|
|||
upgrade_tests.js
|
||||
[test_custom_element_lifecycle.html]
|
||||
[test_custom_element_stack.html]
|
||||
[test_custom_element_define.html]
|
||||
[test_custom_element_define_parser.html]
|
||||
[test_custom_element_template.html]
|
||||
[test_nested_content_element.html]
|
||||
[test_dest_insertion_points.html]
|
||||
[test_fallback_dest_insertion_points.html]
|
||||
|
@ -35,14 +37,10 @@ support-files =
|
|||
[test_dynamic_content_element_matching.html]
|
||||
[test_document_adoptnode.html]
|
||||
[test_document_importnode.html]
|
||||
[test_document_register.html]
|
||||
[test_document_register_parser.html]
|
||||
[test_document_shared_registry.html]
|
||||
[test_event_retarget.html]
|
||||
[test_event_stopping.html]
|
||||
[test_template.html]
|
||||
[test_template_xhtml.html]
|
||||
[test_template_custom_elements.html]
|
||||
[test_shadowroot.html]
|
||||
[test_shadowroot_inert_element.html]
|
||||
[test_shadowroot_style.html]
|
||||
|
|
|
@ -18,19 +18,19 @@ SimpleTest.waitForExplicitFinish();
|
|||
|
||||
var connectedCallbackCount = 0;
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
|
||||
p.connectedCallback = function() {
|
||||
ok(true, "connectedCallback should be called when the parser creates an element in the document.");
|
||||
connectedCallbackCount++;
|
||||
// connectedCallback should be called twice, once for the element created for innerHTML and
|
||||
// once for the element created in this document.
|
||||
if (connectedCallbackCount == 2) {
|
||||
SimpleTest.finish();
|
||||
class Foo extends HTMLElement {
|
||||
connectedCallback() {
|
||||
ok(true, "connectedCallback should be called when the parser creates an element in the document.");
|
||||
connectedCallbackCount++;
|
||||
// connectedCallback should be called twice, once for the element created for innerHTML and
|
||||
// once for the element created in this document.
|
||||
if (connectedCallbackCount == 2) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-foo", { prototype: p });
|
||||
customElements.define("x-foo", Foo);
|
||||
|
||||
var container = document.getElementById("container");
|
||||
container.innerHTML = '<x-foo></x-foo>';
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test for customElements.define</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
|
||||
<div>
|
||||
<x-unresolved id="unresolved"></x-unresolved>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
function testDefineExtend(tag, extend, definition, expectException) {
|
||||
try {
|
||||
customElements.define(tag, definition, { extends: extend });
|
||||
ok(!expectException, "Defined " + tag + " extending " + extend + ".");
|
||||
} catch (ex) {
|
||||
ok(expectException, "Did not define " + tag + " extending " + extend + ".");
|
||||
}
|
||||
}
|
||||
|
||||
function testDefineSimple(tag, definition, expectException) {
|
||||
try {
|
||||
customElements.define(tag, definition);
|
||||
ok(!expectException, "Defined " + tag + " extending HTMLElement.");
|
||||
} catch (ex) {
|
||||
ok(expectException, "Did not define " + tag + " extending HTMLElement.");
|
||||
}
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
// Test defining some simple definition.
|
||||
testDefineSimple("x-html-obj-elem", class extends HTMLElement {}, false);
|
||||
testDefineSimple("x-html-obj-p", class extends HTMLParagraphElement {}, false);
|
||||
|
||||
// Make sure the prototype on unresolved elements is HTMLElement not HTMLUnknownElement.
|
||||
var unresolved = document.getElementById("unresolved");
|
||||
is(unresolved.__proto__, HTMLElement.prototype, "Unresolved custom elements should have HTMLElement as prototype.");
|
||||
|
||||
var anotherUnresolved = document.createElement("maybe-custom-element");
|
||||
is(anotherUnresolved.__proto__, HTMLElement.prototype, "Unresolved custom elements should have HTMLElement as prototype.");
|
||||
|
||||
// Test defining some invalid definition.
|
||||
testDefineSimple("x-invalid-number", 42, true);
|
||||
testDefineSimple("x-invalid-boolean", false, true);
|
||||
testDefineSimple("x-invalid-float", 1.0, true);
|
||||
|
||||
// Test invalid custom element names.
|
||||
testDefineSimple("invalid", class extends HTMLElement {}, true);
|
||||
testDefineSimple("annotation-xml", class extends HTMLElement {}, true);
|
||||
testDefineSimple("color-profile", class extends HTMLElement {}, true);
|
||||
testDefineSimple("font-face", class extends HTMLElement {}, true);
|
||||
testDefineSimple("font-face-src", class extends HTMLElement {}, true);
|
||||
testDefineSimple("font-face-uri", class extends HTMLElement {}, true);
|
||||
testDefineSimple("font-face-format", class extends HTMLElement {}, true);
|
||||
testDefineSimple("font-face-name", class extends HTMLElement {}, true);
|
||||
testDefineSimple("missing-glyph", class extends HTMLElement {}, true);
|
||||
|
||||
// Test defining elements that extend from an existing element.
|
||||
testDefineExtend("x-extend-span", "span", class extends HTMLElement {}, false);
|
||||
testDefineExtend("x-extend-span-caps", "SPAN", class extends HTMLElement {}, true);
|
||||
|
||||
// Test defining elements that extend from a non-existing element.
|
||||
testDefineExtend("x-extend-span-nonexist", "nonexisting", class extends HTMLElement {}, true);
|
||||
|
||||
// Test registration with duplicate type.
|
||||
testDefineSimple("x-dupe-me", class extends HTMLElement {}, false);
|
||||
testDefineSimple("x-dupe-me", class extends HTMLElement {}, true);
|
||||
testDefineSimple("X-DUPE-ME", class extends HTMLElement {}, true);
|
||||
testDefineExtend("x-dupe-me", "span", class extends HTMLElement {}, true);
|
||||
|
||||
// customElements.define with extended type.
|
||||
class ExtendButton extends HTMLButtonElement {};
|
||||
customElements.define("x-extended-button", ExtendButton, { extends: "button" });
|
||||
var extendedButton = document.createElement("button", {is: "x-extended-button"});
|
||||
is(extendedButton.tagName, "BUTTON", "Created element should have local name of BUTTON");
|
||||
is(extendedButton.__proto__, ExtendButton.prototype, "Created element should have the prototype of the extended type.");
|
||||
is(extendedButton.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type.");
|
||||
is(extendedButton.type, "submit", "Created element should be a button with type of \"submit\"");
|
||||
|
||||
// Custom element constructor.
|
||||
var constructedButton = new ExtendButton();
|
||||
is(constructedButton.tagName, "BUTTON", "Created element should have local name of BUTTON");
|
||||
is(constructedButton.__proto__, ExtendButton.prototype, "Created element should have the prototype of the extended type.");
|
||||
|
||||
// Try creating an element with a custom element name, but not in the html namespace.
|
||||
class XInHTMLNamespace extends HTMLElement {};
|
||||
customElements.define("x-in-html-namespace", XInHTMLNamespace);
|
||||
var wrongNamespaceElem = document.createElementNS("http://www.w3.org/2000/svg", "x-in-html-namespace");
|
||||
isnot(wrongNamespaceElem.__proto__, XInHTMLNamespace.prototype, "Definition for element in html namespace should not apply to SVG elements.");
|
||||
}
|
||||
|
||||
startTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,61 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test for customElements.define for elements created by the parser</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script>
|
||||
|
||||
var uncaughtError;
|
||||
window.onerror = function(message, url, lineNumber, columnNumber, error) {
|
||||
uncaughtError = error;
|
||||
};
|
||||
|
||||
var isConnectedCallbackCalled = false;
|
||||
class XButton extends HTMLButtonElement {
|
||||
connectedCallback() {
|
||||
ok(!isConnectedCallbackCalled, "ConnectedCallback should only be called once.");
|
||||
is(this.tagName, "BUTTON", "Only the <button> element should be upgraded.");
|
||||
isConnectedCallbackCalled = true;
|
||||
}
|
||||
};
|
||||
|
||||
customElements.define("x-button", XButton, { extends: "button" });
|
||||
|
||||
class XDiv extends HTMLDivElement {
|
||||
constructor() {
|
||||
// Queue a task to check error and callbacks.
|
||||
setTimeout(() => {
|
||||
ok(isConnectedCallbackCalled, "ConnectedCallback should be called.");
|
||||
ok(uncaughtError instanceof TypeError,
|
||||
"TypeError should be filed for upgrading <x-div> element.");
|
||||
SimpleTest.finish();
|
||||
}, 0);
|
||||
super();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
ok(false, "Connected callback for x-div should not be called.");
|
||||
}
|
||||
};
|
||||
|
||||
customElements.define("x-div", XDiv);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
|
||||
<button is="x-button"></button><!-- should be upgraded -->
|
||||
<x-button></x-button><!-- should not be upgraded -->
|
||||
<span is="x-button"></span><!-- should not be upgraded -->
|
||||
<div is="x-div"></div><!-- should not be upgraded -->
|
||||
<x-div></x-div><!-- should be upgraded, but failed -->
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -105,13 +105,13 @@ attributeChangedCallbackCount = 0;
|
|||
shadow = container.shadowRoot;
|
||||
shadow.innerHTML = "<x-bar></x-bar>";
|
||||
|
||||
var p2 = Object.create(HTMLElement.prototype);
|
||||
|
||||
p2.connectedCallback = function() {
|
||||
connectedCallbackCount++;
|
||||
class Bar extends HTMLElement {
|
||||
connectedCallback() {
|
||||
connectedCallbackCount++;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-bar", { prototype: p2 });
|
||||
customElements.define("x-bar", Bar);
|
||||
is(connectedCallbackCount, 1, "connectedCallback should be called after upgrading element in composed document.");
|
||||
|
||||
</script>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test for document.registerElement lifecycle callback</title>
|
||||
<title>Test for custom elements lifecycle callback</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
@ -18,67 +18,69 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
|||
|
||||
var container = document.getElementById("container");
|
||||
|
||||
// Tests callbacks after registering element type that is already in the document.
|
||||
// create element in document -> register -> remove from document
|
||||
// Tests callbacks after defining element type that is already in the document.
|
||||
// create element in document -> define -> remove from document
|
||||
function testRegisterUnresolved() {
|
||||
var helloElem = document.getElementById("hello");
|
||||
|
||||
var connectedCallbackCalled = false;
|
||||
var disconnectedCallbackCalled = false;
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
p.connectedCallback = function() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
is(this, helloElem, "The 'this' value should be the custom element.");
|
||||
connectedCallbackCalled = true;
|
||||
class Hello extends HTMLElement {
|
||||
connectedCallback() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
is(this, helloElem, "The 'this' value should be the custom element.");
|
||||
connectedCallbackCalled = true;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called before detached");
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
|
||||
disconnectedCallbackCalled = true;
|
||||
is(this, helloElem, "The 'this' value should be the custom element.");
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
ok(false, "attributeChanged callback should never be called in this test.");
|
||||
}
|
||||
};
|
||||
|
||||
p.disconnectedCallback = function() {
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called before detached");
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
|
||||
disconnectedCallbackCalled = true;
|
||||
is(this, helloElem, "The 'this' value should be the custom element.");
|
||||
runNextTest();
|
||||
};
|
||||
|
||||
p.attributeChangedCallback = function(name, oldValue, newValue) {
|
||||
ok(false, "attributeChanged callback should never be called in this test.");
|
||||
};
|
||||
|
||||
document.registerElement("x-hello", { prototype: p });
|
||||
customElements.define("x-hello", Hello);
|
||||
|
||||
// Remove element from document to trigger disconnected callback.
|
||||
container.removeChild(helloElem);
|
||||
}
|
||||
|
||||
// Tests callbacks after registering an extended element type that is already in the document.
|
||||
// create element in document -> register -> remove from document
|
||||
// Tests callbacks after defining an extended element type that is already in the document.
|
||||
// create element in document -> define -> remove from document
|
||||
function testRegisterUnresolvedExtended() {
|
||||
var buttonElem = document.getElementById("extbutton");
|
||||
|
||||
var connectedCallbackCalled = false;
|
||||
var disconnectedCallbackCalled = false;
|
||||
|
||||
var p = Object.create(HTMLButtonElement.prototype);
|
||||
p.connectedCallback = function() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
is(this, buttonElem, "The 'this' value should be the custom element.");
|
||||
connectedCallbackCalled = true;
|
||||
class XButton extends HTMLButtonElement {
|
||||
connectedCallback() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
is(this, buttonElem, "The 'this' value should be the custom element.");
|
||||
connectedCallbackCalled = true;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called before detached");
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
|
||||
disconnectedCallbackCalled = true;
|
||||
is(this, buttonElem, "The 'this' value should be the custom element.");
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
ok(false, "attributeChanged callback should never be called in this test.");
|
||||
}
|
||||
};
|
||||
|
||||
p.disconnectedCallback = function() {
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called before detached");
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
|
||||
disconnectedCallbackCalled = true;
|
||||
is(this, buttonElem, "The 'this' value should be the custom element.");
|
||||
runNextTest();
|
||||
};
|
||||
|
||||
p.attributeChangedCallback = function(name, oldValue, newValue) {
|
||||
ok(false, "attributeChanged callback should never be called in this test.");
|
||||
};
|
||||
|
||||
document.registerElement("x-button", { prototype: p, extends: "button" });
|
||||
customElements.define("x-button", XButton, { extends: "button" });
|
||||
|
||||
// Remove element from document to trigger disconnected callback.
|
||||
container.removeChild(buttonElem);
|
||||
|
@ -87,13 +89,14 @@ function testRegisterUnresolvedExtended() {
|
|||
function testInnerHTML() {
|
||||
var connectedCallbackCalled = false;
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
p.connectedCallback = function() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
class XInnerHTML extends HTMLElement {
|
||||
connectedCallback() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-inner-html", { prototype: p });
|
||||
customElements.define("x-inner-html", XInnerHTML);
|
||||
var div = document.createElement(div);
|
||||
document.documentElement.appendChild(div);
|
||||
div.innerHTML = '<x-inner-html></x-inner-html>';
|
||||
|
@ -104,13 +107,14 @@ function testInnerHTML() {
|
|||
function testInnerHTMLExtended() {
|
||||
var connectedCallbackCalled = false;
|
||||
|
||||
var p = Object.create(HTMLButtonElement.prototype);
|
||||
p.connectedCallback = function() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
class XInnerHTMLExtend extends HTMLButtonElement {
|
||||
connectedCallback() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-inner-html-extended", { prototype: p, extends: "button" });
|
||||
customElements.define("x-inner-html-extended", XInnerHTMLExtend, { extends: "button" });
|
||||
var div = document.createElement(div);
|
||||
document.documentElement.appendChild(div);
|
||||
div.innerHTML = '<button is="x-inner-html-extended"></button>';
|
||||
|
@ -125,13 +129,14 @@ function testInnerHTMLUpgrade() {
|
|||
document.documentElement.appendChild(div);
|
||||
div.innerHTML = '<x-inner-html-upgrade></x-inner-html-upgrade>';
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
p.connectedCallback = function() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
class XInnerHTMLUpgrade extends HTMLElement {
|
||||
connectedCallback() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-inner-html-upgrade", { prototype: p });
|
||||
customElements.define("x-inner-html-upgrade", XInnerHTMLUpgrade);
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called after registering.");
|
||||
runNextTest();
|
||||
}
|
||||
|
@ -143,46 +148,48 @@ function testInnerHTMLExtendedUpgrade() {
|
|||
document.documentElement.appendChild(div);
|
||||
div.innerHTML = '<button is="x-inner-html-extended-upgrade"></button>';
|
||||
|
||||
var p = Object.create(HTMLButtonElement.prototype);
|
||||
p.connectedCallback = function() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
class XInnerHTMLExtnedUpgrade extends HTMLButtonElement {
|
||||
connectedCallback() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-inner-html-extended-upgrade", { prototype: p, extends: "button" });
|
||||
customElements.define("x-inner-html-extended-upgrade", XInnerHTMLExtnedUpgrade, { extends: "button" });
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called after registering.");
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
// Test callback when creating element after registering an element type.
|
||||
// register -> create element -> insert into document -> remove from document
|
||||
// Test callback when creating element after defining an element type.
|
||||
// define -> create element -> insert into document -> remove from document
|
||||
function testRegisterResolved() {
|
||||
var connectedCallbackCalled = false;
|
||||
var disconnectedCallbackCalled = false;
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
p.connectedCallback = function() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called on in this test.");
|
||||
is(this, createdElement, "The 'this' value should be the custom element.");
|
||||
connectedCallbackCalled = true;
|
||||
class Resolved extends HTMLElement {
|
||||
connectedCallback() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called on in this test.");
|
||||
is(this, createdElement, "The 'this' value should be the custom element.");
|
||||
connectedCallbackCalled = true;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called before detached");
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
|
||||
is(this, createdElement, "The 'this' value should be the custom element.");
|
||||
disconnectedCallbackCalled = true;
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
attributeChangedCallback() {
|
||||
ok(false, "attributeChanged callback should never be called in this test.");
|
||||
}
|
||||
};
|
||||
|
||||
p.disconnectedCallback = function() {
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called before detached");
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
|
||||
is(this, createdElement, "The 'this' value should be the custom element.");
|
||||
disconnectedCallbackCalled = true;
|
||||
runNextTest();
|
||||
};
|
||||
|
||||
p.attributeChangedCallback = function() {
|
||||
ok(false, "attributeChanged callback should never be called in this test.");
|
||||
};
|
||||
|
||||
document.registerElement("x-resolved", { prototype: p });
|
||||
customElements.define("x-resolved", Resolved);
|
||||
|
||||
var createdElement = document.createElement("x-resolved");
|
||||
is(createdElement.__proto__, p, "Prototype of custom element should be the registered prototype.");
|
||||
is(createdElement.__proto__, Resolved.prototype, "Prototype of custom element should be the defined prototype.");
|
||||
|
||||
// Insert element into document to trigger attached callback.
|
||||
container.appendChild(createdElement);
|
||||
|
@ -298,19 +305,19 @@ function testUpgradeCandidate() {
|
|||
}
|
||||
|
||||
function testNotInDocEnterLeave() {
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
class DestinedForFragment extends HTMLElement {
|
||||
connectedCallback() {
|
||||
ok(false, "Connected callback should not be called.");
|
||||
}
|
||||
|
||||
p.attached = function() {
|
||||
ok(false, "attached should not be called when not entering the document.");
|
||||
};
|
||||
|
||||
p.detached = function() {
|
||||
ok(false, "leaveView should not be called when not leaving the document.");
|
||||
disconnectedCallback() {
|
||||
ok(false, "Disconnected callback should not be called.");
|
||||
}
|
||||
};
|
||||
|
||||
var createdElement = document.createElement("x-destined-for-fragment");
|
||||
|
||||
document.registerElement("x-destined-for-fragment", { prototype: p });
|
||||
customElements.define("x-destined-for-fragment", DestinedForFragment);
|
||||
|
||||
var fragment = new DocumentFragment();
|
||||
fragment.appendChild(createdElement);
|
||||
|
@ -327,21 +334,22 @@ function testEnterLeaveView() {
|
|||
var connectedCallbackCalled = false;
|
||||
var disconnectedCallbackCalled = false;
|
||||
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
p.connectedCallback = function() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called on in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
};
|
||||
class ElementInDiv extends HTMLElement {
|
||||
connectedCallback() {
|
||||
is(connectedCallbackCalled, false, "Connected callback should only be called on in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
}
|
||||
|
||||
p.disconnectedCallback = function() {
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called before detached");
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
|
||||
disconnectedCallbackCalled = true;
|
||||
runNextTest();
|
||||
disconnectedCallback() {
|
||||
is(connectedCallbackCalled, true, "Connected callback should be called before detached");
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should only be called once in this test.");
|
||||
disconnectedCallbackCalled = true;
|
||||
runNextTest();
|
||||
}
|
||||
};
|
||||
|
||||
var div = document.createElement("div");
|
||||
document.registerElement("x-element-in-div", { prototype: p });
|
||||
customElements.define("x-element-in-div", ElementInDiv);
|
||||
var customElement = document.createElement("x-element-in-div");
|
||||
div.appendChild(customElement);
|
||||
is(connectedCallbackCalled, false, "Appending a custom element to a node that is not in the document should not call the connected callback.");
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1275835
|
||||
-->
|
||||
<head>
|
||||
<title>Test registering invalid lifecycle callbacks for custom elements.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1275835">Bug 1275835</a>
|
||||
<iframe id="iframe"></iframe>
|
||||
<script>
|
||||
|
||||
// Use window from iframe to isolate the test.
|
||||
const testWindow = iframe.contentDocument.defaultView;
|
||||
|
||||
// This is for backward compatibility.
|
||||
// We should do the same checks for the callbacks from v0 spec.
|
||||
[
|
||||
'attributeChangedCallback',
|
||||
].forEach(callback => {
|
||||
var c = class {};
|
||||
var p = c.prototype;
|
||||
|
||||
// Test getting callback throws exception.
|
||||
Object.defineProperty(p, callback, {
|
||||
get() {
|
||||
const e = new Error('this is rethrown');
|
||||
e.name = 'rethrown';
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
SimpleTest.doesThrow(() => {
|
||||
testWindow.document.registerElement(`test-register-${callback}-rethrown`,
|
||||
{ prototype: p });
|
||||
}, `document.registerElement should throw exception if prototype.${callback} throws`);
|
||||
|
||||
SimpleTest.doesThrow(() => {
|
||||
testWindow.customElements.define(`test-define-${callback}-rethrown`, c);
|
||||
}, `customElements.define should throw exception if constructor.${callback} throws`);
|
||||
|
||||
// Test callback is not callable.
|
||||
[
|
||||
{ name: 'null', value: null },
|
||||
{ name: 'object', value: {} },
|
||||
{ name: 'integer', value: 1 },
|
||||
].forEach(data => {
|
||||
var c = class {};
|
||||
var p = c.prototype;
|
||||
|
||||
p[callback] = data.value;
|
||||
|
||||
SimpleTest.doesThrow(() => {
|
||||
testWindow.document.registerElement(`test-register-${callback}-${data.name}`,
|
||||
{ prototype: p });
|
||||
}, `document.registerElement should throw exception if ${callback} is ${data.name}`);
|
||||
|
||||
SimpleTest.doesThrow(() => {
|
||||
testWindow.customElements.define(`test-define-${callback}-${data.name}`, c);
|
||||
}, `customElements.define should throw exception if ${callback} is ${data.name}`);
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -4,7 +4,7 @@
|
|||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test for document.registerElement lifecycle callback</title>
|
||||
<title>Test for custom elements lifecycle callback</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
@ -50,28 +50,29 @@ function testChangeAttributeInEnteredViewCallback() {
|
|||
}
|
||||
|
||||
function testLeaveViewInEnteredViewCallback() {
|
||||
var p = Object.create(HTMLElement.prototype);
|
||||
var connectedCallbackCalled = false;
|
||||
var disconnectedCallbackCalled = false;
|
||||
var container = document.getElementById("container");
|
||||
|
||||
p.connectedCallback = function() {
|
||||
is(this.parentNode, container, "Parent node should the container in which the node was appended.");
|
||||
is(connectedCallbackCalled, false, "Connected callback should be called only once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should not be called prior to removing element from document.");
|
||||
container.removeChild(this);
|
||||
is(disconnectedCallbackCalled, true, "Transition from user-agent implementation to script should run left view callback.");
|
||||
runNextTest();
|
||||
class Three extends HTMLElement {
|
||||
connectedCallback() {
|
||||
is(this.parentNode, container, "Parent node should the container in which the node was appended.");
|
||||
is(connectedCallbackCalled, false, "Connected callback should be called only once in this test.");
|
||||
connectedCallbackCalled = true;
|
||||
is(disconnectedCallbackCalled, false, "Disconnected callback should not be called prior to removing element from document.");
|
||||
container.removeChild(this);
|
||||
is(disconnectedCallbackCalled, true, "Transition from user-agent implementation to script should run left view callback.");
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
is(disconnectedCallbackCalled, false, "The disconnected callback should only be called once in this test.");
|
||||
is(connectedCallbackCalled, true, "The connected callback should be called prior to disconnected callback.");
|
||||
disconnectedCallbackCalled = true;
|
||||
}
|
||||
};
|
||||
|
||||
p.disconnectedCallback = function() {
|
||||
is(disconnectedCallbackCalled, false, "The disconnected callback should only be called once in this test.");
|
||||
is(connectedCallbackCalled, true, "The connected callback should be called prior to disconnected callback.");
|
||||
disconnectedCallbackCalled = true;
|
||||
};
|
||||
|
||||
document.registerElement("x-three", { prototype: p });
|
||||
customElements.define("x-three", Three);
|
||||
var elem = document.createElement("x-three");
|
||||
|
||||
container.appendChild(elem);
|
||||
|
|
|
@ -15,14 +15,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1091425
|
|||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1091425">Bug 1091425</a>
|
||||
<script>
|
||||
|
||||
var p = {};
|
||||
p.createdCallback = function() {
|
||||
ok(false, "Created callback should not be called for custom elements in templates.");
|
||||
class XFoo extends HTMLElement {
|
||||
connectedCallback() {
|
||||
ok(false, "Connected callback should not be called for custom elements in templates.");
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement("x-foo", { prototype: p });
|
||||
customElements.define("x-foo", XFoo);
|
||||
|
||||
ok(true, "Created callback should not be called for custom elements in templates.");
|
||||
ok(true, "Connected callback should not be called for custom elements in templates.");
|
||||
|
||||
</script>
|
||||
<template>
|
|
@ -1,122 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test for document.registerElement 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" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
|
||||
<div>
|
||||
<x-unresolved id="unresolved"></x-unresolved>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
function testRegisterExtend(tag, extend, proto, expectException) {
|
||||
try {
|
||||
document.registerElement(tag, { prototype: proto, extends: extend });
|
||||
ok(!expectException, "Registered " + tag + " extending " + extend + " containing " + proto + " in proto chain.");
|
||||
} catch (ex) {
|
||||
ok(expectException, "Did not register " + tag + " extending " + extend + " containing " + proto + " in proto chain.");
|
||||
}
|
||||
}
|
||||
|
||||
function testRegisterSimple(tag, proto, expectException) {
|
||||
try {
|
||||
document.registerElement(tag, { prototype: proto });
|
||||
ok(!expectException, "Registered " + tag + " containing " + proto + " in proto chain.");
|
||||
} catch (ex) {
|
||||
ok(expectException, "Did not register " + tag + " containing " + proto + " in proto chain.");
|
||||
}
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
// Test registering some simple prototypes.
|
||||
testRegisterSimple("x-html-obj-elem", Object.create(HTMLElement.prototype), false);
|
||||
testRegisterSimple("x-html-obj-p", Object.create(HTMLParagraphElement.prototype), false);
|
||||
|
||||
// If prototype is an interface prototype object for any interface object,
|
||||
// registration will throw.
|
||||
testRegisterSimple("x-html-elem", HTMLElement.prototype, true);
|
||||
testRegisterSimple("x-html-select", HTMLSelectElement.prototype, true);
|
||||
testRegisterSimple("some-elem", HTMLElement.prototype, true);
|
||||
testRegisterSimple("x-html-p", HTMLParagraphElement.prototype, true);
|
||||
testRegisterSimple("x-html-span", HTMLSpanElement.prototype, true);
|
||||
|
||||
// Make sure the prototype on unresolved elements is HTMLElement not HTMLUnknownElement.
|
||||
var unresolved = document.getElementById("unresolved");
|
||||
is(unresolved.__proto__, HTMLElement.prototype, "Unresolved custom elements should have HTMLElement as prototype.");
|
||||
|
||||
var anotherUnresolved = document.createElement("maybe-custom-element");
|
||||
is(anotherUnresolved.__proto__, HTMLElement.prototype, "Unresolved custom elements should have HTMLElement as prototype.");
|
||||
|
||||
// Registering without a prototype should automatically create one inheriting from HTMLElement.
|
||||
testRegisterSimple("x-elem-no-proto", null, false);
|
||||
|
||||
var simpleProto = Object.create(HTMLElement.prototype);
|
||||
testRegisterSimple("x-elem-simple-proto", simpleProto, false);
|
||||
|
||||
// Test registering some invalid prototypes.
|
||||
testRegisterSimple("x-invalid-number", 42, true);
|
||||
testRegisterSimple("x-invalid-boolean", false, true);
|
||||
testRegisterSimple("x-invalid-float", 1.0, true);
|
||||
// A prototype with a non-configurable "constructor" property must throw.
|
||||
var nonConfigProto = Object.create(HTMLElement.prototype,
|
||||
{ constructor: { configurable: false, value: function() {} } });
|
||||
testRegisterSimple("x-non-config-proto", nonConfigProto, true);
|
||||
|
||||
// Test invalid custom element names.
|
||||
testRegisterSimple("invalid", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("annotation-xml", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("color-profile", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("font-face", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("font-face-src", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("font-face-uri", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("font-face-format", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("font-face-name", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("missing-glyph", Object.create(HTMLElement.prototype), true);
|
||||
|
||||
// Test registering elements that extend from an existing element.
|
||||
testRegisterExtend("x-extend-span", "span", Object.create(HTMLElement.prototype), false);
|
||||
testRegisterExtend("x-extend-span-caps", "SPAN", Object.create(HTMLElement.prototype), false);
|
||||
|
||||
// Test registering elements that extend from a non-existing element.
|
||||
testRegisterExtend("x-extend-span-nonexist", "nonexisting", Object.create(HTMLElement.prototype), true);
|
||||
|
||||
// Test registration with duplicate type.
|
||||
testRegisterSimple("x-dupe-me", Object.create(HTMLElement.prototype), false);
|
||||
testRegisterSimple("x-dupe-me", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("X-DUPE-ME", Object.create(HTMLElement.prototype), true);
|
||||
testRegisterSimple("x-dupe-me", null, true);
|
||||
testRegisterExtend("x-dupe-me", "span", Object.create(HTMLElement.prototype), true);
|
||||
|
||||
// document.createElement with extended type.
|
||||
var extendedProto = Object.create(HTMLButtonElement.prototype);
|
||||
var buttonConstructor = document.registerElement("x-extended-button", { prototype: extendedProto, extends: "button" });
|
||||
var extendedButton = document.createElement("button", {is: "x-extended-button"});
|
||||
is(extendedButton.tagName, "BUTTON", "Created element should have local name of BUTTON");
|
||||
is(extendedButton.__proto__, extendedProto, "Created element should have the prototype of the extended type.");
|
||||
is(extendedButton.getAttribute("is"), "x-extended-button", "The |is| attribute of the created element should be the extended type.");
|
||||
is(extendedButton.type, "submit", "Created element should be a button with type of \"submit\"");
|
||||
|
||||
// Custom element constructor.
|
||||
var constructedButton = new buttonConstructor();
|
||||
is(constructedButton.tagName, "BUTTON", "Created element should have local name of BUTTON");
|
||||
is(constructedButton.__proto__, extendedProto, "Created element should have the prototype of the extended type.");
|
||||
|
||||
// Try creating an element with a custom element name, but not in the html namespace.
|
||||
var htmlNamespaceProto = Object.create(HTMLElement.prototype);
|
||||
document.registerElement("x-in-html-namespace", { prototype: htmlNamespaceProto });
|
||||
var wrongNamespaceElem = document.createElementNS("http://www.w3.org/2000/svg", "x-in-html-namespace");
|
||||
isnot(wrongNamespaceElem.__proto__, htmlNamespaceProto, "Definition for element in html namespace should not apply to SVG elements.");
|
||||
}
|
||||
|
||||
startTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,47 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test for document.registerElement for elements created by the parser</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script>
|
||||
|
||||
var extendedButtonProto = Object.create(HTMLButtonElement.prototype);
|
||||
var buttonCallbackCalled = false;
|
||||
extendedButtonProto.connectedCallback = function() {
|
||||
is(buttonCallbackCalled, false, "created callback for x-button should only be called once.");
|
||||
is(this.tagName, "BUTTON", "Only the <button> element should be upgraded.");
|
||||
buttonCallbackCalled = true;
|
||||
};
|
||||
|
||||
document.registerElement("x-button", { prototype: extendedButtonProto, extends: "button" });
|
||||
|
||||
var divProto = Object.create(HTMLDivElement.prototype);
|
||||
var divCallbackCalled = false;
|
||||
divProto.connectedCallback = function() {
|
||||
is(divCallbackCalled, false, "created callback for x-div should only be called once.");
|
||||
is(buttonCallbackCalled, true, "crated callback should be called for x-button before x-div.");
|
||||
is(this.tagName, "X-DIV", "Only the <x-div> element should be upgraded.");
|
||||
divCallbackCalled = true;
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
document.registerElement("x-div", { prototype: divProto });
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
|
||||
<button is="x-button"></button><!-- should be upgraded -->
|
||||
<x-button></x-button><!-- should not be upgraded -->
|
||||
<span is="x-button"></span><!-- should not be upgraded -->
|
||||
<div is="x-div"></div><!-- should not be upgraded -->
|
||||
<x-div></x-div><!-- should be upgraded -->
|
||||
<script>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,46 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test shared registry for associated HTML documents.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
|
||||
<script>
|
||||
var container = document.getElementById("container");
|
||||
|
||||
function registerNoRegistryDoc() {
|
||||
var assocDoc = document.implementation.createDocument(null, "html");
|
||||
try {
|
||||
assocDoc.registerElement("x-dummy", { prototype: Object.create(HTMLElement.prototype) });
|
||||
ok(false, "Registring element in document without registry should throw.");
|
||||
} catch (ex) {
|
||||
ok(true, "Registring element in document without registry should throw.");
|
||||
}
|
||||
|
||||
runNextTest();
|
||||
}
|
||||
|
||||
function runNextTest() {
|
||||
if (testFunctions.length > 0) {
|
||||
var nextTestFunction = testFunctions.shift();
|
||||
nextTestFunction();
|
||||
}
|
||||
}
|
||||
|
||||
var testFunctions = [
|
||||
registerNoRegistryDoc,
|
||||
SimpleTest.finish
|
||||
];
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
runNextTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -42,7 +42,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1111633
|
|||
<span id="del" is="x-del"></span>
|
||||
<script>
|
||||
|
||||
// Before registerElement
|
||||
// Before define
|
||||
var foo = document.querySelector('#foo');
|
||||
is(getComputedStyle(foo).color, "rgb(0, 0, 255)", "foo - color");
|
||||
is(getComputedStyle(foo).backgroundColor, "rgb(0, 0, 255)", "foo - backgroundColor");
|
||||
|
@ -58,25 +58,25 @@ is(getComputedStyle(baz).backgroundColor, "rgb(0, 0, 255)", "baz - backgroundCol
|
|||
var span1 = document.querySelector('#span1');
|
||||
is(getComputedStyle(span1).color, "rgb(255, 0, 0)", "span1 - color");
|
||||
|
||||
var Foo = document.registerElement('x-foo', { prototype: Object.create(HTMLElement.prototype) });
|
||||
customElements.define('x-foo', class extends HTMLElement {});
|
||||
|
||||
var Bar = document.registerElement('x-bar', { extends: 'span', prototype: Object.create(HTMLSpanElement.prototype) });
|
||||
customElements.define('x-bar', class extends HTMLSpanElement {}, { extends: 'span' });
|
||||
|
||||
var Baz = document.registerElement('x-baz', { prototype: Object.create(HTMLElement.prototype) });
|
||||
customElements.define('x-baz', class extends HTMLElement {});
|
||||
|
||||
// After registerElement
|
||||
// After define
|
||||
is(getComputedStyle(foo).color, "rgb(255, 0, 0)",
|
||||
"foo - color (after registerElement)");
|
||||
"foo - color (after define)");
|
||||
|
||||
is(getComputedStyle(bar).color,
|
||||
"rgb(255, 0, 0)", "bar - color (after registerElement)");
|
||||
"rgb(255, 0, 0)", "bar - color (after define)");
|
||||
|
||||
is(getComputedStyle(baz).color,
|
||||
"rgb(255, 0, 0)", "baz - color (after registerElement)");
|
||||
"rgb(255, 0, 0)", "baz - color (after define)");
|
||||
is(getComputedStyle(baz).backgroundColor,
|
||||
"rgb(255, 0, 0)", "baz - backgroundColor (after registerElement)");
|
||||
"rgb(255, 0, 0)", "baz - backgroundColor (after define)");
|
||||
|
||||
is(getComputedStyle(span1).color, "rgb(0, 255, 0)", "span1 - color (after registerElement)");
|
||||
is(getComputedStyle(span1).color, "rgb(0, 255, 0)", "span1 - color (after define)");
|
||||
|
||||
// After tree removal
|
||||
var del = document.querySelector('#del');
|
||||
|
@ -88,9 +88,11 @@ par.removeChild(del);
|
|||
del.setAttribute("is", "foobar");
|
||||
par.appendChild(del);
|
||||
is(getComputedStyle(del).color, "rgb(0, 0, 255)", "del - color (after reappend)");
|
||||
var Del = document.registerElement('x-del', { extends: 'span', prototype: Object.create(HTMLSpanElement.prototype) });
|
||||
|
||||
class Del extends HTMLSpanElement {};
|
||||
customElements.define('x-del', Del, { extends: 'span' });
|
||||
// [is="x-del"] will not match any longer so the rule of span will apply
|
||||
is(getComputedStyle(del).color, "rgb(0, 255, 0)", "del - color (after registerElement)");
|
||||
is(getComputedStyle(del).color, "rgb(0, 255, 0)", "del - color (after define)");
|
||||
// but the element should have been upgraded:
|
||||
ok(del instanceof Del, "element was upgraded correctly after changing |is|");
|
||||
|
||||
|
|
|
@ -264,13 +264,6 @@ partial interface Document {
|
|||
attribute EventHandler onpointerlockerror;
|
||||
};
|
||||
|
||||
//http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-document-register
|
||||
partial interface Document {
|
||||
// this is deprecated from CustomElements v0
|
||||
[Throws, Func="CustomElementRegistry::IsCustomElementEnabled"]
|
||||
object registerElement(DOMString name, optional ElementRegistrationOptions options);
|
||||
};
|
||||
|
||||
// http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface
|
||||
// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface
|
||||
partial interface Document {
|
||||
|
|
|
@ -25,8 +25,3 @@ dictionary LifecycleCallbacks {
|
|||
LifecycleAdoptedCallback? adoptedCallback;
|
||||
LifecycleAttributeChangedCallback? attributeChangedCallback;
|
||||
};
|
||||
|
||||
dictionary ElementRegistrationOptions {
|
||||
object? prototype = null;
|
||||
DOMString? extends = null;
|
||||
};
|
||||
|
|
|
@ -15,15 +15,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1094930
|
|||
<p id="display"></p>
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
var proto = {
|
||||
connectedCallback: function() {
|
||||
class XFoo extends frames[0].HTMLElement {
|
||||
connectedCallback() {
|
||||
ok(true, "connectedCallback was called");
|
||||
SimpleTest.finish()
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
|
||||
var f = document.registerElement.call(frames[0].document, "x-foo", { prototype: proto });
|
||||
frames[0].document.firstChild.appendChild(new f());
|
||||
customElements.define.call(frames[0].customElements, "x-foo", XFoo);
|
||||
frames[0].document.firstChild.appendChild(new XFoo());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,24 +3,26 @@
|
|||
'use strict';
|
||||
// -sp-context: content
|
||||
(function () {
|
||||
let proto = Object.create(HTMLDivElement.prototype);
|
||||
proto.template = `<style></style>`;
|
||||
proto.createdCallback = function() {
|
||||
let shadow = this.createShadowRoot();
|
||||
if (this.template) {
|
||||
let te = document.createElement('template');
|
||||
te.innerHTML = this.template;
|
||||
shadow.appendChild(document.importNode(te.content, true));
|
||||
}
|
||||
};
|
||||
class UiComponentTest extends HTMLDivElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.template = `<style></style>`;
|
||||
}
|
||||
|
||||
let UiComponentTest = document.registerElement('ui-component-test', {
|
||||
prototype: proto,
|
||||
});
|
||||
connectedCallback() {
|
||||
let shadow = this.createShadowRoot();
|
||||
if (this.template) {
|
||||
let te = document.createElement('template');
|
||||
te.innerHTML = this.template;
|
||||
shadow.appendChild(document.importNode(te.content, true));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let uic = new UiComponentTest();
|
||||
document.body.appendChild(uic);
|
||||
customElements.define('ui-component-test', UiComponentTest, { extend: 'div'} );
|
||||
|
||||
let uic = new UiComponentTest();
|
||||
document.body.appendChild(uic);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -17,21 +17,19 @@
|
|||
var template = document.querySelector('template').content;
|
||||
|
||||
// Creates an object based in the HTML Element prototype
|
||||
var MyElementProto = Object.create(HTMLElement.prototype);
|
||||
class MyElement extends HTMLElement {
|
||||
// Fires when an instance of the element is connected
|
||||
connectedCallback() {
|
||||
// Creates the shadow root
|
||||
var shadowRoot = this.createShadowRoot();
|
||||
|
||||
// Fires when an instance of the element is created
|
||||
MyElementProto.createdCallback = function() {
|
||||
// Creates the shadow root
|
||||
var shadowRoot = this.createShadowRoot();
|
||||
|
||||
// Adds a template clone into shadow root
|
||||
var clone = document.importNode(template, true);
|
||||
shadowRoot.appendChild(clone);
|
||||
// Adds a template clone into shadow root
|
||||
var clone = document.importNode(template, true);
|
||||
shadowRoot.appendChild(clone);
|
||||
}
|
||||
};
|
||||
// Registers <my-elem> in the main document
|
||||
window.MyElement = document.registerElement('my-elem', {
|
||||
prototype: MyElementProto
|
||||
});
|
||||
customElements.define('my-elem', MyElement);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -50,27 +50,28 @@ gaia_switch/examples/index.html from the Gaia repository.
|
|||
|
||||
window.GaiaSwitch = (function(win) {
|
||||
// Extend from the HTMLElement prototype
|
||||
var proto = Object.create(HTMLElement.prototype);
|
||||
class GaiaSwitch extends HTMLElement {
|
||||
connectedCallback() {
|
||||
var shadow = this.createShadowRoot();
|
||||
this._template = template.content.cloneNode(true);
|
||||
this._input = this._template.querySelector('input[type="checkbox"]');
|
||||
|
||||
proto.createdCallback = function() {
|
||||
var shadow = this.createShadowRoot();
|
||||
this._template = template.content.cloneNode(true);
|
||||
this._input = this._template.querySelector('input[type="checkbox"]');
|
||||
var checked = this.getAttribute('checked');
|
||||
if (checked !== null) {
|
||||
this._input.checked = true;
|
||||
}
|
||||
|
||||
var checked = this.getAttribute('checked');
|
||||
if (checked !== null) {
|
||||
this._input.checked = true;
|
||||
shadow.appendChild(this._template);
|
||||
|
||||
ComponentUtils.style.call(this, '');
|
||||
}
|
||||
|
||||
shadow.appendChild(this._template);
|
||||
|
||||
ComponentUtils.style.call(this, '');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Proxy the checked property to the input element.
|
||||
*/
|
||||
Object.defineProperty( proto, 'checked', {
|
||||
Object.defineProperty( GaiaSwitch.prototype, 'checked', {
|
||||
get: function() {
|
||||
return this._input.checked;
|
||||
},
|
||||
|
@ -82,7 +83,7 @@ window.GaiaSwitch = (function(win) {
|
|||
/**
|
||||
* Proxy the name property to the input element.
|
||||
*/
|
||||
Object.defineProperty( proto, 'name', {
|
||||
Object.defineProperty( GaiaSwitch.prototype, 'name', {
|
||||
get: function() {
|
||||
return this.getAttribute('name');
|
||||
},
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[historical.html]
|
||||
[document.registerElement should not exist]
|
||||
expected: FAIL
|
||||
|
Загрузка…
Ссылка в новой задаче