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