diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 3d0c325bb069..b3eefe728d3f 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -64,6 +64,7 @@ #include "nsIDOMDOMImplementation.h" #include "nsIDOMDocumentView.h" #include "nsIDOMAbstractView.h" +#include "nsIDOMDocumentXBL.h" #include "nsGenericElement.h" #include "nsICSSStyleSheet.h" @@ -758,6 +759,12 @@ nsresult nsDocument::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(NS_GET_IID(nsIDOMDocumentXBL))) { + nsIDOMDocumentView* tmp = this; + *aInstancePtr = (void*) tmp; + NS_ADDREF_THIS(); + return NS_OK; + } if (aIID.Equals(NS_GET_IID(nsIScriptObjectOwner))) { nsIScriptObjectOwner* tmp = this; *aInstancePtr = (void*) tmp; @@ -2219,6 +2226,27 @@ nsDocument::CreateElementWithNameSpace(const nsString& aTagName, return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +nsDocument::AddBinding(nsIDOMElement* aContent, const nsString& aURL) +{ + nsCOMPtr bm; + GetBindingManager(getter_AddRefs(bm)); + nsCOMPtr content(do_QueryInterface(aContent)); + + return bm->AddLayeredBinding(content, aURL); +} + +NS_IMETHODIMP +nsDocument::RemoveBinding(nsIDOMElement* aContent, const nsString& aURL) +{ + if (mBindingManager) { + nsCOMPtr content(do_QueryInterface(aContent)); + return mBindingManager->RemoveLayeredBinding(content, aURL); + } + + return NS_ERROR_FAILURE; +} + NS_IMETHODIMP nsDocument::GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult) { diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index f4ec4c3f869c..5a1b5320360f 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -28,6 +28,7 @@ #include "nsVoidArray.h" #include "nsIDOMDocument.h" #include "nsIDOMDocumentView.h" +#include "nsIDOMDocumentXBL.h" #include "nsIDOMNSDocument.h" #include "nsIDOMDocumentStyle.h" #include "nsIDOMEventReceiver.h" @@ -131,6 +132,7 @@ class nsDocument : public nsIDocument, public nsIDOMDocumentEvent, public nsIDOMDocumentStyle, public nsIDOMDocumentView, + public nsIDOMDocumentXBL, public nsIDiskDocument, public nsIJSScriptObject, public nsSupportsWeakReference, @@ -395,7 +397,6 @@ public: NS_IMETHOD GetWidth(PRInt32* aWidth); NS_IMETHOD GetHeight(PRInt32* aHeight); NS_IMETHOD Load (const nsString& aUrl, const nsString& aMimeType); - NS_IMETHOD GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult); // nsIDOMNode interface NS_DECL_IDOMNODE @@ -403,6 +404,9 @@ public: // nsIDOMDocumentView NS_DECL_IDOMDOCUMENTVIEW + // nsIDOMDocumentXBL + NS_DECL_IDOMDOCUMENTXBL + // nsIDOMDocumentEvent NS_DECL_IDOMDOCUMENTEVENT diff --git a/content/xbl/public/nsIBindingManager.h b/content/xbl/public/nsIBindingManager.h index a1ce9a8f90a0..ef1f5cddef60 100644 --- a/content/xbl/public/nsIBindingManager.h +++ b/content/xbl/public/nsIBindingManager.h @@ -55,6 +55,9 @@ public: NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult) = 0; NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRBool* aMultipleInsertionPoints) = 0; + + NS_IMETHOD AddLayeredBinding(nsIContent* aContent, const nsString& aURL) = 0; + NS_IMETHOD RemoveLayeredBinding(nsIContent* aContent, const nsString& aURL) = 0; }; #endif // nsIBinding_Manager_h__ diff --git a/content/xbl/public/nsIXBLBinding.h b/content/xbl/public/nsIXBLBinding.h index 53fccd795815..9dc310840567 100644 --- a/content/xbl/public/nsIXBLBinding.h +++ b/content/xbl/public/nsIXBLBinding.h @@ -57,6 +57,9 @@ public: NS_IMETHOD GetBindingElement(nsIContent** aResult) = 0; NS_IMETHOD SetBindingElement(nsIContent* aElement) = 0; + NS_IMETHOD GetBoundElement(nsIContent** aResult) = 0; + NS_IMETHOD SetBoundElement(nsIContent* aElement) = 0; + NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallProperties(nsIContent* aBoundElement) = 0; @@ -72,6 +75,12 @@ public: NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult) = 0; NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints) = 0; + + NS_IMETHOD IsStyleBinding(PRBool* aResult) = 0; + NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) = 0; + + NS_IMETHOD GetRootBinding(nsIXBLBinding** aResult) = 0; + NS_IMETHOD GetFirstStyleBinding(nsIXBLBinding** aResult) = 0; }; extern nsresult diff --git a/content/xbl/public/nsIXBLService.h b/content/xbl/public/nsIXBLService.h index d2666ca8facb..652e2560b921 100644 --- a/content/xbl/public/nsIXBLService.h +++ b/content/xbl/public/nsIXBLService.h @@ -48,10 +48,10 @@ public: // This function loads a particular XBL file and installs all of the bindings // onto the element. - NS_IMETHOD LoadBindings(nsIContent* aContent, const nsString& aURL) = 0; + NS_IMETHOD LoadBindings(nsIContent* aContent, const nsString& aURL, PRBool aAugmentFlag) = 0; // This function clears out the bindings on a given content node. - NS_IMETHOD FlushBindings(nsIContent* aContent) = 0; + NS_IMETHOD FlushStyleBindings(nsIContent* aContent) = 0; // This function clears out the binding documents in our cache. NS_IMETHOD FlushBindingDocuments() = 0; diff --git a/content/xbl/src/nsBindingManager.cpp b/content/xbl/src/nsBindingManager.cpp index 57fffadcd17c..fbeefedc5812 100644 --- a/content/xbl/src/nsBindingManager.cpp +++ b/content/xbl/src/nsBindingManager.cpp @@ -69,6 +69,9 @@ public: NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRBool* aMultipleInsertionPoints); + NS_IMETHOD AddLayeredBinding(nsIContent* aContent, const nsString& aURL); + NS_IMETHOD RemoveLayeredBinding(nsIContent* aContent, const nsString& aURL); + // MEMBER VARIABLES protected: nsSupportsHashtable* mBindingTable; @@ -177,6 +180,58 @@ nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aRes return NS_OK; } +NS_IMETHODIMP +nsBindingManager::AddLayeredBinding(nsIContent* aContent, const nsString& aURL) +{ + // First we need to load our binding. + nsresult rv; + NS_WITH_SERVICE(nsIXBLService, xblService, "component://netscape/xbl", &rv); + if (!xblService) + return rv; + + // Load the bindings. + xblService->LoadBindings(aContent, aURL, PR_TRUE); + + return NS_OK; +} + +NS_IMETHODIMP +nsBindingManager::RemoveLayeredBinding(nsIContent* aContent, const nsString& aURL) +{ + /* + nsCOMPtr binding; + GetBinding(aParent, getter_AddRefs(binding)); + + nsCOMPtr prevBinding; + + while (binding) { + nsCOMPtr nextBinding; + binding->GetBaseBinding(getter_AddRefs(nextBinding)); + + PRBool style; + binding->IsStyleBinding(&style); + if (!style) { + // Remove only our binding. + if (prevBinding) { + prevBinding->SetBaseBinding(nextBinding); + + // XXX Unhooking the binding should kill event handlers and + // fix up the prototype chain. + // e.g., binding->UnhookEventHandlers(); + // binding->FixupPrototypeChain(); + // or maybe just binding->Unhook(); + + } + else SetBinding(aContent, nextBinding); + } + + prevBinding = binding; + binding = nextBinding; + } +*/ + return NS_OK; +} + // Creation Routine /////////////////////////////////////////////////////////////////////// nsresult diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index df4457298feb..bb7b5610c448 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -147,6 +147,9 @@ class nsXBLBinding: public nsIXBLBinding NS_IMETHOD GetBindingElement(nsIContent** aResult); NS_IMETHOD SetBindingElement(nsIContent* aElement); + NS_IMETHOD GetBoundElement(nsIContent** aResult); + NS_IMETHOD SetBoundElement(nsIContent* aElement); + NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); NS_IMETHOD InstallProperties(nsIContent* aBoundElement); @@ -162,6 +165,12 @@ class nsXBLBinding: public nsIXBLBinding NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult); NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints); + NS_IMETHOD IsStyleBinding(PRBool* aResult) { *aResult = mIsStyleBinding; return NS_OK; }; + NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) { mIsStyleBinding = aIsStyle; return NS_OK; }; + + NS_IMETHOD GetRootBinding(nsIXBLBinding** aResult); + NS_IMETHOD GetFirstStyleBinding(nsIXBLBinding** aResult); + public: nsXBLBinding(); virtual ~nsXBLBinding(); @@ -198,6 +207,7 @@ public: static nsIAtom* kNameAtom; static nsIAtom* kReadOnlyAtom; static nsIAtom* kURIAtom; + static nsIAtom* kAttachToAtom; // Used to easily obtain the correct IID for an event. struct EventHandlerMapEntry { @@ -238,6 +248,8 @@ protected: nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it. + PRBool mIsStyleBinding; + nsSupportsHashtable* mAttributeTable; // A table for attribute entries. nsSupportsHashtable* mInsertionPointTable; // A table of insertion points. }; @@ -268,6 +280,7 @@ nsIAtom* nsXBLBinding::kSetterAtom = nsnull; nsIAtom* nsXBLBinding::kNameAtom = nsnull; nsIAtom* nsXBLBinding::kReadOnlyAtom = nsnull; nsIAtom* nsXBLBinding::kURIAtom = nsnull; +nsIAtom* nsXBLBinding::kAttachToAtom = nsnull; nsXBLBinding::EventHandlerMapEntry nsXBLBinding::kEventHandlerMap[] = { @@ -324,7 +337,8 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding) // Constructors/Destructors nsXBLBinding::nsXBLBinding(void) : mAttributeTable(nsnull), - mInsertionPointTable(nsnull) + mInsertionPointTable(nsnull), + mIsStyleBinding(PR_TRUE) { NS_INIT_REFCNT(); gRefCnt++; @@ -352,6 +366,7 @@ nsXBLBinding::nsXBLBinding(void) kNameAtom = NS_NewAtom("name"); kReadOnlyAtom = NS_NewAtom("readonly"); kURIAtom = NS_NewAtom("uri"); + kAttachToAtom = NS_NewAtom("attachto"); EventHandlerMapEntry* entry = kEventHandlerMap; while (entry->mAttributeName) { @@ -392,6 +407,7 @@ nsXBLBinding::~nsXBLBinding(void) NS_RELEASE(kNameAtom); NS_RELEASE(kReadOnlyAtom); NS_RELEASE(kURIAtom); + NS_RELEASE(kAttachToAtom); EventHandlerMapEntry* entry = kEventHandlerMap; while (entry->mAttributeName) { @@ -473,12 +489,26 @@ nsXBLBinding::SetBindingElement(nsIContent* aElement) return NS_OK; } +NS_IMETHODIMP +nsXBLBinding::GetBoundElement(nsIContent** aResult) +{ + *aResult = mBoundElement; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsXBLBinding::SetBoundElement(nsIContent* aElement) +{ + mBoundElement = aElement; + if (mNextBinding) + mNextBinding->SetBoundElement(aElement); + return NS_OK; +} + NS_IMETHODIMP nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) { - // Set our bound element. - mBoundElement = aBoundElement; - // Fetch the content element for this binding. nsCOMPtr content; GetImmediateChild(kContentAtom, getter_AddRefs(content)); @@ -566,9 +596,11 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) BuildInsertionTable(); } + /* XXX Handle selective decision to build anonymous content. if (mNextBinding) { return mNextBinding->GenerateAnonymousContent(aBoundElement); } + */ return NS_OK; } @@ -607,7 +639,21 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) PRBool xul = IsXULHandler(type); nsCOMPtr receiver = do_QueryInterface(mBoundElement); - + nsAutoString attachType; + child->GetAttribute(kNameSpaceID_None, kAttachToAtom, attachType); + if (attachType.EqualsWithConversion("document") || + attachType.EqualsWithConversion("window")) + { + nsCOMPtr boundDoc; + mBoundElement->GetDocument(*getter_AddRefs(boundDoc)); + if (attachType.EqualsWithConversion("window")) { + nsCOMPtr global; + boundDoc->GetScriptGlobalObject(getter_AddRefs(global)); + receiver = do_QueryInterface(global); + } + else receiver = do_QueryInterface(boundDoc); + } + if (mouse || key || focus || xul) { // Create a new nsXBLEventHandler. nsXBLEventHandler* handler; @@ -634,6 +680,7 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) } else { // Call AddScriptEventListener for other IID types + // XXX Want this to all go away! nsAutoString value; child->GetAttribute(kNameSpaceID_None, kValueAtom, value); if (value.IsEmpty()) @@ -1041,7 +1088,9 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen if (mNextBinding) mNextBinding->ChangeDocument(aOldDocument, aNewDocument); - if (aOldDocument) { + // Only style bindings get their prototypes unhooked. + // XXX Stay in sync! What if a layered binding has an ?! + if (!aNewDocument && !mIsStyleBinding) { // Now the binding dies. Unhook our prototypes. nsCOMPtr interfaceElement; GetImmediateChild(kInterfaceAtom, getter_AddRefs(interfaceElement)); @@ -1069,11 +1118,11 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen } } - // Kill the anonymous content. + // Update the anonymous content. nsCOMPtr anonymous; GetAnonymousContent(getter_AddRefs(anonymous)); if (anonymous) - anonymous->SetDocument(nsnull, PR_TRUE, AllowScripts()); + anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); } return NS_OK; @@ -1583,6 +1632,34 @@ nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleIns return NS_OK; } +NS_IMETHODIMP +nsXBLBinding::GetRootBinding(nsIXBLBinding** aResult) +{ + if (mNextBinding) + return mNextBinding->GetRootBinding(aResult); + + *aResult = this; + NS_ADDREF(this); + return NS_OK; +} + +NS_IMETHODIMP +nsXBLBinding::GetFirstStyleBinding(nsIXBLBinding** aResult) +{ + if (mIsStyleBinding) { + *aResult = this; + NS_ADDREF(this); + return NS_OK; + } + else if (mNextBinding) + return mNextBinding->GetFirstStyleBinding(aResult); + + *aResult = nsnull; + return NS_OK; +} + + + // Creation Routine /////////////////////////////////////////////////////////////////////// nsresult diff --git a/content/xbl/src/nsXBLService.cpp b/content/xbl/src/nsXBLService.cpp index 9767f7c11016..569b5b6a3df6 100644 --- a/content/xbl/src/nsXBLService.cpp +++ b/content/xbl/src/nsXBLService.cpp @@ -207,7 +207,7 @@ nsXBLService::~nsXBLService(void) // This function loads a particular XBL file and installs all of the bindings // onto the element. NS_IMETHODIMP -nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL) +nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL, PRBool aAugmentFlag) { nsresult rv; @@ -218,39 +218,73 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL) nsCOMPtr binding; bindingManager->GetBinding(aContent, getter_AddRefs(binding)); - if (binding) { - nsAutoString bindingURI; - binding->GetBindingURI(bindingURI); - if(aURL.Equals(bindingURI)) - return NS_OK; - else - FlushBindings(aContent); + if (binding && !aAugmentFlag) { + nsCOMPtr styleBinding; + binding->GetFirstStyleBinding(getter_AddRefs(styleBinding)); + if (styleBinding) { + // See if the URIs match. + nsAutoString uri; + styleBinding->GetBindingURI(uri); + if (uri.Equals(aURL)) + return NS_OK; + else FlushStyleBindings(aContent); + } } + nsCOMPtr newBinding; nsCAutoString url; url.AssignWithConversion(aURL); - if (NS_FAILED(rv = GetBinding(url, getter_AddRefs(binding)))) { + if (NS_FAILED(rv = GetBinding(url, getter_AddRefs(newBinding)))) { NS_ERROR("Failed loading an XBL document for content node."); return rv; } - if (!binding) { + if (!newBinding) { nsCAutoString str = "Failed to locate XBL binding. XBL is now using id instead of name to reference bindings. Make sure you have switched over. The invalid binding name is: "; str.AppendWithConversion(aURL); NS_ERROR(str); return NS_ERROR_FAILURE; } - // Install the binding on the content node. - bindingManager->SetBinding(aContent, binding); + if (aAugmentFlag) { + nsCOMPtr baseBinding; + nsCOMPtr nextBinding = newBinding; + do { + baseBinding = nextBinding; + baseBinding->GetBaseBinding(getter_AddRefs(nextBinding)); + baseBinding->SetIsStyleBinding(PR_FALSE); + } while (nextBinding); + + // XXX Handle adjusting the prototype chain! We need to somehow indicate to + // InstallProperties that the whole chain should just be whacked and rebuilt. + // We are becoming the new binding. + bindingManager->SetBinding(aContent, newBinding); + baseBinding->SetBaseBinding(binding); + } + else { + // We loaded a style binding. It goes on the end. + if (binding) { + // Get the last binding that is in the append layer. + nsCOMPtr rootBinding; + binding->GetRootBinding(getter_AddRefs(rootBinding)); + rootBinding->SetBaseBinding(newBinding); + } + else { + // Install the binding on the content node. + bindingManager->SetBinding(aContent, newBinding); + } + } + + // Set the binding's bound element. + newBinding->SetBoundElement(aContent); // Tell the binding to build the anonymous content. - binding->GenerateAnonymousContent(aContent); + newBinding->GenerateAnonymousContent(aContent); // Tell the binding to install event handlers - binding->InstallEventHandlers(aContent); + newBinding->InstallEventHandlers(aContent); // Set up our properties - binding->InstallProperties(aContent); + newBinding->InstallProperties(aContent); return NS_OK; } @@ -305,7 +339,7 @@ nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult, n } NS_IMETHODIMP -nsXBLService::FlushBindings(nsIContent* aContent) +nsXBLService::FlushStyleBindings(nsIContent* aContent) { nsCOMPtr document; aContent->GetDocument(*getter_AddRefs(document)); @@ -316,14 +350,20 @@ nsXBLService::FlushBindings(nsIContent* aContent) bindingManager->GetBinding(aContent, getter_AddRefs(binding)); if (binding) { - // Clear out the script references. - nsCOMPtr document; - aContent->GetDocument(*getter_AddRefs(document)); - binding->ChangeDocument(document, nsnull); + nsCOMPtr styleBinding; + binding->GetFirstStyleBinding(getter_AddRefs(styleBinding)); + + if (styleBinding) { + // Clear out the script references. + nsCOMPtr document; + aContent->GetDocument(*getter_AddRefs(document)); + styleBinding->ChangeDocument(document, nsnull); + } + + if (styleBinding == binding) + bindingManager->SetBinding(aContent, nsnull); // Flush old style bindings } - - bindingManager->SetBinding(aContent, nsnull); // Flush old bindings - + return NS_OK; } diff --git a/content/xbl/src/nsXBLService.h b/content/xbl/src/nsXBLService.h index e92fd3a986f9..81036cc6d5f9 100644 --- a/content/xbl/src/nsXBLService.h +++ b/content/xbl/src/nsXBLService.h @@ -42,10 +42,10 @@ class nsXBLService: public nsIXBLService // This function loads a particular XBL file and installs all of the bindings // onto the element. - NS_IMETHOD LoadBindings(nsIContent* aContent, const nsString& aURL); + NS_IMETHOD LoadBindings(nsIContent* aContent, const nsString& aURL, PRBool aAugmentFlag); // This function clears out the bindings on a given content node. - NS_IMETHOD FlushBindings(nsIContent* aContent); + NS_IMETHOD FlushStyleBindings(nsIContent* aContent); // This function clears out the binding doucments in our cache. NS_IMETHOD FlushBindingDocuments(); diff --git a/content/xul/content/src/nsXULPopupListener.cpp b/content/xul/content/src/nsXULPopupListener.cpp index d47c860d5197..e513ed4b5b53 100644 --- a/content/xul/content/src/nsXULPopupListener.cpp +++ b/content/xul/content/src/nsXULPopupListener.cpp @@ -35,7 +35,7 @@ #include "nsIDOMElement.h" #include "nsIDOMXULElement.h" #include "nsIDOMNodeList.h" -#include "nsIDOMNSDocument.h" +#include "nsIDOMDocumentXBL.h" #include "nsIXULPopupListener.h" #include "nsIDOMMouseListener.h" #include "nsIDOMMouseMotionListener.h" @@ -486,7 +486,7 @@ XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY) if (popup) popupContent = do_QueryInterface(popup); } else { - nsCOMPtr nsDoc(do_QueryInterface(xulDocument)); + nsCOMPtr nsDoc(do_QueryInterface(xulDocument)); nsCOMPtr xulElement(do_QueryInterface(content)); nsCOMPtr list; nsDoc->GetAnonymousNodes(xulElement, getter_AddRefs(list)); diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index 5094d943a5f3..e80077fb3386 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -596,6 +596,9 @@ nsXULDocument::QueryInterface(REFNSIID iid, void** result) else if (iid.Equals(NS_GET_IID(nsIDOMDocumentView))) { *result = NS_STATIC_CAST(nsIDOMDocumentView*, this); } + else if (iid.Equals(NS_GET_IID(nsIDOMDocumentXBL))) { + *result = NS_STATIC_CAST(nsIDOMDocumentXBL*, this); + } else if (iid.Equals(NS_GET_IID(nsIJSScriptObject))) { *result = NS_STATIC_CAST(nsIJSScriptObject*, this); } @@ -2889,6 +2892,27 @@ nsXULDocument::GetHeight(PRInt32* aHeight) return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +nsXULDocument::AddBinding(nsIDOMElement* aContent, const nsString& aURL) +{ + nsCOMPtr bm; + GetBindingManager(getter_AddRefs(bm)); + nsCOMPtr content(do_QueryInterface(aContent)); + + return bm->AddLayeredBinding(content, aURL); +} + +NS_IMETHODIMP +nsXULDocument::RemoveBinding(nsIDOMElement* aContent, const nsString& aURL) +{ + if (mBindingManager) { + nsCOMPtr content(do_QueryInterface(aContent)); + return mBindingManager->RemoveLayeredBinding(content, aURL); + } + + return NS_ERROR_FAILURE; +} + NS_IMETHODIMP nsXULDocument::GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult) { diff --git a/content/xul/document/src/nsXULDocument.h b/content/xul/document/src/nsXULDocument.h index 4858c772e357..d188e9ed41df 100644 --- a/content/xul/document/src/nsXULDocument.h +++ b/content/xul/document/src/nsXULDocument.h @@ -36,6 +36,7 @@ #include "nsIDOMHTMLFormElement.h" #include "nsIDOMNSDocument.h" #include "nsIDOMDocumentView.h" +#include "nsIDOMDocumentXBL.h" #include "nsIDOMSelection.h" #include "nsIDOMXULCommandDispatcher.h" #include "nsIDOMXULDocument.h" @@ -96,6 +97,7 @@ class nsXULDocument : public nsIDocument, public nsIDOMXULDocument, public nsIDOMDocumentEvent, public nsIDOMDocumentView, + public nsIDOMDocumentXBL, public nsIDOMNSDocument, public nsIDOMEventCapturer, public nsIJSScriptObject, @@ -355,6 +357,9 @@ public: // nsIDOMDocumentView interface NS_DECL_IDOMDOCUMENTVIEW + // nsIDOMDocumentXBL interface + NS_DECL_IDOMDOCUMENTXBL + // nsIDOMNSDocument interface NS_IMETHOD GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets); NS_IMETHOD GetCharacterSet(nsString& aCharacterSet); @@ -362,7 +367,6 @@ public: NS_IMETHOD CreateRange(nsIDOMRange** aRange); NS_IMETHOD GetWidth(PRInt32* aWidth); NS_IMETHOD GetHeight(PRInt32* aHeight); - NS_IMETHOD GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult); NS_IMETHOD Load (const nsString& aUrl, const nsString& aMimeType); // nsIDOMXULDocument interface diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 2c60be3cffe1..d23248c7b6c5 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -5215,7 +5215,7 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell, return rv; // Load the bindings. - xblService->LoadBindings(aParent, ui->mBehavior); + xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE); // Retrieve the anonymous content that we should build. nsCOMPtr anonymousItems; @@ -5433,7 +5433,7 @@ nsCSSFrameConstructor::CreateAnonymousTreeCellFrames(nsIPresShell* aPresS return rv; // Load the bindings. - xblService->LoadBindings(aParent, ui->mBehavior); + xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE); // Retrieve the anonymous content that we should build. nsCOMPtr childElement; @@ -7405,7 +7405,7 @@ nsCSSFrameConstructor::ConstructFrameInternal( nsIPresShell* aPresShe return rv; // Load the bindings. - xblService->LoadBindings(aContent, ui->mBehavior); + xblService->LoadBindings(aContent, ui->mBehavior, PR_FALSE); nsCOMPtr baseTag; PRInt32 nameSpaceID; diff --git a/layout/base/src/nsDocument.cpp b/layout/base/src/nsDocument.cpp index 3d0c325bb069..b3eefe728d3f 100644 --- a/layout/base/src/nsDocument.cpp +++ b/layout/base/src/nsDocument.cpp @@ -64,6 +64,7 @@ #include "nsIDOMDOMImplementation.h" #include "nsIDOMDocumentView.h" #include "nsIDOMAbstractView.h" +#include "nsIDOMDocumentXBL.h" #include "nsGenericElement.h" #include "nsICSSStyleSheet.h" @@ -758,6 +759,12 @@ nsresult nsDocument::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_ADDREF_THIS(); return NS_OK; } + if (aIID.Equals(NS_GET_IID(nsIDOMDocumentXBL))) { + nsIDOMDocumentView* tmp = this; + *aInstancePtr = (void*) tmp; + NS_ADDREF_THIS(); + return NS_OK; + } if (aIID.Equals(NS_GET_IID(nsIScriptObjectOwner))) { nsIScriptObjectOwner* tmp = this; *aInstancePtr = (void*) tmp; @@ -2219,6 +2226,27 @@ nsDocument::CreateElementWithNameSpace(const nsString& aTagName, return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +nsDocument::AddBinding(nsIDOMElement* aContent, const nsString& aURL) +{ + nsCOMPtr bm; + GetBindingManager(getter_AddRefs(bm)); + nsCOMPtr content(do_QueryInterface(aContent)); + + return bm->AddLayeredBinding(content, aURL); +} + +NS_IMETHODIMP +nsDocument::RemoveBinding(nsIDOMElement* aContent, const nsString& aURL) +{ + if (mBindingManager) { + nsCOMPtr content(do_QueryInterface(aContent)); + return mBindingManager->RemoveLayeredBinding(content, aURL); + } + + return NS_ERROR_FAILURE; +} + NS_IMETHODIMP nsDocument::GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult) { diff --git a/layout/base/src/nsDocument.h b/layout/base/src/nsDocument.h index f4ec4c3f869c..5a1b5320360f 100644 --- a/layout/base/src/nsDocument.h +++ b/layout/base/src/nsDocument.h @@ -28,6 +28,7 @@ #include "nsVoidArray.h" #include "nsIDOMDocument.h" #include "nsIDOMDocumentView.h" +#include "nsIDOMDocumentXBL.h" #include "nsIDOMNSDocument.h" #include "nsIDOMDocumentStyle.h" #include "nsIDOMEventReceiver.h" @@ -131,6 +132,7 @@ class nsDocument : public nsIDocument, public nsIDOMDocumentEvent, public nsIDOMDocumentStyle, public nsIDOMDocumentView, + public nsIDOMDocumentXBL, public nsIDiskDocument, public nsIJSScriptObject, public nsSupportsWeakReference, @@ -395,7 +397,6 @@ public: NS_IMETHOD GetWidth(PRInt32* aWidth); NS_IMETHOD GetHeight(PRInt32* aHeight); NS_IMETHOD Load (const nsString& aUrl, const nsString& aMimeType); - NS_IMETHOD GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult); // nsIDOMNode interface NS_DECL_IDOMNODE @@ -403,6 +404,9 @@ public: // nsIDOMDocumentView NS_DECL_IDOMDOCUMENTVIEW + // nsIDOMDocumentXBL + NS_DECL_IDOMDOCUMENTXBL + // nsIDOMDocumentEvent NS_DECL_IDOMDOCUMENTEVENT diff --git a/layout/html/style/src/nsCSSFrameConstructor.cpp b/layout/html/style/src/nsCSSFrameConstructor.cpp index 2c60be3cffe1..d23248c7b6c5 100644 --- a/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -5215,7 +5215,7 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell, return rv; // Load the bindings. - xblService->LoadBindings(aParent, ui->mBehavior); + xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE); // Retrieve the anonymous content that we should build. nsCOMPtr anonymousItems; @@ -5433,7 +5433,7 @@ nsCSSFrameConstructor::CreateAnonymousTreeCellFrames(nsIPresShell* aPresS return rv; // Load the bindings. - xblService->LoadBindings(aParent, ui->mBehavior); + xblService->LoadBindings(aParent, ui->mBehavior, PR_FALSE); // Retrieve the anonymous content that we should build. nsCOMPtr childElement; @@ -7405,7 +7405,7 @@ nsCSSFrameConstructor::ConstructFrameInternal( nsIPresShell* aPresShe return rv; // Load the bindings. - xblService->LoadBindings(aContent, ui->mBehavior); + xblService->LoadBindings(aContent, ui->mBehavior, PR_FALSE); nsCOMPtr baseTag; PRInt32 nameSpaceID; diff --git a/layout/xbl/public/nsIBindingManager.h b/layout/xbl/public/nsIBindingManager.h index a1ce9a8f90a0..ef1f5cddef60 100644 --- a/layout/xbl/public/nsIBindingManager.h +++ b/layout/xbl/public/nsIBindingManager.h @@ -55,6 +55,9 @@ public: NS_IMETHOD GetInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult) = 0; NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRBool* aMultipleInsertionPoints) = 0; + + NS_IMETHOD AddLayeredBinding(nsIContent* aContent, const nsString& aURL) = 0; + NS_IMETHOD RemoveLayeredBinding(nsIContent* aContent, const nsString& aURL) = 0; }; #endif // nsIBinding_Manager_h__ diff --git a/layout/xbl/public/nsIXBLBinding.h b/layout/xbl/public/nsIXBLBinding.h index 53fccd795815..9dc310840567 100644 --- a/layout/xbl/public/nsIXBLBinding.h +++ b/layout/xbl/public/nsIXBLBinding.h @@ -57,6 +57,9 @@ public: NS_IMETHOD GetBindingElement(nsIContent** aResult) = 0; NS_IMETHOD SetBindingElement(nsIContent* aElement) = 0; + NS_IMETHOD GetBoundElement(nsIContent** aResult) = 0; + NS_IMETHOD SetBoundElement(nsIContent* aElement) = 0; + NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement) = 0; NS_IMETHOD InstallProperties(nsIContent* aBoundElement) = 0; @@ -72,6 +75,12 @@ public: NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult) = 0; NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints) = 0; + + NS_IMETHOD IsStyleBinding(PRBool* aResult) = 0; + NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) = 0; + + NS_IMETHOD GetRootBinding(nsIXBLBinding** aResult) = 0; + NS_IMETHOD GetFirstStyleBinding(nsIXBLBinding** aResult) = 0; }; extern nsresult diff --git a/layout/xbl/public/nsIXBLService.h b/layout/xbl/public/nsIXBLService.h index d2666ca8facb..652e2560b921 100644 --- a/layout/xbl/public/nsIXBLService.h +++ b/layout/xbl/public/nsIXBLService.h @@ -48,10 +48,10 @@ public: // This function loads a particular XBL file and installs all of the bindings // onto the element. - NS_IMETHOD LoadBindings(nsIContent* aContent, const nsString& aURL) = 0; + NS_IMETHOD LoadBindings(nsIContent* aContent, const nsString& aURL, PRBool aAugmentFlag) = 0; // This function clears out the bindings on a given content node. - NS_IMETHOD FlushBindings(nsIContent* aContent) = 0; + NS_IMETHOD FlushStyleBindings(nsIContent* aContent) = 0; // This function clears out the binding documents in our cache. NS_IMETHOD FlushBindingDocuments() = 0; diff --git a/layout/xbl/src/nsBindingManager.cpp b/layout/xbl/src/nsBindingManager.cpp index 57fffadcd17c..fbeefedc5812 100644 --- a/layout/xbl/src/nsBindingManager.cpp +++ b/layout/xbl/src/nsBindingManager.cpp @@ -69,6 +69,9 @@ public: NS_IMETHOD GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aResult, PRBool* aMultipleInsertionPoints); + NS_IMETHOD AddLayeredBinding(nsIContent* aContent, const nsString& aURL); + NS_IMETHOD RemoveLayeredBinding(nsIContent* aContent, const nsString& aURL); + // MEMBER VARIABLES protected: nsSupportsHashtable* mBindingTable; @@ -177,6 +180,58 @@ nsBindingManager::GetSingleInsertionPoint(nsIContent* aParent, nsIContent** aRes return NS_OK; } +NS_IMETHODIMP +nsBindingManager::AddLayeredBinding(nsIContent* aContent, const nsString& aURL) +{ + // First we need to load our binding. + nsresult rv; + NS_WITH_SERVICE(nsIXBLService, xblService, "component://netscape/xbl", &rv); + if (!xblService) + return rv; + + // Load the bindings. + xblService->LoadBindings(aContent, aURL, PR_TRUE); + + return NS_OK; +} + +NS_IMETHODIMP +nsBindingManager::RemoveLayeredBinding(nsIContent* aContent, const nsString& aURL) +{ + /* + nsCOMPtr binding; + GetBinding(aParent, getter_AddRefs(binding)); + + nsCOMPtr prevBinding; + + while (binding) { + nsCOMPtr nextBinding; + binding->GetBaseBinding(getter_AddRefs(nextBinding)); + + PRBool style; + binding->IsStyleBinding(&style); + if (!style) { + // Remove only our binding. + if (prevBinding) { + prevBinding->SetBaseBinding(nextBinding); + + // XXX Unhooking the binding should kill event handlers and + // fix up the prototype chain. + // e.g., binding->UnhookEventHandlers(); + // binding->FixupPrototypeChain(); + // or maybe just binding->Unhook(); + + } + else SetBinding(aContent, nextBinding); + } + + prevBinding = binding; + binding = nextBinding; + } +*/ + return NS_OK; +} + // Creation Routine /////////////////////////////////////////////////////////////////////// nsresult diff --git a/layout/xbl/src/nsXBLBinding.cpp b/layout/xbl/src/nsXBLBinding.cpp index df4457298feb..bb7b5610c448 100644 --- a/layout/xbl/src/nsXBLBinding.cpp +++ b/layout/xbl/src/nsXBLBinding.cpp @@ -147,6 +147,9 @@ class nsXBLBinding: public nsIXBLBinding NS_IMETHOD GetBindingElement(nsIContent** aResult); NS_IMETHOD SetBindingElement(nsIContent* aElement); + NS_IMETHOD GetBoundElement(nsIContent** aResult); + NS_IMETHOD SetBoundElement(nsIContent* aElement); + NS_IMETHOD GenerateAnonymousContent(nsIContent* aBoundElement); NS_IMETHOD InstallEventHandlers(nsIContent* aBoundElement); NS_IMETHOD InstallProperties(nsIContent* aBoundElement); @@ -162,6 +165,12 @@ class nsXBLBinding: public nsIXBLBinding NS_IMETHOD GetInsertionPoint(nsIContent* aChild, nsIContent** aResult); NS_IMETHOD GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleInsertionPoints); + NS_IMETHOD IsStyleBinding(PRBool* aResult) { *aResult = mIsStyleBinding; return NS_OK; }; + NS_IMETHOD SetIsStyleBinding(PRBool aIsStyle) { mIsStyleBinding = aIsStyle; return NS_OK; }; + + NS_IMETHOD GetRootBinding(nsIXBLBinding** aResult); + NS_IMETHOD GetFirstStyleBinding(nsIXBLBinding** aResult); + public: nsXBLBinding(); virtual ~nsXBLBinding(); @@ -198,6 +207,7 @@ public: static nsIAtom* kNameAtom; static nsIAtom* kReadOnlyAtom; static nsIAtom* kURIAtom; + static nsIAtom* kAttachToAtom; // Used to easily obtain the correct IID for an event. struct EventHandlerMapEntry { @@ -238,6 +248,8 @@ protected: nsIContent* mBoundElement; // [WEAK] We have a reference, but we don't own it. + PRBool mIsStyleBinding; + nsSupportsHashtable* mAttributeTable; // A table for attribute entries. nsSupportsHashtable* mInsertionPointTable; // A table of insertion points. }; @@ -268,6 +280,7 @@ nsIAtom* nsXBLBinding::kSetterAtom = nsnull; nsIAtom* nsXBLBinding::kNameAtom = nsnull; nsIAtom* nsXBLBinding::kReadOnlyAtom = nsnull; nsIAtom* nsXBLBinding::kURIAtom = nsnull; +nsIAtom* nsXBLBinding::kAttachToAtom = nsnull; nsXBLBinding::EventHandlerMapEntry nsXBLBinding::kEventHandlerMap[] = { @@ -324,7 +337,8 @@ NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding) // Constructors/Destructors nsXBLBinding::nsXBLBinding(void) : mAttributeTable(nsnull), - mInsertionPointTable(nsnull) + mInsertionPointTable(nsnull), + mIsStyleBinding(PR_TRUE) { NS_INIT_REFCNT(); gRefCnt++; @@ -352,6 +366,7 @@ nsXBLBinding::nsXBLBinding(void) kNameAtom = NS_NewAtom("name"); kReadOnlyAtom = NS_NewAtom("readonly"); kURIAtom = NS_NewAtom("uri"); + kAttachToAtom = NS_NewAtom("attachto"); EventHandlerMapEntry* entry = kEventHandlerMap; while (entry->mAttributeName) { @@ -392,6 +407,7 @@ nsXBLBinding::~nsXBLBinding(void) NS_RELEASE(kNameAtom); NS_RELEASE(kReadOnlyAtom); NS_RELEASE(kURIAtom); + NS_RELEASE(kAttachToAtom); EventHandlerMapEntry* entry = kEventHandlerMap; while (entry->mAttributeName) { @@ -473,12 +489,26 @@ nsXBLBinding::SetBindingElement(nsIContent* aElement) return NS_OK; } +NS_IMETHODIMP +nsXBLBinding::GetBoundElement(nsIContent** aResult) +{ + *aResult = mBoundElement; + NS_IF_ADDREF(*aResult); + return NS_OK; +} + +NS_IMETHODIMP +nsXBLBinding::SetBoundElement(nsIContent* aElement) +{ + mBoundElement = aElement; + if (mNextBinding) + mNextBinding->SetBoundElement(aElement); + return NS_OK; +} + NS_IMETHODIMP nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) { - // Set our bound element. - mBoundElement = aBoundElement; - // Fetch the content element for this binding. nsCOMPtr content; GetImmediateChild(kContentAtom, getter_AddRefs(content)); @@ -566,9 +596,11 @@ nsXBLBinding::GenerateAnonymousContent(nsIContent* aBoundElement) BuildInsertionTable(); } + /* XXX Handle selective decision to build anonymous content. if (mNextBinding) { return mNextBinding->GenerateAnonymousContent(aBoundElement); } + */ return NS_OK; } @@ -607,7 +639,21 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) PRBool xul = IsXULHandler(type); nsCOMPtr receiver = do_QueryInterface(mBoundElement); - + nsAutoString attachType; + child->GetAttribute(kNameSpaceID_None, kAttachToAtom, attachType); + if (attachType.EqualsWithConversion("document") || + attachType.EqualsWithConversion("window")) + { + nsCOMPtr boundDoc; + mBoundElement->GetDocument(*getter_AddRefs(boundDoc)); + if (attachType.EqualsWithConversion("window")) { + nsCOMPtr global; + boundDoc->GetScriptGlobalObject(getter_AddRefs(global)); + receiver = do_QueryInterface(global); + } + else receiver = do_QueryInterface(boundDoc); + } + if (mouse || key || focus || xul) { // Create a new nsXBLEventHandler. nsXBLEventHandler* handler; @@ -634,6 +680,7 @@ nsXBLBinding::InstallEventHandlers(nsIContent* aBoundElement) } else { // Call AddScriptEventListener for other IID types + // XXX Want this to all go away! nsAutoString value; child->GetAttribute(kNameSpaceID_None, kValueAtom, value); if (value.IsEmpty()) @@ -1041,7 +1088,9 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen if (mNextBinding) mNextBinding->ChangeDocument(aOldDocument, aNewDocument); - if (aOldDocument) { + // Only style bindings get their prototypes unhooked. + // XXX Stay in sync! What if a layered binding has an ?! + if (!aNewDocument && !mIsStyleBinding) { // Now the binding dies. Unhook our prototypes. nsCOMPtr interfaceElement; GetImmediateChild(kInterfaceAtom, getter_AddRefs(interfaceElement)); @@ -1069,11 +1118,11 @@ nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocumen } } - // Kill the anonymous content. + // Update the anonymous content. nsCOMPtr anonymous; GetAnonymousContent(getter_AddRefs(anonymous)); if (anonymous) - anonymous->SetDocument(nsnull, PR_TRUE, AllowScripts()); + anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); } return NS_OK; @@ -1583,6 +1632,34 @@ nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRBool* aMultipleIns return NS_OK; } +NS_IMETHODIMP +nsXBLBinding::GetRootBinding(nsIXBLBinding** aResult) +{ + if (mNextBinding) + return mNextBinding->GetRootBinding(aResult); + + *aResult = this; + NS_ADDREF(this); + return NS_OK; +} + +NS_IMETHODIMP +nsXBLBinding::GetFirstStyleBinding(nsIXBLBinding** aResult) +{ + if (mIsStyleBinding) { + *aResult = this; + NS_ADDREF(this); + return NS_OK; + } + else if (mNextBinding) + return mNextBinding->GetFirstStyleBinding(aResult); + + *aResult = nsnull; + return NS_OK; +} + + + // Creation Routine /////////////////////////////////////////////////////////////////////// nsresult diff --git a/layout/xbl/src/nsXBLService.cpp b/layout/xbl/src/nsXBLService.cpp index 9767f7c11016..569b5b6a3df6 100644 --- a/layout/xbl/src/nsXBLService.cpp +++ b/layout/xbl/src/nsXBLService.cpp @@ -207,7 +207,7 @@ nsXBLService::~nsXBLService(void) // This function loads a particular XBL file and installs all of the bindings // onto the element. NS_IMETHODIMP -nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL) +nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL, PRBool aAugmentFlag) { nsresult rv; @@ -218,39 +218,73 @@ nsXBLService::LoadBindings(nsIContent* aContent, const nsString& aURL) nsCOMPtr binding; bindingManager->GetBinding(aContent, getter_AddRefs(binding)); - if (binding) { - nsAutoString bindingURI; - binding->GetBindingURI(bindingURI); - if(aURL.Equals(bindingURI)) - return NS_OK; - else - FlushBindings(aContent); + if (binding && !aAugmentFlag) { + nsCOMPtr styleBinding; + binding->GetFirstStyleBinding(getter_AddRefs(styleBinding)); + if (styleBinding) { + // See if the URIs match. + nsAutoString uri; + styleBinding->GetBindingURI(uri); + if (uri.Equals(aURL)) + return NS_OK; + else FlushStyleBindings(aContent); + } } + nsCOMPtr newBinding; nsCAutoString url; url.AssignWithConversion(aURL); - if (NS_FAILED(rv = GetBinding(url, getter_AddRefs(binding)))) { + if (NS_FAILED(rv = GetBinding(url, getter_AddRefs(newBinding)))) { NS_ERROR("Failed loading an XBL document for content node."); return rv; } - if (!binding) { + if (!newBinding) { nsCAutoString str = "Failed to locate XBL binding. XBL is now using id instead of name to reference bindings. Make sure you have switched over. The invalid binding name is: "; str.AppendWithConversion(aURL); NS_ERROR(str); return NS_ERROR_FAILURE; } - // Install the binding on the content node. - bindingManager->SetBinding(aContent, binding); + if (aAugmentFlag) { + nsCOMPtr baseBinding; + nsCOMPtr nextBinding = newBinding; + do { + baseBinding = nextBinding; + baseBinding->GetBaseBinding(getter_AddRefs(nextBinding)); + baseBinding->SetIsStyleBinding(PR_FALSE); + } while (nextBinding); + + // XXX Handle adjusting the prototype chain! We need to somehow indicate to + // InstallProperties that the whole chain should just be whacked and rebuilt. + // We are becoming the new binding. + bindingManager->SetBinding(aContent, newBinding); + baseBinding->SetBaseBinding(binding); + } + else { + // We loaded a style binding. It goes on the end. + if (binding) { + // Get the last binding that is in the append layer. + nsCOMPtr rootBinding; + binding->GetRootBinding(getter_AddRefs(rootBinding)); + rootBinding->SetBaseBinding(newBinding); + } + else { + // Install the binding on the content node. + bindingManager->SetBinding(aContent, newBinding); + } + } + + // Set the binding's bound element. + newBinding->SetBoundElement(aContent); // Tell the binding to build the anonymous content. - binding->GenerateAnonymousContent(aContent); + newBinding->GenerateAnonymousContent(aContent); // Tell the binding to install event handlers - binding->InstallEventHandlers(aContent); + newBinding->InstallEventHandlers(aContent); // Set up our properties - binding->InstallProperties(aContent); + newBinding->InstallProperties(aContent); return NS_OK; } @@ -305,7 +339,7 @@ nsXBLService::GetContentList(nsIContent* aContent, nsISupportsArray** aResult, n } NS_IMETHODIMP -nsXBLService::FlushBindings(nsIContent* aContent) +nsXBLService::FlushStyleBindings(nsIContent* aContent) { nsCOMPtr document; aContent->GetDocument(*getter_AddRefs(document)); @@ -316,14 +350,20 @@ nsXBLService::FlushBindings(nsIContent* aContent) bindingManager->GetBinding(aContent, getter_AddRefs(binding)); if (binding) { - // Clear out the script references. - nsCOMPtr document; - aContent->GetDocument(*getter_AddRefs(document)); - binding->ChangeDocument(document, nsnull); + nsCOMPtr styleBinding; + binding->GetFirstStyleBinding(getter_AddRefs(styleBinding)); + + if (styleBinding) { + // Clear out the script references. + nsCOMPtr document; + aContent->GetDocument(*getter_AddRefs(document)); + styleBinding->ChangeDocument(document, nsnull); + } + + if (styleBinding == binding) + bindingManager->SetBinding(aContent, nsnull); // Flush old style bindings } - - bindingManager->SetBinding(aContent, nsnull); // Flush old bindings - + return NS_OK; } diff --git a/layout/xbl/src/nsXBLService.h b/layout/xbl/src/nsXBLService.h index e92fd3a986f9..81036cc6d5f9 100644 --- a/layout/xbl/src/nsXBLService.h +++ b/layout/xbl/src/nsXBLService.h @@ -42,10 +42,10 @@ class nsXBLService: public nsIXBLService // This function loads a particular XBL file and installs all of the bindings // onto the element. - NS_IMETHOD LoadBindings(nsIContent* aContent, const nsString& aURL); + NS_IMETHOD LoadBindings(nsIContent* aContent, const nsString& aURL, PRBool aAugmentFlag); // This function clears out the bindings on a given content node. - NS_IMETHOD FlushBindings(nsIContent* aContent); + NS_IMETHOD FlushStyleBindings(nsIContent* aContent); // This function clears out the binding doucments in our cache. NS_IMETHOD FlushBindingDocuments(); diff --git a/rdf/content/src/nsXULDocument.cpp b/rdf/content/src/nsXULDocument.cpp index 5094d943a5f3..e80077fb3386 100644 --- a/rdf/content/src/nsXULDocument.cpp +++ b/rdf/content/src/nsXULDocument.cpp @@ -596,6 +596,9 @@ nsXULDocument::QueryInterface(REFNSIID iid, void** result) else if (iid.Equals(NS_GET_IID(nsIDOMDocumentView))) { *result = NS_STATIC_CAST(nsIDOMDocumentView*, this); } + else if (iid.Equals(NS_GET_IID(nsIDOMDocumentXBL))) { + *result = NS_STATIC_CAST(nsIDOMDocumentXBL*, this); + } else if (iid.Equals(NS_GET_IID(nsIJSScriptObject))) { *result = NS_STATIC_CAST(nsIJSScriptObject*, this); } @@ -2889,6 +2892,27 @@ nsXULDocument::GetHeight(PRInt32* aHeight) return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +nsXULDocument::AddBinding(nsIDOMElement* aContent, const nsString& aURL) +{ + nsCOMPtr bm; + GetBindingManager(getter_AddRefs(bm)); + nsCOMPtr content(do_QueryInterface(aContent)); + + return bm->AddLayeredBinding(content, aURL); +} + +NS_IMETHODIMP +nsXULDocument::RemoveBinding(nsIDOMElement* aContent, const nsString& aURL) +{ + if (mBindingManager) { + nsCOMPtr content(do_QueryInterface(aContent)); + return mBindingManager->RemoveLayeredBinding(content, aURL); + } + + return NS_ERROR_FAILURE; +} + NS_IMETHODIMP nsXULDocument::GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult) { diff --git a/rdf/content/src/nsXULDocument.h b/rdf/content/src/nsXULDocument.h index 4858c772e357..d188e9ed41df 100644 --- a/rdf/content/src/nsXULDocument.h +++ b/rdf/content/src/nsXULDocument.h @@ -36,6 +36,7 @@ #include "nsIDOMHTMLFormElement.h" #include "nsIDOMNSDocument.h" #include "nsIDOMDocumentView.h" +#include "nsIDOMDocumentXBL.h" #include "nsIDOMSelection.h" #include "nsIDOMXULCommandDispatcher.h" #include "nsIDOMXULDocument.h" @@ -96,6 +97,7 @@ class nsXULDocument : public nsIDocument, public nsIDOMXULDocument, public nsIDOMDocumentEvent, public nsIDOMDocumentView, + public nsIDOMDocumentXBL, public nsIDOMNSDocument, public nsIDOMEventCapturer, public nsIJSScriptObject, @@ -355,6 +357,9 @@ public: // nsIDOMDocumentView interface NS_DECL_IDOMDOCUMENTVIEW + // nsIDOMDocumentXBL interface + NS_DECL_IDOMDOCUMENTXBL + // nsIDOMNSDocument interface NS_IMETHOD GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets); NS_IMETHOD GetCharacterSet(nsString& aCharacterSet); @@ -362,7 +367,6 @@ public: NS_IMETHOD CreateRange(nsIDOMRange** aRange); NS_IMETHOD GetWidth(PRInt32* aWidth); NS_IMETHOD GetHeight(PRInt32* aHeight); - NS_IMETHOD GetAnonymousNodes(nsIDOMElement* aElement, nsIDOMNodeList** aResult); NS_IMETHOD Load (const nsString& aUrl, const nsString& aMimeType); // nsIDOMXULDocument interface diff --git a/rdf/content/src/nsXULPopupListener.cpp b/rdf/content/src/nsXULPopupListener.cpp index d47c860d5197..e513ed4b5b53 100644 --- a/rdf/content/src/nsXULPopupListener.cpp +++ b/rdf/content/src/nsXULPopupListener.cpp @@ -35,7 +35,7 @@ #include "nsIDOMElement.h" #include "nsIDOMXULElement.h" #include "nsIDOMNodeList.h" -#include "nsIDOMNSDocument.h" +#include "nsIDOMDocumentXBL.h" #include "nsIXULPopupListener.h" #include "nsIDOMMouseListener.h" #include "nsIDOMMouseMotionListener.h" @@ -486,7 +486,7 @@ XULPopupListenerImpl::LaunchPopup(PRInt32 aClientX, PRInt32 aClientY) if (popup) popupContent = do_QueryInterface(popup); } else { - nsCOMPtr nsDoc(do_QueryInterface(xulDocument)); + nsCOMPtr nsDoc(do_QueryInterface(xulDocument)); nsCOMPtr xulElement(do_QueryInterface(content)); nsCOMPtr list; nsDoc->GetAnonymousNodes(xulElement, getter_AddRefs(list));