2000-03-21 13:14:34 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
|
|
* Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Original Author: David W. Hyatt (hyatt@netscape.com)
|
|
|
|
*
|
2000-07-01 02:36:18 +00:00
|
|
|
* Contributor(s): Brendan Eich (brendan@mozilla.org)
|
2000-03-21 13:14:34 +00:00
|
|
|
*/
|
|
|
|
|
2000-01-13 02:23:54 +00:00
|
|
|
#include "nsCOMPtr.h"
|
|
|
|
#include "nsIXBLBinding.h"
|
2000-08-12 06:28:02 +00:00
|
|
|
#include "nsIXBLDocumentInfo.h"
|
2000-01-13 02:23:54 +00:00
|
|
|
#include "nsIInputStream.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsHashtable.h"
|
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsIURL.h"
|
2000-01-26 11:43:31 +00:00
|
|
|
#include "nsIDOMEventReceiver.h"
|
2000-01-13 02:23:54 +00:00
|
|
|
#include "nsIChannel.h"
|
|
|
|
#include "nsXPIDLString.h"
|
|
|
|
#include "nsIParser.h"
|
|
|
|
#include "nsParserCIID.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "plstr.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDocument.h"
|
2000-03-11 10:36:39 +00:00
|
|
|
#include "nsIXMLContent.h"
|
2000-05-19 04:48:43 +00:00
|
|
|
#include "nsIXULContent.h"
|
2001-02-20 01:05:34 +00:00
|
|
|
#include "nsIXULDocument.h"
|
2000-01-13 02:23:54 +00:00
|
|
|
#include "nsIXMLContentSink.h"
|
2001-02-19 12:55:42 +00:00
|
|
|
#include "nsContentCID.h"
|
2000-01-13 02:23:54 +00:00
|
|
|
#include "nsXMLDocument.h"
|
2000-01-13 09:21:09 +00:00
|
|
|
#include "nsIDOMElement.h"
|
2000-03-14 11:09:46 +00:00
|
|
|
#include "nsIDOMText.h"
|
2000-01-13 09:21:09 +00:00
|
|
|
#include "nsSupportsArray.h"
|
2000-03-11 10:36:39 +00:00
|
|
|
#include "nsINameSpace.h"
|
2000-03-31 03:13:43 +00:00
|
|
|
#include "nsJSUtils.h"
|
2000-04-03 06:31:32 +00:00
|
|
|
#include "nsIJSRuntimeService.h"
|
2000-05-28 04:10:50 +00:00
|
|
|
#include "nsXBLService.h"
|
2001-02-02 00:54:47 +00:00
|
|
|
#include "nsIXBLInsertionPoint.h"
|
2000-01-13 02:23:54 +00:00
|
|
|
|
2000-01-26 11:43:31 +00:00
|
|
|
// Event listeners
|
2000-03-23 22:19:49 +00:00
|
|
|
#include "nsIEventListenerManager.h"
|
2000-01-26 11:43:31 +00:00
|
|
|
#include "nsIDOMMouseListener.h"
|
|
|
|
#include "nsIDOMMouseMotionListener.h"
|
|
|
|
#include "nsIDOMLoadListener.h"
|
|
|
|
#include "nsIDOMFocusListener.h"
|
|
|
|
#include "nsIDOMPaintListener.h"
|
|
|
|
#include "nsIDOMKeyListener.h"
|
|
|
|
#include "nsIDOMFormListener.h"
|
|
|
|
#include "nsIDOMMenuListener.h"
|
|
|
|
#include "nsIDOMDragListener.h"
|
2000-11-27 07:55:20 +00:00
|
|
|
#include "nsIDOMMutationListener.h"
|
2000-01-26 11:43:31 +00:00
|
|
|
|
2000-03-11 10:36:39 +00:00
|
|
|
#include "nsIDOMAttr.h"
|
|
|
|
#include "nsIDOMNamedNodeMap.h"
|
|
|
|
|
2000-09-02 01:09:47 +00:00
|
|
|
#include "nsIXBLPrototypeHandler.h"
|
2000-09-20 07:16:04 +00:00
|
|
|
|
|
|
|
#include "nsXBLKeyHandler.h"
|
|
|
|
#include "nsXBLFocusHandler.h"
|
|
|
|
#include "nsXBLMouseHandler.h"
|
|
|
|
#include "nsXBLMouseMotionHandler.h"
|
2000-11-27 07:55:20 +00:00
|
|
|
#include "nsXBLMutationHandler.h"
|
2000-09-20 07:16:04 +00:00
|
|
|
#include "nsXBLXULHandler.h"
|
|
|
|
#include "nsXBLScrollHandler.h"
|
|
|
|
#include "nsXBLFormHandler.h"
|
|
|
|
#include "nsXBLDragHandler.h"
|
|
|
|
#include "nsXBLLoadHandler.h"
|
|
|
|
|
2000-06-22 00:36:19 +00:00
|
|
|
#include "nsXBLBinding.h"
|
2000-01-13 02:23:54 +00:00
|
|
|
|
|
|
|
// Static IIDs/CIDs. Try to minimize these.
|
2000-03-11 10:36:39 +00:00
|
|
|
static char kNameSpaceSeparator = ':';
|
2000-01-13 02:23:54 +00:00
|
|
|
|
2000-01-25 06:35:27 +00:00
|
|
|
// Helper classes
|
2000-01-13 02:23:54 +00:00
|
|
|
|
2000-03-31 03:13:43 +00:00
|
|
|
/***********************************************************************/
|
|
|
|
//
|
|
|
|
// The JS class for XBLBinding
|
|
|
|
//
|
|
|
|
PR_STATIC_CALLBACK(void)
|
2000-05-27 08:20:04 +00:00
|
|
|
XBLFinalize(JSContext *cx, JSObject *obj)
|
2000-03-31 03:13:43 +00:00
|
|
|
{
|
2000-07-01 02:36:18 +00:00
|
|
|
nsXBLJSClass* c = NS_STATIC_CAST(nsXBLJSClass*, ::JS_GetClass(cx, obj));
|
|
|
|
c->Drop();
|
2000-03-31 03:13:43 +00:00
|
|
|
}
|
|
|
|
|
2000-07-01 02:36:18 +00:00
|
|
|
nsXBLJSClass::nsXBLJSClass(const nsCString& aClassName)
|
|
|
|
{
|
|
|
|
memset(this, 0, sizeof(nsXBLJSClass));
|
|
|
|
next = prev = NS_STATIC_CAST(JSCList*, this);
|
|
|
|
name = nsXPIDLCString::Copy(aClassName);
|
|
|
|
addProperty = delProperty = setProperty = getProperty = ::JS_PropertyStub;
|
|
|
|
enumerate = ::JS_EnumerateStub;
|
|
|
|
resolve = ::JS_ResolveStub;
|
|
|
|
convert = ::JS_ConvertStub;
|
|
|
|
finalize = XBLFinalize;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsrefcnt
|
|
|
|
nsXBLJSClass::Destroy()
|
2000-05-27 08:20:04 +00:00
|
|
|
{
|
2000-07-01 02:36:18 +00:00
|
|
|
NS_ASSERTION(next == prev && prev == NS_STATIC_CAST(JSCList*, this),
|
|
|
|
"referenced nsXBLJSClass is on LRU list already!?");
|
|
|
|
|
2000-08-01 21:39:28 +00:00
|
|
|
if (nsXBLService::gClassTable) {
|
2000-08-10 06:19:37 +00:00
|
|
|
nsCStringKey key(name);
|
2000-08-01 21:39:28 +00:00
|
|
|
(nsXBLService::gClassTable)->Remove(&key);
|
|
|
|
}
|
|
|
|
|
2000-07-01 02:36:18 +00:00
|
|
|
if (nsXBLService::gClassLRUListLength >= nsXBLService::gClassLRUListQuota) {
|
|
|
|
// Over LRU list quota, just unhash and delete this class.
|
|
|
|
delete this;
|
|
|
|
} else {
|
|
|
|
// Put this most-recently-used class on end of the LRU-sorted freelist.
|
|
|
|
JSCList* mru = NS_STATIC_CAST(JSCList*, this);
|
|
|
|
JS_APPEND_LINK(mru, &nsXBLService::gClassLRUList);
|
|
|
|
nsXBLService::gClassLRUListLength++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2000-05-27 08:20:04 +00:00
|
|
|
}
|
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
// Static initialization
|
|
|
|
PRUint32 nsXBLBinding::gRefCnt = 0;
|
2000-05-28 04:10:50 +00:00
|
|
|
|
2000-09-15 06:38:35 +00:00
|
|
|
nsIAtom* nsXBLBinding::kXULTemplateAtom = nsnull;
|
|
|
|
nsIAtom* nsXBLBinding::kXULObservesAtom = nsnull;
|
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
nsIAtom* nsXBLBinding::kContentAtom = nsnull;
|
2000-09-01 01:38:04 +00:00
|
|
|
nsIAtom* nsXBLBinding::kImplementationAtom = nsnull;
|
2000-01-13 09:21:09 +00:00
|
|
|
nsIAtom* nsXBLBinding::kHandlersAtom = nsnull;
|
|
|
|
nsIAtom* nsXBLBinding::kExcludesAtom = nsnull;
|
2000-05-22 08:23:09 +00:00
|
|
|
nsIAtom* nsXBLBinding::kIncludesAtom = nsnull;
|
2000-01-13 09:21:09 +00:00
|
|
|
nsIAtom* nsXBLBinding::kInheritsAtom = nsnull;
|
2000-09-01 01:38:04 +00:00
|
|
|
nsIAtom* nsXBLBinding::kEventAtom = nsnull;
|
|
|
|
nsIAtom* nsXBLBinding::kPhaseAtom = nsnull;
|
2000-03-11 10:36:39 +00:00
|
|
|
nsIAtom* nsXBLBinding::kExtendsAtom = nsnull;
|
2000-09-01 01:38:04 +00:00
|
|
|
nsIAtom* nsXBLBinding::kActionAtom = nsnull;
|
2000-03-29 01:24:35 +00:00
|
|
|
nsIAtom* nsXBLBinding::kMethodAtom = nsnull;
|
2000-09-02 01:20:36 +00:00
|
|
|
nsIAtom* nsXBLBinding::kParameterAtom = nsnull;
|
2000-03-29 01:24:35 +00:00
|
|
|
nsIAtom* nsXBLBinding::kBodyAtom = nsnull;
|
|
|
|
nsIAtom* nsXBLBinding::kPropertyAtom = nsnull;
|
|
|
|
nsIAtom* nsXBLBinding::kOnSetAtom = nsnull;
|
|
|
|
nsIAtom* nsXBLBinding::kOnGetAtom = nsnull;
|
2000-04-30 06:41:41 +00:00
|
|
|
nsIAtom* nsXBLBinding::kGetterAtom = nsnull;
|
|
|
|
nsIAtom* nsXBLBinding::kSetterAtom = nsnull;
|
2000-03-29 01:24:35 +00:00
|
|
|
nsIAtom* nsXBLBinding::kNameAtom = nsnull;
|
|
|
|
nsIAtom* nsXBLBinding::kReadOnlyAtom = nsnull;
|
2000-06-02 08:13:29 +00:00
|
|
|
nsIAtom* nsXBLBinding::kAttachToAtom = nsnull;
|
2000-08-17 21:11:38 +00:00
|
|
|
|
2000-01-26 11:43:31 +00:00
|
|
|
nsXBLBinding::EventHandlerMapEntry
|
|
|
|
nsXBLBinding::kEventHandlerMap[] = {
|
|
|
|
{ "click", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
|
|
|
|
{ "dblclick", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
|
|
|
|
{ "mousedown", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
|
|
|
|
{ "mouseup", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
|
|
|
|
{ "mouseover", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
|
|
|
|
{ "mouseout", nsnull, &NS_GET_IID(nsIDOMMouseListener) },
|
|
|
|
|
|
|
|
{ "mousemove", nsnull, &NS_GET_IID(nsIDOMMouseMotionListener) },
|
|
|
|
|
|
|
|
{ "keydown", nsnull, &NS_GET_IID(nsIDOMKeyListener) },
|
|
|
|
{ "keyup", nsnull, &NS_GET_IID(nsIDOMKeyListener) },
|
|
|
|
{ "keypress", nsnull, &NS_GET_IID(nsIDOMKeyListener) },
|
|
|
|
|
|
|
|
{ "load", nsnull, &NS_GET_IID(nsIDOMLoadListener) },
|
|
|
|
{ "unload", nsnull, &NS_GET_IID(nsIDOMLoadListener) },
|
|
|
|
{ "abort", nsnull, &NS_GET_IID(nsIDOMLoadListener) },
|
|
|
|
{ "error", nsnull, &NS_GET_IID(nsIDOMLoadListener) },
|
|
|
|
|
|
|
|
{ "create", nsnull, &NS_GET_IID(nsIDOMMenuListener) },
|
|
|
|
{ "close", nsnull, &NS_GET_IID(nsIDOMMenuListener) },
|
|
|
|
{ "destroy", nsnull, &NS_GET_IID(nsIDOMMenuListener) },
|
|
|
|
{ "command", nsnull, &NS_GET_IID(nsIDOMMenuListener) },
|
|
|
|
{ "broadcast", nsnull, &NS_GET_IID(nsIDOMMenuListener) },
|
|
|
|
{ "commandupdate", nsnull, &NS_GET_IID(nsIDOMMenuListener) },
|
2000-06-28 00:00:18 +00:00
|
|
|
|
|
|
|
{ "overflow", nsnull, &NS_GET_IID(nsIDOMScrollListener) },
|
|
|
|
{ "underflow", nsnull, &NS_GET_IID(nsIDOMScrollListener) },
|
|
|
|
{ "overflowchanged", nsnull, &NS_GET_IID(nsIDOMScrollListener) },
|
2000-01-26 11:43:31 +00:00
|
|
|
|
|
|
|
{ "focus", nsnull, &NS_GET_IID(nsIDOMFocusListener) },
|
|
|
|
{ "blur", nsnull, &NS_GET_IID(nsIDOMFocusListener) },
|
|
|
|
|
|
|
|
{ "submit", nsnull, &NS_GET_IID(nsIDOMFormListener) },
|
|
|
|
{ "reset", nsnull, &NS_GET_IID(nsIDOMFormListener) },
|
|
|
|
{ "change", nsnull, &NS_GET_IID(nsIDOMFormListener) },
|
|
|
|
{ "select", nsnull, &NS_GET_IID(nsIDOMFormListener) },
|
|
|
|
{ "input", nsnull, &NS_GET_IID(nsIDOMFormListener) },
|
|
|
|
|
|
|
|
{ "paint", nsnull, &NS_GET_IID(nsIDOMPaintListener) },
|
2000-09-20 07:16:04 +00:00
|
|
|
{ "resize", nsnull, &NS_GET_IID(nsIDOMPaintListener) },
|
|
|
|
{ "scroll", nsnull, &NS_GET_IID(nsIDOMPaintListener) },
|
|
|
|
|
2000-01-26 11:43:31 +00:00
|
|
|
{ "dragenter", nsnull, &NS_GET_IID(nsIDOMDragListener) },
|
|
|
|
{ "dragover", nsnull, &NS_GET_IID(nsIDOMDragListener) },
|
|
|
|
{ "dragexit", nsnull, &NS_GET_IID(nsIDOMDragListener) },
|
|
|
|
{ "dragdrop", nsnull, &NS_GET_IID(nsIDOMDragListener) },
|
|
|
|
{ "draggesture", nsnull, &NS_GET_IID(nsIDOMDragListener) },
|
|
|
|
|
2000-11-27 07:55:20 +00:00
|
|
|
{ "DOMSubtreeModified", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
|
|
|
|
{ "DOMAttrModified", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
|
|
|
|
{ "DOMCharacterDataModified", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
|
|
|
|
{ "DOMNodeInserted", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
|
|
|
|
{ "DOMNodeRemoved", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
|
|
|
|
{ "DOMNodeInsertedIntoDocument", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
|
|
|
|
{ "DOMNodeRemovedFromDocument", nsnull, &NS_GET_IID(nsIDOMMutationListener) },
|
|
|
|
|
2000-01-26 11:43:31 +00:00
|
|
|
{ nsnull, nsnull, nsnull }
|
|
|
|
};
|
2000-01-13 02:23:54 +00:00
|
|
|
|
|
|
|
// Implementation /////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// Implement our nsISupports methods
|
2000-05-27 08:20:04 +00:00
|
|
|
NS_IMPL_ISUPPORTS1(nsXBLBinding, nsIXBLBinding)
|
2000-01-13 02:23:54 +00:00
|
|
|
|
|
|
|
// Constructors/Destructors
|
2000-09-27 20:23:49 +00:00
|
|
|
nsXBLBinding::nsXBLBinding(nsIXBLPrototypeBinding* aBinding)
|
|
|
|
: mFirstHandler(nsnull),
|
2001-02-02 00:54:47 +00:00
|
|
|
mInsertionPointTable(nsnull),
|
2000-06-22 00:36:19 +00:00
|
|
|
mIsStyleBinding(PR_TRUE),
|
2000-09-27 20:23:49 +00:00
|
|
|
mMarkedForDeath(PR_FALSE)
|
2000-01-13 02:23:54 +00:00
|
|
|
{
|
|
|
|
NS_INIT_REFCNT();
|
2000-09-27 20:23:49 +00:00
|
|
|
mPrototypeBinding = aBinding;
|
2000-01-13 09:21:09 +00:00
|
|
|
gRefCnt++;
|
2000-10-28 22:17:53 +00:00
|
|
|
// printf("REF COUNT UP: %d %s\n", gRefCnt, (const char*)mID);
|
2000-08-14 04:04:18 +00:00
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
if (gRefCnt == 1) {
|
2000-09-15 06:38:35 +00:00
|
|
|
kXULTemplateAtom = NS_NewAtom("template");
|
|
|
|
kXULObservesAtom = NS_NewAtom("observes");
|
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
kContentAtom = NS_NewAtom("content");
|
2000-09-01 01:38:04 +00:00
|
|
|
kImplementationAtom = NS_NewAtom("implementation");
|
2000-01-13 09:21:09 +00:00
|
|
|
kHandlersAtom = NS_NewAtom("handlers");
|
|
|
|
kExcludesAtom = NS_NewAtom("excludes");
|
2000-05-22 08:23:09 +00:00
|
|
|
kIncludesAtom = NS_NewAtom("includes");
|
2000-01-13 09:21:09 +00:00
|
|
|
kInheritsAtom = NS_NewAtom("inherits");
|
2000-09-01 01:38:04 +00:00
|
|
|
kEventAtom = NS_NewAtom("event");
|
|
|
|
kPhaseAtom = NS_NewAtom("phase");
|
2000-03-11 10:36:39 +00:00
|
|
|
kExtendsAtom = NS_NewAtom("extends");
|
2000-09-01 01:38:04 +00:00
|
|
|
kActionAtom = NS_NewAtom("action");
|
2000-03-29 01:24:35 +00:00
|
|
|
kMethodAtom = NS_NewAtom("method");
|
2000-09-02 01:20:36 +00:00
|
|
|
kParameterAtom = NS_NewAtom("parameter");
|
2000-03-29 01:24:35 +00:00
|
|
|
kBodyAtom = NS_NewAtom("body");
|
|
|
|
kPropertyAtom = NS_NewAtom("property");
|
|
|
|
kOnSetAtom = NS_NewAtom("onset");
|
|
|
|
kOnGetAtom = NS_NewAtom("onget");
|
2000-04-30 06:41:41 +00:00
|
|
|
kGetterAtom = NS_NewAtom("getter");
|
|
|
|
kSetterAtom = NS_NewAtom("setter");
|
2000-03-29 01:24:35 +00:00
|
|
|
kNameAtom = NS_NewAtom("name");
|
|
|
|
kReadOnlyAtom = NS_NewAtom("readonly");
|
2000-06-02 08:13:29 +00:00
|
|
|
kAttachToAtom = NS_NewAtom("attachto");
|
2000-10-04 00:41:53 +00:00
|
|
|
|
2000-01-27 07:49:50 +00:00
|
|
|
EventHandlerMapEntry* entry = kEventHandlerMap;
|
|
|
|
while (entry->mAttributeName) {
|
2000-01-27 11:19:09 +00:00
|
|
|
entry->mAttributeAtom = NS_NewAtom(entry->mAttributeName);
|
|
|
|
++entry;
|
2000-01-27 07:49:50 +00:00
|
|
|
}
|
2000-01-13 09:21:09 +00:00
|
|
|
}
|
2000-01-13 02:23:54 +00:00
|
|
|
}
|
|
|
|
|
2000-04-03 07:13:07 +00:00
|
|
|
|
2000-01-13 02:23:54 +00:00
|
|
|
nsXBLBinding::~nsXBLBinding(void)
|
|
|
|
{
|
2001-02-02 00:54:47 +00:00
|
|
|
delete mInsertionPointTable;
|
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
gRefCnt--;
|
2000-10-28 22:17:53 +00:00
|
|
|
// printf("REF COUNT DOWN: %d %s\n", gRefCnt, (const char*)mID);
|
2000-08-14 04:04:18 +00:00
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
if (gRefCnt == 0) {
|
2000-09-15 06:38:35 +00:00
|
|
|
NS_RELEASE(kXULTemplateAtom);
|
|
|
|
NS_RELEASE(kXULObservesAtom);
|
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
NS_RELEASE(kContentAtom);
|
2000-09-01 01:38:04 +00:00
|
|
|
NS_RELEASE(kImplementationAtom);
|
2000-01-13 09:21:09 +00:00
|
|
|
NS_RELEASE(kHandlersAtom);
|
|
|
|
NS_RELEASE(kExcludesAtom);
|
2000-05-22 08:23:09 +00:00
|
|
|
NS_RELEASE(kIncludesAtom);
|
2000-01-13 09:21:09 +00:00
|
|
|
NS_RELEASE(kInheritsAtom);
|
2000-09-01 01:38:04 +00:00
|
|
|
NS_RELEASE(kEventAtom);
|
|
|
|
NS_RELEASE(kPhaseAtom);
|
2000-03-11 10:36:39 +00:00
|
|
|
NS_RELEASE(kExtendsAtom);
|
2000-09-01 01:38:04 +00:00
|
|
|
NS_RELEASE(kActionAtom);
|
2000-03-29 01:24:35 +00:00
|
|
|
NS_RELEASE(kMethodAtom);
|
2000-09-02 01:20:36 +00:00
|
|
|
NS_RELEASE(kParameterAtom);
|
2000-03-29 01:24:35 +00:00
|
|
|
NS_RELEASE(kBodyAtom);
|
|
|
|
NS_RELEASE(kPropertyAtom);
|
|
|
|
NS_RELEASE(kOnSetAtom);
|
|
|
|
NS_RELEASE(kOnGetAtom);
|
2000-04-30 06:41:41 +00:00
|
|
|
NS_RELEASE(kGetterAtom);
|
|
|
|
NS_RELEASE(kSetterAtom);
|
2000-03-29 01:24:35 +00:00
|
|
|
NS_RELEASE(kNameAtom);
|
|
|
|
NS_RELEASE(kReadOnlyAtom);
|
2000-06-02 08:13:29 +00:00
|
|
|
NS_RELEASE(kAttachToAtom);
|
2000-09-27 20:23:49 +00:00
|
|
|
|
2000-01-27 11:19:09 +00:00
|
|
|
EventHandlerMapEntry* entry = kEventHandlerMap;
|
|
|
|
while (entry->mAttributeName) {
|
|
|
|
NS_IF_RELEASE(entry->mAttributeAtom);
|
|
|
|
++entry;
|
|
|
|
}
|
2000-01-13 09:21:09 +00:00
|
|
|
}
|
2000-01-13 02:23:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// nsIXBLBinding Interface ////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::GetBaseBinding(nsIXBLBinding** aResult)
|
|
|
|
{
|
2000-01-13 09:21:09 +00:00
|
|
|
*aResult = mNextBinding;
|
2000-01-13 02:23:54 +00:00
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::SetBaseBinding(nsIXBLBinding* aBinding)
|
|
|
|
{
|
2000-08-14 04:04:18 +00:00
|
|
|
if (mNextBinding) {
|
|
|
|
NS_ERROR("Base XBL binding is already defined!");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
mNextBinding = aBinding; // Comptr handles rel/add
|
2000-01-13 02:23:54 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::GetAnonymousContent(nsIContent** aResult)
|
|
|
|
{
|
2000-01-13 09:21:09 +00:00
|
|
|
*aResult = mContent;
|
2000-01-13 02:23:54 +00:00
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::SetAnonymousContent(nsIContent* aParent)
|
|
|
|
{
|
2000-01-13 09:43:42 +00:00
|
|
|
// First cache the element.
|
2000-01-13 09:21:09 +00:00
|
|
|
mContent = aParent;
|
2000-01-13 09:43:42 +00:00
|
|
|
|
|
|
|
// Now we need to ensure two things.
|
|
|
|
// (1) The anonymous content should be fooled into thinking it's in the bound
|
|
|
|
// element's document.
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
mBoundElement->GetDocument(*getter_AddRefs(doc));
|
|
|
|
|
2000-05-19 04:48:43 +00:00
|
|
|
mContent->SetDocument(doc, PR_TRUE, AllowScripts());
|
2001-02-20 01:05:34 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(doc));
|
|
|
|
|
2000-01-13 09:43:42 +00:00
|
|
|
// (2) The children's parent back pointer should not be to this synthetic root
|
|
|
|
// but should instead point to the bound element.
|
|
|
|
PRInt32 childCount;
|
|
|
|
mContent->ChildCount(childCount);
|
|
|
|
for (PRInt32 i = 0; i < childCount; i++) {
|
|
|
|
nsCOMPtr<nsIContent> child;
|
|
|
|
mContent->ChildAt(i, *getter_AddRefs(child));
|
|
|
|
child->SetParent(mBoundElement);
|
2000-08-29 03:08:35 +00:00
|
|
|
child->SetBindingParent(mBoundElement);
|
2001-02-20 01:05:34 +00:00
|
|
|
|
|
|
|
// To make XUL templates work (and other goodies that happen when
|
|
|
|
// an element is added to a XUL document), we need to notify the
|
|
|
|
// XUL document using its special API.
|
|
|
|
if (xuldoc)
|
|
|
|
xuldoc->AddSubtreeToDocument(child);
|
2000-01-13 09:43:42 +00:00
|
|
|
}
|
|
|
|
|
2000-01-13 02:23:54 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-09-27 20:23:49 +00:00
|
|
|
nsXBLBinding::GetPrototypeBinding(nsIXBLPrototypeBinding** aResult)
|
2000-01-13 02:23:54 +00:00
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
*aResult = mPrototypeBinding;
|
2000-01-13 02:23:54 +00:00
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-09-27 20:23:49 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::SetPrototypeBinding(nsIXBLPrototypeBinding* aProtoBinding)
|
|
|
|
{
|
|
|
|
mPrototypeBinding = aProtoBinding;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-01-13 02:23:54 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-09-27 20:23:49 +00:00
|
|
|
nsXBLBinding::GetBindingElement(nsIContent** aResult)
|
2000-01-13 02:23:54 +00:00
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
return mPrototypeBinding->GetBindingElement(aResult);
|
|
|
|
}
|
2000-08-12 06:28:02 +00:00
|
|
|
|
2000-09-27 20:23:49 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::SetBindingElement(nsIContent* aElement)
|
|
|
|
{
|
|
|
|
return mPrototypeBinding->SetBindingElement(aElement);
|
2000-01-13 02:23:54 +00:00
|
|
|
}
|
|
|
|
|
2000-01-13 08:54:16 +00:00
|
|
|
NS_IMETHODIMP
|
2000-06-02 08:13:29 +00:00
|
|
|
nsXBLBinding::GetBoundElement(nsIContent** aResult)
|
|
|
|
{
|
|
|
|
*aResult = mBoundElement;
|
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::SetBoundElement(nsIContent* aElement)
|
2000-01-13 08:54:16 +00:00
|
|
|
{
|
2000-06-02 08:13:29 +00:00
|
|
|
mBoundElement = aElement;
|
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->SetBoundElement(aElement);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-01-13 09:43:42 +00:00
|
|
|
|
2000-09-08 10:01:18 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::HasStyleSheets(PRBool* aResolveStyle)
|
|
|
|
{
|
|
|
|
// Find out if we need to re-resolve style. We'll need to do this
|
|
|
|
// if we have additional stylesheets in our binding document.
|
|
|
|
nsCOMPtr<nsIXBLDocumentInfo> info;
|
2000-09-27 20:23:49 +00:00
|
|
|
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
2000-09-08 10:01:18 +00:00
|
|
|
if (!info)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsISupportsArray> rules;
|
|
|
|
info->GetRuleProcessors(getter_AddRefs(rules));
|
|
|
|
if (rules) {
|
|
|
|
*aResolveStyle = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mNextBinding)
|
|
|
|
return mNextBinding->HasStyleSheets(aResolveStyle);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-02-02 00:54:47 +00:00
|
|
|
struct ContentListData {
|
|
|
|
nsXBLBinding* mBinding;
|
|
|
|
nsIBindingManager* mBindingManager;
|
|
|
|
|
|
|
|
ContentListData(nsXBLBinding* aBinding, nsIBindingManager* aManager)
|
|
|
|
:mBinding(aBinding), mBindingManager(aManager)
|
|
|
|
{};
|
|
|
|
};
|
|
|
|
|
|
|
|
PRBool PR_CALLBACK BuildContentLists(nsHashKey* aKey, void* aData, void* aClosure)
|
|
|
|
{
|
|
|
|
ContentListData* data = (ContentListData*)aClosure;
|
|
|
|
nsIBindingManager* bm = data->mBindingManager;
|
|
|
|
nsXBLBinding* binding = data->mBinding;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> boundElement;
|
|
|
|
binding->GetBoundElement(getter_AddRefs(boundElement));
|
|
|
|
|
|
|
|
nsISupportsArray* arr = (nsISupportsArray*)aData;
|
|
|
|
PRUint32 count;
|
|
|
|
arr->Count(&count);
|
|
|
|
|
|
|
|
if (count == 0)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// XXX Could this array just be altered in place and passed directly to
|
|
|
|
// SetContentListFor? We'd save space if we could pull this off.
|
|
|
|
nsCOMPtr<nsISupportsArray> contentList;
|
|
|
|
NS_NewISupportsArray(getter_AddRefs(contentList));
|
|
|
|
|
|
|
|
// Figure out the relevant content node.
|
|
|
|
PRUint32 j = 0;
|
|
|
|
nsCOMPtr<nsIXBLInsertionPoint> currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
|
|
|
|
nsCOMPtr<nsIContent> parent;
|
2001-02-07 07:45:36 +00:00
|
|
|
PRInt32 currIndex;
|
2001-02-02 00:54:47 +00:00
|
|
|
currPoint->GetInsertionParent(getter_AddRefs(parent));
|
|
|
|
currPoint->GetInsertionIndex(&currIndex);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNodeList> nodeList;
|
|
|
|
if (parent == boundElement) {
|
|
|
|
// We are altering anonymous nodes to accommodate insertion points.
|
|
|
|
binding->GetAnonymousNodes(getter_AddRefs(nodeList));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// We are altering the explicit content list of a node to accommodate insertion points.
|
|
|
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(parent));
|
|
|
|
node->GetChildNodes(getter_AddRefs(nodeList));
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXBLInsertionPoint> pseudoPoint;
|
|
|
|
PRUint32 childCount;
|
|
|
|
nodeList->GetLength(&childCount);
|
|
|
|
for (PRUint32 i = 0; i < childCount; i++) {
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nodeList->Item(i, getter_AddRefs(node));
|
|
|
|
nsCOMPtr<nsIContent> child(do_QueryInterface(node));
|
2001-02-07 07:45:36 +00:00
|
|
|
if (((PRInt32)i) == currIndex) {
|
2001-02-02 00:54:47 +00:00
|
|
|
// Add the currPoint to the supports array.
|
|
|
|
contentList->AppendElement(currPoint);
|
|
|
|
|
|
|
|
// Get the next real insertion point and update our currIndex.
|
|
|
|
j++;
|
|
|
|
if (j < count) {
|
|
|
|
currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
|
|
|
|
currPoint->GetInsertionIndex(&currIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Null out our current pseudo-point.
|
|
|
|
pseudoPoint = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pseudoPoint) {
|
2001-02-07 07:45:36 +00:00
|
|
|
NS_NewXBLInsertionPoint(parent, -1, getter_AddRefs(pseudoPoint));
|
2001-02-02 00:54:47 +00:00
|
|
|
contentList->AppendElement(pseudoPoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
pseudoPoint->AddChild(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add in all the remaining insertion points.
|
|
|
|
for ( ; j < count; j++) {
|
|
|
|
currPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
|
|
|
|
contentList->AppendElement(currPoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now set the content list using the binding manager,
|
|
|
|
// If the bound element is the parent, then we alter the anonymous node list
|
|
|
|
// instead. This allows us to always maintain two distinct lists should
|
|
|
|
// insertion points be nested into an inner binding.
|
|
|
|
if (parent == boundElement)
|
|
|
|
bm->SetAnonymousNodesFor(parent, contentList);
|
|
|
|
else
|
|
|
|
bm->SetContentListFor(parent, contentList);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2000-06-02 08:13:29 +00:00
|
|
|
NS_IMETHODIMP
|
2001-02-22 23:47:30 +00:00
|
|
|
nsXBLBinding::GenerateAnonymousContent()
|
2000-06-02 08:13:29 +00:00
|
|
|
{
|
2000-01-13 09:21:09 +00:00
|
|
|
// Fetch the content element for this binding.
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
GetImmediateChild(kContentAtom, getter_AddRefs(content));
|
|
|
|
|
|
|
|
if (!content) {
|
|
|
|
// We have no anonymous content.
|
|
|
|
if (mNextBinding)
|
2001-02-22 23:47:30 +00:00
|
|
|
return mNextBinding->GenerateAnonymousContent();
|
2000-01-13 09:21:09 +00:00
|
|
|
else return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-09-27 20:23:49 +00:00
|
|
|
// Find out if we're really building kids or if we're just
|
|
|
|
// using the attribute-setting shorthand hack.
|
|
|
|
PRInt32 contentCount;
|
|
|
|
content->ChildCount(contentCount);
|
2000-07-27 06:20:57 +00:00
|
|
|
|
2000-09-27 20:23:49 +00:00
|
|
|
// Plan to build the content by default.
|
|
|
|
PRBool hasContent = (contentCount > 0);
|
|
|
|
PRBool hasInsertionPoints;
|
|
|
|
mPrototypeBinding->HasInsertionPoints(&hasInsertionPoints);
|
|
|
|
|
|
|
|
if (hasContent && !hasInsertionPoints) {
|
|
|
|
// See if there's an includes attribute.
|
|
|
|
nsAutoString includes;
|
|
|
|
content->GetAttribute(kNameSpaceID_None, kIncludesAtom, includes);
|
2001-03-05 22:29:52 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (!includes.IsEmpty()) {
|
|
|
|
nsCAutoString id;
|
|
|
|
mPrototypeBinding->GetID(id);
|
|
|
|
nsCAutoString message("An XBL Binding with an id of ");
|
|
|
|
message += id;
|
|
|
|
message += " and found in the file ";
|
|
|
|
nsCAutoString uri;
|
|
|
|
mPrototypeBinding->GetDocURI(uri);
|
|
|
|
message += uri;
|
|
|
|
message += " is still using the deprecated\n<content includes=\"\"> syntax! Use <children> instead!\n";
|
|
|
|
NS_WARNING(message);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-09-27 20:23:49 +00:00
|
|
|
if (includes != NS_LITERAL_STRING("*")) {
|
|
|
|
PRInt32 childCount;
|
2001-02-22 23:47:30 +00:00
|
|
|
mBoundElement->ChildCount(childCount);
|
2000-09-27 20:23:49 +00:00
|
|
|
if (childCount > 0) {
|
|
|
|
// We'll only build content if all the explicit children are
|
|
|
|
// in the includes list.
|
|
|
|
// Walk the children and ensure that all of them
|
|
|
|
// are in the includes array.
|
|
|
|
for (PRInt32 i = 0; i < childCount; i++) {
|
|
|
|
nsCOMPtr<nsIContent> child;
|
2001-02-22 23:47:30 +00:00
|
|
|
mBoundElement->ChildAt(i, *getter_AddRefs(child));
|
2000-09-27 20:23:49 +00:00
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
|
|
child->GetTag(*getter_AddRefs(tag));
|
|
|
|
if (!IsInExcludesList(tag, includes)) {
|
|
|
|
// XXX HACK! Ignore <template> and <observes>
|
|
|
|
if (tag.get() != kXULTemplateAtom &&
|
|
|
|
tag.get() != kXULObservesAtom) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-03-25 02:18:55 +00:00
|
|
|
}
|
2000-01-13 09:21:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-09-27 20:23:49 +00:00
|
|
|
|
|
|
|
if (hasContent) {
|
|
|
|
nsCOMPtr<nsIContent> clonedContent;
|
2000-09-15 06:38:35 +00:00
|
|
|
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(content));
|
2000-03-14 11:09:46 +00:00
|
|
|
|
2000-09-15 06:38:35 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> clonedNode;
|
|
|
|
domElement->CloneNode(PR_TRUE, getter_AddRefs(clonedNode));
|
2000-09-27 20:23:49 +00:00
|
|
|
|
|
|
|
clonedContent = do_QueryInterface(clonedNode);
|
2000-09-15 06:38:35 +00:00
|
|
|
SetAnonymousContent(clonedContent);
|
2001-02-02 00:54:47 +00:00
|
|
|
|
|
|
|
mPrototypeBinding->SetInitialAttributes(mBoundElement, mContent);
|
|
|
|
|
|
|
|
if (hasInsertionPoints) {
|
|
|
|
// Now check and see if we have a single insertion point
|
|
|
|
// or multiple insertion points.
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
mBoundElement->GetDocument(*getter_AddRefs(doc));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIBindingManager> bindingManager;
|
|
|
|
doc->GetBindingManager(getter_AddRefs(bindingManager));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNodeList> children;
|
|
|
|
bindingManager->GetContentListFor(mBoundElement, getter_AddRefs(children));
|
|
|
|
|
|
|
|
// Enumerate the prototype binding's insertion table to build
|
|
|
|
// our table of instantiated insertion points.
|
|
|
|
mPrototypeBinding->InstantiateInsertionPoints(this);
|
|
|
|
|
|
|
|
// We now have our insertion point table constructed. We
|
|
|
|
// enumerate this table. For each array of insertion points
|
|
|
|
// bundled under the same content node, we generate a content
|
|
|
|
// list. In the case of the bound element, we generate a new
|
|
|
|
// anonymous node list that will be used in place of the binding's
|
|
|
|
// cached anonymous node list.
|
|
|
|
ContentListData data(this, bindingManager);
|
|
|
|
mInsertionPointTable->Enumerate(BuildContentLists, &data);
|
|
|
|
|
|
|
|
// We need to place the children
|
|
|
|
// at their respective insertion points.
|
|
|
|
nsCOMPtr<nsIContent> singlePoint;
|
|
|
|
PRUint32 index = 0;
|
|
|
|
PRBool multiplePoints = PR_FALSE;
|
|
|
|
GetSingleInsertionPoint(getter_AddRefs(singlePoint), &index, &multiplePoints);
|
|
|
|
|
|
|
|
if (children) {
|
|
|
|
if (multiplePoints) {
|
|
|
|
// We must walk the entire content list in order to determine where
|
|
|
|
// each child belongs.
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
PRUint32 length;
|
|
|
|
children->GetLength(&length);
|
|
|
|
for (PRUint32 i = 0; i < length; i++) {
|
|
|
|
children->Item(i, getter_AddRefs(node));
|
|
|
|
content = do_QueryInterface(node);
|
|
|
|
|
|
|
|
// Now determine the insertion point in the prototype table.
|
|
|
|
nsCOMPtr<nsIContent> point;
|
|
|
|
PRUint32 index;
|
|
|
|
GetInsertionPoint(content, getter_AddRefs(point), &index);
|
|
|
|
bindingManager->SetInsertionParent(content, point);
|
|
|
|
|
|
|
|
// Find the correct nsIXBLInsertion point in our table.
|
|
|
|
nsCOMPtr<nsIXBLInsertionPoint> insertionPoint;
|
|
|
|
nsCOMPtr<nsISupportsArray> arr;
|
|
|
|
GetInsertionPointsFor(point, getter_AddRefs(arr));
|
|
|
|
PRUint32 arrCount;
|
|
|
|
arr->Count(&arrCount);
|
|
|
|
for (PRUint32 j = 0; j < arrCount; j++) {
|
|
|
|
insertionPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(j));
|
|
|
|
PRBool matches;
|
|
|
|
insertionPoint->Matches(point, index, &matches);
|
|
|
|
if (matches)
|
|
|
|
break;
|
|
|
|
insertionPoint = nsnull;
|
|
|
|
}
|
|
|
|
|
2001-03-05 22:29:52 +00:00
|
|
|
if (insertionPoint)
|
2001-02-02 00:54:47 +00:00
|
|
|
insertionPoint->AddChild(content);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// All of our children are shunted to this single insertion point.
|
|
|
|
nsCOMPtr<nsISupportsArray> arr;
|
|
|
|
GetInsertionPointsFor(singlePoint, getter_AddRefs(arr));
|
|
|
|
PRUint32 arrCount;
|
|
|
|
arr->Count(&arrCount);
|
|
|
|
nsCOMPtr<nsIXBLInsertionPoint> insertionPoint = getter_AddRefs((nsIXBLInsertionPoint*)arr->ElementAt(0));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> node;
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
PRUint32 length;
|
|
|
|
children->GetLength(&length);
|
|
|
|
for (PRUint32 i = 0; i < length; i++) {
|
|
|
|
children->Item(i, getter_AddRefs(node));
|
|
|
|
content = do_QueryInterface(node);
|
|
|
|
bindingManager->SetInsertionParent(content, singlePoint);
|
|
|
|
insertionPoint->AddChild(content);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-09-27 20:23:49 +00:00
|
|
|
}
|
2000-03-14 11:09:46 +00:00
|
|
|
|
2000-09-27 20:23:49 +00:00
|
|
|
// Always check the content element for potential attributes.
|
|
|
|
// This shorthand hack always happens, even when we didn't
|
|
|
|
// build anonymous content.
|
|
|
|
PRInt32 length;
|
|
|
|
content->GetAttributeCount(length);
|
|
|
|
|
|
|
|
PRInt32 namespaceID;
|
|
|
|
nsCOMPtr<nsIAtom> name;
|
|
|
|
nsCOMPtr<nsIAtom> prefix;
|
|
|
|
|
|
|
|
for (PRInt32 i = 0; i < length; ++i) {
|
2001-03-02 03:35:04 +00:00
|
|
|
content->GetAttributeNameAt(i, namespaceID, *getter_AddRefs(name), *getter_AddRefs(prefix));
|
2000-09-15 06:38:35 +00:00
|
|
|
|
2000-09-27 20:23:49 +00:00
|
|
|
if (name.get() != kIncludesAtom) {
|
|
|
|
nsAutoString value;
|
|
|
|
mBoundElement->GetAttribute(namespaceID, name, value);
|
|
|
|
if (value.IsEmpty()) {
|
|
|
|
nsAutoString value2;
|
|
|
|
content->GetAttribute(namespaceID, name, value2);
|
|
|
|
mBoundElement->SetAttribute(namespaceID, name, value2, PR_FALSE);
|
|
|
|
}
|
2000-03-14 11:09:46 +00:00
|
|
|
}
|
2000-09-27 20:23:49 +00:00
|
|
|
|
|
|
|
// Conserve space by wiping the attributes off the clone.
|
|
|
|
if (mContent)
|
|
|
|
mContent->UnsetAttribute(namespaceID, name, PR_FALSE);
|
2000-01-13 09:21:09 +00:00
|
|
|
}
|
|
|
|
|
2000-01-13 08:54:16 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-02-22 23:47:30 +00:00
|
|
|
nsXBLBinding::InstallEventHandlers(nsIXBLBinding** aBinding)
|
2000-01-13 08:54:16 +00:00
|
|
|
{
|
2000-09-02 01:09:47 +00:00
|
|
|
// Don't install handlers if scripts aren't allowed.
|
2000-09-03 05:35:36 +00:00
|
|
|
if (AllowScripts()) {
|
|
|
|
// Fetch the handlers prototypes for this binding.
|
|
|
|
nsCOMPtr<nsIXBLDocumentInfo> info;
|
2000-09-27 20:23:49 +00:00
|
|
|
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
2000-09-03 05:35:36 +00:00
|
|
|
if (!info)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXBLPrototypeHandler> handlerChain;
|
2000-10-04 00:41:53 +00:00
|
|
|
nsCOMPtr<nsIXBLPrototypeHandler> specialChain;
|
|
|
|
mPrototypeBinding->GetPrototypeHandlers(getter_AddRefs(handlerChain), getter_AddRefs(specialChain));
|
2000-09-03 05:35:36 +00:00
|
|
|
|
2000-10-04 00:41:53 +00:00
|
|
|
if (specialChain && !*aBinding) {
|
|
|
|
*aBinding = this;
|
|
|
|
NS_ADDREF(*aBinding);
|
|
|
|
}
|
|
|
|
|
2000-09-03 05:35:36 +00:00
|
|
|
nsCOMPtr<nsIXBLPrototypeHandler> curr = handlerChain;
|
|
|
|
nsXBLEventHandler* currHandler = nsnull;
|
2000-06-02 08:13:29 +00:00
|
|
|
|
2000-09-03 05:35:36 +00:00
|
|
|
while (curr) {
|
|
|
|
nsCOMPtr<nsIContent> child;
|
|
|
|
curr->GetHandlerElement(getter_AddRefs(child));
|
2000-09-02 01:09:47 +00:00
|
|
|
|
2000-09-03 05:35:36 +00:00
|
|
|
// Fetch the type attribute.
|
|
|
|
// XXX Deal with a comma-separated list of types
|
2000-09-22 05:02:20 +00:00
|
|
|
nsCOMPtr<nsIAtom> eventAtom;
|
|
|
|
curr->GetEventName(getter_AddRefs(eventAtom));
|
|
|
|
|
|
|
|
nsIID iid;
|
|
|
|
PRBool found = PR_FALSE;
|
2000-10-04 00:41:53 +00:00
|
|
|
GetEventHandlerIID(eventAtom, &iid, &found);
|
2000-09-22 05:02:20 +00:00
|
|
|
|
2000-10-04 00:41:53 +00:00
|
|
|
if (found) {
|
2000-09-22 05:02:20 +00:00
|
|
|
nsCOMPtr<nsIDOMEventReceiver> receiver = do_QueryInterface(mBoundElement);
|
2001-03-05 21:45:13 +00:00
|
|
|
/*
|
|
|
|
// Disable ATTACHTO capability for Mozilla 1.0
|
2000-09-22 05:02:20 +00:00
|
|
|
nsAutoString attachType;
|
|
|
|
child->GetAttribute(kNameSpaceID_None, kAttachToAtom, attachType);
|
|
|
|
if (attachType == NS_LITERAL_STRING("_document") ||
|
|
|
|
attachType == NS_LITERAL_STRING("_window"))
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDocument> boundDoc;
|
|
|
|
mBoundElement->GetDocument(*getter_AddRefs(boundDoc));
|
|
|
|
if (attachType == NS_LITERAL_STRING("_window")) {
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> global;
|
|
|
|
boundDoc->GetScriptGlobalObject(getter_AddRefs(global));
|
|
|
|
receiver = do_QueryInterface(global);
|
2000-09-03 05:35:36 +00:00
|
|
|
}
|
2000-09-22 05:02:20 +00:00
|
|
|
else receiver = do_QueryInterface(boundDoc);
|
|
|
|
}
|
|
|
|
else if (!attachType.IsEmpty() && !attachType.Equals(NS_LITERAL_STRING("_element"))) {
|
|
|
|
nsCOMPtr<nsIDocument> boundDoc;
|
|
|
|
mBoundElement->GetDocument(*getter_AddRefs(boundDoc));
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDoc(do_QueryInterface(boundDoc));
|
|
|
|
nsCOMPtr<nsIDOMElement> otherElement;
|
|
|
|
domDoc->GetElementById(attachType, getter_AddRefs(otherElement));
|
|
|
|
receiver = do_QueryInterface(otherElement);
|
|
|
|
}
|
2001-03-05 21:45:13 +00:00
|
|
|
*/
|
2000-09-02 01:09:47 +00:00
|
|
|
|
2000-09-22 05:02:20 +00:00
|
|
|
// Figure out if we're using capturing or not.
|
|
|
|
PRBool useCapture = PR_FALSE;
|
|
|
|
nsAutoString capturer;
|
|
|
|
child->GetAttribute(kNameSpaceID_None, kPhaseAtom, capturer);
|
|
|
|
if (capturer == NS_LITERAL_STRING("capturing"))
|
|
|
|
useCapture = PR_TRUE;
|
|
|
|
|
|
|
|
// Create a new nsXBLEventHandler.
|
|
|
|
nsXBLEventHandler* handler = nsnull;
|
|
|
|
|
|
|
|
nsAutoString type;
|
|
|
|
eventAtom->ToString(type);
|
|
|
|
|
|
|
|
// Add the event listener.
|
2000-10-04 00:41:53 +00:00
|
|
|
if (iid.Equals(NS_GET_IID(nsIDOMMouseListener))) {
|
2000-09-22 05:02:20 +00:00
|
|
|
nsXBLMouseHandler* mouseHandler;
|
|
|
|
NS_NewXBLMouseHandler(receiver, curr, &mouseHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMMouseListener*)mouseHandler, useCapture);
|
|
|
|
handler = mouseHandler;
|
|
|
|
}
|
|
|
|
else if(iid.Equals(NS_GET_IID(nsIDOMKeyListener))) {
|
|
|
|
nsXBLKeyHandler* keyHandler;
|
|
|
|
NS_NewXBLKeyHandler(receiver, curr, &keyHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMKeyListener*)keyHandler, useCapture);
|
|
|
|
handler = keyHandler;
|
|
|
|
}
|
|
|
|
else if (iid.Equals(NS_GET_IID(nsIDOMMouseMotionListener))) {
|
|
|
|
nsXBLMouseMotionHandler* mouseHandler;
|
|
|
|
NS_NewXBLMouseMotionHandler(receiver, curr, &mouseHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMMouseListener*)mouseHandler, useCapture);
|
|
|
|
handler = mouseHandler;
|
|
|
|
}
|
|
|
|
else if(iid.Equals(NS_GET_IID(nsIDOMFocusListener))) {
|
|
|
|
nsXBLFocusHandler* focusHandler;
|
|
|
|
NS_NewXBLFocusHandler(receiver, curr, &focusHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMFocusListener*)focusHandler, useCapture);
|
|
|
|
handler = focusHandler;
|
|
|
|
}
|
|
|
|
else if (iid.Equals(NS_GET_IID(nsIDOMMenuListener))) {
|
|
|
|
nsXBLXULHandler* xulHandler;
|
|
|
|
NS_NewXBLXULHandler(receiver, curr, &xulHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMMenuListener*)xulHandler, useCapture);
|
|
|
|
handler = xulHandler;
|
|
|
|
}
|
|
|
|
else if (iid.Equals(NS_GET_IID(nsIDOMScrollListener))) {
|
|
|
|
nsXBLScrollHandler* scrollHandler;
|
|
|
|
NS_NewXBLScrollHandler(receiver, curr, &scrollHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMScrollListener*)scrollHandler, useCapture);
|
|
|
|
handler = scrollHandler;
|
|
|
|
}
|
|
|
|
else if (iid.Equals(NS_GET_IID(nsIDOMFormListener))) {
|
|
|
|
nsXBLFormHandler* formHandler;
|
|
|
|
NS_NewXBLFormHandler(receiver, curr, &formHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMFormListener*)formHandler, useCapture);
|
|
|
|
handler = formHandler;
|
|
|
|
}
|
|
|
|
else if(iid.Equals(NS_GET_IID(nsIDOMDragListener))) {
|
|
|
|
nsXBLDragHandler* dragHandler;
|
|
|
|
NS_NewXBLDragHandler(receiver, curr, &dragHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMDragListener*)dragHandler, useCapture);
|
|
|
|
handler = dragHandler;
|
|
|
|
}
|
|
|
|
else if(iid.Equals(NS_GET_IID(nsIDOMLoadListener))) {
|
|
|
|
nsXBLLoadHandler* loadHandler;
|
|
|
|
NS_NewXBLLoadHandler(receiver, curr, &loadHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMLoadListener*)loadHandler, useCapture);
|
|
|
|
handler = loadHandler;
|
|
|
|
}
|
2000-11-27 07:55:20 +00:00
|
|
|
else if(iid.Equals(NS_GET_IID(nsIDOMMutationListener))) {
|
|
|
|
nsXBLMutationHandler* mutationHandler;
|
|
|
|
NS_NewXBLMutationHandler(receiver, curr, &mutationHandler);
|
|
|
|
receiver->AddEventListener(type, (nsIDOMMutationListener*)mutationHandler, useCapture);
|
|
|
|
handler = mutationHandler;
|
|
|
|
}
|
2000-09-22 05:02:20 +00:00
|
|
|
else {
|
|
|
|
NS_WARNING("***** Non-compliant XBL event listener attached! *****");
|
|
|
|
nsAutoString value;
|
|
|
|
child->GetAttribute(kNameSpaceID_None, kActionAtom, value);
|
|
|
|
if (value.IsEmpty())
|
|
|
|
GetTextData(child, value);
|
|
|
|
AddScriptEventListener(mBoundElement, eventAtom, value, iid);
|
|
|
|
}
|
2000-09-03 05:35:36 +00:00
|
|
|
|
2000-09-22 05:02:20 +00:00
|
|
|
// We chain all our event handlers together for easy
|
|
|
|
// removal later (if/when the binding dies).
|
|
|
|
if (handler) {
|
|
|
|
if (!currHandler)
|
|
|
|
mFirstHandler = handler;
|
|
|
|
else
|
|
|
|
currHandler->SetNextHandler(handler);
|
2000-09-03 05:35:36 +00:00
|
|
|
|
2000-09-22 05:02:20 +00:00
|
|
|
currHandler = handler;
|
2000-09-03 05:35:36 +00:00
|
|
|
|
2000-10-04 00:41:53 +00:00
|
|
|
// Let the listener manager hold on to the handler.
|
|
|
|
NS_RELEASE(handler);
|
2000-09-15 23:28:29 +00:00
|
|
|
}
|
2000-01-26 11:43:31 +00:00
|
|
|
}
|
2000-09-02 01:09:47 +00:00
|
|
|
|
2000-09-03 05:35:36 +00:00
|
|
|
nsCOMPtr<nsIXBLPrototypeHandler> next;
|
|
|
|
curr->GetNextHandler(getter_AddRefs(next));
|
|
|
|
curr = next;
|
|
|
|
}
|
2000-01-26 11:43:31 +00:00
|
|
|
}
|
|
|
|
|
2000-07-28 00:35:02 +00:00
|
|
|
if (mNextBinding) {
|
|
|
|
nsCOMPtr<nsIXBLBinding> binding;
|
2001-02-22 23:47:30 +00:00
|
|
|
mNextBinding->InstallEventHandlers(getter_AddRefs(binding));
|
2000-07-28 00:35:02 +00:00
|
|
|
if (!*aBinding) {
|
|
|
|
*aBinding = binding;
|
|
|
|
NS_IF_ADDREF(*aBinding);
|
|
|
|
}
|
|
|
|
}
|
2000-01-27 09:44:58 +00:00
|
|
|
|
2000-01-13 08:54:16 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-03-29 01:24:35 +00:00
|
|
|
const char* gPropertyArg[] = { "val" };
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-02-22 23:47:30 +00:00
|
|
|
nsXBLBinding::InstallProperties()
|
2000-03-29 01:24:35 +00:00
|
|
|
{
|
|
|
|
// Always install the base class properties first, so that
|
|
|
|
// derived classes can reference the base class properties.
|
|
|
|
if (mNextBinding)
|
2001-02-22 23:47:30 +00:00
|
|
|
mNextBinding->InstallProperties();
|
2000-03-29 01:24:35 +00:00
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
// Fetch the interface element for this binding.
|
2000-03-29 01:24:35 +00:00
|
|
|
nsCOMPtr<nsIContent> interfaceElement;
|
2000-09-01 01:38:04 +00:00
|
|
|
GetImmediateChild(kImplementationAtom, getter_AddRefs(interfaceElement));
|
2000-03-29 01:24:35 +00:00
|
|
|
|
2000-05-19 04:48:43 +00:00
|
|
|
if (interfaceElement && AllowScripts()) {
|
2000-03-29 01:24:35 +00:00
|
|
|
// Get our bound element's script context.
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIDocument> document;
|
|
|
|
mBoundElement->GetDocument(*getter_AddRefs(document));
|
|
|
|
if (!document)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> global;
|
|
|
|
document->GetScriptGlobalObject(getter_AddRefs(global));
|
|
|
|
|
|
|
|
if (!global)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIScriptContext> context;
|
|
|
|
rv = global->GetContext(getter_AddRefs(context));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
// Init our class and insert it into the prototype chain.
|
|
|
|
nsAutoString className;
|
2000-08-12 06:28:02 +00:00
|
|
|
nsCAutoString classStr;
|
2000-05-27 08:20:04 +00:00
|
|
|
interfaceElement->GetAttribute(kNameSpaceID_None, kNameAtom, className);
|
2000-08-12 06:28:02 +00:00
|
|
|
if (!className.IsEmpty()) {
|
|
|
|
classStr.AssignWithConversion(className);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
GetBindingURI(classStr);
|
2000-05-27 08:20:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JSObject* scriptObject;
|
|
|
|
JSObject* classObject;
|
|
|
|
if (NS_FAILED(rv = InitClass(classStr, context, document, (void**)&scriptObject, (void**)&classObject)))
|
2000-03-31 03:13:43 +00:00
|
|
|
return rv;
|
2000-03-29 01:24:35 +00:00
|
|
|
|
2000-03-31 03:13:43 +00:00
|
|
|
JSContext* cx = (JSContext*)context->GetNativeContext();
|
2000-03-29 01:24:35 +00:00
|
|
|
|
|
|
|
// Do a walk.
|
|
|
|
PRInt32 childCount;
|
|
|
|
interfaceElement->ChildCount(childCount);
|
|
|
|
for (PRInt32 i = 0; i < childCount; i++) {
|
|
|
|
nsCOMPtr<nsIContent> child;
|
|
|
|
interfaceElement->ChildAt(i, *getter_AddRefs(child));
|
|
|
|
|
|
|
|
// See if we're a property or a method.
|
|
|
|
nsCOMPtr<nsIAtom> tagName;
|
|
|
|
child->GetTag(*getter_AddRefs(tagName));
|
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
if (tagName.get() == kMethodAtom && classObject) {
|
2000-03-29 01:24:35 +00:00
|
|
|
// Obtain our name attribute.
|
|
|
|
nsAutoString name, body;
|
|
|
|
child->GetAttribute(kNameSpaceID_None, kNameAtom, name);
|
|
|
|
|
|
|
|
// Now walk all of our args.
|
|
|
|
// XXX I'm lame. 32 max args allowed.
|
|
|
|
char* args[32];
|
|
|
|
PRUint32 argCount = 0;
|
|
|
|
PRInt32 kidCount;
|
|
|
|
child->ChildCount(kidCount);
|
2000-03-29 02:26:46 +00:00
|
|
|
for (PRInt32 j = 0; j < kidCount; j++)
|
2000-03-29 01:24:35 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> arg;
|
|
|
|
child->ChildAt(j, *getter_AddRefs(arg));
|
|
|
|
nsCOMPtr<nsIAtom> kidTagName;
|
|
|
|
arg->GetTag(*getter_AddRefs(kidTagName));
|
2000-09-02 01:20:36 +00:00
|
|
|
if (kidTagName.get() == kParameterAtom) {
|
2000-03-29 01:24:35 +00:00
|
|
|
// Get the argname and add it to the array.
|
|
|
|
nsAutoString argName;
|
|
|
|
arg->GetAttribute(kNameSpaceID_None, kNameAtom, argName);
|
|
|
|
char* argStr = argName.ToNewCString();
|
|
|
|
args[argCount] = argStr;
|
|
|
|
argCount++;
|
|
|
|
}
|
|
|
|
else if (kidTagName.get() == kBodyAtom) {
|
|
|
|
PRInt32 textCount;
|
|
|
|
arg->ChildCount(textCount);
|
|
|
|
|
|
|
|
for (PRInt32 k = 0; k < textCount; k++) {
|
|
|
|
// Get the child.
|
|
|
|
nsCOMPtr<nsIContent> textChild;
|
|
|
|
arg->ChildAt(k, *getter_AddRefs(textChild));
|
|
|
|
nsCOMPtr<nsIDOMText> text(do_QueryInterface(textChild));
|
|
|
|
if (text) {
|
|
|
|
nsAutoString data;
|
|
|
|
text->GetData(data);
|
|
|
|
body += data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we have a body and args, compile the function
|
|
|
|
// and then define it as a property.
|
|
|
|
if (!body.IsEmpty()) {
|
|
|
|
void* myFunc;
|
2000-04-16 11:19:26 +00:00
|
|
|
nsCAutoString cname; cname.AssignWithConversion(name.GetUnicode());
|
2000-10-27 00:51:23 +00:00
|
|
|
nsCAutoString functionUri = classStr;
|
|
|
|
functionUri += ".";
|
|
|
|
functionUri += cname;
|
|
|
|
functionUri += "()";
|
|
|
|
|
2000-05-31 07:02:47 +00:00
|
|
|
rv = context->CompileFunction(classObject,
|
2000-04-16 11:19:26 +00:00
|
|
|
cname,
|
2000-03-29 01:24:35 +00:00
|
|
|
argCount,
|
|
|
|
(const char**)args,
|
|
|
|
body,
|
2001-03-02 09:26:57 +00:00
|
|
|
functionUri.get(),
|
2000-03-29 01:24:35 +00:00
|
|
|
0,
|
|
|
|
PR_FALSE,
|
|
|
|
&myFunc);
|
|
|
|
}
|
2000-06-01 07:01:54 +00:00
|
|
|
for (PRUint32 l = 0; l < argCount; l++) {
|
2000-06-03 09:46:12 +00:00
|
|
|
nsMemory::Free(args[l]);
|
2000-06-01 07:01:54 +00:00
|
|
|
}
|
2000-03-29 01:24:35 +00:00
|
|
|
}
|
|
|
|
else if (tagName.get() == kPropertyAtom) {
|
|
|
|
// Obtain our name attribute.
|
|
|
|
nsAutoString name;
|
|
|
|
child->GetAttribute(kNameSpaceID_None, kNameAtom, name);
|
|
|
|
|
|
|
|
if (!name.IsEmpty()) {
|
|
|
|
// We have a property.
|
|
|
|
nsAutoString getter, setter, readOnly;
|
|
|
|
child->GetAttribute(kNameSpaceID_None, kOnGetAtom, getter);
|
|
|
|
child->GetAttribute(kNameSpaceID_None, kOnSetAtom, setter);
|
|
|
|
child->GetAttribute(kNameSpaceID_None, kReadOnlyAtom, readOnly);
|
|
|
|
|
|
|
|
void* getFunc = nsnull;
|
|
|
|
void* setFunc = nsnull;
|
2000-06-02 01:19:15 +00:00
|
|
|
uintN attrs = JSPROP_ENUMERATE;
|
2000-03-29 01:24:35 +00:00
|
|
|
|
2000-08-30 02:45:02 +00:00
|
|
|
if (readOnly == NS_LITERAL_STRING("true"))
|
2000-03-29 01:24:35 +00:00
|
|
|
attrs |= JSPROP_READONLY;
|
|
|
|
|
2000-04-30 06:41:41 +00:00
|
|
|
// try for first <getter> tag
|
|
|
|
if (getter.IsEmpty()) {
|
|
|
|
PRInt32 childCount;
|
|
|
|
child->ChildCount(childCount);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> getterElement;
|
|
|
|
for (PRInt32 j=0; j<childCount; j++) {
|
|
|
|
child->ChildAt(j, *getter_AddRefs(getterElement));
|
|
|
|
|
|
|
|
if (!getterElement) continue;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> getterTag;
|
|
|
|
getterElement->GetTag(*getter_AddRefs(getterTag));
|
|
|
|
|
|
|
|
if (getterTag.get() == kGetterAtom) {
|
|
|
|
GetTextData(getterElement, getter);
|
|
|
|
break; // stop at first tag
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
if (!getter.IsEmpty() && classObject) {
|
2000-10-27 00:51:23 +00:00
|
|
|
nsCAutoString functionUri = classStr;
|
|
|
|
functionUri += ".";
|
|
|
|
functionUri.AppendWithConversion(name.GetUnicode());
|
|
|
|
functionUri += " (getter)";
|
2000-05-27 08:20:04 +00:00
|
|
|
rv = context->CompileFunction(classObject,
|
2000-08-19 22:23:46 +00:00
|
|
|
nsCAutoString("onget"),
|
2000-03-29 01:24:35 +00:00
|
|
|
0,
|
|
|
|
nsnull,
|
|
|
|
getter,
|
2001-03-02 09:26:57 +00:00
|
|
|
functionUri.get(),
|
2000-03-29 01:24:35 +00:00
|
|
|
0,
|
|
|
|
PR_FALSE,
|
|
|
|
&getFunc);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
2000-12-20 07:25:19 +00:00
|
|
|
attrs |= JSPROP_GETTER | JSPROP_SHARED;
|
2000-03-29 01:24:35 +00:00
|
|
|
}
|
|
|
|
|
2000-04-30 06:41:41 +00:00
|
|
|
// try for first <setter> tag
|
|
|
|
if (setter.IsEmpty()) {
|
|
|
|
PRInt32 childCount;
|
|
|
|
child->ChildCount(childCount);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> setterElement;
|
|
|
|
for (PRInt32 j=0; j<childCount; j++) {
|
|
|
|
child->ChildAt(j, *getter_AddRefs(setterElement));
|
|
|
|
|
|
|
|
if (!setterElement) continue;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> setterTag;
|
|
|
|
setterElement->GetTag(*getter_AddRefs(setterTag));
|
|
|
|
if (setterTag.get() == kSetterAtom) {
|
|
|
|
GetTextData(setterElement, setter);
|
|
|
|
break; // stop at first tag
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
if (!setter.IsEmpty() && classObject) {
|
2000-10-27 00:51:23 +00:00
|
|
|
nsCAutoString functionUri = classStr;
|
|
|
|
functionUri += ".";
|
|
|
|
functionUri.AppendWithConversion(name.GetUnicode());
|
|
|
|
functionUri += " (setter)";
|
2000-05-27 08:20:04 +00:00
|
|
|
rv = context->CompileFunction(classObject,
|
2000-08-19 22:23:46 +00:00
|
|
|
nsCAutoString("onset"),
|
2000-03-29 01:24:35 +00:00
|
|
|
1,
|
|
|
|
gPropertyArg,
|
|
|
|
setter,
|
2001-03-02 09:26:57 +00:00
|
|
|
functionUri.get(),
|
2000-03-29 01:24:35 +00:00
|
|
|
0,
|
|
|
|
PR_FALSE,
|
|
|
|
&setFunc);
|
|
|
|
if (NS_FAILED(rv)) return NS_ERROR_FAILURE;
|
2000-12-20 07:25:19 +00:00
|
|
|
attrs |= JSPROP_SETTER | JSPROP_SHARED;
|
2000-03-29 01:24:35 +00:00
|
|
|
}
|
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
if ((getFunc || setFunc) && classObject) {
|
2000-03-29 01:24:35 +00:00
|
|
|
// Having either a getter or setter results in the
|
|
|
|
// destruction of any initial value that might be set.
|
|
|
|
// This means we only have to worry about defining the getter
|
|
|
|
// or setter.
|
2000-06-12 23:52:31 +00:00
|
|
|
::JS_DefineUCProperty(cx, (JSObject*)classObject, NS_REINTERPRET_CAST(const jschar*, name.GetUnicode()),
|
2000-03-29 01:24:35 +00:00
|
|
|
name.Length(), JSVAL_VOID,
|
|
|
|
(JSPropertyOp) getFunc,
|
|
|
|
(JSPropertyOp) setFunc,
|
|
|
|
attrs);
|
|
|
|
} else {
|
|
|
|
// Look for a normal value and just define that.
|
|
|
|
nsCOMPtr<nsIContent> textChild;
|
|
|
|
PRInt32 textCount;
|
|
|
|
child->ChildCount(textCount);
|
|
|
|
nsAutoString answer;
|
|
|
|
for (PRInt32 j = 0; j < textCount; j++) {
|
|
|
|
// Get the child.
|
|
|
|
child->ChildAt(j, *getter_AddRefs(textChild));
|
|
|
|
nsCOMPtr<nsIDOMText> text(do_QueryInterface(textChild));
|
|
|
|
if (text) {
|
|
|
|
nsAutoString data;
|
|
|
|
text->GetData(data);
|
|
|
|
answer += data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!answer.IsEmpty()) {
|
|
|
|
// Evaluate our script and obtain a value.
|
2000-04-05 04:00:13 +00:00
|
|
|
jsval result = nsnull;
|
2000-03-29 01:24:35 +00:00
|
|
|
PRBool undefined;
|
|
|
|
rv = context->EvaluateStringWithValue(answer,
|
2000-05-27 08:20:04 +00:00
|
|
|
scriptObject,
|
2000-03-29 01:24:35 +00:00
|
|
|
nsnull, nsnull, 0, nsnull,
|
2000-04-05 04:00:13 +00:00
|
|
|
(void*) &result, &undefined);
|
2000-03-29 01:24:35 +00:00
|
|
|
|
|
|
|
if (!undefined) {
|
|
|
|
// Define that value as a property
|
2000-06-12 23:52:31 +00:00
|
|
|
::JS_DefineUCProperty(cx, (JSObject*)scriptObject, NS_REINTERPRET_CAST(const jschar*, name.GetUnicode()),
|
2000-04-05 04:00:13 +00:00
|
|
|
name.Length(), result,
|
2000-03-29 01:24:35 +00:00
|
|
|
nsnull, nsnull,
|
|
|
|
attrs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-02-22 23:47:30 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::LoadResources()
|
|
|
|
{
|
|
|
|
mPrototypeBinding->LoadResources();
|
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->LoadResources();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-03-11 10:36:39 +00:00
|
|
|
NS_IMETHODIMP
|
2000-05-24 08:19:10 +00:00
|
|
|
nsXBLBinding::GetBaseTag(PRInt32* aNameSpaceID, nsIAtom** aResult)
|
2000-03-11 10:36:39 +00:00
|
|
|
{
|
2000-12-07 10:11:21 +00:00
|
|
|
mPrototypeBinding->GetBaseTag(aNameSpaceID, aResult);
|
|
|
|
if (!*aResult && mNextBinding)
|
2000-05-24 08:19:10 +00:00
|
|
|
return mNextBinding->GetBaseTag(aNameSpaceID, aResult);
|
2000-12-07 10:11:21 +00:00
|
|
|
return NS_OK;
|
2000-03-11 10:36:39 +00:00
|
|
|
}
|
|
|
|
|
2000-01-25 06:35:27 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::AttributeChanged(nsIAtom* aAttribute, PRInt32 aNameSpaceID, PRBool aRemoveFlag)
|
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
// XXX Change if we ever allow multiple bindings in a chain to contribute anonymous content
|
|
|
|
if (!mContent) {
|
|
|
|
if (mNextBinding)
|
|
|
|
return mNextBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag);
|
2000-01-25 06:35:27 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-09-27 20:23:49 +00:00
|
|
|
return mPrototypeBinding->AttributeChanged(aAttribute, aNameSpaceID, aRemoveFlag, mBoundElement, mContent);
|
2000-01-25 06:35:27 +00:00
|
|
|
}
|
|
|
|
|
2000-07-28 00:35:02 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::ExecuteAttachedHandler()
|
|
|
|
{
|
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->ExecuteAttachedHandler();
|
|
|
|
|
2000-10-04 00:41:53 +00:00
|
|
|
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mBoundElement));
|
|
|
|
mPrototypeBinding->BindingAttached(rec);
|
2000-07-28 00:35:02 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::ExecuteDetachedHandler()
|
|
|
|
{
|
2000-10-04 00:41:53 +00:00
|
|
|
nsCOMPtr<nsIDOMEventReceiver> rec(do_QueryInterface(mBoundElement));
|
|
|
|
mPrototypeBinding->BindingDetached(rec);
|
2000-07-28 00:35:02 +00:00
|
|
|
|
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->ExecuteDetachedHandler();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-06-22 00:36:19 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::UnhookEventHandlers()
|
|
|
|
{
|
|
|
|
if (mFirstHandler) {
|
|
|
|
// Unhook our event handlers.
|
|
|
|
mFirstHandler->RemoveEventHandlers();
|
|
|
|
mFirstHandler = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-03-31 10:27:12 +00:00
|
|
|
NS_IMETHODIMP
|
2000-05-04 04:25:50 +00:00
|
|
|
nsXBLBinding::ChangeDocument(nsIDocument* aOldDocument, nsIDocument* aNewDocument)
|
2000-03-31 10:27:12 +00:00
|
|
|
{
|
2000-05-04 04:25:50 +00:00
|
|
|
if (aOldDocument != aNewDocument) {
|
2000-08-16 08:14:01 +00:00
|
|
|
if (mFirstHandler) {
|
|
|
|
mFirstHandler->MarkForDeath();
|
|
|
|
mFirstHandler = nsnull;
|
|
|
|
}
|
2000-06-22 00:36:19 +00:00
|
|
|
|
2000-05-04 04:25:50 +00:00
|
|
|
if (mNextBinding)
|
|
|
|
mNextBinding->ChangeDocument(aOldDocument, aNewDocument);
|
|
|
|
|
2000-06-02 08:13:29 +00:00
|
|
|
// Only style bindings get their prototypes unhooked.
|
2000-06-22 00:36:19 +00:00
|
|
|
if (mIsStyleBinding) {
|
2000-05-27 08:20:04 +00:00
|
|
|
// Now the binding dies. Unhook our prototypes.
|
|
|
|
nsCOMPtr<nsIContent> interfaceElement;
|
2000-09-01 01:38:04 +00:00
|
|
|
GetImmediateChild(kImplementationAtom, getter_AddRefs(interfaceElement));
|
2000-05-04 04:25:50 +00:00
|
|
|
|
2000-06-22 00:36:19 +00:00
|
|
|
if (interfaceElement) {
|
2000-05-04 04:25:50 +00:00
|
|
|
nsCOMPtr<nsIScriptGlobalObject> global;
|
2000-05-27 08:20:04 +00:00
|
|
|
aOldDocument->GetScriptGlobalObject(getter_AddRefs(global));
|
2000-05-04 04:25:50 +00:00
|
|
|
if (global) {
|
|
|
|
nsCOMPtr<nsIScriptContext> context;
|
|
|
|
global->GetContext(getter_AddRefs(context));
|
2000-05-27 08:20:04 +00:00
|
|
|
if (context) {
|
|
|
|
JSObject* scriptObject;
|
|
|
|
nsCOMPtr<nsIScriptObjectOwner> owner(do_QueryInterface(mBoundElement));
|
|
|
|
owner->GetScriptObject(context, (void**)&scriptObject);
|
|
|
|
if (scriptObject) {
|
2000-06-22 00:36:19 +00:00
|
|
|
// XXX Stay in sync! What if a layered binding has an <interface>?!
|
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
// XXX Sanity check to make sure our class name matches
|
|
|
|
// Pull ourselves out of the proto chain.
|
|
|
|
JSContext* jscontext = (JSContext*)context->GetNativeContext();
|
2000-07-01 02:36:18 +00:00
|
|
|
JSObject* ourProto = ::JS_GetPrototype(jscontext, scriptObject);
|
|
|
|
JSObject* grandProto = ::JS_GetPrototype(jscontext, ourProto);
|
|
|
|
::JS_SetPrototype(jscontext, scriptObject, grandProto);
|
2000-05-27 08:20:04 +00:00
|
|
|
}
|
|
|
|
}
|
2000-05-04 04:25:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-03-31 10:27:12 +00:00
|
|
|
|
2000-06-02 08:13:29 +00:00
|
|
|
// Update the anonymous content.
|
2000-05-04 04:25:50 +00:00
|
|
|
nsCOMPtr<nsIContent> anonymous;
|
|
|
|
GetAnonymousContent(getter_AddRefs(anonymous));
|
2000-06-22 00:36:19 +00:00
|
|
|
if (anonymous) {
|
2001-02-20 01:05:34 +00:00
|
|
|
// To make XUL templates work (and other XUL-specific stuff),
|
|
|
|
// we'll need to notify it using its add & remove APIs. Grab the
|
|
|
|
// interface now...
|
|
|
|
nsCOMPtr<nsIXULDocument> xuldoc(do_QueryInterface(aOldDocument));
|
|
|
|
|
|
|
|
if (mIsStyleBinding) {
|
2000-09-27 20:23:49 +00:00
|
|
|
anonymous->SetDocument(nsnull, PR_TRUE, PR_TRUE); // Kill it.
|
2001-02-20 01:05:34 +00:00
|
|
|
if (xuldoc)
|
|
|
|
xuldoc->RemoveSubtreeFromDocument(anonymous);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
anonymous->SetDocument(aNewDocument, PR_TRUE, AllowScripts()); // Keep it around.
|
|
|
|
if (xuldoc)
|
|
|
|
xuldoc->RemoveSubtreeFromDocument(anonymous);
|
|
|
|
|
|
|
|
xuldoc = do_QueryInterface(aNewDocument);
|
|
|
|
if (xuldoc)
|
|
|
|
xuldoc->AddSubtreeToDocument(anonymous);
|
|
|
|
}
|
2000-06-22 00:36:19 +00:00
|
|
|
}
|
2000-03-31 10:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-04-27 02:08:35 +00:00
|
|
|
NS_IMETHODIMP
|
2000-08-12 06:28:02 +00:00
|
|
|
nsXBLBinding::GetBindingURI(nsCString& aResult)
|
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
return mPrototypeBinding->GetBindingURI(aResult);
|
2000-08-12 06:28:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::GetDocURI(nsCString& aResult)
|
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
return mPrototypeBinding->GetDocURI(aResult);
|
2000-08-12 06:28:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::GetID(nsCString& aResult)
|
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
return mPrototypeBinding->GetID(aResult);
|
2000-08-12 06:28:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::InheritsStyle(PRBool* aResult)
|
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
// XXX Will have to change if we ever allow multiple bindings to contribute anonymous content.
|
|
|
|
// Most derived binding with anonymous content determines style inheritance for now.
|
|
|
|
|
|
|
|
// XXX What about bindings with <content> but no kids, e.g., my treecell-text binding?
|
2000-08-24 09:21:27 +00:00
|
|
|
if (mContent)
|
2000-09-27 20:23:49 +00:00
|
|
|
return mPrototypeBinding->InheritsStyle(aResult);
|
|
|
|
|
|
|
|
if (mNextBinding)
|
2000-08-24 09:21:27 +00:00
|
|
|
return mNextBinding->InheritsStyle(aResult);
|
|
|
|
|
2000-08-12 06:28:02 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData)
|
2000-04-27 02:08:35 +00:00
|
|
|
{
|
2000-09-08 10:01:18 +00:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (mNextBinding) {
|
|
|
|
rv = mNextBinding->WalkRules(aFunc, aData);
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2000-08-12 06:28:02 +00:00
|
|
|
}
|
|
|
|
|
2000-09-08 10:01:18 +00:00
|
|
|
nsCOMPtr<nsIXBLDocumentInfo> info;
|
2000-09-27 20:23:49 +00:00
|
|
|
mPrototypeBinding->GetXBLDocumentInfo(mBoundElement, getter_AddRefs(info));
|
2000-09-08 10:01:18 +00:00
|
|
|
if (!info)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsISupportsArray> rules;
|
|
|
|
info->GetRuleProcessors(getter_AddRefs(rules));
|
|
|
|
if (rules)
|
|
|
|
rules->EnumerateForwards(aFunc, aData);
|
|
|
|
|
|
|
|
return rv;
|
2000-04-27 02:08:35 +00:00
|
|
|
}
|
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
// Internal helper methods ////////////////////////////////////////////////////////////////
|
2000-03-31 03:13:43 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2000-05-27 08:20:04 +00:00
|
|
|
nsXBLBinding::InitClass(const nsCString& aClassName, nsIScriptContext* aContext,
|
|
|
|
nsIDocument* aDocument, void** aScriptObject, void** aClassObject)
|
2000-03-31 03:13:43 +00:00
|
|
|
{
|
2000-05-27 08:20:04 +00:00
|
|
|
*aClassObject = nsnull;
|
|
|
|
*aScriptObject = nsnull;
|
2000-03-31 10:27:12 +00:00
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
// Obtain the bound element's current script object.
|
|
|
|
nsCOMPtr<nsIScriptObjectOwner> owner(do_QueryInterface(mBoundElement));
|
|
|
|
owner->GetScriptObject(aContext, aScriptObject);
|
|
|
|
if (!(*aScriptObject))
|
|
|
|
return NS_ERROR_FAILURE;
|
2000-03-31 03:13:43 +00:00
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
JSObject* object = (JSObject*)(*aScriptObject);
|
2000-01-13 09:21:09 +00:00
|
|
|
|
2000-03-31 03:13:43 +00:00
|
|
|
// First ensure our JS class is initialized.
|
2000-05-27 08:20:04 +00:00
|
|
|
JSContext* jscontext = (JSContext*)aContext->GetNativeContext();
|
2000-07-01 02:36:18 +00:00
|
|
|
JSObject* global = ::JS_GetGlobalObject(jscontext);
|
2000-03-31 03:13:43 +00:00
|
|
|
jsval vp;
|
2000-07-01 02:36:18 +00:00
|
|
|
JSObject* proto;
|
2000-03-31 03:13:43 +00:00
|
|
|
|
2000-07-01 02:36:18 +00:00
|
|
|
if ((! ::JS_LookupProperty(jscontext, global, aClassName, &vp)) ||
|
|
|
|
JSVAL_IS_PRIMITIVE(vp)) {
|
2000-05-27 08:20:04 +00:00
|
|
|
// We need to initialize the class.
|
|
|
|
|
2000-07-01 02:36:18 +00:00
|
|
|
nsXBLJSClass* c;
|
2000-05-27 08:20:04 +00:00
|
|
|
void* classObject;
|
2000-08-10 06:19:37 +00:00
|
|
|
nsCStringKey key(aClassName);
|
2000-05-28 04:10:50 +00:00
|
|
|
classObject = (nsXBLService::gClassTable)->Get(&key);
|
2000-05-27 08:20:04 +00:00
|
|
|
|
2000-07-01 02:36:18 +00:00
|
|
|
if (classObject) {
|
|
|
|
c = NS_STATIC_CAST(nsXBLJSClass*, classObject);
|
|
|
|
|
|
|
|
// If c is on the LRU list (i.e., not linked to itself), remove it now!
|
|
|
|
JSCList* link = NS_STATIC_CAST(JSCList*, c);
|
|
|
|
if (c->next != link) {
|
|
|
|
JS_REMOVE_AND_INIT_LINK(link);
|
|
|
|
nsXBLService::gClassLRUListLength--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (JS_CLIST_IS_EMPTY(&nsXBLService::gClassLRUList)) {
|
|
|
|
// We need to create a struct for this class.
|
|
|
|
c = new nsXBLJSClass(aClassName);
|
|
|
|
if (!c)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
} else {
|
|
|
|
// Pull the least recently used class struct off the list.
|
|
|
|
JSCList* lru = (nsXBLService::gClassLRUList).next;
|
|
|
|
JS_REMOVE_AND_INIT_LINK(lru);
|
|
|
|
nsXBLService::gClassLRUListLength--;
|
|
|
|
|
|
|
|
// Remove any mapping from the old name to the class struct.
|
|
|
|
c = NS_STATIC_CAST(nsXBLJSClass*, lru);
|
2000-08-10 06:19:37 +00:00
|
|
|
nsCStringKey oldKey(c->name);
|
2000-07-01 02:36:18 +00:00
|
|
|
(nsXBLService::gClassTable)->Remove(&oldKey);
|
|
|
|
|
|
|
|
// Change the class name and we're done.
|
2000-08-19 17:07:46 +00:00
|
|
|
nsMemory::Free((void*) c->name);
|
2000-07-01 02:36:18 +00:00
|
|
|
c->name = nsXPIDLCString::Copy(aClassName);
|
|
|
|
}
|
2000-05-27 08:20:04 +00:00
|
|
|
|
|
|
|
// Add c to our table.
|
2000-05-28 04:10:50 +00:00
|
|
|
(nsXBLService::gClassTable)->Put(&key, (void*)c);
|
2000-05-27 08:20:04 +00:00
|
|
|
}
|
|
|
|
|
2000-07-01 02:36:18 +00:00
|
|
|
// Retrieve the current prototype of the JS object.
|
|
|
|
JSObject* parent_proto = ::JS_GetPrototype(jscontext, object);
|
|
|
|
|
|
|
|
// Make a new object prototyped by parent_proto and parented by global.
|
|
|
|
proto = ::JS_InitClass(jscontext, // context
|
|
|
|
global, // global object
|
|
|
|
parent_proto, // parent proto
|
|
|
|
c, // JSClass
|
|
|
|
NULL, // JSNative ctor
|
|
|
|
0, // ctor args
|
|
|
|
nsnull, // proto props
|
|
|
|
nsnull, // proto funcs
|
|
|
|
nsnull, // ctor props (static)
|
|
|
|
nsnull); // ctor funcs (static)
|
|
|
|
if (!proto) {
|
|
|
|
(nsXBLService::gClassTable)->Remove(&key);
|
|
|
|
delete c;
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2000-03-31 03:13:43 +00:00
|
|
|
}
|
|
|
|
|
2000-07-01 02:36:18 +00:00
|
|
|
// The prototype holds a strong reference to its class struct.
|
|
|
|
c->Hold();
|
2000-05-27 08:20:04 +00:00
|
|
|
*aClassObject = (void*)proto;
|
2000-03-31 03:13:43 +00:00
|
|
|
}
|
|
|
|
else {
|
2000-07-01 02:36:18 +00:00
|
|
|
proto = JSVAL_TO_OBJECT(vp);
|
2000-03-31 03:13:43 +00:00
|
|
|
}
|
|
|
|
|
2000-05-27 08:20:04 +00:00
|
|
|
// Set the prototype of our object to be the new class.
|
2000-07-01 02:36:18 +00:00
|
|
|
::JS_SetPrototype(jscontext, object, proto);
|
2000-03-31 03:13:43 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
void
|
|
|
|
nsXBLBinding::GetImmediateChild(nsIAtom* aTag, nsIContent** aResult)
|
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
nsCOMPtr<nsIContent> binding;
|
|
|
|
mPrototypeBinding->GetBindingElement(getter_AddRefs(binding));
|
|
|
|
|
2000-01-13 09:43:42 +00:00
|
|
|
*aResult = nsnull;
|
|
|
|
PRInt32 childCount;
|
2000-09-27 20:23:49 +00:00
|
|
|
binding->ChildCount(childCount);
|
2000-01-13 09:43:42 +00:00
|
|
|
for (PRInt32 i = 0; i < childCount; i++) {
|
|
|
|
nsCOMPtr<nsIContent> child;
|
2000-09-27 20:23:49 +00:00
|
|
|
binding->ChildAt(i, *getter_AddRefs(child));
|
2000-01-13 09:43:42 +00:00
|
|
|
nsCOMPtr<nsIAtom> tag;
|
|
|
|
child->GetTag(*getter_AddRefs(tag));
|
|
|
|
if (aTag == tag.get()) {
|
|
|
|
*aResult = child;
|
|
|
|
NS_ADDREF(*aResult);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2000-01-13 09:21:09 +00:00
|
|
|
|
2000-01-13 09:43:42 +00:00
|
|
|
return;
|
2000-01-13 09:21:09 +00:00
|
|
|
}
|
2000-01-13 09:43:42 +00:00
|
|
|
|
2000-01-13 09:21:09 +00:00
|
|
|
PRBool
|
2000-01-13 09:43:42 +00:00
|
|
|
nsXBLBinding::IsInExcludesList(nsIAtom* aTag, const nsString& aList)
|
2000-01-13 09:21:09 +00:00
|
|
|
{
|
2000-01-13 09:43:42 +00:00
|
|
|
nsAutoString element;
|
|
|
|
aTag->ToString(element);
|
|
|
|
|
2000-08-30 02:45:02 +00:00
|
|
|
if (aList == NS_LITERAL_STRING("*"))
|
2000-01-13 09:43:42 +00:00
|
|
|
return PR_TRUE; // match _everything_!
|
|
|
|
|
|
|
|
PRInt32 indx = aList.Find(element);
|
|
|
|
if (indx == -1)
|
|
|
|
return PR_FALSE; // not in the list at all
|
|
|
|
|
|
|
|
// okay, now make sure it's not a substring snafu; e.g., 'ur'
|
|
|
|
// found inside of 'blur'.
|
|
|
|
if (indx > 0) {
|
|
|
|
PRUnichar ch = aList[indx - 1];
|
2000-09-15 06:38:35 +00:00
|
|
|
if (! nsCRT::IsAsciiSpace(ch) && ch != PRUnichar('|'))
|
2000-01-13 09:43:42 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (indx + element.Length() < aList.Length()) {
|
|
|
|
PRUnichar ch = aList[indx + element.Length()];
|
2000-09-15 06:38:35 +00:00
|
|
|
if (! nsCRT::IsAsciiSpace(ch) && ch != PRUnichar('|'))
|
2000-01-13 09:43:42 +00:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
2000-01-13 09:21:09 +00:00
|
|
|
}
|
|
|
|
|
2000-01-26 11:43:31 +00:00
|
|
|
void
|
|
|
|
nsXBLBinding::GetEventHandlerIID(nsIAtom* aName, nsIID* aIID, PRBool* aFound)
|
|
|
|
{
|
|
|
|
*aFound = PR_FALSE;
|
|
|
|
|
|
|
|
EventHandlerMapEntry* entry = kEventHandlerMap;
|
|
|
|
while (entry->mAttributeAtom) {
|
|
|
|
if (entry->mAttributeAtom == aName) {
|
|
|
|
*aIID = *entry->mHandlerIID;
|
|
|
|
*aFound = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++entry;
|
|
|
|
}
|
|
|
|
}
|
2000-09-20 07:16:04 +00:00
|
|
|
|
2000-03-23 22:19:49 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::AddScriptEventListener(nsIContent* aElement, nsIAtom* aName, const nsString& aValue, REFNSIID aIID)
|
|
|
|
{
|
|
|
|
nsAutoString val;
|
|
|
|
aName->ToString(val);
|
|
|
|
|
2000-04-16 11:19:26 +00:00
|
|
|
nsAutoString eventStr; eventStr.AssignWithConversion("on");
|
2000-03-23 22:19:49 +00:00
|
|
|
eventStr += val;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> eventName = getter_AddRefs(NS_NewAtom(eventStr));
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIDocument> document;
|
|
|
|
aElement->GetDocument(*getter_AddRefs(document));
|
|
|
|
if (!document)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEventReceiver> receiver(do_QueryInterface(aElement));
|
|
|
|
if (!receiver)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> global;
|
|
|
|
document->GetScriptGlobalObject(getter_AddRefs(global));
|
|
|
|
|
|
|
|
// This can happen normally as part of teardown code.
|
|
|
|
if (!global)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIScriptContext> context;
|
|
|
|
rv = global->GetContext(getter_AddRefs(context));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIEventListenerManager> manager;
|
|
|
|
rv = receiver->GetListenerManager(getter_AddRefs(manager));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIScriptObjectOwner> scriptOwner(do_QueryInterface(receiver));
|
|
|
|
if (!scriptOwner)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
rv = manager->AddScriptEventListener(context, scriptOwner, eventName, aValue, aIID, PR_FALSE);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2000-04-30 06:41:41 +00:00
|
|
|
nsresult
|
|
|
|
nsXBLBinding::GetTextData(nsIContent *aParent, nsString& aResult)
|
|
|
|
{
|
|
|
|
aResult.Truncate(0);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> textChild;
|
|
|
|
PRInt32 textCount;
|
|
|
|
aParent->ChildCount(textCount);
|
|
|
|
nsAutoString answer;
|
|
|
|
for (PRInt32 j = 0; j < textCount; j++) {
|
|
|
|
// Get the child.
|
|
|
|
aParent->ChildAt(j, *getter_AddRefs(textChild));
|
|
|
|
nsCOMPtr<nsIDOMText> text(do_QueryInterface(textChild));
|
|
|
|
if (text) {
|
|
|
|
nsAutoString data;
|
|
|
|
text->GetData(data);
|
|
|
|
aResult += data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-05-19 04:48:43 +00:00
|
|
|
PRBool
|
|
|
|
nsXBLBinding::AllowScripts()
|
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
PRBool result;
|
|
|
|
mPrototypeBinding->GetAllowScripts(&result);
|
|
|
|
return result;
|
2000-05-19 04:48:43 +00:00
|
|
|
}
|
|
|
|
|
2000-05-22 08:23:09 +00:00
|
|
|
NS_IMETHODIMP
|
2001-02-02 00:54:47 +00:00
|
|
|
nsXBLBinding::GetInsertionPointsFor(nsIContent* aParent, nsISupportsArray** aResult)
|
|
|
|
{
|
|
|
|
if (!mInsertionPointTable)
|
|
|
|
mInsertionPointTable = new nsSupportsHashtable(4);
|
|
|
|
|
|
|
|
nsISupportsKey key(aParent);
|
|
|
|
*aResult = NS_STATIC_CAST(nsISupportsArray*, mInsertionPointTable->Get(&key));
|
|
|
|
|
|
|
|
if (!*aResult) {
|
|
|
|
NS_NewISupportsArray(aResult);
|
|
|
|
mInsertionPointTable->Put(&key, *aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::GetInsertionPoint(nsIContent* aChild, nsIContent** aResult, PRUint32* aIndex)
|
2000-05-22 08:23:09 +00:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
2000-12-10 09:23:43 +00:00
|
|
|
if (mContent)
|
2001-02-02 00:54:47 +00:00
|
|
|
return mPrototypeBinding->GetInsertionPoint(mBoundElement, mContent, aChild, aResult, aIndex);
|
2000-12-10 09:23:43 +00:00
|
|
|
else if (mNextBinding)
|
2001-02-02 00:54:47 +00:00
|
|
|
return mNextBinding->GetInsertionPoint(aChild, aResult, aIndex);
|
2000-12-10 09:23:43 +00:00
|
|
|
return NS_OK;
|
2000-05-22 08:23:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2001-02-02 00:54:47 +00:00
|
|
|
nsXBLBinding::GetSingleInsertionPoint(nsIContent** aResult, PRUint32* aIndex, PRBool* aMultipleInsertionPoints)
|
2000-05-22 08:23:09 +00:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
*aMultipleInsertionPoints = PR_FALSE;
|
2000-12-10 09:23:43 +00:00
|
|
|
if (mContent)
|
2001-02-02 00:54:47 +00:00
|
|
|
return mPrototypeBinding->GetSingleInsertionPoint(mBoundElement, mContent, aResult, aIndex, aMultipleInsertionPoints);
|
2000-12-10 09:23:43 +00:00
|
|
|
else if (mNextBinding)
|
2001-02-02 00:54:47 +00:00
|
|
|
return mNextBinding->GetSingleInsertionPoint(aResult, aIndex, aMultipleInsertionPoints);
|
2000-12-10 09:23:43 +00:00
|
|
|
return NS_OK;
|
2000-05-22 08:23:09 +00:00
|
|
|
}
|
|
|
|
|
2000-06-02 08:13:29 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2000-08-14 04:04:18 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::MarkForDeath()
|
|
|
|
{
|
|
|
|
mMarkedForDeath = PR_TRUE;
|
2000-09-27 20:23:49 +00:00
|
|
|
ExecuteDetachedHandler();
|
2000-08-14 04:04:18 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-06-02 08:13:29 +00:00
|
|
|
|
2000-08-14 04:04:18 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::MarkedForDeath(PRBool* aResult)
|
|
|
|
{
|
|
|
|
*aResult = mMarkedForDeath;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-06-02 08:13:29 +00:00
|
|
|
|
2000-12-07 10:11:21 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::ImplementsInterface(REFNSIID aIID, PRBool* aResult)
|
|
|
|
{
|
|
|
|
mPrototypeBinding->ImplementsInterface(aIID, aResult);
|
|
|
|
if (!*aResult && mNextBinding)
|
|
|
|
return mNextBinding->ImplementsInterface(aIID, aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-12-10 09:23:43 +00:00
|
|
|
NS_IMETHODIMP
|
2001-02-02 00:54:47 +00:00
|
|
|
nsXBLBinding::GetAnonymousNodes(nsIDOMNodeList** aResult)
|
2000-12-10 09:23:43 +00:00
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
if (mContent) {
|
|
|
|
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(mContent));
|
|
|
|
return elt->GetChildNodes(aResult);
|
|
|
|
}
|
|
|
|
else if (mNextBinding)
|
2001-02-02 00:54:47 +00:00
|
|
|
return mNextBinding->GetAnonymousNodes(aResult);
|
2000-12-10 09:23:43 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-12-07 10:11:21 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsXBLBinding::ShouldBuildChildFrames(PRBool* aResult)
|
|
|
|
{
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
if (mContent)
|
|
|
|
return mPrototypeBinding->ShouldBuildChildFrames(aResult);
|
|
|
|
else if (mNextBinding)
|
|
|
|
return mNextBinding->ShouldBuildChildFrames(aResult);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-01-13 02:23:54 +00:00
|
|
|
// Creation Routine ///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
nsresult
|
2000-09-27 20:23:49 +00:00
|
|
|
NS_NewXBLBinding(nsIXBLPrototypeBinding* aBinding, nsIXBLBinding** aResult)
|
2000-01-13 02:23:54 +00:00
|
|
|
{
|
2000-09-27 20:23:49 +00:00
|
|
|
*aResult = new nsXBLBinding(aBinding);
|
2000-01-13 02:23:54 +00:00
|
|
|
if (!*aResult)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
2000-01-13 23:07:43 +00:00
|
|
|
}
|