Diff
Modified: trunk/LayoutTests/ChangeLog (204610 => 204611)
--- trunk/LayoutTests/ChangeLog 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/LayoutTests/ChangeLog 2016-08-18 22:19:59 UTC (rev 204611)
@@ -1,3 +1,20 @@
+2016-08-17 Ryosuke Niwa <[email protected]>
+
+ Add basic support for connected and disconnected callbacks
+ https://bugs.webkit.org/show_bug.cgi?id=160950
+
+ Reviewed by Chris Dumez.
+
+ Added W3C style testharness.js tests for connectedCallback and disconnectedCallback.
+
+ Four test cases are failing due to a bug in window-less document's custom element registry,
+ which will be addressed in a future patch.
+
+ * fast/custom-elements/connected-callbacks-expected.txt: Added.
+ * fast/custom-elements/connected-callbacks.html: Added.
+ * fast/custom-elements/disconnected-callbacks-expected.txt: Added.
+ * fast/custom-elements/disconnected-callbacks.html: Added.
+
2016-08-18 Chris Dumez <[email protected]>
Align our encoding labels with the encoding specification
Added: trunk/LayoutTests/fast/custom-elements/connected-callbacks-expected.txt (0 => 204611)
--- trunk/LayoutTests/fast/custom-elements/connected-callbacks-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/connected-callbacks-expected.txt 2016-08-18 22:19:59 UTC (rev 204611)
@@ -0,0 +1,10 @@
+
+PASS Inserting a custom element into a document must enqueue and invoke connectedCallback
+PASS Inserting a custom element into a detached node must not enqueue and invoke connectedCallback
+FAIL Inserting a custom element into a window-less document must enqueue and invoke connectedCallback assert_array_equals: lengths differ, expected 2 got 0
+PASS Inserting an ancestor of a custom element into a document must enqueue and invoke connectedCallback
+FAIL Inserting an ancestor of custom element into a window-less document must enqueue and invoke connectedCallback assert_array_equals: lengths differ, expected 2 got 0
+PASS Inserting a custom element into a connected shadow tree must enqueue and invoke connectedCallback
+PASS Inserting the shadow host of a shadow tree with a custom element into a document must enqueue and invoke connectedCallback
+PASS Inserting a custom element into a detached shadow tree must not enqueue and invoke connectedCallback
+
Added: trunk/LayoutTests/fast/custom-elements/connected-callbacks.html (0 => 204611)
--- trunk/LayoutTests/fast/custom-elements/connected-callbacks.html (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/connected-callbacks.html 2016-08-18 22:19:59 UTC (rev 204611)
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: connectedCallback</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content="connectedCallback must be enqueued whenever custom element is inserted into a document">
+<link rel="help" href=""
+<script src=""
+<script src=""
+<link rel='stylesheet' href=''>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+var calls = [];
+class MyCustomElement extends HTMLElement {
+ connectedCallback() { calls.push('connected', this); }
+ disconnectedCallback() { calls.push('disconnected', this); }
+}
+customElements.define('my-custom-element', MyCustomElement);
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+
+ calls = [];
+ document.body.appendChild(instance);
+ assert_array_equals(calls, ['connected', instance]);
+}, 'Inserting a custom element into a document must enqueue and invoke connectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+
+ calls = [];
+ var parent = document.createElement('div');
+ parent.appendChild(instance);
+ assert_array_equals(calls, []);
+}, 'Inserting a custom element into a detached node must not enqueue and invoke connectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var documentWithoutWindow = document.implementation.createHTMLDocument();
+
+ calls = [];
+ documentWithoutWindow.body.appendChild(instance);
+ assert_array_equals(calls, ['connected', instance]);
+}, 'Inserting a custom element into a window-less document must enqueue and invoke connectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var parent = document.createElement('div');
+ parent.appendChild(instance);
+
+ calls = [];
+ document.body.appendChild(parent);
+ assert_array_equals(calls, ['connected', instance]);
+}, 'Inserting an ancestor of a custom element into a document must enqueue and invoke connectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var parent = document.createElement('div');
+ parent.appendChild(instance);
+ var documentWithoutWindow = document.implementation.createHTMLDocument();
+
+ calls = [];
+ documentWithoutWindow.body.appendChild(parent);
+ assert_array_equals(calls, ['connected', instance]);
+}, 'Inserting an ancestor of custom element into a window-less document must enqueue and invoke connectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({mode: 'closed'});
+ document.body.appendChild(host);
+
+ calls = [];
+ shadowRoot.appendChild(instance);
+ assert_array_equals(calls, ['connected', instance]);
+}, 'Inserting a custom element into a connected shadow tree must enqueue and invoke connectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({mode: 'closed'});
+ shadowRoot.appendChild(instance);
+
+ calls = [];
+ document.body.appendChild(host);
+ assert_array_equals(calls, ['connected', instance]);
+}, 'Inserting the shadow host of a shadow tree with a custom element into a document must enqueue and invoke connectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({mode: 'closed'});
+
+ calls = [];
+ shadowRoot.appendChild(instance);
+ assert_array_equals(calls, []);
+}, 'Inserting a custom element into a detached shadow tree must not enqueue and invoke connectedCallback');
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/custom-elements/disconnected-callbacks-expected.txt (0 => 204611)
--- trunk/LayoutTests/fast/custom-elements/disconnected-callbacks-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/disconnected-callbacks-expected.txt 2016-08-18 22:19:59 UTC (rev 204611)
@@ -0,0 +1,10 @@
+
+PASS Removing a custom element from a document must enqueue and invoke disconnectedCallback
+PASS Removing a custom element from a detahed node must not enqueue and invoke connectedCallback
+FAIL Removing a custom element from a window-less document must enqueue and invoke disconnectedCallback assert_array_equals: lengths differ, expected 2 got 0
+PASS Removing an ancestor of a custom element from a document must enqueue and invoke disconnectedCallback
+FAIL Removing an ancestor of custom element from a a window-less document must enqueue and invoke disconnectedCallback assert_array_equals: lengths differ, expected 2 got 0
+PASS Removing a custom element from a connected shadow tree must enqueue and invoke disconnectedCallback
+PASS Removing the shadow host of a shadow tree with a custom element from a document must enqueue and invoke disconnectedCallback
+PASS Removing a custom element from a detached shadow tree must not enqueue and invoke disconnectedCallback
+
Added: trunk/LayoutTests/fast/custom-elements/disconnected-callbacks.html (0 => 204611)
--- trunk/LayoutTests/fast/custom-elements/disconnected-callbacks.html (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/disconnected-callbacks.html 2016-08-18 22:19:59 UTC (rev 204611)
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: disconnectedCallback</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content="disconnectedCallback must be enqueued whenever custom element is removed from a document">
+<link rel="help" href=""
+<script src=""
+<script src=""
+<link rel='stylesheet' href=''>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+var calls = [];
+class MyCustomElement extends HTMLElement {
+ connectedCallback() { calls.push('connected', this); }
+ disconnectedCallback() { calls.push('disconnected', this); }
+}
+customElements.define('my-custom-element', MyCustomElement);
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ document.body.appendChild(instance);
+
+ calls = [];
+ document.body.removeChild(instance);
+ assert_array_equals(calls, ['disconnected', instance]);
+}, 'Removing a custom element from a document must enqueue and invoke disconnectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var parent = document.createElement('div');
+ parent.appendChild(instance);
+
+ calls = [];
+ parent.removeChild(instance);
+ assert_array_equals(calls, []);
+}, 'Removing a custom element from a detahed node must not enqueue and invoke connectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var documentWithoutWindow = document.implementation.createHTMLDocument();
+ documentWithoutWindow.body.appendChild(instance);
+
+ calls = [];
+ documentWithoutWindow.body.removeChild(instance);
+ assert_array_equals(calls, ['disconnected', instance]);
+}, 'Removing a custom element from a window-less document must enqueue and invoke disconnectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var parent = document.createElement('div');
+ parent.appendChild(instance);
+ document.body.appendChild(parent);
+
+ calls = [];
+ document.body.removeChild(parent);
+ assert_array_equals(calls, ['disconnected', instance]);
+}, 'Removing an ancestor of a custom element from a document must enqueue and invoke disconnectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var parent = document.createElement('div');
+ parent.appendChild(instance);
+ var documentWithoutWindow = document.implementation.createHTMLDocument();
+ documentWithoutWindow.body.appendChild(parent);
+
+ calls = [];
+ documentWithoutWindow.body.removeChild(parent);
+ assert_array_equals(calls, ['disconnected', instance]);
+}, 'Removing an ancestor of custom element from a a window-less document must enqueue and invoke disconnectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var host = document.createElement('div');
+ document.body.appendChild(host);
+ var shadowRoot = host.attachShadow({mode: 'closed'});
+ shadowRoot.appendChild(instance);
+
+ calls = [];
+ shadowRoot.removeChild(instance);
+ assert_array_equals(calls, ['disconnected', instance]);
+}, 'Removing a custom element from a connected shadow tree must enqueue and invoke disconnectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({mode: 'closed'});
+ shadowRoot.appendChild(instance);
+ document.body.appendChild(host);
+
+ calls = [];
+ document.body.removeChild(host);
+ assert_array_equals(calls, ['disconnected', instance]);
+}, 'Removing the shadow host of a shadow tree with a custom element from a document must enqueue and invoke disconnectedCallback');
+
+test(function () {
+ var instance = document.createElement('my-custom-element');
+ var host = document.createElement('div');
+ var shadowRoot = host.attachShadow({mode: 'closed'});
+ shadowRoot.appendChild(instance);
+
+ calls = [];
+ shadowRoot.removeChild(instance);
+ assert_array_equals(calls, []);
+}, 'Removing a custom element from a detached shadow tree must not enqueue and invoke disconnectedCallback');
+
+
+</script>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (204610 => 204611)
--- trunk/Source/WebCore/ChangeLog 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/ChangeLog 2016-08-18 22:19:59 UTC (rev 204611)
@@ -1,3 +1,53 @@
+2016-08-17 Ryosuke Niwa <[email protected]>
+
+ Add basic support for connected and disconnected callbacks
+ https://bugs.webkit.org/show_bug.cgi?id=160950
+
+ Reviewed by Chris Dumez.
+
+ Added the basic support for custom elements' connectedCallback and disconnectedCallback. These callbacks
+ are enqueued by inserting and removing a node as spec'ed by https://dom.spec.whatwg.org/#concept-node-insert
+ and https://dom.spec.whatwg.org/#concept-node-remove
+
+ For now, we only support callbacks on appendChild and removeChild to limit the amount of code changes and
+ tests that need to be included in this patch.
+
+ This patch also renames InvokesCustomElementLifecycleCallbacks IDL attribute to CEReactions to match
+ the latest specification: https://html.spec.whatwg.org/multipage/scripting.html#cereactions
+
+ Tests: fast/custom-elements/connected-callbacks.html
+ fast/custom-elements/disconnected-callbacks.html
+
+ * bindings/js/JSCustomElementInterface.cpp:
+ (WebCore::JSCustomElementInterface::invokeCallback): Extracted from invokeAttributeChangedCallback.
+ (WebCore::JSCustomElementInterface::setConnectedCallback): Added.
+ (WebCore::JSCustomElementInterface::invokeConnectedCallback): Added.
+ (WebCore::JSCustomElementInterface::setDisconnectedCallback): Added.
+ (WebCore::JSCustomElementInterface::invokeDisconnectedCallback): Added.
+ (WebCore::JSCustomElementInterface::setAttributeChangedCallback):
+ (WebCore::JSCustomElementInterface::invokeAttributeChangedCallback): Renamed from attributeChanged.
+ * bindings/js/JSCustomElementInterface.h: Added m_connectedCallback and m_disconnectedCallback as instance
+ variables. Also removed the superfluous mutable qualifier from m_constructor m_attributeChangedCallback.
+ * bindings/js/JSCustomElementsRegistryCustom.cpp:
+ (WebCore::JSCustomElementsRegistry::define): Store connectedCallback and disconnectedCallback.
+ * bindings/scripts/CodeGeneratorJS.pm:
+ (GenerateImplementation):
+ * bindings/scripts/IDLAttributes.txt:
+ * dom/CustomElementsRegistry.idl:
+ * dom/Element.cpp:
+ (WebCore::Element::insertedInto): Call enqueueConnectedCallbackIfNeeded.
+ (WebCore::Element::removedFrom): Call enqueueDisconnectedCallbackIfNeeded.
+ * dom/Element.idl:
+ * dom/LifecycleCallbackQueue.cpp:
+ (WebCore::LifecycleQueueItem::invoke): Added calls to invokeConnectedCallback and invokeDisconnectedCallback.
+ (WebCore::findInterfaceForCustomElement): Extracted from enqueueAttributeChangedCallbackIfNeeded.
+ (WebCore::LifecycleCallbackQueue::enqueueConnectedCallbackIfNeeded): Added.
+ (WebCore::LifecycleCallbackQueue::enqueueDisconnectedCallbackIfNeeded): Added.
+ (WebCore::LifecycleCallbackQueue::enqueueAttributeChangedCallbackIfNeeded):
+ (WebCore::CustomElementLifecycleProcessingStack::ensureCurrentQueue):
+ * dom/LifecycleCallbackQueue.h:
+ * dom/Node.idl:
+
2016-08-18 Beth Dakin <[email protected]>
Update the accessibility titles for list insertion
Modified: trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp (204610 => 204611)
--- trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp 2016-08-18 22:19:59 UTC (rev 204611)
@@ -151,27 +151,19 @@
ASSERT(wrappedElement->isCustomElement());
}
-void JSCustomElementInterface::setAttributeChangedCallback(JSC::JSObject* callback, const Vector<String>& observedAttributes)
+void JSCustomElementInterface::invokeCallback(Element& element, JSObject* callback, const Function<void(ExecState*, MarkedArgumentBuffer&)>& addArguments)
{
- m_attributeChangedCallback = callback;
- m_observedAttributes.clear();
- for (auto& name : observedAttributes)
- m_observedAttributes.add(name);
-}
-
-void JSCustomElementInterface::attributeChanged(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
-{
if (!canInvokeCallback())
return;
+ auto* context = scriptExecutionContext();
+ if (!context)
+ return;
+
Ref<JSCustomElementInterface> protectedThis(*this);
-
JSLockHolder lock(m_isolatedWorld->vm());
- ScriptExecutionContext* context = scriptExecutionContext();
- if (!context)
- return;
-
+ ASSERT(context);
ASSERT(context->isDocument());
JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, *m_isolatedWorld);
ExecState* state = globalObject->globalExec();
@@ -179,20 +171,16 @@
JSObject* jsElement = asObject(toJS(state, globalObject, element));
CallData callData;
- CallType callType = m_attributeChangedCallback->methodTable()->getCallData(m_attributeChangedCallback.get(), callData);
+ CallType callType = callback->methodTable()->getCallData(callback, callData);
ASSERT(callType != CallType::None);
- const AtomicString& namespaceURI = attributeName.namespaceURI();
MarkedArgumentBuffer args;
- args.append(jsStringWithCache(state, attributeName.localName()));
- args.append(oldValue == nullAtom ? jsNull() : jsStringWithCache(state, oldValue));
- args.append(newValue == nullAtom ? jsNull() : jsStringWithCache(state, newValue));
- args.append(namespaceURI == nullAtom ? jsNull() : jsStringWithCache(state, attributeName.namespaceURI()));
+ addArguments(state, args);
InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData);
NakedPtr<Exception> exception;
- JSMainThreadExecState::call(state, m_attributeChangedCallback.get(), callType, callData, jsElement, args, exception);
+ JSMainThreadExecState::call(state, callback, callType, callData, jsElement, args, exception);
InspectorInstrumentation::didCallFunction(cookie, context);
@@ -199,7 +187,45 @@
if (exception)
reportException(state, exception);
}
-
+
+void JSCustomElementInterface::setConnectedCallback(JSC::JSObject* callback)
+{
+ m_connectedCallback = callback;
+}
+
+void JSCustomElementInterface::invokeConnectedCallback(Element& element)
+{
+ invokeCallback(element, m_connectedCallback.get());
+}
+
+void JSCustomElementInterface::setDisconnectedCallback(JSC::JSObject* callback)
+{
+ m_disconnectedCallback = callback;
+}
+
+void JSCustomElementInterface::invokeDisconnectedCallback(Element& element)
+{
+ invokeCallback(element, m_disconnectedCallback.get());
+}
+
+void JSCustomElementInterface::setAttributeChangedCallback(JSC::JSObject* callback, const Vector<String>& observedAttributes)
+{
+ m_attributeChangedCallback = callback;
+ m_observedAttributes.clear();
+ for (auto& name : observedAttributes)
+ m_observedAttributes.add(name);
+}
+
+void JSCustomElementInterface::invokeAttributeChangedCallback(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
+{
+ invokeCallback(element, m_attributeChangedCallback.get(), [&](ExecState* state, MarkedArgumentBuffer& args) {
+ args.append(jsStringWithCache(state, attributeName.localName()));
+ args.append(jsStringOrNull(state, oldValue));
+ args.append(jsStringOrNull(state, newValue));
+ args.append(jsStringOrNull(state, attributeName.namespaceURI()));
+ });
+}
+
void JSCustomElementInterface::didUpgradeLastElementInConstructionStack()
{
m_constructionStack.last() = nullptr;
Modified: trunk/Source/WebCore/bindings/js/JSCustomElementInterface.h (204610 => 204611)
--- trunk/Source/WebCore/bindings/js/JSCustomElementInterface.h 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/bindings/js/JSCustomElementInterface.h 2016-08-18 22:19:59 UTC (rev 204611)
@@ -35,6 +35,7 @@
#include <heap/WeakInlines.h>
#include <runtime/JSObject.h>
#include <wtf/Forward.h>
+#include <wtf/Function.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
#include <wtf/text/AtomicStringHash.h>
@@ -66,9 +67,15 @@
void upgradeElement(Element&);
+ void setConnectedCallback(JSC::JSObject*);
+ void invokeConnectedCallback(Element&);
+
+ void setDisconnectedCallback(JSC::JSObject*);
+ void invokeDisconnectedCallback(Element&);
+
void setAttributeChangedCallback(JSC::JSObject* callback, const Vector<String>& observedAttributes);
bool observesAttribute(const AtomicString& name) const { return m_observedAttributes.contains(name); }
- void attributeChanged(Element&, const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
+ void invokeAttributeChangedCallback(Element&, const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); }
JSC::JSObject* constructor() { return m_constructor.get(); }
@@ -84,9 +91,13 @@
private:
JSCustomElementInterface(const QualifiedName&, JSC::JSObject* callback, JSDOMGlobalObject*);
+ void invokeCallback(Element&, JSC::JSObject* callback, const Function<void(JSC::ExecState*, JSC::MarkedArgumentBuffer&)>& addArguments = {});
+
QualifiedName m_name;
- mutable JSC::Weak<JSC::JSObject> m_constructor;
- mutable JSC::Weak<JSC::JSObject> m_attributeChangedCallback;
+ JSC::Weak<JSC::JSObject> m_constructor;
+ JSC::Weak<JSC::JSObject> m_connectedCallback;
+ JSC::Weak<JSC::JSObject> m_disconnectedCallback;
+ JSC::Weak<JSC::JSObject> m_attributeChangedCallback;
RefPtr<DOMWrapperWorld> m_isolatedWorld;
Vector<RefPtr<Element>, 1> m_constructionStack;
HashSet<AtomicString> m_observedAttributes;
Modified: trunk/Source/WebCore/bindings/js/JSCustomElementsRegistryCustom.cpp (204610 => 204611)
--- trunk/Source/WebCore/bindings/js/JSCustomElementsRegistryCustom.cpp 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/bindings/js/JSCustomElementsRegistryCustom.cpp 2016-08-18 22:19:59 UTC (rev 204611)
@@ -104,15 +104,20 @@
return throwTypeError(&state, ASCIILiteral("Custom element constructor's prototype must be an object"));
JSObject& prototypeObject = *asObject(prototypeValue);
- // FIXME: Add the support for connectedCallback.
- getLifecycleCallback(state, prototypeObject, Identifier::fromString(&vm, "connectedCallback"));
+ QualifiedName name(nullAtom, localName, HTMLNames::xhtmlNamespaceURI);
+ auto elementInterface = JSCustomElementInterface::create(name, constructor, globalObject());
+
+ auto* connectedCallback = getLifecycleCallback(state, prototypeObject, Identifier::fromString(&vm, "connectedCallback"));
if (state.hadException())
return jsUndefined();
+ if (connectedCallback)
+ elementInterface->setConnectedCallback(connectedCallback);
- // FIXME: Add the support for disconnectedCallback.
- getLifecycleCallback(state, prototypeObject, Identifier::fromString(&vm, "disconnectedCallback"));
+ auto* disconnectedCallback = getLifecycleCallback(state, prototypeObject, Identifier::fromString(&vm, "disconnectedCallback"));
if (state.hadException())
return jsUndefined();
+ if (disconnectedCallback)
+ elementInterface->setDisconnectedCallback(disconnectedCallback);
// FIXME: Add the support for adoptedCallback.
getLifecycleCallback(state, prototypeObject, Identifier::fromString(&vm, "adoptedCallback"));
@@ -119,9 +124,6 @@
if (state.hadException())
return jsUndefined();
- QualifiedName name(nullAtom, localName, HTMLNames::xhtmlNamespaceURI);
- auto elementInterface = JSCustomElementInterface::create(name, constructor, globalObject());
-
auto* attributeChangedCallback = getLifecycleCallback(state, prototypeObject, Identifier::fromString(&vm, "attributeChangedCallback"));
if (state.hadException())
return jsUndefined();
Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (204610 => 204611)
--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2016-08-18 22:19:59 UTC (rev 204611)
@@ -3340,7 +3340,7 @@
$implIncludes{"<runtime/Error.h>"} = 1;
- if ($function->signature->extendedAttributes->{"InvokesCustomElementLifecycleCallbacks"}) {
+ if ($function->signature->extendedAttributes->{"CEReactions"}) {
push(@implContent, "#if ENABLE(CUSTOM_ELEMENTS)\n");
push(@implContent, " CustomElementLifecycleProcessingStack customElementLifecycleProcessingStack;\n");
push(@implContent, "#endif\n");
Modified: trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt (204610 => 204611)
--- trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt 2016-08-18 22:19:59 UTC (rev 204611)
@@ -21,6 +21,7 @@
ActiveDOMObject
AppleCopyright
AtomicString
+CEReactions
CachedAttribute
CallbackNeedsOperatorEqual
Callback=FunctionOnly
@@ -91,7 +92,6 @@
LenientThis
MasqueradesAsUndefined
NamedConstructor=*
-InvokesCustomElementLifecycleCallbacks
NewImpurePropertyFiresWatchpoints
NewObject
NoInterfaceObject
Modified: trunk/Source/WebCore/dom/CustomElementsRegistry.idl (204610 => 204611)
--- trunk/Source/WebCore/dom/CustomElementsRegistry.idl 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/dom/CustomElementsRegistry.idl 2016-08-18 22:19:59 UTC (rev 204611)
@@ -29,6 +29,6 @@
ImplementationLacksVTable
] interface CustomElementsRegistry {
- [InvokesCustomElementLifecycleCallbacks, Custom] void define(DOMString name, Function constructor);
+ [CEReactions, Custom] void define(DOMString name, Function constructor);
};
Modified: trunk/Source/WebCore/dom/Element.cpp (204610 => 204611)
--- trunk/Source/WebCore/dom/Element.cpp 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/dom/Element.cpp 2016-08-18 22:19:59 UTC (rev 204611)
@@ -1596,6 +1596,11 @@
updateLabel(*newScope, nullAtom, attributeWithoutSynchronization(forAttr));
}
+#if ENABLE(CUSTOM_ELEMENTS)
+ if (newDocument && UNLIKELY(isCustomElement()))
+ LifecycleCallbackQueue::enqueueConnectedCallbackIfNeeded(*this);
+#endif
+
return InsertionDone;
}
@@ -1641,6 +1646,11 @@
if (oldScope->shouldCacheLabelsByForAttribute())
updateLabel(*oldScope, attributeWithoutSynchronization(forAttr), nullAtom);
}
+
+#if ENABLE(CUSTOM_ELEMENTS)
+ if (oldDocument && UNLIKELY(isCustomElement()))
+ LifecycleCallbackQueue::enqueueDisconnectedCallbackIfNeeded(*this);
+#endif
}
if (!parentNode()) {
Modified: trunk/Source/WebCore/dom/Element.idl (204610 => 204611)
--- trunk/Source/WebCore/dom/Element.idl 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/dom/Element.idl 2016-08-18 22:19:59 UTC (rev 204611)
@@ -31,15 +31,13 @@
DOMString? getAttribute(DOMString name);
- [ObjCLegacyUnnamedParameters, RaisesException, InvokesCustomElementLifecycleCallbacks]
+ [ObjCLegacyUnnamedParameters, RaisesException, CEReactions] void setAttribute(DOMString name, DOMString value);
- void setAttribute(DOMString name, DOMString value);
-
- [InvokesCustomElementLifecycleCallbacks] void removeAttribute(DOMString name);
+ [CEReactions] void removeAttribute(DOMString name);
Attr? getAttributeNode(DOMString name);
- [RaisesException, InvokesCustomElementLifecycleCallbacks] Attr? setAttributeNode(Attr newAttr);
- [RaisesException, InvokesCustomElementLifecycleCallbacks] Attr removeAttributeNode(Attr oldAttr);
+ [RaisesException, CEReactions] Attr? setAttributeNode(Attr newAttr);
+ [RaisesException, CEReactions] Attr removeAttributeNode(Attr oldAttr);
HTMLCollection getElementsByTagName(DOMString name);
@@ -50,16 +48,14 @@
[ObjCLegacyUnnamedParameters] DOMString? getAttributeNS(DOMString? namespaceURI, DOMString localName);
- [ObjCLegacyUnnamedParameters, RaisesException, InvokesCustomElementLifecycleCallbacks]
+ [ObjCLegacyUnnamedParameters, RaisesException, CEReactions] void setAttributeNS(DOMString? namespaceURI, DOMString qualifiedName, DOMString value);
- void setAttributeNS(DOMString? namespaceURI, DOMString qualifiedName, DOMString value);
+ [ObjCLegacyUnnamedParameters, CEReactions] void removeAttributeNS(DOMString? namespaceURI, DOMString localName);
- [ObjCLegacyUnnamedParameters, InvokesCustomElementLifecycleCallbacks] void removeAttributeNS(DOMString? namespaceURI, DOMString localName);
-
HTMLCollection getElementsByTagNameNS(DOMString? namespaceURI, DOMString localName);
[ObjCLegacyUnnamedParameters] Attr? getAttributeNodeNS(DOMString? namespaceURI, DOMString localName);
- [RaisesException, InvokesCustomElementLifecycleCallbacks] Attr? setAttributeNodeNS(Attr newAttr);
+ [RaisesException, CEReactions] Attr? setAttributeNodeNS(Attr newAttr);
boolean hasAttribute(DOMString name);
[ObjCLegacyUnnamedParameters] boolean hasAttributeNS(DOMString? namespaceURI, DOMString localName);
Modified: trunk/Source/WebCore/dom/LifecycleCallbackQueue.cpp (204610 => 204611)
--- trunk/Source/WebCore/dom/LifecycleCallbackQueue.cpp 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/dom/LifecycleCallbackQueue.cpp 2016-08-18 22:19:59 UTC (rev 204611)
@@ -44,6 +44,8 @@
public:
enum class Type {
ElementUpgrade,
+ Connected,
+ Disconnected,
AttributeChanged,
};
@@ -68,9 +70,15 @@
case Type::ElementUpgrade:
m_interface->upgradeElement(m_element.get());
break;
+ case Type::Connected:
+ m_interface->invokeConnectedCallback(m_element.get());
+ break;
+ case Type::Disconnected:
+ m_interface->invokeDisconnectedCallback(m_element.get());
+ break;
case Type::AttributeChanged:
ASSERT(m_attributeName);
- m_interface->attributeChanged(m_element.get(), m_attributeName.value(), m_oldValue, m_newValue);
+ m_interface->invokeAttributeChangedCallback(m_element.get(), m_attributeName.value(), m_oldValue, m_newValue);
break;
}
}
@@ -98,25 +106,50 @@
queue->m_items.append(LifecycleQueueItem(LifecycleQueueItem::Type::ElementUpgrade, element, elementInterface));
}
-void LifecycleCallbackQueue::enqueueAttributeChangedCallbackIfNeeded(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
+static JSCustomElementInterface* findInterfaceForCustomElement(Element& element)
{
ASSERT(element.isCustomElement());
auto* window = element.document().domWindow();
if (!window)
- return;
+ return nullptr;
auto* registry = window->customElementsRegistry();
if (!registry)
+ return nullptr;
+
+ return registry->findInterface(element.tagQName());
+}
+
+void LifecycleCallbackQueue::enqueueConnectedCallbackIfNeeded(Element& element)
+{
+ auto* elementInterface = findInterfaceForCustomElement(element);
+ if (!elementInterface)
return;
- auto* elementInterface = registry->findInterface(element.tagQName());
- if (!elementInterface->observesAttribute(attributeName.localName()))
+ if (auto* queue = CustomElementLifecycleProcessingStack::ensureCurrentQueue())
+ queue->m_items.append({LifecycleQueueItem::Type::Connected, element, *elementInterface});
+}
+
+void LifecycleCallbackQueue::enqueueDisconnectedCallbackIfNeeded(Element& element)
+{
+ auto* elementInterface = findInterfaceForCustomElement(element);
+ if (!elementInterface)
return;
if (auto* queue = CustomElementLifecycleProcessingStack::ensureCurrentQueue())
- queue->m_items.append(LifecycleQueueItem(element, *elementInterface, attributeName, oldValue, newValue));
+ queue->m_items.append({LifecycleQueueItem::Type::Disconnected, element, *elementInterface});
}
+void LifecycleCallbackQueue::enqueueAttributeChangedCallbackIfNeeded(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue)
+{
+ auto* elementInterface = findInterfaceForCustomElement(element);
+ if (!elementInterface || !elementInterface->observesAttribute(attributeName.localName()))
+ return;
+
+ if (auto* queue = CustomElementLifecycleProcessingStack::ensureCurrentQueue())
+ queue->m_items.append({element, *elementInterface, attributeName, oldValue, newValue});
+}
+
void LifecycleCallbackQueue::invokeAll()
{
Vector<LifecycleQueueItem> items;
@@ -127,7 +160,7 @@
LifecycleCallbackQueue* CustomElementLifecycleProcessingStack::ensureCurrentQueue()
{
- // FIXME: This early exit indicates a bug that some DOM API is missing InvokesCustomElementLifecycleCallbacks
+ // FIXME: This early exit indicates a bug that some DOM API is missing CEReactions
if (!s_currentProcessingStack)
return nullptr;
Modified: trunk/Source/WebCore/dom/LifecycleCallbackQueue.h (204610 => 204611)
--- trunk/Source/WebCore/dom/LifecycleCallbackQueue.h 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/dom/LifecycleCallbackQueue.h 2016-08-18 22:19:59 UTC (rev 204611)
@@ -46,6 +46,8 @@
~LifecycleCallbackQueue();
static void enqueueElementUpgrade(Element&, JSCustomElementInterface&);
+ static void enqueueConnectedCallbackIfNeeded(Element&);
+ static void enqueueDisconnectedCallbackIfNeeded(Element&);
static void enqueueAttributeChangedCallbackIfNeeded(Element&, const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
void invokeAll();
Modified: trunk/Source/WebCore/dom/Node.idl (204610 => 204611)
--- trunk/Source/WebCore/dom/Node.idl 2016-08-18 21:19:26 UTC (rev 204610)
+++ trunk/Source/WebCore/dom/Node.idl 2016-08-18 22:19:59 UTC (rev 204611)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
* Copyright (C) 2006 Samuel Weinig <[email protected]>
*
* This library is free software; you can redistribute it and/or
@@ -57,13 +57,12 @@
[ObjCLegacyUnnamedParameters, Custom, RaisesException] Node insertBefore([CustomReturn] Node newChild, Node? refChild);
[ObjCLegacyUnnamedParameters, Custom, RaisesException] Node replaceChild(Node newChild, [CustomReturn] Node oldChild);
- [Custom, RaisesException] Node removeChild([CustomReturn] Node oldChild);
- [Custom, RaisesException] Node appendChild([CustomReturn] Node newChild);
+ [Custom, RaisesException, CEReactions] Node removeChild([CustomReturn] Node oldChild);
+ [Custom, RaisesException, CEReactions] Node appendChild([CustomReturn] Node newChild);
boolean hasChildNodes();
- [NewObject, RaisesException, ImplementedAs=cloneNodeForBindings, InvokesCustomElementLifecycleCallbacks]
- Node cloneNode(optional boolean deep = false);
+ [NewObject, RaisesException, ImplementedAs=cloneNodeForBindings, CEReactions] Node cloneNode(optional boolean deep = false);
void normalize();