зеркало из https://github.com/mozilla/gecko-dev.git
Bug 783129 - Implementation of document.register without shadow DOM support. r=mrbkap
This commit is contained in:
Родитель
c4b46247ca
Коммит
a9e43bd562
|
@ -474,6 +474,7 @@ user_pref("app.update.staging.enabled", false);
|
|||
user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
|
||||
user_pref("dom.w3c_touch_events.enabled", 1);
|
||||
user_pref("dom.undo_manager.enabled", true);
|
||||
user_pref("dom.webcomponents.enabled", true);
|
||||
// Set a future policy version to avoid the telemetry prompt.
|
||||
user_pref("toolkit.telemetry.prompted", 999);
|
||||
user_pref("toolkit.telemetry.notifiedOptOut", 999);
|
||||
|
|
|
@ -92,6 +92,7 @@ class DocumentFragment;
|
|||
class DocumentType;
|
||||
class DOMImplementation;
|
||||
class Element;
|
||||
struct ElementRegistrationOptions;
|
||||
class GlobalObject;
|
||||
class HTMLBodyElement;
|
||||
class Link;
|
||||
|
@ -1910,6 +1911,10 @@ public:
|
|||
{
|
||||
return GetRootElement();
|
||||
}
|
||||
virtual JSObject*
|
||||
Register(JSContext* aCx, const nsAString& aName,
|
||||
const mozilla::dom::ElementRegistrationOptions& aOptions,
|
||||
mozilla::ErrorResult& rv) = 0;
|
||||
already_AddRefed<nsContentList>
|
||||
GetElementsByTagName(const nsAString& aTagName)
|
||||
{
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIScriptRuntime.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
|
||||
#include "nsGUIEvent.h"
|
||||
#include "nsAsyncDOMEvent.h"
|
||||
|
@ -138,10 +139,12 @@
|
|||
#include "nsIPrompt.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
#include "nsIDOMPageTransitionEvent.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "nsHtml5TreeOpExecutor.h"
|
||||
#include "nsIDOMElementReplaceEvent.h"
|
||||
#ifdef MOZ_MEDIA
|
||||
#include "nsHTMLMediaElement.h"
|
||||
#endif // MOZ_MEDIA
|
||||
|
@ -171,8 +174,10 @@
|
|||
#include "mozilla/dom/Comment.h"
|
||||
#include "nsTextNode.h"
|
||||
#include "mozilla/dom/Link.h"
|
||||
#include "mozilla/dom/HTMLElementBinding.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsDOMTouchEvent.h"
|
||||
#include "DictionaryHelpers.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
|
@ -183,6 +188,7 @@
|
|||
#include "nsIAppsService.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DocumentFragment.h"
|
||||
#include "mozilla/dom/WebComponentsBinding.h"
|
||||
#include "mozilla/dom/HTMLBodyElement.h"
|
||||
#include "mozilla/dom/NodeFilterBinding.h"
|
||||
#include "mozilla/dom/UndoManager.h"
|
||||
|
@ -1372,6 +1378,13 @@ nsDocument::~nsDocument()
|
|||
mInDestructor = true;
|
||||
mInUnlinkOrDeletion = true;
|
||||
|
||||
mCustomPrototypes.Clear();
|
||||
|
||||
nsISupports* supports;
|
||||
QueryInterface(NS_GET_IID(nsCycleCollectionISupports), reinterpret_cast<void**>(&supports));
|
||||
NS_ASSERTION(supports, "Failed to QI to nsCycleCollectionISupports?!");
|
||||
nsContentUtils::DropJSObjects(supports);
|
||||
|
||||
// Clear mObservers to keep it in sync with the mutationobserver list
|
||||
mObservers.Clear();
|
||||
|
||||
|
@ -1478,6 +1491,7 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
|
|||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIInlineEventHandlers)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocumentRegister)
|
||||
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIObserver)
|
||||
NS_OFFSET_AND_INTERFACE_TABLE_END
|
||||
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
|
||||
|
@ -1716,7 +1730,25 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
|
||||
struct CustomPrototypeTraceArgs {
|
||||
TraceCallback callback;
|
||||
void* closure;
|
||||
};
|
||||
|
||||
|
||||
static PLDHashOperator
|
||||
CustomPrototypeTrace(const nsAString& aName, JSObject* aObject, void *aArg)
|
||||
{
|
||||
CustomPrototypeTraceArgs* traceArgs = static_cast<CustomPrototypeTraceArgs*>(aArg);
|
||||
MOZ_ASSERT(aObject, "Protocol object value must not be null");
|
||||
traceArgs->callback(aObject, "mCustomPrototypes entry", traceArgs->closure);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument)
|
||||
CustomPrototypeTraceArgs customPrototypeArgs = { aCallback, aClosure };
|
||||
tmp->mCustomPrototypes.EnumerateRead(CustomPrototypeTrace, &customPrototypeArgs);
|
||||
nsINode::Trace(tmp, aCallback, aClosure);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
|
@ -1781,6 +1813,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
|||
|
||||
tmp->mIdentifierMap.Clear();
|
||||
|
||||
tmp->mCustomPrototypes.Clear();
|
||||
|
||||
if (tmp->mAnimationController) {
|
||||
tmp->mAnimationController->Unlink();
|
||||
}
|
||||
|
@ -1805,6 +1839,7 @@ nsDocument::Init()
|
|||
mIdentifierMap.Init();
|
||||
mStyledLinks.Init();
|
||||
mRadioGroups.Init();
|
||||
mCustomPrototypes.Init();
|
||||
|
||||
// Force initialization.
|
||||
nsINode::nsSlots* slots = Slots();
|
||||
|
@ -1841,6 +1876,15 @@ nsDocument::Init()
|
|||
mImageTracker.Init();
|
||||
mPlugins.Init();
|
||||
|
||||
nsXPCOMCycleCollectionParticipant* participant;
|
||||
CallQueryInterface(this, &participant);
|
||||
NS_ASSERTION(participant, "Failed to QI to nsXPCOMCycleCollectionParticipant!");
|
||||
|
||||
nsISupports* thisSupports;
|
||||
QueryInterface(NS_GET_IID(nsCycleCollectionISupports), reinterpret_cast<void**>(&thisSupports));
|
||||
NS_ASSERTION(thisSupports, "Failed to QI to nsCycleCollectionISupports!");
|
||||
nsContentUtils::HoldJSObjects(thisSupports, participant);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1961,6 +2005,8 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
|||
mInUnlinkOrDeletion = oldVal;
|
||||
mCachedRootElement = nullptr;
|
||||
|
||||
mCustomPrototypes.Clear();
|
||||
|
||||
// Reset our stylesheets
|
||||
ResetStylesheetsToURI(aURI);
|
||||
|
||||
|
@ -4845,6 +4891,205 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
|
|||
return attribute.forget();
|
||||
}
|
||||
|
||||
static JSBool
|
||||
CustomElementConstructor(JSContext *aCx, unsigned aArgc, JS::Value* aVp)
|
||||
{
|
||||
JS::Value calleeVal = JS_CALLEE(aCx, aVp);
|
||||
|
||||
JSObject* global = JS_GetGlobalForObject(aCx, &calleeVal.toObject());
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryWrapper(aCx, global);
|
||||
MOZ_ASSERT(window, "Should have a non-null window");
|
||||
|
||||
nsIDocument* document = window->GetDoc();
|
||||
|
||||
// Function name is the type of the custom element.
|
||||
JSString* jsFunName = JS_GetFunctionId(JS_ValueToFunction(aCx, calleeVal));
|
||||
nsDependentJSString elemName;
|
||||
if (!elemName.init(aCx, jsFunName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> newElement;
|
||||
nsresult rv = document->CreateElem(elemName, nullptr, kNameSpaceID_XHTML,
|
||||
getter_AddRefs(newElement));
|
||||
JS::Value v;
|
||||
rv = nsContentUtils::WrapNative(aCx, global, newElement, newElement, &v);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
JS_SET_RVAL(aCx, aVp, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::RegisterEnabled()
|
||||
{
|
||||
static bool sPrefValue =
|
||||
Preferences::GetBool("dom.webcomponents.enabled", false);
|
||||
return sPrefValue;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::Register(const nsAString& aName, const JS::Value& aOptions,
|
||||
JSContext* aCx, uint8_t aOptionalArgc,
|
||||
jsval* aConstructor /* out param */)
|
||||
{
|
||||
ElementRegistrationOptions options;
|
||||
if (aOptionalArgc > 0) {
|
||||
JSAutoCompartment ac(aCx, GetWrapper());
|
||||
NS_ENSURE_TRUE(JS_WrapValue(aCx, const_cast<JS::Value*>(&aOptions)),
|
||||
NS_ERROR_UNEXPECTED);
|
||||
NS_ENSURE_TRUE(options.Init(aCx, nullptr, aOptions),
|
||||
NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
||||
ErrorResult rv;
|
||||
JSObject* object = Register(aCx, aName, options, rv);
|
||||
if (rv.Failed()) {
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
NS_ENSURE_TRUE(object, NS_ERROR_UNEXPECTED);
|
||||
|
||||
*aConstructor = OBJECT_TO_JSVAL(object);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
nsDocument::Register(JSContext* aCx, const nsAString& aName,
|
||||
const ElementRegistrationOptions& aOptions,
|
||||
ErrorResult& rv)
|
||||
{
|
||||
nsAutoString lcName;
|
||||
nsContentUtils::ASCIIToLower(aName, lcName);
|
||||
if (!StringBeginsWith(lcName, NS_LITERAL_STRING("x-"))) {
|
||||
rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
if (NS_FAILED(nsContentUtils::CheckQName(lcName, false))) {
|
||||
rv.Throw(NS_ERROR_DOM_INVALID_CHARACTER_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIScriptGlobalObject* sgo = GetScopeObject();
|
||||
if (!sgo) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
JSObject* global = sgo->GetGlobalJSObject();
|
||||
|
||||
JSAutoCompartment ac(aCx, global);
|
||||
|
||||
JSObject* htmlProto = HTMLElementBinding::GetProtoObject(aCx, global);
|
||||
if (!htmlProto) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* protoObject;
|
||||
if (!aOptions.mPrototype) {
|
||||
protoObject = JS_NewObject(aCx, NULL, htmlProto, NULL);
|
||||
if (!protoObject) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// If a prototype is provided, we must check to ensure that it inherits
|
||||
// from HTMLElement.
|
||||
protoObject = aOptions.mPrototype;
|
||||
if (!JS_WrapObject(aCx, &protoObject)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check the proto chain for HTMLElement prototype.
|
||||
JSObject* protoProto;
|
||||
if (!JS_GetPrototype(aCx, protoObject, &protoProto)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
while (protoProto) {
|
||||
if (protoProto == htmlProto) {
|
||||
break;
|
||||
}
|
||||
if (!JS_GetPrototype(aCx, protoProto, &protoProto)) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!protoProto) {
|
||||
rv.Throw(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Associate the prototype with the custom element.
|
||||
mCustomPrototypes.Put(lcName, protoObject);
|
||||
|
||||
// Do element upgrade.
|
||||
nsRefPtr<nsContentList> list = GetElementsByTagName(lcName);
|
||||
for (int32_t i = 0; i < list->Length(false); i++) {
|
||||
nsCOMPtr<nsINode> oldNode = list->Item(i, false);
|
||||
|
||||
// TODO(wchen): Perform upgrade on Shadow DOM when implemented.
|
||||
// Bug 806506.
|
||||
nsCOMPtr<nsINode> newNode;
|
||||
rv = nsNodeUtils::Clone(oldNode, true, getter_AddRefs(newNode));
|
||||
if (rv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsINode* parentNode = oldNode->GetParentNode();
|
||||
MOZ_ASSERT(parentNode, "Node obtained by GetElementsByTagName.");
|
||||
nsCOMPtr<nsIDOMElement> newElement = do_QueryInterface(newNode);
|
||||
MOZ_ASSERT(newElement, "Cloned of node obtained by GetElementsByTagName.");
|
||||
|
||||
parentNode->ReplaceChild(*newNode, *oldNode, rv);
|
||||
if (rv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Dispatch elementreplaced to replaced elements.
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
rv = CreateEvent(NS_LITERAL_STRING("elementreplace"), getter_AddRefs(event));
|
||||
if (rv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aOptions.mLifecycle.mCreated) {
|
||||
// Don't abort the upgrade algorithm if the callback throws an
|
||||
// exception.
|
||||
ErrorResult dummy;
|
||||
aOptions.mLifecycle.mCreated->Call(newElement.get(), dummy);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMElementReplaceEvent> ptEvent = do_QueryInterface(event);
|
||||
MOZ_ASSERT(ptEvent);
|
||||
|
||||
rv = ptEvent->InitElementReplaceEvent(NS_LITERAL_STRING("elementreplace"),
|
||||
false, false, newElement);
|
||||
if (rv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
event->SetTrusted(true);
|
||||
event->SetTarget(oldNode);
|
||||
nsEventDispatcher::DispatchDOMEvent(oldNode, nullptr, event,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
|
||||
NS_LITERAL_STRING("elementupgrade"),
|
||||
true, true);
|
||||
|
||||
// Create constructor to return. Store the name of the custom element as the
|
||||
// name of the function.
|
||||
JSFunction* constructor = JS_NewFunction(aCx, CustomElementConstructor, 0,
|
||||
JSFUN_CONSTRUCTOR, nullptr,
|
||||
NS_ConvertUTF16toUTF8(lcName).get());
|
||||
JSObject* constructorObject = JS_GetFunctionObject(constructor);
|
||||
return constructorObject;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetElementsByTagName(const nsAString& aTagname,
|
||||
nsIDOMNodeList** aReturn)
|
||||
|
@ -7427,6 +7672,8 @@ nsDocument::Destroy()
|
|||
// tearing down all those frame trees right now is the right thing to do.
|
||||
mExternalResourceMap.Shutdown();
|
||||
|
||||
mCustomPrototypes.Clear();
|
||||
|
||||
// XXX We really should let cycle collection do this, but that currently still
|
||||
// leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
|
||||
nsContentUtils::ReleaseWrapper(static_cast<nsINode*>(this), this);
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
#include "nsIProgressEventSink.h"
|
||||
#include "nsISecurityEventSink.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIDocumentRegister.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "mozilla/dom/DOMImplementation.h"
|
||||
#include "nsIDOMTouchEvent.h"
|
||||
|
@ -480,6 +481,7 @@ class nsDocument : public nsIDocument,
|
|||
public nsStubMutationObserver,
|
||||
public nsIDOMDocumentTouch,
|
||||
public nsIInlineEventHandlers,
|
||||
public nsIDocumentRegister,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
|
@ -779,6 +781,9 @@ public:
|
|||
// nsIInlineEventHandlers
|
||||
NS_DECL_NSIINLINEEVENTHANDLERS
|
||||
|
||||
// nsIDocumentRegister
|
||||
NS_DECL_NSIDOCUMENTREGISTER
|
||||
|
||||
// nsIObserver
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
|
@ -1013,9 +1018,22 @@ public:
|
|||
|
||||
virtual nsIDOMNode* AsDOMNode() { return this; }
|
||||
|
||||
JSObject* GetCustomPrototype(const nsAString& aElementName)
|
||||
{
|
||||
JSObject* prototype = nullptr;
|
||||
mCustomPrototypes.Get(aElementName, &prototype);
|
||||
return prototype;
|
||||
}
|
||||
|
||||
static bool RegisterEnabled();
|
||||
|
||||
// WebIDL bits
|
||||
virtual mozilla::dom::DOMImplementation*
|
||||
GetImplementation(mozilla::ErrorResult& rv);
|
||||
virtual JSObject*
|
||||
Register(JSContext* aCx, const nsAString& aName,
|
||||
const mozilla::dom::ElementRegistrationOptions& aOptions,
|
||||
mozilla::ErrorResult& rv);
|
||||
virtual nsIDOMStyleSheetList* StyleSheets();
|
||||
virtual void SetSelectedStyleSheetSet(const nsAString& aSheetSet);
|
||||
virtual void GetLastStyleSheetSet(nsString& aSheetSet);
|
||||
|
@ -1184,6 +1202,10 @@ protected:
|
|||
// non-null when this document is in fullscreen mode.
|
||||
nsWeakPtr mFullscreenRoot;
|
||||
|
||||
// Hashtable for custom element prototypes in web components.
|
||||
// Custom prototypes are in the document's compartment.
|
||||
nsDataHashtable<nsStringHashKey, JSObject*> mCustomPrototypes;
|
||||
|
||||
nsRefPtr<nsEventListenerManager> mListenerManager;
|
||||
nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
|
||||
nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;
|
||||
|
|
|
@ -156,6 +156,16 @@ public:
|
|||
nullptr, aNodesWithProperties, nullptr, aResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones aNode, its attributes and, if aDeep is true, its descendant nodes
|
||||
*/
|
||||
static nsresult Clone(nsINode *aNode, bool aDeep, nsINode **aResult)
|
||||
{
|
||||
nsCOMArray<nsINode> dummyNodeWithProperties;
|
||||
return CloneAndAdopt(aNode, true, aDeep, nullptr, nullptr, nullptr,
|
||||
dummyNodeWithProperties, aNode->GetParent(), aResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks aNode, its attributes and descendant nodes. If aNewNodeInfoManager is
|
||||
* not null, it is used to create new nodeinfos for the nodes. Also reparents
|
||||
|
|
|
@ -54,6 +54,7 @@ MOCHITEST_CHROME_FILES = \
|
|||
test_domparsing.xul \
|
||||
test_bug814638.xul \
|
||||
host_bug814638.xul \
|
||||
test_document_register.xul \
|
||||
frame_bug814638.xul \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<window title="Mozilla Bug 549682"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129"
|
||||
target="_blank">Mozilla Bug 783129</a>
|
||||
<iframe onload="startTests()" id="fooframe" src="http://example.com"></iframe>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
|
||||
/** Test for Bug 783129 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function startTests() {
|
||||
var c = $("fooframe").contentDocument.register("x-foo");
|
||||
var elem = new c();
|
||||
is(elem.tagName, "X-FOO", "Constructor should create an x-foo element.");
|
||||
|
||||
var anotherElem = $("fooframe").contentDocument.createElement("x-foo");
|
||||
is(anotherElem.tagName, "X-FOO", "createElement should create an x-foo element.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
]]></script>
|
||||
</window>
|
|
@ -866,6 +866,8 @@ nsEventDispatcher::CreateEvent(nsPresContext* aPresContext,
|
|||
if (aEventType.LowerCaseEqualsLiteral("commandevent") ||
|
||||
aEventType.LowerCaseEqualsLiteral("commandevents"))
|
||||
return NS_NewDOMCommandEvent(aDOMEvent, aPresContext, nullptr);
|
||||
if (aEventType.LowerCaseEqualsLiteral("elementreplace"))
|
||||
return NS_NewDOMElementReplaceEvent(aDOMEvent, aPresContext, nullptr);
|
||||
if (aEventType.LowerCaseEqualsLiteral("datacontainerevent") ||
|
||||
aEventType.LowerCaseEqualsLiteral("datacontainerevents"))
|
||||
return NS_NewDOMDataContainerEvent(aDOMEvent, aPresContext, nullptr);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsDocument.h"
|
||||
#include "HTMLUnknownElement.h"
|
||||
#include "mozilla/dom/HTMLElementBinding.h"
|
||||
|
||||
|
@ -18,7 +19,19 @@ JSObject*
|
|||
HTMLUnknownElement::WrapNode(JSContext *aCx, JSObject *aScope,
|
||||
bool *aTriedToWrap)
|
||||
{
|
||||
return HTMLUnknownElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
|
||||
JSObject* obj =
|
||||
HTMLUnknownElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
|
||||
if (obj && Substring(NodeName(), 0, 2).LowerCaseEqualsLiteral("x-")) {
|
||||
// If we have a registered x-tag then we fix the prototype.
|
||||
JSAutoCompartment ac(aCx, obj);
|
||||
nsDocument* document = static_cast<nsDocument*>(OwnerDoc());
|
||||
JSObject* prototype = document->GetCustomPrototype(LocalName());
|
||||
if (prototype) {
|
||||
NS_ENSURE_TRUE(JS_WrapObject(aCx, &prototype), nullptr);
|
||||
NS_ENSURE_TRUE(JS_SetPrototype(aCx, obj, prototype), nullptr);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
// QueryInterface implementation for HTMLUnknownElement
|
||||
|
|
|
@ -2044,6 +2044,8 @@ nsDOMClassInfo::Init()
|
|||
|
||||
DOM_CLASSINFO_MAP_BEGIN(HTMLDocument, nsIDOMHTMLDocument)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMHTMLDocument)
|
||||
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDocumentRegister,
|
||||
nsDocument::RegisterEnabled())
|
||||
DOM_CLASSINFO_DOCUMENT_MAP_ENTRIES
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ SDK_XPIDLSRCS = \
|
|||
nsIDOMNodeList.idl \
|
||||
nsIDOMProcessingInstruction.idl \
|
||||
nsIDOMText.idl \
|
||||
nsIDocumentRegister.idl \
|
||||
$(NULL)
|
||||
XPIDLSRCS = \
|
||||
nsIDOMDOMStringList.idl \
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(e35935bd-ebae-4e0d-93bf-efa93ab14c05)]
|
||||
interface nsIDocumentRegister : nsISupports
|
||||
{
|
||||
[optional_argc,
|
||||
implicit_jscontext] jsval register(in DOMString name,
|
||||
[optional] in jsval options)
|
||||
raises(DOMException);
|
||||
};
|
||||
|
|
@ -48,6 +48,7 @@ XPIDLSRCS = \
|
|||
nsIDOMUserProximityEvent.idl \
|
||||
nsIDOMDeviceOrientationEvent.idl \
|
||||
nsIDOMDeviceMotionEvent.idl \
|
||||
nsIDOMElementReplaceEvent.idl \
|
||||
nsIDOMScrollAreaEvent.idl \
|
||||
nsIDOMTransitionEvent.idl \
|
||||
nsIDOMAnimationEvent.idl \
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIDOMEvent.idl"
|
||||
|
||||
interface nsIDOMElement;
|
||||
|
||||
[scriptable, builtinclass, uuid(19a31767-54bf-4044-8769-cd172e37eca2)]
|
||||
interface nsIDOMElementReplaceEvent : nsIDOMEvent
|
||||
{
|
||||
readonly attribute nsIDOMElement upgrade;
|
||||
|
||||
void initElementReplaceEvent(in DOMString typeArg,
|
||||
in boolean canBubbleArg,
|
||||
in boolean canCancelArg,
|
||||
in nsIDOMElement upgrade);
|
||||
};
|
||||
|
||||
dictionary ElementReplaceEventInit : EventInit
|
||||
{
|
||||
nsIDOMElement upgrade;
|
||||
};
|
|
@ -64,6 +64,7 @@ var interfaceNamesInGlobalScope =
|
|||
"HTMLOptionElement",
|
||||
"Pkcs11",
|
||||
"NotifyAudioAvailableEvent",
|
||||
"ElementReplaceEvent",
|
||||
"Array",
|
||||
"SVGZoomAndPan",
|
||||
"XULPopupElement",
|
||||
|
|
|
@ -21,6 +21,7 @@ DIRS += [
|
|||
'storageevent',
|
||||
'pointerlock',
|
||||
'webapps',
|
||||
'webcomponents',
|
||||
]
|
||||
|
||||
#needs IPC support, also tests do not run successfully in Firefox for now
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DEPTH = @DEPTH@
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = @relativesrcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MOCHITEST_FILES = \
|
||||
test_document_register.html \
|
||||
test_document_register_lifecycle.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,5 @@
|
|||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test for document.register using custom prototype</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script>
|
||||
var gElementUpgraded = false;
|
||||
var gElementReplaced = false;
|
||||
|
||||
function elementUpgrade() {
|
||||
gElementUpgraded = true;
|
||||
|
||||
// Check for prototype on upgraded element.
|
||||
var documentElement = document.getElementById("grabme");
|
||||
ok(documentElement.hello, "Upgraded element should inherit 'hello' method from prototype.");
|
||||
documentElement.hello();
|
||||
|
||||
var customChild = document.getElementById("kid");
|
||||
ok(customChild, "Upgrade should preserve children.");
|
||||
ok(customChild.parentNode == documentElement, "Parent should be updated to new custom element.");
|
||||
|
||||
// Try creating new element and checking for prototype.
|
||||
var constructedElement = document.createElement("x-hello");
|
||||
ok(constructedElement.hello, "Created element should inherit 'hello' method from prototype.");
|
||||
constructedElement.hello();
|
||||
}
|
||||
|
||||
function elementReplace(e) {
|
||||
gElementReplaced = true;
|
||||
|
||||
ok(e.upgrade != e.target, "Upgraded element should be different from the target.");
|
||||
ok(e.upgrade.firstElementChild.id == "kid", "Upgrade element should have a child.");
|
||||
ok(e.target.firstElementChild.id == "kid", "Replacement element should have a child.");
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
// Create a prototype that inheits from HTMLElement.
|
||||
var customProto = {};
|
||||
customProto.__proto__ = HTMLElement.prototype;
|
||||
customProto.hello = function() {
|
||||
ok(true, "Custom element should use provided prototype.");
|
||||
};
|
||||
|
||||
var oldElem = document.getElementById("grabme");
|
||||
oldElem.addEventListener("elementreplace", elementReplace);
|
||||
|
||||
document.addEventListener("elementupgrade", elementUpgrade);
|
||||
var elementConstructor = document.register("x-hello", { prototype: customProto });
|
||||
|
||||
// Try creating new element and checking for prototype.
|
||||
var constructedElement = new elementConstructor();
|
||||
ok(constructedElement.hello, "Created element should inherit 'hello' method from prototype.");
|
||||
constructedElement.hello();
|
||||
|
||||
ok(!oldElem.hello, "Element obtained prior to registration should not have inherited prototype.");
|
||||
|
||||
ok(gElementUpgraded && gElementReplaced, "Upgrade and replace events should have been fired.");
|
||||
|
||||
// Check that custom elements registered without a prototype inherit from HTMLElement.
|
||||
document.register("x-bye");
|
||||
var byeElement = document.createElement("x-bye");
|
||||
ok(byeElement.__proto__.__proto__, HTMLElement.prototype, "Element registered without prototype should inherit from HTMLElement.");
|
||||
|
||||
// Check that element registration with a prototype that does not inherit from HTMLElement results in exception.
|
||||
try {
|
||||
document.register("x-foo", { "prototype": {} });
|
||||
ok(false, "Prototype that does not inherit from HTMLElement should throw exception");
|
||||
} catch (ex) {
|
||||
ok(true, "Prototype that does not inherit from HTMLElement should throw exception");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body onload="startTest()">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
|
||||
<x-hello id="grabme">
|
||||
<div id="kid"></div>
|
||||
</x-hello>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=783129
|
||||
-->
|
||||
<head>
|
||||
<title>Test for document.register lifecycle callback</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script>
|
||||
|
||||
var gLifecycleCallbackCalled = false;
|
||||
|
||||
var lifecycleCallbacks = {
|
||||
created: function() {
|
||||
is(this.getAttribute("id"), "grabme", "|this| value should be the upgrade element");
|
||||
gLifecycleCallbackCalled = true;
|
||||
}
|
||||
};
|
||||
|
||||
function startTest() {
|
||||
var HtmlProto = function() {};
|
||||
HtmlProto.prototype = HTMLElement.prototype;
|
||||
|
||||
// Create a prototype that inheits from HTMLElement.
|
||||
var customProto = new HtmlProto();
|
||||
customProto.hello = function() {
|
||||
ok(true, "Custom element should use provided prototype.");
|
||||
};
|
||||
|
||||
var elementConstructor = document.register("x-hello", { prototype: customProto, lifecycle: lifecycleCallbacks });
|
||||
|
||||
ok(gLifecycleCallbackCalled, "Lifecycle callback should be called.");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body onload="startTest()">
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783129">Bug 783129</a>
|
||||
<x-hello id="grabme">
|
||||
<div id="kid"></div>
|
||||
</x-hello>
|
||||
</body>
|
||||
</html>
|
|
@ -228,6 +228,12 @@ partial interface Document {
|
|||
void mozExitPointerLock ();
|
||||
};
|
||||
|
||||
//http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-document-register
|
||||
partial interface Document {
|
||||
[Throws, Pref="dom.webcomponents.enabled"]
|
||||
object register(DOMString name, optional ElementRegistrationOptions options);
|
||||
};
|
||||
|
||||
// http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface
|
||||
partial interface Document {
|
||||
readonly attribute boolean hidden;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
interface DocumentFragment;
|
||||
|
||||
callback LifecycleCreatedCallback = void();
|
||||
|
||||
dictionary LifecycleCallbacks {
|
||||
LifecycleCreatedCallback? created = null;
|
||||
};
|
||||
|
||||
dictionary ElementRegistrationOptions {
|
||||
object? prototype = null;
|
||||
LifecycleCallbacks lifecycle;
|
||||
};
|
||||
|
|
@ -217,6 +217,7 @@ webidl_files = \
|
|||
TreeWalker.webidl \
|
||||
URL.webidl \
|
||||
ValidityState.webidl \
|
||||
WebComponents.webidl \
|
||||
WebSocket.webidl \
|
||||
UndoManager.webidl \
|
||||
URLUtils.webidl \
|
||||
|
|
|
@ -39,6 +39,7 @@ simple_events = [
|
|||
'MozVoicemailEvent',
|
||||
'USSDReceivedEvent',
|
||||
#endif
|
||||
'ElementReplaceEvent',
|
||||
'MozSmsEvent',
|
||||
'DeviceStorageChangeEvent',
|
||||
'PopupBlockedEvent',
|
||||
|
|
Загрузка…
Ссылка в новой задаче