Bug 359675 - provide an option to manually fill forms and log in. p=poshannessy@mozil...
[wine-gecko.git] / content / events / src / nsXMLEventsManager.cpp
blob6f2340b50533f0899967959123e94df5c97a4492
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Olli Pettay.
19 * Portions created by the Initial Developer are Copyright (C) 2004
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Olli Pettay <Olli.Pettay@helsinki.fi> (original author)
25 * Alternatively, the contents of this file may be used under the terms of
26 * either of the GNU General Public License Version 2 or later (the "GPL"),
27 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsIDOMMutationEvent.h"
40 #include "nsXMLEventsManager.h"
41 #include "nsGkAtoms.h"
42 #include "nsIDOMElement.h"
43 #include "nsIDOMDocument.h"
44 #include "nsIDOMEventTarget.h"
45 #include "nsNetUtil.h"
46 #include "nsIURL.h"
47 #include "nsIDOMEventListener.h"
48 #include "nsINameSpaceManager.h"
49 #include "nsINodeInfo.h"
51 PRBool nsXMLEventsListener::InitXMLEventsListener(nsIDocument * aDocument,
52 nsXMLEventsManager * aManager,
53 nsIContent * aContent)
55 nsresult rv;
56 PRInt32 nameSpaceID;
57 if (aContent->GetDocument() != aDocument)
58 return PR_FALSE;
59 if (aContent->NodeInfo()->Equals(nsGkAtoms::listener,
60 kNameSpaceID_XMLEvents))
61 nameSpaceID = kNameSpaceID_None;
62 else
63 nameSpaceID = kNameSpaceID_XMLEvents;
64 nsAutoString eventType;
65 aContent->GetAttr(nameSpaceID, nsGkAtoms::event, eventType);
66 if (eventType.IsEmpty())
67 return PR_FALSE;
68 nsAutoString handlerURIStr;
69 PRBool hasHandlerURI = PR_FALSE;
70 nsCOMPtr<nsIContent> handler;
71 nsAutoString observerID;
72 nsAutoString targetIdref;
74 if (aContent->GetAttr(nameSpaceID, nsGkAtoms::handler, handlerURIStr)) {
75 hasHandlerURI = PR_TRUE;
76 nsCAutoString handlerRef;
77 nsCOMPtr<nsIURI> handlerURI;
78 PRBool equals = PR_FALSE;
79 nsIURI *docURI = aDocument->GetDocumentURI();
80 nsIURI *baseURI = aDocument->GetBaseURI();
81 rv = NS_NewURI( getter_AddRefs(handlerURI), handlerURIStr, nsnull, baseURI);
82 if (NS_SUCCEEDED(rv)) {
83 nsCOMPtr<nsIURL> handlerURL(do_QueryInterface(handlerURI));
84 if (handlerURL) {
85 handlerURL->GetRef(handlerRef);
86 handlerURL->SetRef(EmptyCString());
87 //We support only XML Events Basic.
88 docURI->Equals(handlerURL, &equals);
89 if (equals) {
90 nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(aDocument));
91 if (doc) {
92 nsCOMPtr<nsIDOMElement> domhandler;
93 doc->GetElementById(NS_ConvertUTF8toUTF16(handlerRef),
94 getter_AddRefs(domhandler));
95 handler = do_QueryInterface(domhandler);
101 else
102 handler = aContent;
103 if (!handler)
104 return PR_FALSE;
106 aContent->GetAttr(nameSpaceID, nsGkAtoms::target, targetIdref);
108 PRBool hasObserver =
109 aContent->GetAttr(nameSpaceID, nsGkAtoms::observer, observerID);
111 PRBool capture =
112 aContent->AttrValueIs(nameSpaceID, nsGkAtoms::phase,
113 nsGkAtoms::capture, eCaseMatters);
115 PRBool stopPropagation =
116 aContent->AttrValueIs(nameSpaceID, nsGkAtoms::propagate,
117 nsGkAtoms::stop, eCaseMatters);
119 PRBool cancelDefault =
120 aContent->AttrValueIs(nameSpaceID, nsGkAtoms::defaultAction,
121 nsGkAtoms::cancel, eCaseMatters);
123 nsCOMPtr<nsIContent> observer;
124 if (!hasObserver) {
125 if (!hasHandlerURI) //Parent should be the observer
126 observer = aContent->GetParent();
127 else //We have the handler, so this is the observer
128 observer = aContent;
130 else if (!observerID.IsEmpty()) {
131 nsCOMPtr<nsIDOMDocument> doc(do_QueryInterface(aDocument));
132 if (doc) {
133 nsCOMPtr<nsIDOMElement> el;
134 doc->GetElementById(observerID, getter_AddRefs(el));
135 observer = do_QueryInterface(el);
138 nsCOMPtr<nsIDOMEventTarget> eventObserver;
139 if (observer)
140 eventObserver = do_QueryInterface(observer);
141 if (eventObserver) {
142 nsXMLEventsListener * eli = new nsXMLEventsListener(aManager,
143 aContent,
144 observer,
145 handler,
146 eventType,
147 capture,
148 stopPropagation,
149 cancelDefault,
150 targetIdref);
151 if (eli) {
152 nsresult rv = eventObserver->AddEventListener(eventType, eli, capture);
153 if (NS_SUCCEEDED(rv)) {
154 aManager->RemoveXMLEventsContent(aContent);
155 aManager->RemoveListener(aContent);
156 aManager->AddListener(aContent, eli);
157 return PR_TRUE;
159 else
160 delete eli;
163 return PR_FALSE;
166 nsXMLEventsListener::nsXMLEventsListener(nsXMLEventsManager * aManager,
167 nsIContent * aElement,
168 nsIContent * aObserver,
169 nsIContent * aHandler,
170 const nsAString& aEvent,
171 PRBool aPhase,
172 PRBool aStopPropagation,
173 PRBool aCancelDefault,
174 const nsAString& aTarget)
175 : mManager(aManager),
176 mElement(aElement),
177 mObserver(aObserver),
178 mHandler(aHandler),
179 mEvent(aEvent),
180 mPhase(aPhase),
181 mStopPropagation(aStopPropagation),
182 mCancelDefault(aCancelDefault)
184 if (!aTarget.IsEmpty())
185 mTarget = do_GetAtom(aTarget);
188 nsXMLEventsListener::~nsXMLEventsListener()
192 void nsXMLEventsListener::Unregister()
194 nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mObserver);
195 if (target) {
196 target->RemoveEventListener(mEvent, this, mPhase);
198 mObserver = nsnull;
199 mHandler = nsnull;
202 void nsXMLEventsListener::SetIncomplete()
204 Unregister();
205 mManager->AddXMLEventsContent(mElement);
206 mElement = nsnull;
209 PRBool nsXMLEventsListener::ObserverEquals(nsIContent * aTarget)
211 return aTarget == mObserver;
214 PRBool nsXMLEventsListener::HandlerEquals(nsIContent * aTarget)
216 return aTarget == mHandler;
219 NS_IMPL_ISUPPORTS1(nsXMLEventsListener, nsIDOMEventListener)
220 NS_IMETHODIMP
221 nsXMLEventsListener::HandleEvent(nsIDOMEvent* aEvent)
223 if (!aEvent)
224 return NS_ERROR_INVALID_ARG;
225 PRBool targetMatched = PR_TRUE;
226 nsCOMPtr<nsIDOMEvent> event(aEvent);
227 if (mTarget) {
228 targetMatched = PR_FALSE;
229 nsCOMPtr<nsIDOMEventTarget> target;
230 aEvent->GetTarget(getter_AddRefs(target));
231 nsCOMPtr<nsIContent> targetEl(do_QueryInterface(target));
232 if (targetEl && targetEl->GetID() == mTarget)
233 targetMatched = PR_TRUE;
235 if (!targetMatched)
236 return NS_OK;
237 nsCOMPtr<nsIDOMEventListener> handler(do_QueryInterface(mHandler));
238 if (handler) {
239 nsresult rv = handler->HandleEvent(event);
240 if (NS_SUCCEEDED(rv)) {
241 if (mStopPropagation)
242 event->StopPropagation();
243 if (mCancelDefault)
244 event->PreventDefault();
246 return rv;
248 return NS_OK;
252 //XMLEventsManager / DocumentObserver
254 PR_STATIC_CALLBACK(PLDHashOperator) EnumAndUnregisterListener(nsISupports * aContent,
255 nsCOMPtr<nsXMLEventsListener> & aListener,
256 void * aData)
258 if (aListener)
259 aListener->Unregister();
260 return PL_DHASH_NEXT;
263 PR_STATIC_CALLBACK(PLDHashOperator) EnumAndSetIncomplete(nsISupports * aContent,
264 nsCOMPtr<nsXMLEventsListener> & aListener,
265 void * aData)
267 if (aListener && aData) {
268 nsCOMPtr<nsIContent> content = static_cast<nsIContent *>(aData);
269 if (content) {
270 if (aListener->ObserverEquals(content) || aListener->HandlerEquals(content)) {
271 aListener->SetIncomplete();
272 return PL_DHASH_REMOVE;
276 return PL_DHASH_NEXT;
279 nsXMLEventsManager::nsXMLEventsManager()
281 mListeners.Init();
283 nsXMLEventsManager::~nsXMLEventsManager()
287 NS_IMPL_ISUPPORTS2(nsXMLEventsManager, nsIDocumentObserver, nsIMutationObserver)
289 void nsXMLEventsManager::AddXMLEventsContent(nsIContent * aContent)
291 mIncomplete.RemoveObject(aContent);
292 mIncomplete.AppendObject(aContent);
295 void nsXMLEventsManager::RemoveXMLEventsContent(nsIContent * aContent)
297 mIncomplete.RemoveObject(aContent);
300 void nsXMLEventsManager::AddListener(nsIContent * aContent,
301 nsXMLEventsListener * aListener)
303 mListeners.Put(aContent, aListener);
306 PRBool nsXMLEventsManager::RemoveListener(nsIContent * aContent)
308 nsCOMPtr<nsXMLEventsListener> listener;
309 mListeners.Get(aContent, getter_AddRefs(listener));
310 if (listener) {
311 listener->Unregister();
312 mListeners.Remove(aContent);
313 return PR_TRUE;
315 return PR_FALSE;
318 void nsXMLEventsManager::AddListeners(nsIDocument* aDocument)
320 nsIContent *cur;
321 for (int i = 0; i < mIncomplete.Count(); ++i) {
322 cur = mIncomplete[i];
323 //If this succeeds, the object will be removed from mIncomplete
324 if (nsXMLEventsListener::InitXMLEventsListener(aDocument, this, cur) == PR_TRUE)
325 --i;
329 void
330 nsXMLEventsManager::BeginUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType) {}
331 void
332 nsXMLEventsManager::EndUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType) {}
333 void
334 nsXMLEventsManager::NodeWillBeDestroyed(const nsINode* aNode)
336 mIncomplete.Clear();
337 mListeners.Enumerate(EnumAndUnregisterListener, this);
338 mListeners.Clear();
341 void
342 nsXMLEventsManager::BeginLoad(nsIDocument* aDocument) {}
344 void
345 nsXMLEventsManager::EndLoad(nsIDocument* aDocument)
347 AddListeners(aDocument);
349 NS_IMPL_NSIDOCUMENTOBSERVER_STATE_STUB(nsXMLEventsManager)
350 void
351 nsXMLEventsManager::CharacterDataWillChange(nsIDocument* aDocument,
352 nsIContent* aContent,
353 CharacterDataChangeInfo* aInfo) {}
354 void
355 nsXMLEventsManager::CharacterDataChanged(nsIDocument* aDocument,
356 nsIContent* aContent,
357 CharacterDataChangeInfo* aInfo) {}
358 void
359 nsXMLEventsManager::AttributeChanged(nsIDocument* aDocument,
360 nsIContent* aContent,
361 PRInt32 aNameSpaceID,
362 nsIAtom* aAttribute,
363 PRInt32 aModType,
364 PRUint32 aStateMask)
366 if (aNameSpaceID == kNameSpaceID_XMLEvents &&
367 (aAttribute == nsGkAtoms::event ||
368 aAttribute == nsGkAtoms::handler ||
369 aAttribute == nsGkAtoms::target ||
370 aAttribute == nsGkAtoms::observer ||
371 aAttribute == nsGkAtoms::phase ||
372 aAttribute == nsGkAtoms::propagate)) {
373 RemoveListener(aContent);
374 AddXMLEventsContent(aContent);
375 nsXMLEventsListener::InitXMLEventsListener(aDocument, this, aContent);
377 else {
378 if (aContent->NodeInfo()->Equals(nsGkAtoms::listener,
379 kNameSpaceID_XMLEvents)) {
380 RemoveListener(aContent);
381 AddXMLEventsContent(aContent);
382 nsXMLEventsListener::InitXMLEventsListener(aDocument, this, aContent);
384 else if (aContent->GetIDAttributeName() == aAttribute) {
385 if (aModType == nsIDOMMutationEvent::REMOVAL)
386 mListeners.Enumerate(EnumAndSetIncomplete, aContent);
387 else if (aModType == nsIDOMMutationEvent::MODIFICATION) {
388 //Remove possible listener
389 mListeners.Enumerate(EnumAndSetIncomplete, aContent);
390 //Add new listeners
391 AddListeners(aDocument);
393 else {
394 //If we are adding the ID attribute, we must check whether we can
395 //add new listeners
396 AddListeners(aDocument);
402 void
403 nsXMLEventsManager::ContentAppended(nsIDocument* aDocument,
404 nsIContent* aContainer,
405 PRInt32 aNewIndexInContainer)
407 AddListeners(aDocument);
410 void
411 nsXMLEventsManager::ContentInserted(nsIDocument* aDocument,
412 nsIContent* aContainer,
413 nsIContent* aChild,
414 PRInt32 aIndexInContainer)
416 AddListeners(aDocument);
419 void
420 nsXMLEventsManager::ContentRemoved(nsIDocument* aDocument,
421 nsIContent* aContainer,
422 nsIContent* aChild,
423 PRInt32 aIndexInContainer)
425 if (!aChild || !aChild->IsNodeOfType(nsINode::eELEMENT))
426 return;
427 //Note, we can't use IDs here, the observer may not always have an ID.
428 //And to remember: the same observer can be referenced by many
429 //XMLEventsListeners
431 //If the content was an XML Events observer or handler
432 mListeners.Enumerate(EnumAndSetIncomplete, aChild);
434 //If the content was an XML Events attributes container
435 if (RemoveListener(aChild)) {
436 //for aContainer.appendChild(aContainer.removeChild(aChild));
437 AddXMLEventsContent(aChild);
440 PRUint32 count = aChild->GetChildCount();
441 for (PRUint32 i = 0; i < count; ++i) {
442 ContentRemoved(aDocument, aChild, aChild->GetChildAt(i), i);
446 void
447 nsXMLEventsManager::ParentChainChanged(nsIContent *aContent)
451 NS_IMPL_NSIDOCUMENTOBSERVER_STYLE_STUB(nsXMLEventsManager)