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
4 : *
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/
9 : *
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.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Joe Hewitt <hewitt@netscape.com> (Original Author)
24 : * Dean Tessman <dean_tessman@hotmail.com>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "nsFormFillController.h"
41 :
42 : #include "nsIFormAutoComplete.h"
43 : #include "nsIInputListAutoComplete.h"
44 : #include "nsIAutoCompleteSimpleResult.h"
45 : #include "nsString.h"
46 : #include "nsReadableUtils.h"
47 : #include "nsIServiceManager.h"
48 : #include "nsIInterfaceRequestor.h"
49 : #include "nsIInterfaceRequestorUtils.h"
50 : #include "nsIDocShellTreeItem.h"
51 : #include "nsPIDOMWindow.h"
52 : #include "nsIWebNavigation.h"
53 : #include "nsIContentViewer.h"
54 : #include "nsIDOMEventTarget.h"
55 : #include "nsIDOMKeyEvent.h"
56 : #include "nsIPrivateDOMEvent.h"
57 : #include "nsIDOMDocument.h"
58 : #include "nsIDOMElement.h"
59 : #include "nsIFormControl.h"
60 : #include "nsIDocument.h"
61 : #include "nsIContent.h"
62 : #include "nsIPresShell.h"
63 : #include "nsIFrame.h"
64 : #include "nsRect.h"
65 : #include "nsIDOMHTMLFormElement.h"
66 : #include "nsILoginManager.h"
67 : #include "nsIDOMMouseEvent.h"
68 : #include "mozilla/ModuleUtils.h"
69 : #include "nsToolkitCompsCID.h"
70 : #include "nsEmbedCID.h"
71 : #include "nsIDOMNSEditableElement.h"
72 : #include "nsIDOMNSEvent.h"
73 : #include "mozilla/dom/Element.h"
74 : #include "nsContentUtils.h"
75 :
76 0 : NS_IMPL_ISUPPORTS5(nsFormFillController,
77 : nsIFormFillController,
78 : nsIAutoCompleteInput,
79 : nsIAutoCompleteSearch,
80 : nsIDOMEventListener,
81 : nsIMutationObserver)
82 :
83 0 : nsFormFillController::nsFormFillController() :
84 : mFocusedInput(nsnull),
85 : mFocusedInputNode(nsnull),
86 : mListNode(nsnull),
87 : mTimeout(50),
88 : mMinResultsForPopup(1),
89 : mMaxRows(0),
90 : mDisableAutoComplete(false),
91 : mCompleteDefaultIndex(false),
92 : mCompleteSelectedIndex(false),
93 : mForceComplete(false),
94 0 : mSuppressOnInput(false)
95 : {
96 0 : mController = do_GetService("@mozilla.org/autocomplete/controller;1");
97 0 : mDocShells = do_CreateInstance("@mozilla.org/supports-array;1");
98 0 : mPopups = do_CreateInstance("@mozilla.org/supports-array;1");
99 0 : mPwmgrInputs.Init();
100 0 : }
101 :
102 : struct PwmgrInputsEnumData
103 0 : {
104 0 : PwmgrInputsEnumData(nsFormFillController* aFFC, nsIDocument* aDoc)
105 0 : : mFFC(aFFC), mDoc(aDoc) {}
106 :
107 : nsFormFillController* mFFC;
108 : nsCOMPtr<nsIDocument> mDoc;
109 : };
110 :
111 0 : nsFormFillController::~nsFormFillController()
112 : {
113 0 : if (mListNode) {
114 0 : mListNode->RemoveMutationObserver(this);
115 0 : mListNode = nsnull;
116 : }
117 0 : if (mFocusedInputNode) {
118 0 : MaybeRemoveMutationObserver(mFocusedInputNode);
119 0 : mFocusedInputNode = nsnull;
120 0 : mFocusedInput = nsnull;
121 : }
122 0 : PwmgrInputsEnumData ed(this, nsnull);
123 0 : mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
124 :
125 : // Remove ourselves as a focus listener from all cached docShells
126 : PRUint32 count;
127 0 : mDocShells->Count(&count);
128 0 : for (PRUint32 i = 0; i < count; ++i) {
129 0 : nsCOMPtr<nsIDocShell> docShell;
130 0 : mDocShells->GetElementAt(i, getter_AddRefs(docShell));
131 0 : nsCOMPtr<nsIDOMWindow> domWindow = GetWindowForDocShell(docShell);
132 0 : RemoveWindowListeners(domWindow);
133 : }
134 0 : }
135 :
136 : ////////////////////////////////////////////////////////////////////////
137 : //// nsIMutationObserver
138 : //
139 :
140 : void
141 0 : nsFormFillController::AttributeChanged(nsIDocument* aDocument,
142 : mozilla::dom::Element* aElement,
143 : PRInt32 aNameSpaceID,
144 : nsIAtom* aAttribute, PRInt32 aModType)
145 : {
146 0 : if (mListNode && mListNode->Contains(aElement)) {
147 0 : RevalidateDataList();
148 : }
149 0 : }
150 :
151 : void
152 0 : nsFormFillController::ContentAppended(nsIDocument* aDocument,
153 : nsIContent* aContainer,
154 : nsIContent* aChild,
155 : PRInt32 aIndexInContainer)
156 : {
157 0 : if (mListNode && mListNode->Contains(aContainer)) {
158 0 : RevalidateDataList();
159 : }
160 0 : }
161 :
162 : void
163 0 : nsFormFillController::ContentInserted(nsIDocument* aDocument,
164 : nsIContent* aContainer,
165 : nsIContent* aChild,
166 : PRInt32 aIndexInContainer)
167 : {
168 0 : if (mListNode && mListNode->Contains(aContainer)) {
169 0 : RevalidateDataList();
170 : }
171 0 : }
172 :
173 : void
174 0 : nsFormFillController::ContentRemoved(nsIDocument* aDocument,
175 : nsIContent* aContainer,
176 : nsIContent* aChild,
177 : PRInt32 aIndexInContainer,
178 : nsIContent* aPreviousSibling)
179 : {
180 0 : if (mListNode && mListNode->Contains(aContainer)) {
181 0 : RevalidateDataList();
182 : }
183 0 : }
184 :
185 : void
186 0 : nsFormFillController::CharacterDataWillChange(nsIDocument* aDocument,
187 : nsIContent* aContent,
188 : CharacterDataChangeInfo* aInfo)
189 : {
190 0 : }
191 :
192 : void
193 0 : nsFormFillController::CharacterDataChanged(nsIDocument* aDocument,
194 : nsIContent* aContent,
195 : CharacterDataChangeInfo* aInfo)
196 : {
197 0 : }
198 :
199 : void
200 0 : nsFormFillController::AttributeWillChange(nsIDocument* aDocument,
201 : mozilla::dom::Element* aElement,
202 : PRInt32 aNameSpaceID,
203 : nsIAtom* aAttribute, PRInt32 aModType)
204 : {
205 0 : }
206 :
207 : void
208 0 : nsFormFillController::ParentChainChanged(nsIContent* aContent)
209 : {
210 0 : }
211 :
212 : void
213 0 : nsFormFillController::NodeWillBeDestroyed(const nsINode* aNode)
214 : {
215 0 : mPwmgrInputs.Remove(aNode);
216 0 : if (aNode == mListNode) {
217 0 : mListNode = nsnull;
218 0 : RevalidateDataList();
219 0 : } else if (aNode == mFocusedInputNode) {
220 0 : mFocusedInputNode = nsnull;
221 0 : mFocusedInput = nsnull;
222 : }
223 0 : }
224 :
225 : void
226 0 : nsFormFillController::MaybeRemoveMutationObserver(nsINode* aNode)
227 : {
228 : // Nodes being tracked in mPwmgrInputs will have their observers removed when
229 : // they stop being tracked.
230 : bool dummy;
231 0 : if (!mPwmgrInputs.Get(aNode, &dummy)) {
232 0 : aNode->RemoveMutationObserver(this);
233 : }
234 0 : }
235 :
236 : ////////////////////////////////////////////////////////////////////////
237 : //// nsIFormFillController
238 :
239 : NS_IMETHODIMP
240 0 : nsFormFillController::AttachToBrowser(nsIDocShell *aDocShell, nsIAutoCompletePopup *aPopup)
241 : {
242 0 : NS_ENSURE_TRUE(aDocShell && aPopup, NS_ERROR_ILLEGAL_VALUE);
243 :
244 0 : mDocShells->AppendElement(aDocShell);
245 0 : mPopups->AppendElement(aPopup);
246 :
247 : // Listen for focus events on the domWindow of the docShell
248 0 : nsCOMPtr<nsIDOMWindow> domWindow = GetWindowForDocShell(aDocShell);
249 0 : AddWindowListeners(domWindow);
250 :
251 0 : return NS_OK;
252 : }
253 :
254 : NS_IMETHODIMP
255 0 : nsFormFillController::DetachFromBrowser(nsIDocShell *aDocShell)
256 : {
257 0 : PRInt32 index = GetIndexOfDocShell(aDocShell);
258 0 : NS_ENSURE_TRUE(index >= 0, NS_ERROR_FAILURE);
259 :
260 : // Stop listening for focus events on the domWindow of the docShell
261 0 : nsCOMPtr<nsIDocShell> docShell;
262 0 : mDocShells->GetElementAt(index, getter_AddRefs(docShell));
263 0 : nsCOMPtr<nsIDOMWindow> domWindow = GetWindowForDocShell(docShell);
264 0 : RemoveWindowListeners(domWindow);
265 :
266 0 : mDocShells->RemoveElementAt(index);
267 0 : mPopups->RemoveElementAt(index);
268 :
269 0 : return NS_OK;
270 : }
271 :
272 :
273 : NS_IMETHODIMP
274 0 : nsFormFillController::MarkAsLoginManagerField(nsIDOMHTMLInputElement *aInput)
275 : {
276 : /*
277 : * The Login Manager can supply autocomplete results for username fields,
278 : * when a user has multiple logins stored for a site. It uses this
279 : * interface to indicate that the form manager shouldn't handle the
280 : * autocomplete. The form manager also checks for this tag when saving
281 : * form history (so it doesn't save usernames).
282 : */
283 0 : nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
284 0 : NS_ENSURE_STATE(node);
285 0 : mPwmgrInputs.Put(node, true);
286 0 : node->AddMutationObserverUnlessExists(this);
287 :
288 0 : if (!mLoginManager)
289 0 : mLoginManager = do_GetService("@mozilla.org/login-manager;1");
290 :
291 0 : return NS_OK;
292 : }
293 :
294 :
295 : ////////////////////////////////////////////////////////////////////////
296 : //// nsIAutoCompleteInput
297 :
298 : NS_IMETHODIMP
299 0 : nsFormFillController::GetPopup(nsIAutoCompletePopup **aPopup)
300 : {
301 0 : *aPopup = mFocusedPopup;
302 0 : NS_IF_ADDREF(*aPopup);
303 0 : return NS_OK;
304 : }
305 :
306 : NS_IMETHODIMP
307 0 : nsFormFillController::GetController(nsIAutoCompleteController **aController)
308 : {
309 0 : *aController = mController;
310 0 : NS_IF_ADDREF(*aController);
311 0 : return NS_OK;
312 : }
313 :
314 : NS_IMETHODIMP
315 0 : nsFormFillController::GetPopupOpen(bool *aPopupOpen)
316 : {
317 0 : if (mFocusedPopup)
318 0 : mFocusedPopup->GetPopupOpen(aPopupOpen);
319 : else
320 0 : *aPopupOpen = false;
321 0 : return NS_OK;
322 : }
323 :
324 : NS_IMETHODIMP
325 0 : nsFormFillController::SetPopupOpen(bool aPopupOpen)
326 : {
327 0 : if (mFocusedPopup) {
328 0 : if (aPopupOpen) {
329 : // make sure input field is visible before showing popup (bug 320938)
330 0 : nsCOMPtr<nsIContent> content = do_QueryInterface(mFocusedInput);
331 0 : NS_ENSURE_STATE(content);
332 0 : nsCOMPtr<nsIDocShell> docShell = GetDocShellForInput(mFocusedInput);
333 0 : NS_ENSURE_STATE(docShell);
334 0 : nsCOMPtr<nsIPresShell> presShell;
335 0 : docShell->GetPresShell(getter_AddRefs(presShell));
336 0 : NS_ENSURE_STATE(presShell);
337 0 : presShell->ScrollContentIntoView(content,
338 : NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
339 : NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
340 0 : nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
341 : // mFocusedPopup can be destroyed after ScrollContentIntoView, see bug 420089
342 0 : if (mFocusedPopup)
343 0 : mFocusedPopup->OpenAutocompletePopup(this, mFocusedInput);
344 : } else
345 0 : mFocusedPopup->ClosePopup();
346 : }
347 :
348 0 : return NS_OK;
349 : }
350 :
351 : NS_IMETHODIMP
352 0 : nsFormFillController::GetDisableAutoComplete(bool *aDisableAutoComplete)
353 : {
354 0 : *aDisableAutoComplete = mDisableAutoComplete;
355 0 : return NS_OK;
356 : }
357 :
358 : NS_IMETHODIMP
359 0 : nsFormFillController::SetDisableAutoComplete(bool aDisableAutoComplete)
360 : {
361 0 : mDisableAutoComplete = aDisableAutoComplete;
362 0 : return NS_OK;
363 : }
364 :
365 : NS_IMETHODIMP
366 0 : nsFormFillController::GetCompleteDefaultIndex(bool *aCompleteDefaultIndex)
367 : {
368 0 : *aCompleteDefaultIndex = mCompleteDefaultIndex;
369 0 : return NS_OK;
370 : }
371 :
372 : NS_IMETHODIMP
373 0 : nsFormFillController::SetCompleteDefaultIndex(bool aCompleteDefaultIndex)
374 : {
375 0 : mCompleteDefaultIndex = aCompleteDefaultIndex;
376 0 : return NS_OK;
377 : }
378 :
379 : NS_IMETHODIMP
380 0 : nsFormFillController::GetCompleteSelectedIndex(bool *aCompleteSelectedIndex)
381 : {
382 0 : *aCompleteSelectedIndex = mCompleteSelectedIndex;
383 0 : return NS_OK;
384 : }
385 :
386 : NS_IMETHODIMP
387 0 : nsFormFillController::SetCompleteSelectedIndex(bool aCompleteSelectedIndex)
388 : {
389 0 : mCompleteSelectedIndex = aCompleteSelectedIndex;
390 0 : return NS_OK;
391 : }
392 :
393 : NS_IMETHODIMP
394 0 : nsFormFillController::GetForceComplete(bool *aForceComplete)
395 : {
396 0 : *aForceComplete = mForceComplete;
397 0 : return NS_OK;
398 : }
399 :
400 0 : NS_IMETHODIMP nsFormFillController::SetForceComplete(bool aForceComplete)
401 : {
402 0 : mForceComplete = aForceComplete;
403 0 : return NS_OK;
404 : }
405 :
406 : NS_IMETHODIMP
407 0 : nsFormFillController::GetMinResultsForPopup(PRUint32 *aMinResultsForPopup)
408 : {
409 0 : *aMinResultsForPopup = mMinResultsForPopup;
410 0 : return NS_OK;
411 : }
412 :
413 0 : NS_IMETHODIMP nsFormFillController::SetMinResultsForPopup(PRUint32 aMinResultsForPopup)
414 : {
415 0 : mMinResultsForPopup = aMinResultsForPopup;
416 0 : return NS_OK;
417 : }
418 :
419 : NS_IMETHODIMP
420 0 : nsFormFillController::GetMaxRows(PRUint32 *aMaxRows)
421 : {
422 0 : *aMaxRows = mMaxRows;
423 0 : return NS_OK;
424 : }
425 :
426 : NS_IMETHODIMP
427 0 : nsFormFillController::SetMaxRows(PRUint32 aMaxRows)
428 : {
429 0 : mMaxRows = aMaxRows;
430 0 : return NS_OK;
431 : }
432 :
433 : NS_IMETHODIMP
434 0 : nsFormFillController::GetShowImageColumn(bool *aShowImageColumn)
435 : {
436 0 : *aShowImageColumn = false;
437 0 : return NS_OK;
438 : }
439 :
440 0 : NS_IMETHODIMP nsFormFillController::SetShowImageColumn(bool aShowImageColumn)
441 : {
442 0 : return NS_ERROR_NOT_IMPLEMENTED;
443 : }
444 :
445 :
446 : NS_IMETHODIMP
447 0 : nsFormFillController::GetShowCommentColumn(bool *aShowCommentColumn)
448 : {
449 0 : *aShowCommentColumn = false;
450 0 : return NS_OK;
451 : }
452 :
453 0 : NS_IMETHODIMP nsFormFillController::SetShowCommentColumn(bool aShowCommentColumn)
454 : {
455 0 : return NS_ERROR_NOT_IMPLEMENTED;
456 : }
457 :
458 : NS_IMETHODIMP
459 0 : nsFormFillController::GetTimeout(PRUint32 *aTimeout)
460 : {
461 0 : *aTimeout = mTimeout;
462 0 : return NS_OK;
463 : }
464 :
465 0 : NS_IMETHODIMP nsFormFillController::SetTimeout(PRUint32 aTimeout)
466 : {
467 0 : mTimeout = aTimeout;
468 0 : return NS_OK;
469 : }
470 :
471 : NS_IMETHODIMP
472 0 : nsFormFillController::SetSearchParam(const nsAString &aSearchParam)
473 : {
474 0 : return NS_ERROR_NOT_IMPLEMENTED;
475 : }
476 :
477 : NS_IMETHODIMP
478 0 : nsFormFillController::GetSearchParam(nsAString &aSearchParam)
479 : {
480 0 : if (!mFocusedInput) {
481 0 : NS_WARNING("mFocusedInput is null for some reason! avoiding a crash. should find out why... - ben");
482 0 : return NS_ERROR_FAILURE; // XXX why? fix me.
483 : }
484 :
485 0 : mFocusedInput->GetName(aSearchParam);
486 0 : if (aSearchParam.IsEmpty())
487 0 : mFocusedInput->GetId(aSearchParam);
488 :
489 0 : return NS_OK;
490 : }
491 :
492 : NS_IMETHODIMP
493 0 : nsFormFillController::GetSearchCount(PRUint32 *aSearchCount)
494 : {
495 0 : *aSearchCount = 1;
496 0 : return NS_OK;
497 : }
498 :
499 : NS_IMETHODIMP
500 0 : nsFormFillController::GetSearchAt(PRUint32 index, nsACString & _retval)
501 : {
502 0 : _retval.Assign("form-history");
503 0 : return NS_OK;
504 : }
505 :
506 : NS_IMETHODIMP
507 0 : nsFormFillController::GetTextValue(nsAString & aTextValue)
508 : {
509 0 : if (mFocusedInput) {
510 0 : mFocusedInput->GetValue(aTextValue);
511 : } else {
512 0 : aTextValue.Truncate();
513 : }
514 0 : return NS_OK;
515 : }
516 :
517 : NS_IMETHODIMP
518 0 : nsFormFillController::SetTextValue(const nsAString & aTextValue)
519 : {
520 0 : nsCOMPtr<nsIDOMNSEditableElement> editable = do_QueryInterface(mFocusedInput);
521 0 : if (editable) {
522 0 : mSuppressOnInput = true;
523 0 : editable->SetUserInput(aTextValue);
524 0 : mSuppressOnInput = false;
525 : }
526 0 : return NS_OK;
527 : }
528 :
529 : NS_IMETHODIMP
530 0 : nsFormFillController::GetSelectionStart(PRInt32 *aSelectionStart)
531 : {
532 0 : if (mFocusedInput)
533 0 : mFocusedInput->GetSelectionStart(aSelectionStart);
534 0 : return NS_OK;
535 : }
536 :
537 : NS_IMETHODIMP
538 0 : nsFormFillController::GetSelectionEnd(PRInt32 *aSelectionEnd)
539 : {
540 0 : if (mFocusedInput)
541 0 : mFocusedInput->GetSelectionEnd(aSelectionEnd);
542 0 : return NS_OK;
543 : }
544 :
545 : NS_IMETHODIMP
546 0 : nsFormFillController::SelectTextRange(PRInt32 aStartIndex, PRInt32 aEndIndex)
547 : {
548 0 : if (mFocusedInput)
549 0 : mFocusedInput->SetSelectionRange(aStartIndex, aEndIndex, EmptyString());
550 0 : return NS_OK;
551 : }
552 :
553 : NS_IMETHODIMP
554 0 : nsFormFillController::OnSearchBegin()
555 : {
556 0 : return NS_OK;
557 : }
558 :
559 : NS_IMETHODIMP
560 0 : nsFormFillController::OnSearchComplete()
561 : {
562 0 : return NS_OK;
563 : }
564 :
565 : NS_IMETHODIMP
566 0 : nsFormFillController::OnTextEntered(bool* aPrevent)
567 : {
568 0 : NS_ENSURE_ARG(aPrevent);
569 0 : NS_ENSURE_TRUE(mFocusedInput, NS_OK);
570 : // Fire off a DOMAutoComplete event
571 0 : nsCOMPtr<nsIDOMDocument> domDoc;
572 0 : mFocusedInput->GetOwnerDocument(getter_AddRefs(domDoc));
573 0 : NS_ENSURE_STATE(domDoc);
574 :
575 0 : nsCOMPtr<nsIDOMEvent> event;
576 0 : domDoc->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
577 0 : nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
578 0 : NS_ENSURE_STATE(privateEvent);
579 :
580 0 : event->InitEvent(NS_LITERAL_STRING("DOMAutoComplete"), true, true);
581 :
582 : // XXXjst: We mark this event as a trusted event, it's up to the
583 : // callers of this to ensure that it's only called from trusted
584 : // code.
585 0 : privateEvent->SetTrusted(true);
586 :
587 0 : nsCOMPtr<nsIDOMEventTarget> targ = do_QueryInterface(mFocusedInput);
588 :
589 : bool defaultActionEnabled;
590 0 : targ->DispatchEvent(event, &defaultActionEnabled);
591 0 : *aPrevent = !defaultActionEnabled;
592 0 : return NS_OK;
593 : }
594 :
595 : NS_IMETHODIMP
596 0 : nsFormFillController::OnTextReverted(bool *_retval)
597 : {
598 0 : return NS_OK;
599 : }
600 :
601 : NS_IMETHODIMP
602 0 : nsFormFillController::GetConsumeRollupEvent(bool *aConsumeRollupEvent)
603 : {
604 0 : *aConsumeRollupEvent = false;
605 0 : return NS_OK;
606 : }
607 :
608 :
609 : ////////////////////////////////////////////////////////////////////////
610 : //// nsIAutoCompleteSearch
611 :
612 : NS_IMETHODIMP
613 0 : nsFormFillController::StartSearch(const nsAString &aSearchString, const nsAString &aSearchParam,
614 : nsIAutoCompleteResult *aPreviousResult, nsIAutoCompleteObserver *aListener)
615 : {
616 : nsresult rv;
617 0 : nsCOMPtr<nsIAutoCompleteResult> result;
618 :
619 : // If the login manager has indicated it's responsible for this field, let it
620 : // handle the autocomplete. Otherwise, handle with form history.
621 : bool dummy;
622 0 : if (mPwmgrInputs.Get(mFocusedInputNode, &dummy)) {
623 : // XXX aPreviousResult shouldn't ever be a historyResult type, since we're not letting
624 : // satchel manage the field?
625 0 : rv = mLoginManager->AutoCompleteSearch(aSearchString,
626 : aPreviousResult,
627 : mFocusedInput,
628 0 : getter_AddRefs(result));
629 : } else {
630 0 : nsCOMPtr<nsIAutoCompleteResult> formHistoryResult;
631 :
632 : // It appears that mFocusedInput is always null when we are focusing a XUL
633 : // element. Scary :)
634 0 : if (!mFocusedInput || nsContentUtils::IsAutocompleteEnabled(mFocusedInput)) {
635 : nsCOMPtr <nsIFormAutoComplete> formAutoComplete =
636 0 : do_GetService("@mozilla.org/satchel/form-autocomplete;1", &rv);
637 0 : NS_ENSURE_SUCCESS(rv, rv);
638 :
639 0 : rv = formAutoComplete->AutoCompleteSearch(aSearchParam,
640 : aSearchString,
641 : mFocusedInput,
642 : aPreviousResult,
643 0 : getter_AddRefs(formHistoryResult));
644 :
645 0 : NS_ENSURE_SUCCESS(rv, rv);
646 : }
647 :
648 0 : mLastSearchResult = formHistoryResult;
649 0 : mLastListener = aListener;
650 0 : mLastSearchString = aSearchString;
651 :
652 : nsCOMPtr <nsIInputListAutoComplete> inputListAutoComplete =
653 0 : do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv);
654 0 : NS_ENSURE_SUCCESS(rv, rv);
655 :
656 0 : rv = inputListAutoComplete->AutoCompleteSearch(formHistoryResult,
657 : aSearchString,
658 : mFocusedInput,
659 0 : getter_AddRefs(result));
660 :
661 0 : if (mFocusedInput) {
662 0 : nsCOMPtr<nsIDOMHTMLElement> list;
663 0 : mFocusedInput->GetList(getter_AddRefs(list));
664 :
665 0 : nsCOMPtr<nsINode> node = do_QueryInterface(list);
666 0 : if (mListNode != node) {
667 0 : if (mListNode) {
668 0 : mListNode->RemoveMutationObserver(this);
669 0 : mListNode = nsnull;
670 : }
671 0 : if (node) {
672 0 : node->AddMutationObserverUnlessExists(this);
673 0 : mListNode = node;
674 : }
675 : }
676 : }
677 : }
678 0 : NS_ENSURE_SUCCESS(rv, rv);
679 :
680 0 : aListener->OnSearchResult(this, result);
681 :
682 0 : return NS_OK;
683 : }
684 :
685 : class UpdateSearchResultRunnable : public nsRunnable
686 0 : {
687 : public:
688 0 : UpdateSearchResultRunnable(nsIAutoCompleteObserver* aObserver,
689 : nsIAutoCompleteSearch* aSearch,
690 : nsIAutoCompleteResult* aResult)
691 : : mObserver(aObserver)
692 : , mSearch(aSearch)
693 0 : , mResult(aResult)
694 0 : {}
695 :
696 0 : NS_IMETHOD Run() {
697 0 : NS_ASSERTION(mObserver, "You shouldn't call this runnable with a null observer!");
698 :
699 0 : mObserver->OnUpdateSearchResult(mSearch, mResult);
700 0 : return NS_OK;
701 : }
702 :
703 : private:
704 : nsCOMPtr<nsIAutoCompleteObserver> mObserver;
705 : nsCOMPtr<nsIAutoCompleteSearch> mSearch;
706 : nsCOMPtr<nsIAutoCompleteResult> mResult;
707 : };
708 :
709 0 : void nsFormFillController::RevalidateDataList()
710 : {
711 0 : if (!mLastListener) {
712 0 : return;
713 : }
714 : nsresult rv;
715 : nsCOMPtr <nsIInputListAutoComplete> inputListAutoComplete =
716 0 : do_GetService("@mozilla.org/satchel/inputlist-autocomplete;1", &rv);
717 :
718 0 : nsCOMPtr<nsIAutoCompleteResult> result;
719 :
720 0 : rv = inputListAutoComplete->AutoCompleteSearch(mLastSearchResult,
721 : mLastSearchString,
722 : mFocusedInput,
723 0 : getter_AddRefs(result));
724 :
725 : nsCOMPtr<nsIRunnable> event =
726 0 : new UpdateSearchResultRunnable(mLastListener, this, result);
727 0 : NS_DispatchToCurrentThread(event);
728 : }
729 :
730 : NS_IMETHODIMP
731 0 : nsFormFillController::StopSearch()
732 : {
733 0 : return NS_OK;
734 : }
735 :
736 : ////////////////////////////////////////////////////////////////////////
737 : //// nsIDOMEventListener
738 :
739 : NS_IMETHODIMP
740 0 : nsFormFillController::HandleEvent(nsIDOMEvent* aEvent)
741 : {
742 0 : nsAutoString type;
743 0 : aEvent->GetType(type);
744 :
745 0 : if (type.EqualsLiteral("focus")) {
746 0 : return Focus(aEvent);
747 : }
748 0 : if (type.EqualsLiteral("mousedown")) {
749 0 : return MouseDown(aEvent);
750 : }
751 0 : if (type.EqualsLiteral("keypress")) {
752 0 : return KeyPress(aEvent);
753 : }
754 0 : if (type.EqualsLiteral("input")) {
755 0 : return (!mSuppressOnInput && mController && mFocusedInput) ?
756 0 : mController->HandleText() : NS_OK;
757 : }
758 0 : if (type.EqualsLiteral("blur")) {
759 0 : if (mFocusedInput)
760 0 : StopControllingInput();
761 0 : return NS_OK;
762 : }
763 0 : if (type.EqualsLiteral("compositionstart")) {
764 0 : NS_ASSERTION(mController, "should have a controller!");
765 0 : if (mController && mFocusedInput)
766 0 : mController->HandleStartComposition();
767 0 : return NS_OK;
768 : }
769 0 : if (type.EqualsLiteral("compositionend")) {
770 0 : NS_ASSERTION(mController, "should have a controller!");
771 0 : if (mController && mFocusedInput)
772 0 : mController->HandleEndComposition();
773 0 : return NS_OK;
774 : }
775 0 : if (type.EqualsLiteral("contextmenu")) {
776 0 : if (mFocusedPopup)
777 0 : mFocusedPopup->ClosePopup();
778 0 : return NS_OK;
779 : }
780 0 : if (type.EqualsLiteral("pagehide")) {
781 0 : nsCOMPtr<nsIDOMEventTarget> target;
782 0 : aEvent->GetTarget(getter_AddRefs(target));
783 :
784 0 : nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(target);
785 0 : if (!domDoc)
786 0 : return NS_OK;
787 :
788 0 : if (mFocusedInput) {
789 0 : nsCOMPtr<nsIDOMDocument> inputDoc;
790 0 : mFocusedInput->GetOwnerDocument(getter_AddRefs(inputDoc));
791 0 : if (domDoc == inputDoc)
792 0 : StopControllingInput();
793 : }
794 :
795 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
796 0 : PwmgrInputsEnumData ed(this, doc);
797 0 : mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
798 : }
799 :
800 0 : return NS_OK;
801 : }
802 :
803 :
804 : /* static */ PLDHashOperator
805 0 : nsFormFillController::RemoveForDocumentEnumerator(const nsINode* aKey,
806 : bool& aEntry,
807 : void* aUserData)
808 : {
809 0 : PwmgrInputsEnumData* ed = static_cast<PwmgrInputsEnumData*>(aUserData);
810 0 : if (aKey && (!ed->mDoc || aKey->OwnerDoc() == ed->mDoc)) {
811 : // mFocusedInputNode's observer is tracked separately, don't remove it here.
812 0 : if (aKey != ed->mFFC->mFocusedInputNode) {
813 0 : const_cast<nsINode*>(aKey)->RemoveMutationObserver(ed->mFFC);
814 : }
815 0 : return PL_DHASH_REMOVE;
816 : }
817 0 : return PL_DHASH_NEXT;
818 : }
819 :
820 : nsresult
821 0 : nsFormFillController::Focus(nsIDOMEvent* aEvent)
822 : {
823 0 : nsCOMPtr<nsIDOMEventTarget> target;
824 0 : aEvent->GetTarget(getter_AddRefs(target));
825 :
826 0 : nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(target);
827 0 : nsCOMPtr<nsINode> inputNode = do_QueryInterface(input);
828 0 : if (!inputNode)
829 0 : return NS_OK;
830 :
831 0 : bool isReadOnly = false;
832 0 : input->GetReadOnly(&isReadOnly);
833 :
834 0 : bool autocomplete = nsContentUtils::IsAutocompleteEnabled(input);
835 :
836 0 : nsCOMPtr<nsIDOMHTMLElement> datalist;
837 0 : input->GetList(getter_AddRefs(datalist));
838 0 : bool hasList = datalist != nsnull;
839 :
840 : bool dummy;
841 0 : bool isPwmgrInput = false;
842 0 : if (mPwmgrInputs.Get(inputNode, &dummy))
843 0 : isPwmgrInput = true;
844 :
845 0 : nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(input);
846 0 : if (isPwmgrInput || (formControl &&
847 0 : formControl->IsSingleLineTextControl(PR_TRUE) &&
848 0 : (hasList || autocomplete) && !isReadOnly)) {
849 0 : StartControllingInput(input);
850 : }
851 :
852 0 : return NS_OK;
853 : }
854 :
855 : nsresult
856 0 : nsFormFillController::KeyPress(nsIDOMEvent* aEvent)
857 : {
858 0 : NS_ASSERTION(mController, "should have a controller!");
859 0 : if (!mFocusedInput || !mController)
860 0 : return NS_OK;
861 :
862 0 : nsCOMPtr<nsIDOMKeyEvent> keyEvent = do_QueryInterface(aEvent);
863 0 : if (!keyEvent)
864 0 : return NS_ERROR_FAILURE;
865 :
866 0 : bool cancel = false;
867 :
868 : PRUint32 k;
869 0 : keyEvent->GetKeyCode(&k);
870 0 : switch (k) {
871 : case nsIDOMKeyEvent::DOM_VK_DELETE:
872 : #ifndef XP_MACOSX
873 0 : mController->HandleDelete(&cancel);
874 0 : break;
875 : case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
876 0 : mController->HandleText();
877 0 : break;
878 : #else
879 : case nsIDOMKeyEvent::DOM_VK_BACK_SPACE:
880 : {
881 : bool isShift = false;
882 : keyEvent->GetShiftKey(&isShift);
883 :
884 : if (isShift)
885 : mController->HandleDelete(&cancel);
886 : else
887 : mController->HandleText();
888 :
889 : break;
890 : }
891 : #endif
892 : case nsIDOMKeyEvent::DOM_VK_PAGE_UP:
893 : case nsIDOMKeyEvent::DOM_VK_PAGE_DOWN:
894 : {
895 : bool isCtrl, isAlt, isMeta;
896 0 : keyEvent->GetCtrlKey(&isCtrl);
897 0 : keyEvent->GetAltKey(&isAlt);
898 0 : keyEvent->GetMetaKey(&isMeta);
899 0 : if (isCtrl || isAlt || isMeta)
900 0 : break;
901 : }
902 : /* fall through */
903 : case nsIDOMKeyEvent::DOM_VK_UP:
904 : case nsIDOMKeyEvent::DOM_VK_DOWN:
905 : case nsIDOMKeyEvent::DOM_VK_LEFT:
906 : case nsIDOMKeyEvent::DOM_VK_RIGHT:
907 0 : mController->HandleKeyNavigation(k, &cancel);
908 0 : break;
909 : case nsIDOMKeyEvent::DOM_VK_ESCAPE:
910 0 : mController->HandleEscape(&cancel);
911 0 : break;
912 : case nsIDOMKeyEvent::DOM_VK_TAB:
913 0 : mController->HandleTab();
914 0 : cancel = false;
915 0 : break;
916 : case nsIDOMKeyEvent::DOM_VK_RETURN:
917 0 : mController->HandleEnter(false, &cancel);
918 0 : break;
919 : }
920 :
921 0 : if (cancel) {
922 0 : aEvent->PreventDefault();
923 : }
924 :
925 0 : return NS_OK;
926 : }
927 :
928 : nsresult
929 0 : nsFormFillController::MouseDown(nsIDOMEvent* aEvent)
930 : {
931 0 : nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(aEvent));
932 0 : if (!mouseEvent)
933 0 : return NS_ERROR_FAILURE;
934 :
935 0 : nsCOMPtr<nsIDOMEventTarget> target;
936 0 : aEvent->GetTarget(getter_AddRefs(target));
937 0 : nsCOMPtr<nsIDOMHTMLInputElement> targetInput = do_QueryInterface(target);
938 0 : if (!targetInput)
939 0 : return NS_OK;
940 :
941 : PRUint16 button;
942 0 : mouseEvent->GetButton(&button);
943 0 : if (button != 0)
944 0 : return NS_OK;
945 :
946 0 : bool isOpen = false;
947 0 : GetPopupOpen(&isOpen);
948 0 : if (isOpen)
949 0 : return NS_OK;
950 :
951 0 : nsCOMPtr<nsIAutoCompleteInput> input;
952 0 : mController->GetInput(getter_AddRefs(input));
953 0 : if (!input)
954 0 : return NS_OK;
955 :
956 0 : nsAutoString value;
957 0 : input->GetTextValue(value);
958 0 : if (value.Length() > 0) {
959 : // Show the popup with a filtered result set
960 0 : mController->SetSearchString(EmptyString());
961 0 : mController->HandleText();
962 : } else {
963 : // Show the popup with the complete result set. Can't use HandleText()
964 : // because it doesn't display the popup if the input is blank.
965 0 : bool cancel = false;
966 0 : mController->HandleKeyNavigation(nsIDOMKeyEvent::DOM_VK_DOWN, &cancel);
967 : }
968 :
969 0 : return NS_OK;
970 : }
971 :
972 : ////////////////////////////////////////////////////////////////////////
973 : //// nsFormFillController
974 :
975 : void
976 0 : nsFormFillController::AddWindowListeners(nsIDOMWindow *aWindow)
977 : {
978 0 : if (!aWindow)
979 0 : return;
980 :
981 0 : nsCOMPtr<nsPIDOMWindow> privateDOMWindow(do_QueryInterface(aWindow));
982 0 : nsIDOMEventTarget* target = nsnull;
983 0 : if (privateDOMWindow)
984 0 : target = privateDOMWindow->GetChromeEventHandler();
985 :
986 0 : if (!target)
987 : return;
988 :
989 0 : target->AddEventListener(NS_LITERAL_STRING("focus"), this,
990 0 : true, false);
991 0 : target->AddEventListener(NS_LITERAL_STRING("blur"), this,
992 0 : true, false);
993 0 : target->AddEventListener(NS_LITERAL_STRING("pagehide"), this,
994 0 : true, false);
995 0 : target->AddEventListener(NS_LITERAL_STRING("mousedown"), this,
996 0 : true, false);
997 0 : target->AddEventListener(NS_LITERAL_STRING("input"), this,
998 0 : true, false);
999 0 : target->AddEventListener(NS_LITERAL_STRING("compositionstart"), this,
1000 0 : true, false);
1001 0 : target->AddEventListener(NS_LITERAL_STRING("compositionend"), this,
1002 0 : true, false);
1003 0 : target->AddEventListener(NS_LITERAL_STRING("contextmenu"), this,
1004 0 : true, false);
1005 :
1006 : // Note that any additional listeners added should ensure that they ignore
1007 : // untrusted events, which might be sent by content that's up to no good.
1008 : }
1009 :
1010 : void
1011 0 : nsFormFillController::RemoveWindowListeners(nsIDOMWindow *aWindow)
1012 : {
1013 0 : if (!aWindow)
1014 0 : return;
1015 :
1016 0 : StopControllingInput();
1017 :
1018 0 : nsCOMPtr<nsIDOMDocument> domDoc;
1019 0 : aWindow->GetDocument(getter_AddRefs(domDoc));
1020 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
1021 0 : PwmgrInputsEnumData ed(this, doc);
1022 0 : mPwmgrInputs.Enumerate(RemoveForDocumentEnumerator, &ed);
1023 :
1024 0 : nsCOMPtr<nsPIDOMWindow> privateDOMWindow(do_QueryInterface(aWindow));
1025 0 : nsIDOMEventTarget* target = nsnull;
1026 0 : if (privateDOMWindow)
1027 0 : target = privateDOMWindow->GetChromeEventHandler();
1028 :
1029 0 : if (!target)
1030 : return;
1031 :
1032 0 : target->RemoveEventListener(NS_LITERAL_STRING("focus"), this, true);
1033 0 : target->RemoveEventListener(NS_LITERAL_STRING("blur"), this, true);
1034 0 : target->RemoveEventListener(NS_LITERAL_STRING("pagehide"), this, true);
1035 0 : target->RemoveEventListener(NS_LITERAL_STRING("mousedown"), this, true);
1036 0 : target->RemoveEventListener(NS_LITERAL_STRING("input"), this, true);
1037 0 : target->RemoveEventListener(NS_LITERAL_STRING("compositionstart"), this,
1038 0 : true);
1039 0 : target->RemoveEventListener(NS_LITERAL_STRING("compositionend"), this,
1040 0 : true);
1041 0 : target->RemoveEventListener(NS_LITERAL_STRING("contextmenu"), this, true);
1042 : }
1043 :
1044 : void
1045 0 : nsFormFillController::AddKeyListener(nsIDOMHTMLInputElement *aInput)
1046 : {
1047 0 : if (!aInput)
1048 0 : return;
1049 :
1050 0 : nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(aInput);
1051 :
1052 0 : target->AddEventListener(NS_LITERAL_STRING("keypress"), this,
1053 0 : true, false);
1054 : }
1055 :
1056 : void
1057 0 : nsFormFillController::RemoveKeyListener()
1058 : {
1059 0 : if (!mFocusedInput)
1060 0 : return;
1061 :
1062 0 : nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mFocusedInput);
1063 0 : target->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, true);
1064 : }
1065 :
1066 : void
1067 0 : nsFormFillController::StartControllingInput(nsIDOMHTMLInputElement *aInput)
1068 : {
1069 : // Make sure we're not still attached to an input
1070 0 : StopControllingInput();
1071 :
1072 : // Find the currently focused docShell
1073 0 : nsCOMPtr<nsIDocShell> docShell = GetDocShellForInput(aInput);
1074 0 : PRInt32 index = GetIndexOfDocShell(docShell);
1075 0 : if (index < 0)
1076 : return;
1077 :
1078 : // Cache the popup for the focused docShell
1079 0 : mPopups->GetElementAt(index, getter_AddRefs(mFocusedPopup));
1080 :
1081 0 : nsCOMPtr<nsINode> node = do_QueryInterface(aInput);
1082 0 : if (!node) {
1083 : return;
1084 : }
1085 :
1086 0 : AddKeyListener(aInput);
1087 :
1088 0 : node->AddMutationObserverUnlessExists(this);
1089 0 : mFocusedInputNode = node;
1090 0 : mFocusedInput = aInput;
1091 :
1092 0 : nsCOMPtr<nsIDOMHTMLElement> list;
1093 0 : mFocusedInput->GetList(getter_AddRefs(list));
1094 0 : nsCOMPtr<nsINode> listNode = do_QueryInterface(list);
1095 0 : if (listNode) {
1096 0 : listNode->AddMutationObserverUnlessExists(this);
1097 0 : mListNode = listNode;
1098 : }
1099 :
1100 : // Now we are the autocomplete controller's bitch
1101 0 : mController->SetInput(this);
1102 : }
1103 :
1104 : void
1105 0 : nsFormFillController::StopControllingInput()
1106 : {
1107 0 : RemoveKeyListener();
1108 :
1109 0 : if (mListNode) {
1110 0 : mListNode->RemoveMutationObserver(this);
1111 0 : mListNode = nsnull;
1112 : }
1113 :
1114 : // Reset the controller's input, but not if it has been switched
1115 : // to another input already, which might happen if the user switches
1116 : // focus by clicking another autocomplete textbox
1117 0 : nsCOMPtr<nsIAutoCompleteInput> input;
1118 0 : mController->GetInput(getter_AddRefs(input));
1119 0 : if (input == this)
1120 0 : mController->SetInput(nsnull);
1121 :
1122 0 : if (mFocusedInputNode) {
1123 0 : MaybeRemoveMutationObserver(mFocusedInputNode);
1124 0 : mFocusedInputNode = nsnull;
1125 0 : mFocusedInput = nsnull;
1126 : }
1127 0 : mFocusedPopup = nsnull;
1128 0 : }
1129 :
1130 : nsIDocShell *
1131 0 : nsFormFillController::GetDocShellForInput(nsIDOMHTMLInputElement *aInput)
1132 : {
1133 0 : nsCOMPtr<nsIDOMDocument> domDoc;
1134 0 : aInput->GetOwnerDocument(getter_AddRefs(domDoc));
1135 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
1136 0 : NS_ENSURE_TRUE(doc, nsnull);
1137 0 : nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(doc->GetWindow());
1138 0 : nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webNav);
1139 0 : return docShell;
1140 : }
1141 :
1142 : nsIDOMWindow *
1143 0 : nsFormFillController::GetWindowForDocShell(nsIDocShell *aDocShell)
1144 : {
1145 0 : nsCOMPtr<nsIContentViewer> contentViewer;
1146 0 : aDocShell->GetContentViewer(getter_AddRefs(contentViewer));
1147 0 : NS_ENSURE_TRUE(contentViewer, nsnull);
1148 :
1149 0 : nsCOMPtr<nsIDOMDocument> domDoc;
1150 0 : contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
1151 0 : nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
1152 0 : NS_ENSURE_TRUE(doc, nsnull);
1153 :
1154 0 : return doc->GetWindow();
1155 : }
1156 :
1157 : PRInt32
1158 0 : nsFormFillController::GetIndexOfDocShell(nsIDocShell *aDocShell)
1159 : {
1160 0 : if (!aDocShell)
1161 0 : return -1;
1162 :
1163 : // Loop through our cached docShells looking for the given docShell
1164 : PRUint32 count;
1165 0 : mDocShells->Count(&count);
1166 0 : for (PRUint32 i = 0; i < count; ++i) {
1167 0 : nsCOMPtr<nsIDocShell> docShell;
1168 0 : mDocShells->GetElementAt(i, getter_AddRefs(docShell));
1169 0 : if (docShell == aDocShell)
1170 0 : return i;
1171 : }
1172 :
1173 : // Recursively check the parent docShell of this one
1174 0 : nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(aDocShell);
1175 0 : nsCOMPtr<nsIDocShellTreeItem> parentItem;
1176 0 : treeItem->GetParent(getter_AddRefs(parentItem));
1177 0 : if (parentItem) {
1178 0 : nsCOMPtr<nsIDocShell> parentShell = do_QueryInterface(parentItem);
1179 0 : return GetIndexOfDocShell(parentShell);
1180 : }
1181 :
1182 0 : return -1;
1183 : }
1184 :
1185 0 : NS_GENERIC_FACTORY_CONSTRUCTOR(nsFormFillController)
1186 :
1187 : NS_DEFINE_NAMED_CID(NS_FORMFILLCONTROLLER_CID);
1188 :
1189 : static const mozilla::Module::CIDEntry kSatchelCIDs[] = {
1190 : { &kNS_FORMFILLCONTROLLER_CID, false, NULL, nsFormFillControllerConstructor },
1191 : { NULL }
1192 : };
1193 :
1194 : static const mozilla::Module::ContractIDEntry kSatchelContracts[] = {
1195 : { "@mozilla.org/satchel/form-fill-controller;1", &kNS_FORMFILLCONTROLLER_CID },
1196 : { NS_FORMHISTORYAUTOCOMPLETE_CONTRACTID, &kNS_FORMFILLCONTROLLER_CID },
1197 : { NULL }
1198 : };
1199 :
1200 : static const mozilla::Module kSatchelModule = {
1201 : mozilla::Module::kVersion,
1202 : kSatchelCIDs,
1203 : kSatchelContracts
1204 : };
1205 :
1206 : NSMODULE_DEFN(satchel) = &kSatchelModule;
1207 :
|