EventListenerManager::Listener* EventListenerManager::SetEventHandlerInternal( JS::Handle<JSObject*> aScopeObject, nsIAtom* aName, const nsAString& aTypeString, const nsEventHandler& aHandler, bool aPermitUntrustedEvents) { MOZ_ASSERT(aScopeObject || aHandler.HasEventHandler(), "Must have one or the other!"); MOZ_ASSERT(aName || !aTypeString.IsEmpty()); uint32_t eventType = nsContentUtils::GetEventId(aName); Listener* listener = FindEventHandler(eventType, aName, aTypeString); if (!listener) { // If we didn't find a script listener or no listeners existed // create and add a new one. EventListenerFlags flags; flags.mListenerIsJSListener = true; nsCOMPtr<nsIJSEventListener> jsListener; NS_NewJSEventListener(aScopeObject, mTarget, aName, aHandler, getter_AddRefs(jsListener)); EventListenerHolder listenerHolder(jsListener); AddEventListenerInternal(listenerHolder, eventType, aName, aTypeString, flags, true); listener = FindEventHandler(eventType, aName, aTypeString); } else { nsIJSEventListener* jsListener = listener->GetJSListener(); MOZ_ASSERT(jsListener, "How can we have an event handler with no nsIJSEventListener?"); bool same = jsListener->GetHandler() == aHandler; // Possibly the same listener, but update still the context and scope. jsListener->SetHandler(aHandler, aScopeObject); if (mTarget && !same && aName) { mTarget->EventListenerRemoved(aName); mTarget->EventListenerAdded(aName); } } // Set flag to indicate possible need for compilation later listener->mHandlerIsString = !aHandler.HasEventHandler(); if (aPermitUntrustedEvents) { listener->mFlags.mAllowUntrustedEvents = true; } return listener; }
nsresult nsXBLPrototypeHandler::ExecuteHandler(nsPIDOMEventTarget* aTarget, nsIDOMEvent* aEvent) { nsresult rv = NS_ERROR_FAILURE; // Prevent default action? if (mType & NS_HANDLER_TYPE_PREVENTDEFAULT) { aEvent->PreventDefault(); // If we prevent default, then it's okay for // mHandlerElement and mHandlerText to be null rv = NS_OK; } if (!mHandlerElement) // This works for both types of handlers. In both cases, the union's var should be defined. return rv; // See if our event receiver is a content node (and not us). PRBool isXULKey = !!(mType & NS_HANDLER_TYPE_XUL); PRBool isXBLCommand = !!(mType & NS_HANDLER_TYPE_XBL_COMMAND); NS_ASSERTION(!(isXULKey && isXBLCommand), "can't be both a key and xbl command handler"); // XUL handlers and commands shouldn't be triggered by non-trusted // events. if (isXULKey || isXBLCommand) { nsCOMPtr<nsIDOMNSEvent> domNSEvent = do_QueryInterface(aEvent); PRBool trustedEvent = PR_FALSE; if (domNSEvent) { domNSEvent->GetIsTrusted(&trustedEvent); } if (!trustedEvent) return NS_OK; } if (isXBLCommand) { return DispatchXBLCommand(aTarget, aEvent); } // If we're executing on a XUL key element, just dispatch a command // event at the element. It will take care of retargeting it to its // command element, if applicable, and executing the event handler. if (isXULKey) { return DispatchXULKeyCommand(aEvent); } // Look for a compiled handler on the element. // Should be compiled and bound with "on" in front of the name. nsAutoString onEvent(NS_LITERAL_STRING("onxbl")); nsAutoString str; mEventName->ToString(str); onEvent += str; nsCOMPtr<nsIAtom> onEventAtom = do_GetAtom(onEvent); // Compile the event handler. PRUint32 stID = nsIProgrammingLanguage::JAVASCRIPT; // Compile the handler and bind it to the element. nsCOMPtr<nsIScriptGlobalObject> boundGlobal; nsCOMPtr<nsPIWindowRoot> winRoot(do_QueryInterface(aTarget)); nsCOMPtr<nsIDOMWindow> window; if (winRoot) { window = winRoot->GetWindow(); } if (window) { nsCOMPtr<nsPIDOMWindow> piWin(do_QueryInterface(window)); if (piWin) { piWin = piWin->GetCurrentInnerWindow(); NS_ENSURE_TRUE(piWin, NS_ERROR_UNEXPECTED); } boundGlobal = do_QueryInterface(piWin->GetPrivateRoot()); } else boundGlobal = do_QueryInterface(aTarget); if (!boundGlobal) { nsCOMPtr<nsIDocument> boundDocument(do_QueryInterface(aTarget)); if (!boundDocument) { // We must be an element. nsCOMPtr<nsIContent> content(do_QueryInterface(aTarget)); if (!content) return NS_OK; boundDocument = content->GetOwnerDoc(); if (!boundDocument) return NS_OK; } boundGlobal = boundDocument->GetScopeObject(); } if (!boundGlobal) return NS_OK; nsIScriptContext *boundContext = boundGlobal->GetScriptContext(stID); if (!boundContext) return NS_OK; nsScriptObjectHolder handler(boundContext); nsISupports *scriptTarget; if (winRoot) { scriptTarget = boundGlobal; } else { scriptTarget = aTarget; } rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, handler); NS_ENSURE_SUCCESS(rv, rv); // Temporarily bind it to the bound element void *scope = boundGlobal->GetScriptGlobal(stID); rv = boundContext->BindCompiledEventHandler(scriptTarget, scope, onEventAtom, handler); NS_ENSURE_SUCCESS(rv, rv); // Execute it. nsCOMPtr<nsIDOMEventListener> eventListener; NS_NewJSEventListener(boundContext, scope, scriptTarget, getter_AddRefs(eventListener)); nsCOMPtr<nsIJSEventListener> jsListener(do_QueryInterface(eventListener)); jsListener->SetEventName(onEventAtom); // Handle the event. eventListener->HandleEvent(aEvent); return NS_OK; }