From 91f9dc53a10539462cdb058d59cc84c367c5f9e1 Mon Sep 17 00:00:00 2001 From: "hyatt%netscape.com" Date: Sat, 11 Mar 2000 10:36:39 +0000 Subject: [PATCH] new XBL features --- content/xbl/public/nsIXBLBinding.h | 2 + content/xbl/public/nsIXBLService.h | 4 + content/xbl/src/nsXBLBinding.cpp | 171 ++++++++++++++++++------- content/xbl/src/nsXBLService.cpp | 33 ++++- layout/xbl/public/nsIBindableContent.h | 3 + layout/xbl/public/nsIXBLBinding.h | 2 + layout/xbl/public/nsIXBLService.h | 4 + layout/xbl/src/nsXBLBinding.cpp | 171 ++++++++++++++++++------- layout/xbl/src/nsXBLService.cpp | 33 ++++- 9 files changed, 317 insertions(+), 106 deletions(-) diff --git a/content/xbl/public/nsIXBLBinding.h b/content/xbl/public/nsIXBLBinding.h index 8870181c8fb5..770adb02d84b 100644 --- a/content/xbl/public/nsIXBLBinding.h +++ b/content/xbl/public/nsIXBLBinding.h @@ -56,6 +56,8 @@ public: NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement) = 0; + NS_IMETHOD GetBaseTag(nsIAtom** aResult) = 0; + // Called when an attribute changes on a binding. NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag) = 0; diff --git a/content/xbl/public/nsIXBLService.h b/content/xbl/public/nsIXBLService.h index a890ee748e68..75548e980eca 100644 --- a/content/xbl/public/nsIXBLService.h +++ b/content/xbl/public/nsIXBLService.h @@ -51,6 +51,10 @@ public: // For a given element, returns a flat list of all the anonymous children that need // frames built. NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult) = 0; + + // Retrieves our base class (e.g., tells us what type of frame and content node to build) + NS_IMETHOD GetBaseTag(nsIContent* aContent, nsIAtom** aResult) = 0; + }; #endif // nsIXBLService_h__ diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index f4baa3fa54b1..e09c163c6be6 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -14,11 +14,13 @@ #include "plstr.h" #include "nsIContent.h" #include "nsIDocument.h" +#include "nsIXMLContent.h" #include "nsIXMLContentSink.h" #include "nsLayoutCID.h" #include "nsXMLDocument.h" #include "nsIDOMElement.h" #include "nsSupportsArray.h" +#include "nsINameSpace.h" // Event listeners #include "nsIDOMMouseListener.h" @@ -31,11 +33,14 @@ #include "nsIDOMMenuListener.h" #include "nsIDOMDragListener.h" +#include "nsIDOMAttr.h" +#include "nsIDOMNamedNodeMap.h" + #include "nsXBLEventHandler.h" #include "nsIXBLBinding.h" // Static IIDs/CIDs. Try to minimize these. -// None +static char kNameSpaceSeparator = ':'; // Helper classes // {A2892B81-CED9-11d3-97FB-00400553EEF0} @@ -86,6 +91,8 @@ class nsXBLBinding: public nsIXBLBinding NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); + NS_IMETHOD GetBaseTag(nsIAtom** aResult); + NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag); public: @@ -102,6 +109,7 @@ public: static nsIAtom* kInheritsAtom; static nsIAtom* kTypeAtom; static nsIAtom* kCapturerAtom; + static nsIAtom* kExtendsAtom; // Used to easily obtain the correct IID for an event. struct EventHandlerMapEntry { @@ -145,6 +153,7 @@ nsIAtom* nsXBLBinding::kExcludesAtom = nsnull; nsIAtom* nsXBLBinding::kInheritsAtom = nsnull; nsIAtom* nsXBLBinding::kTypeAtom = nsnull; nsIAtom* nsXBLBinding::kCapturerAtom = nsnull; +nsIAtom* nsXBLBinding::kExtendsAtom = nsnull; nsXBLBinding::EventHandlerMapEntry nsXBLBinding::kEventHandlerMap[] = { @@ -212,6 +221,7 @@ nsXBLBinding::nsXBLBinding(void) kInheritsAtom = NS_NewAtom("inherits"); kTypeAtom = NS_NewAtom("type"); kCapturerAtom = NS_NewAtom("capturer"); + kExtendsAtom = NS_NewAtom("extends"); EventHandlerMapEntry* entry = kEventHandlerMap; while (entry->mAttributeName) { @@ -234,6 +244,7 @@ nsXBLBinding::~nsXBLBinding(void) NS_RELEASE(kInheritsAtom); NS_RELEASE(kTypeAtom); NS_RELEASE(kCapturerAtom); + NS_RELEASE(kExtendsAtom); EventHandlerMapEntry* entry = kEventHandlerMap; while (entry->mAttributeName) { @@ -331,6 +342,32 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) else return NS_OK; } + nsCOMPtr node(do_QueryInterface(content)); + nsCOMPtr namedMap; + + node->GetAttributes(getter_AddRefs(namedMap)); + PRUint32 length; + namedMap->GetLength(&length); + + nsCOMPtr attribute; + for (PRUint32 i = 0; i < length; ++i) + { + namedMap->Item(i, getter_AddRefs(attribute)); + nsCOMPtr attr(do_QueryInterface(attribute)); + nsAutoString name; + attr->GetName(name); + if (name != L"excludes") { + nsAutoString value; + nsCOMPtr element(do_QueryInterface(mBoundElement)); + element->GetAttribute(name, value); + if (value == "") { + nsAutoString value2; + attr->GetValue(value2); + element->SetAttribute(name, value2); + } + } + } + // Plan to build the content by default. PRBool buildContent = PR_TRUE; PRInt32 childCount; @@ -382,58 +419,57 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) nsCOMPtr handlers; GetImmediateChild(kHandlersAtom, getter_AddRefs(handlers)); - if (!handlers) - return NS_OK; + if (handlers) { + // Now walk the handlers and add event listeners to the bound + // element. + PRInt32 childCount; + handlers->ChildCount(childCount); + for (PRInt32 i = 0; i < childCount; i++) { + nsCOMPtr child; + handlers->ChildAt(i, *getter_AddRefs(child)); - // Now walk the handlers and add event listeners to the bound - // element. - PRInt32 childCount; - handlers->ChildCount(childCount); - for (PRInt32 i = 0; i < childCount; i++) { - nsCOMPtr child; - handlers->ChildAt(i, *getter_AddRefs(child)); - - // Fetch the type attribute. - // XXX Deal with a comma-separated list of types - nsAutoString type; - child->GetAttribute(kNameSpaceID_None, kTypeAtom, type); + // Fetch the type attribute. + // XXX Deal with a comma-separated list of types + nsAutoString type; + child->GetAttribute(kNameSpaceID_None, kTypeAtom, type); - if (type != "") { - nsCOMPtr eventAtom = getter_AddRefs(NS_NewAtom(type)); - PRBool found = PR_FALSE; - nsIID iid; - GetEventHandlerIID(eventAtom, &iid, &found); - if (found) { - // Add an event listener for mouse and key events only. - PRBool mouse = IsMouseHandler(type); - PRBool key = IsKeyHandler(type); - PRBool xul = IsXULHandler(type); + if (type != "") { + nsCOMPtr eventAtom = getter_AddRefs(NS_NewAtom(type)); + PRBool found = PR_FALSE; + nsIID iid; + GetEventHandlerIID(eventAtom, &iid, &found); + if (found) { + // Add an event listener for mouse and key events only. + PRBool mouse = IsMouseHandler(type); + PRBool key = IsKeyHandler(type); + PRBool xul = IsXULHandler(type); - if (mouse || key || xul) { - // Create a new nsXBLEventHandler. - nsXBLEventHandler* handler; - NS_NewXBLEventHandler(mBoundElement, child, type, &handler); + if (mouse || key || xul) { + // Create a new nsXBLEventHandler. + nsXBLEventHandler* handler; + NS_NewXBLEventHandler(mBoundElement, child, type, &handler); - // Figure out if we're using capturing or not. - PRBool useCapture = PR_FALSE; - nsAutoString capturer; - child->GetAttribute(kNameSpaceID_None, kCapturerAtom, capturer); - if (capturer == "true") - useCapture = PR_TRUE; + // Figure out if we're using capturing or not. + PRBool useCapture = PR_FALSE; + nsAutoString capturer; + child->GetAttribute(kNameSpaceID_None, kCapturerAtom, capturer); + if (capturer == "true") + useCapture = PR_TRUE; - // Add the event listener. - nsCOMPtr receiver = do_QueryInterface(mBoundElement); - if (mouse) - receiver->AddEventListener(type, (nsIDOMMouseListener*)handler, useCapture); - else if(key) - receiver->AddEventListener(type, (nsIDOMKeyListener*)handler, useCapture); - else - receiver->AddEventListener(type, (nsIDOMMenuListener*)handler, useCapture); + // Add the event listener. + nsCOMPtr receiver = do_QueryInterface(mBoundElement); + if (mouse) + receiver->AddEventListener(type, (nsIDOMMouseListener*)handler, useCapture); + else if(key) + receiver->AddEventListener(type, (nsIDOMKeyListener*)handler, useCapture); + else + receiver->AddEventListener(type, (nsIDOMMenuListener*)handler, useCapture); - NS_RELEASE(handler); - } + NS_RELEASE(handler); + } - // XXX Call AddScriptEventListener for other IID types + // XXX Call AddScriptEventListener for other IID types + } } } } @@ -444,6 +480,49 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) return NS_OK; } +NS_IMETHODIMP +nsXBLBinding::GetBaseTag(nsIAtom** aResult) +{ + if (mNextBinding) + return mNextBinding->GetBaseTag(aResult); + + // XXX Cache the value as a "base" attribute so that we don't do this + // check over and over each time the bound element occurs. + + // We are the base binding. Obtain the extends attribute. + nsAutoString extends; + mBinding->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends); + + if (extends != "") { + // Obtain the namespace prefix. + nsAutoString prefix; + PRInt32 offset = extends.FindChar(kNameSpaceSeparator); + if (-1 != offset) { + extends.Left(prefix, offset); + extends.Cut(0, offset+1); + } + if (prefix.Length() > 0) { + // Look up the prefix. + nsCOMPtr prefixAtom = getter_AddRefs(NS_NewAtom(prefix)); + nsCOMPtr nameSpace; + nsCOMPtr xmlContent(do_QueryInterface(mBinding)); + if (xmlContent) { + xmlContent->GetContainingNameSpace(*getter_AddRefs(nameSpace)); + + nsCOMPtr tagSpace; + nameSpace->FindNameSpace(prefixAtom, *getter_AddRefs(tagSpace)); + if (tagSpace) { + // Score! Return the tag. + // XXX We should really return the namespace as well. + *aResult = NS_NewAtom(extends); // The addref happens here + } + } + } + } + + return NS_OK; +} + NS_IMETHODIMP nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag) { diff --git a/content/xbl/src/nsXBLService.cpp b/content/xbl/src/nsXBLService.cpp index 743cfcfb0645..913d2ccba925 100644 --- a/content/xbl/src/nsXBLService.cpp +++ b/content/xbl/src/nsXBLService.cpp @@ -98,6 +98,9 @@ class nsXBLService: public nsIXBLService // frames built. NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult); + // Gets the object's base class type. + NS_IMETHOD GetBaseTag(nsIContent* aContent, nsIAtom** aResult); + public: nsXBLService(); virtual ~nsXBLService(); @@ -279,6 +282,7 @@ nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult) (*aResult)->AppendElement(anonymousChild); } + return NS_OK; } nsCOMPtr nextBinding; @@ -288,6 +292,16 @@ nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult) return NS_OK; } +NS_IMETHODIMP +nsXBLService::GetBaseTag(nsIContent* aContent, nsIAtom** aResult) +{ + *aResult = nsnull; + nsCOMPtr bindable = do_QueryInterface(aContent); + if (!bindable) + return NS_ERROR_FAILURE; + + return bindable->GetBaseTag(aResult); +} // Internal helper methods //////////////////////////////////////////////////////////////// @@ -344,13 +358,18 @@ NS_IMETHODIMP nsXBLService::GetBinding(nsCAutoString& aURLStr, nsIXBLBinding** a // Check for the presence of an extends attribute child->GetAttribute(kNameSpaceID_None, kExtendsAtom, value); if (value != "") { - // We have a base class binding. Load it right now. - nsCOMPtr baseBinding; - nsCAutoString url = value; - GetBinding(url, getter_AddRefs(baseBinding)); - if (!baseBinding) - return NS_OK; // At least we got the derived class binding loaded. - (*aResult)->SetBaseBinding(baseBinding); + // See if we are extending a builtin tag. + nsCOMPtr tag; + (*aResult)->GetBaseTag(getter_AddRefs(tag)); + if (!tag) { + // We have a base class binding. Load it right now. + nsCOMPtr baseBinding; + nsCAutoString url = value; + GetBinding(url, getter_AddRefs(baseBinding)); + if (!baseBinding) + return NS_OK; // At least we got the derived class binding loaded. + (*aResult)->SetBaseBinding(baseBinding); + } } break; diff --git a/layout/xbl/public/nsIBindableContent.h b/layout/xbl/public/nsIBindableContent.h index c7e57fc67a26..a2fe01fb18f8 100644 --- a/layout/xbl/public/nsIBindableContent.h +++ b/layout/xbl/public/nsIBindableContent.h @@ -34,6 +34,7 @@ class nsIContent; class nsIXBLBinding; +class nsIAtom; // {55D70FE0-C8E5-11d3-97FB-00400553EEF0} #define NS_IBINDABLE_CONTENT_IID \ @@ -46,6 +47,8 @@ public: NS_IMETHOD SetBinding(nsIXBLBinding* aBinding) = 0; NS_IMETHOD GetBinding(nsIXBLBinding** aResult) = 0; + + NS_IMETHOD GetBaseTag(nsIAtom** aResult) = 0; }; #endif // nsIBINDABLE_CONTENT_h__ diff --git a/layout/xbl/public/nsIXBLBinding.h b/layout/xbl/public/nsIXBLBinding.h index 8870181c8fb5..770adb02d84b 100644 --- a/layout/xbl/public/nsIXBLBinding.h +++ b/layout/xbl/public/nsIXBLBinding.h @@ -56,6 +56,8 @@ public: NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement) = 0; + NS_IMETHOD GetBaseTag(nsIAtom** aResult) = 0; + // Called when an attribute changes on a binding. NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag) = 0; diff --git a/layout/xbl/public/nsIXBLService.h b/layout/xbl/public/nsIXBLService.h index a890ee748e68..75548e980eca 100644 --- a/layout/xbl/public/nsIXBLService.h +++ b/layout/xbl/public/nsIXBLService.h @@ -51,6 +51,10 @@ public: // For a given element, returns a flat list of all the anonymous children that need // frames built. NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult) = 0; + + // Retrieves our base class (e.g., tells us what type of frame and content node to build) + NS_IMETHOD GetBaseTag(nsIContent* aContent, nsIAtom** aResult) = 0; + }; #endif // nsIXBLService_h__ diff --git a/layout/xbl/src/nsXBLBinding.cpp b/layout/xbl/src/nsXBLBinding.cpp index f4baa3fa54b1..e09c163c6be6 100644 --- a/layout/xbl/src/nsXBLBinding.cpp +++ b/layout/xbl/src/nsXBLBinding.cpp @@ -14,11 +14,13 @@ #include "plstr.h" #include "nsIContent.h" #include "nsIDocument.h" +#include "nsIXMLContent.h" #include "nsIXMLContentSink.h" #include "nsLayoutCID.h" #include "nsXMLDocument.h" #include "nsIDOMElement.h" #include "nsSupportsArray.h" +#include "nsINameSpace.h" // Event listeners #include "nsIDOMMouseListener.h" @@ -31,11 +33,14 @@ #include "nsIDOMMenuListener.h" #include "nsIDOMDragListener.h" +#include "nsIDOMAttr.h" +#include "nsIDOMNamedNodeMap.h" + #include "nsXBLEventHandler.h" #include "nsIXBLBinding.h" // Static IIDs/CIDs. Try to minimize these. -// None +static char kNameSpaceSeparator = ':'; // Helper classes // {A2892B81-CED9-11d3-97FB-00400553EEF0} @@ -86,6 +91,8 @@ class nsXBLBinding: public nsIXBLBinding NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); + NS_IMETHOD GetBaseTag(nsIAtom** aResult); + NS_IMETHOD AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag); public: @@ -102,6 +109,7 @@ public: static nsIAtom* kInheritsAtom; static nsIAtom* kTypeAtom; static nsIAtom* kCapturerAtom; + static nsIAtom* kExtendsAtom; // Used to easily obtain the correct IID for an event. struct EventHandlerMapEntry { @@ -145,6 +153,7 @@ nsIAtom* nsXBLBinding::kExcludesAtom = nsnull; nsIAtom* nsXBLBinding::kInheritsAtom = nsnull; nsIAtom* nsXBLBinding::kTypeAtom = nsnull; nsIAtom* nsXBLBinding::kCapturerAtom = nsnull; +nsIAtom* nsXBLBinding::kExtendsAtom = nsnull; nsXBLBinding::EventHandlerMapEntry nsXBLBinding::kEventHandlerMap[] = { @@ -212,6 +221,7 @@ nsXBLBinding::nsXBLBinding(void) kInheritsAtom = NS_NewAtom("inherits"); kTypeAtom = NS_NewAtom("type"); kCapturerAtom = NS_NewAtom("capturer"); + kExtendsAtom = NS_NewAtom("extends"); EventHandlerMapEntry* entry = kEventHandlerMap; while (entry->mAttributeName) { @@ -234,6 +244,7 @@ nsXBLBinding::~nsXBLBinding(void) NS_RELEASE(kInheritsAtom); NS_RELEASE(kTypeAtom); NS_RELEASE(kCapturerAtom); + NS_RELEASE(kExtendsAtom); EventHandlerMapEntry* entry = kEventHandlerMap; while (entry->mAttributeName) { @@ -331,6 +342,32 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) else return NS_OK; } + nsCOMPtr node(do_QueryInterface(content)); + nsCOMPtr namedMap; + + node->GetAttributes(getter_AddRefs(namedMap)); + PRUint32 length; + namedMap->GetLength(&length); + + nsCOMPtr attribute; + for (PRUint32 i = 0; i < length; ++i) + { + namedMap->Item(i, getter_AddRefs(attribute)); + nsCOMPtr attr(do_QueryInterface(attribute)); + nsAutoString name; + attr->GetName(name); + if (name != L"excludes") { + nsAutoString value; + nsCOMPtr element(do_QueryInterface(mBoundElement)); + element->GetAttribute(name, value); + if (value == "") { + nsAutoString value2; + attr->GetValue(value2); + element->SetAttribute(name, value2); + } + } + } + // Plan to build the content by default. PRBool buildContent = PR_TRUE; PRInt32 childCount; @@ -382,58 +419,57 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) nsCOMPtr handlers; GetImmediateChild(kHandlersAtom, getter_AddRefs(handlers)); - if (!handlers) - return NS_OK; + if (handlers) { + // Now walk the handlers and add event listeners to the bound + // element. + PRInt32 childCount; + handlers->ChildCount(childCount); + for (PRInt32 i = 0; i < childCount; i++) { + nsCOMPtr child; + handlers->ChildAt(i, *getter_AddRefs(child)); - // Now walk the handlers and add event listeners to the bound - // element. - PRInt32 childCount; - handlers->ChildCount(childCount); - for (PRInt32 i = 0; i < childCount; i++) { - nsCOMPtr child; - handlers->ChildAt(i, *getter_AddRefs(child)); - - // Fetch the type attribute. - // XXX Deal with a comma-separated list of types - nsAutoString type; - child->GetAttribute(kNameSpaceID_None, kTypeAtom, type); + // Fetch the type attribute. + // XXX Deal with a comma-separated list of types + nsAutoString type; + child->GetAttribute(kNameSpaceID_None, kTypeAtom, type); - if (type != "") { - nsCOMPtr eventAtom = getter_AddRefs(NS_NewAtom(type)); - PRBool found = PR_FALSE; - nsIID iid; - GetEventHandlerIID(eventAtom, &iid, &found); - if (found) { - // Add an event listener for mouse and key events only. - PRBool mouse = IsMouseHandler(type); - PRBool key = IsKeyHandler(type); - PRBool xul = IsXULHandler(type); + if (type != "") { + nsCOMPtr eventAtom = getter_AddRefs(NS_NewAtom(type)); + PRBool found = PR_FALSE; + nsIID iid; + GetEventHandlerIID(eventAtom, &iid, &found); + if (found) { + // Add an event listener for mouse and key events only. + PRBool mouse = IsMouseHandler(type); + PRBool key = IsKeyHandler(type); + PRBool xul = IsXULHandler(type); - if (mouse || key || xul) { - // Create a new nsXBLEventHandler. - nsXBLEventHandler* handler; - NS_NewXBLEventHandler(mBoundElement, child, type, &handler); + if (mouse || key || xul) { + // Create a new nsXBLEventHandler. + nsXBLEventHandler* handler; + NS_NewXBLEventHandler(mBoundElement, child, type, &handler); - // Figure out if we're using capturing or not. - PRBool useCapture = PR_FALSE; - nsAutoString capturer; - child->GetAttribute(kNameSpaceID_None, kCapturerAtom, capturer); - if (capturer == "true") - useCapture = PR_TRUE; + // Figure out if we're using capturing or not. + PRBool useCapture = PR_FALSE; + nsAutoString capturer; + child->GetAttribute(kNameSpaceID_None, kCapturerAtom, capturer); + if (capturer == "true") + useCapture = PR_TRUE; - // Add the event listener. - nsCOMPtr receiver = do_QueryInterface(mBoundElement); - if (mouse) - receiver->AddEventListener(type, (nsIDOMMouseListener*)handler, useCapture); - else if(key) - receiver->AddEventListener(type, (nsIDOMKeyListener*)handler, useCapture); - else - receiver->AddEventListener(type, (nsIDOMMenuListener*)handler, useCapture); + // Add the event listener. + nsCOMPtr receiver = do_QueryInterface(mBoundElement); + if (mouse) + receiver->AddEventListener(type, (nsIDOMMouseListener*)handler, useCapture); + else if(key) + receiver->AddEventListener(type, (nsIDOMKeyListener*)handler, useCapture); + else + receiver->AddEventListener(type, (nsIDOMMenuListener*)handler, useCapture); - NS_RELEASE(handler); - } + NS_RELEASE(handler); + } - // XXX Call AddScriptEventListener for other IID types + // XXX Call AddScriptEventListener for other IID types + } } } } @@ -444,6 +480,49 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) return NS_OK; } +NS_IMETHODIMP +nsXBLBinding::GetBaseTag(nsIAtom** aResult) +{ + if (mNextBinding) + return mNextBinding->GetBaseTag(aResult); + + // XXX Cache the value as a "base" attribute so that we don't do this + // check over and over each time the bound element occurs. + + // We are the base binding. Obtain the extends attribute. + nsAutoString extends; + mBinding->GetAttribute(kNameSpaceID_None, kExtendsAtom, extends); + + if (extends != "") { + // Obtain the namespace prefix. + nsAutoString prefix; + PRInt32 offset = extends.FindChar(kNameSpaceSeparator); + if (-1 != offset) { + extends.Left(prefix, offset); + extends.Cut(0, offset+1); + } + if (prefix.Length() > 0) { + // Look up the prefix. + nsCOMPtr prefixAtom = getter_AddRefs(NS_NewAtom(prefix)); + nsCOMPtr nameSpace; + nsCOMPtr xmlContent(do_QueryInterface(mBinding)); + if (xmlContent) { + xmlContent->GetContainingNameSpace(*getter_AddRefs(nameSpace)); + + nsCOMPtr tagSpace; + nameSpace->FindNameSpace(prefixAtom, *getter_AddRefs(tagSpace)); + if (tagSpace) { + // Score! Return the tag. + // XXX We should really return the namespace as well. + *aResult = NS_NewAtom(extends); // The addref happens here + } + } + } + } + + return NS_OK; +} + NS_IMETHODIMP nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag) { diff --git a/layout/xbl/src/nsXBLService.cpp b/layout/xbl/src/nsXBLService.cpp index 743cfcfb0645..913d2ccba925 100644 --- a/layout/xbl/src/nsXBLService.cpp +++ b/layout/xbl/src/nsXBLService.cpp @@ -98,6 +98,9 @@ class nsXBLService: public nsIXBLService // frames built. NS_IMETHOD GetContentList(nsIContent* aContent, nsISupportsArray** aResult); + // Gets the object's base class type. + NS_IMETHOD GetBaseTag(nsIContent* aContent, nsIAtom** aResult); + public: nsXBLService(); virtual ~nsXBLService(); @@ -279,6 +282,7 @@ nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult) (*aResult)->AppendElement(anonymousChild); } + return NS_OK; } nsCOMPtr nextBinding; @@ -288,6 +292,16 @@ nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult) return NS_OK; } +NS_IMETHODIMP +nsXBLService::GetBaseTag(nsIContent* aContent, nsIAtom** aResult) +{ + *aResult = nsnull; + nsCOMPtr bindable = do_QueryInterface(aContent); + if (!bindable) + return NS_ERROR_FAILURE; + + return bindable->GetBaseTag(aResult); +} // Internal helper methods //////////////////////////////////////////////////////////////// @@ -344,13 +358,18 @@ NS_IMETHODIMP nsXBLService::GetBinding(nsCAutoString& aURLStr, nsIXBLBinding** a // Check for the presence of an extends attribute child->GetAttribute(kNameSpaceID_None, kExtendsAtom, value); if (value != "") { - // We have a base class binding. Load it right now. - nsCOMPtr baseBinding; - nsCAutoString url = value; - GetBinding(url, getter_AddRefs(baseBinding)); - if (!baseBinding) - return NS_OK; // At least we got the derived class binding loaded. - (*aResult)->SetBaseBinding(baseBinding); + // See if we are extending a builtin tag. + nsCOMPtr tag; + (*aResult)->GetBaseTag(getter_AddRefs(tag)); + if (!tag) { + // We have a base class binding. Load it right now. + nsCOMPtr baseBinding; + nsCAutoString url = value; + GetBinding(url, getter_AddRefs(baseBinding)); + if (!baseBinding) + return NS_OK; // At least we got the derived class binding loaded. + (*aResult)->SetBaseBinding(baseBinding); + } } break;