1010
1111var EXPORTED_SYMBOLS = [ "FormValidationParent" ] ;
1212
13+ ChromeUtils . defineModuleGetter (
14+ this ,
15+ "BrowserWindowTracker" ,
16+ "resource:///modules/BrowserWindowTracker.jsm"
17+ ) ;
18+
19+ const { Services } = ChromeUtils . import ( "resource://gre/modules/Services.jsm" ) ;
20+
21+ class PopupShownObserver {
22+ _weakContext = null ;
23+
24+ constructor ( browsingContext ) {
25+ this . _weakContext = Cu . getWeakReference ( browsingContext ) ;
26+ }
27+
28+ observe ( subject , topic , data ) {
29+ let ctxt = this . _weakContext . get ( ) ;
30+ let actor = ctxt . currentWindowGlobal ?. getExistingActor ( "FormValidation" ) ;
31+ if ( ! actor ) {
32+ Services . obs . removeObserver ( this , "popup-shown" ) ;
33+ return ;
34+ }
35+ // If any panel besides ourselves shows, hide ourselves again.
36+ if ( topic == "popup-shown" && subject != actor . _panel ) {
37+ actor . _hidePopup ( ) ;
38+ }
39+ }
40+
41+ QueryInterface = ChromeUtils . generateQI ( [
42+ Ci . nsIObserver ,
43+ Ci . nsISupportsWeakReference ,
44+ ] ) ;
45+ }
46+
1347class FormValidationParent extends JSWindowActorParent {
1448 constructor ( ) {
1549 super ( ) ;
1650
1751 this . _panel = null ;
52+ this . _obs = null ;
53+ }
54+
55+ static hasOpenPopups ( ) {
56+ for ( let win of BrowserWindowTracker . orderedWindows ) {
57+ let popups = win . document . querySelectorAll ( "panel,menupopup" ) ;
58+ for ( let popup of popups ) {
59+ let { state } = popup ;
60+ if ( state == "open" || state == "showing" ) {
61+ return true ;
62+ }
63+ }
64+ }
65+ return false ;
1866 }
1967
2068 /*
@@ -23,6 +71,7 @@ class FormValidationParent extends JSWindowActorParent {
2371
2472 uninit ( ) {
2573 this . _panel = null ;
74+ this . _obs = null ;
2675 }
2776
2877 hidePopup ( ) {
@@ -47,6 +96,10 @@ class FormValidationParent extends JSWindowActorParent {
4796 return ;
4897 }
4998
99+ if ( FormValidationParent . hasOpenPopups ( ) ) {
100+ return ;
101+ }
102+
50103 this . _showPopup ( data ) ;
51104 break ;
52105 case "FormValidation:HidePopup" :
@@ -55,10 +108,6 @@ class FormValidationParent extends JSWindowActorParent {
55108 }
56109 }
57110
58- observe ( aSubject , aTopic , aData ) {
59- this . _hidePopup ( ) ;
60- }
61-
62111 handleEvent ( aEvent ) {
63112 switch ( aEvent . type ) {
64113 case "FullZoomChange" :
@@ -78,11 +127,13 @@ class FormValidationParent extends JSWindowActorParent {
78127
79128 _onPopupHiding ( aEvent ) {
80129 aEvent . originalTarget . removeEventListener ( "popuphiding" , this , true ) ;
130+ Services . obs . removeObserver ( this . _obs , "popup-shown" ) ;
81131 let tabBrowser = aEvent . originalTarget . ownerGlobal . gBrowser ;
82132 tabBrowser . selectedBrowser . removeEventListener ( "scroll" , this , true ) ;
83133 tabBrowser . selectedBrowser . removeEventListener ( "FullZoomChange" , this ) ;
84134 tabBrowser . selectedBrowser . removeEventListener ( "TextZoomChange" , this ) ;
85135
136+ this . _obs = null ;
86137 this . _panel = null ;
87138 }
88139
@@ -110,6 +161,9 @@ class FormValidationParent extends JSWindowActorParent {
110161 if ( ! previouslyShown ) {
111162 // Cleanup after the popup is hidden
112163 this . _panel . addEventListener ( "popuphiding" , this , true ) ;
164+ // Hide ourselves if other popups shown
165+ this . _obs = new PopupShownObserver ( this . browsingContext ) ;
166+ Services . obs . addObserver ( this . _obs , "popup-shown" , true ) ;
113167
114168 // Hide if the user scrolls the page
115169 tabBrowser . selectedBrowser . addEventListener ( "scroll" , this , true ) ;
0 commit comments