|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () { |
|
6 return Cu.import("resource://gre/modules/FxAccountsCommon.js", {}); |
|
7 }); |
|
8 |
|
9 const PREF_SYNC_START_DOORHANGER = "services.sync.ui.showSyncStartDoorhanger"; |
|
10 const DOORHANGER_ACTIVATE_DELAY_MS = 5000; |
|
11 |
|
12 let gFxAccounts = { |
|
13 |
|
14 _initialized: false, |
|
15 _inCustomizationMode: false, |
|
16 |
|
17 get weave() { |
|
18 delete this.weave; |
|
19 return this.weave = Cc["@mozilla.org/weave/service;1"] |
|
20 .getService(Ci.nsISupports) |
|
21 .wrappedJSObject; |
|
22 }, |
|
23 |
|
24 get topics() { |
|
25 // Do all this dance to lazy-load FxAccountsCommon. |
|
26 delete this.topics; |
|
27 return this.topics = [ |
|
28 "weave:service:ready", |
|
29 "weave:service:sync:start", |
|
30 "weave:service:login:error", |
|
31 "weave:service:setup-complete", |
|
32 FxAccountsCommon.ONVERIFIED_NOTIFICATION, |
|
33 FxAccountsCommon.ONLOGOUT_NOTIFICATION |
|
34 ]; |
|
35 }, |
|
36 |
|
37 get button() { |
|
38 delete this.button; |
|
39 return this.button = document.getElementById("PanelUI-fxa-status"); |
|
40 }, |
|
41 |
|
42 get loginFailed() { |
|
43 // Referencing Weave.Service will implicitly initialize sync, and we don't |
|
44 // want to force that - so first check if it is ready. |
|
45 let service = Cc["@mozilla.org/weave/service;1"] |
|
46 .getService(Components.interfaces.nsISupports) |
|
47 .wrappedJSObject; |
|
48 if (!service.ready) { |
|
49 return false; |
|
50 } |
|
51 // LOGIN_FAILED_LOGIN_REJECTED explicitly means "you must log back in". |
|
52 // All other login failures are assumed to be transient and should go |
|
53 // away by themselves, so aren't reflected here. |
|
54 return Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED; |
|
55 }, |
|
56 |
|
57 get isActiveWindow() { |
|
58 let fm = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); |
|
59 return fm.activeWindow == window; |
|
60 }, |
|
61 |
|
62 init: function () { |
|
63 // Bail out if we're already initialized and for pop-up windows. |
|
64 if (this._initialized || !window.toolbar.visible) { |
|
65 return; |
|
66 } |
|
67 |
|
68 for (let topic of this.topics) { |
|
69 Services.obs.addObserver(this, topic, false); |
|
70 } |
|
71 |
|
72 addEventListener("activate", this); |
|
73 gNavToolbox.addEventListener("customizationstarting", this); |
|
74 gNavToolbox.addEventListener("customizationending", this); |
|
75 |
|
76 this._initialized = true; |
|
77 |
|
78 this.updateUI(); |
|
79 }, |
|
80 |
|
81 uninit: function () { |
|
82 if (!this._initialized) { |
|
83 return; |
|
84 } |
|
85 |
|
86 for (let topic of this.topics) { |
|
87 Services.obs.removeObserver(this, topic); |
|
88 } |
|
89 |
|
90 this._initialized = false; |
|
91 }, |
|
92 |
|
93 observe: function (subject, topic) { |
|
94 switch (topic) { |
|
95 case FxAccountsCommon.ONVERIFIED_NOTIFICATION: |
|
96 Services.prefs.setBoolPref(PREF_SYNC_START_DOORHANGER, true); |
|
97 break; |
|
98 case "weave:service:sync:start": |
|
99 this.onSyncStart(); |
|
100 break; |
|
101 default: |
|
102 this.updateUI(); |
|
103 break; |
|
104 } |
|
105 }, |
|
106 |
|
107 onSyncStart: function () { |
|
108 if (!this.isActiveWindow) { |
|
109 return; |
|
110 } |
|
111 |
|
112 let showDoorhanger = false; |
|
113 |
|
114 try { |
|
115 showDoorhanger = Services.prefs.getBoolPref(PREF_SYNC_START_DOORHANGER); |
|
116 } catch (e) { /* The pref might not exist. */ } |
|
117 |
|
118 if (showDoorhanger) { |
|
119 Services.prefs.clearUserPref(PREF_SYNC_START_DOORHANGER); |
|
120 this.showSyncStartedDoorhanger(); |
|
121 } |
|
122 }, |
|
123 |
|
124 handleEvent: function (event) { |
|
125 if (event.type == "activate") { |
|
126 // Our window might have been in the background while we received the |
|
127 // sync:start notification. If still needed, show the doorhanger after |
|
128 // a short delay. Without this delay the doorhanger would not show up |
|
129 // or with a too small delay show up while we're still animating the |
|
130 // window. |
|
131 setTimeout(() => this.onSyncStart(), DOORHANGER_ACTIVATE_DELAY_MS); |
|
132 } else { |
|
133 this._inCustomizationMode = event.type == "customizationstarting"; |
|
134 this.updateUI(); |
|
135 } |
|
136 }, |
|
137 |
|
138 showDoorhanger: function (id) { |
|
139 let panel = document.getElementById(id); |
|
140 let anchor = document.getElementById("PanelUI-menu-button"); |
|
141 |
|
142 let iconAnchor = |
|
143 document.getAnonymousElementByAttribute(anchor, "class", |
|
144 "toolbarbutton-icon"); |
|
145 |
|
146 panel.hidden = false; |
|
147 panel.openPopup(iconAnchor || anchor, "bottomcenter topright"); |
|
148 }, |
|
149 |
|
150 showSyncStartedDoorhanger: function () { |
|
151 this.showDoorhanger("sync-start-panel"); |
|
152 }, |
|
153 |
|
154 showSyncFailedDoorhanger: function () { |
|
155 this.showDoorhanger("sync-error-panel"); |
|
156 }, |
|
157 |
|
158 updateUI: function () { |
|
159 // Bail out if FxA is disabled. |
|
160 if (!this.weave.fxAccountsEnabled) { |
|
161 return; |
|
162 } |
|
163 |
|
164 // FxA is enabled, show the widget. |
|
165 this.button.removeAttribute("hidden"); |
|
166 |
|
167 // Make sure the button is disabled in customization mode. |
|
168 if (this._inCustomizationMode) { |
|
169 this.button.setAttribute("disabled", "true"); |
|
170 } else { |
|
171 this.button.removeAttribute("disabled"); |
|
172 } |
|
173 |
|
174 let defaultLabel = this.button.getAttribute("defaultlabel"); |
|
175 let errorLabel = this.button.getAttribute("errorlabel"); |
|
176 |
|
177 // If the user is signed into their Firefox account and we are not |
|
178 // currently in customization mode, show their email address. |
|
179 let doUpdate = userData => { |
|
180 // Reset the button to its original state. |
|
181 this.button.setAttribute("label", defaultLabel); |
|
182 this.button.removeAttribute("tooltiptext"); |
|
183 this.button.removeAttribute("signedin"); |
|
184 this.button.removeAttribute("failed"); |
|
185 |
|
186 if (!this._inCustomizationMode) { |
|
187 if (this.loginFailed) { |
|
188 this.button.setAttribute("failed", "true"); |
|
189 this.button.setAttribute("label", errorLabel); |
|
190 } else if (userData) { |
|
191 this.button.setAttribute("signedin", "true"); |
|
192 this.button.setAttribute("label", userData.email); |
|
193 this.button.setAttribute("tooltiptext", userData.email); |
|
194 } |
|
195 } |
|
196 } |
|
197 fxAccounts.getSignedInUser().then(userData => { |
|
198 doUpdate(userData); |
|
199 }).then(null, error => { |
|
200 // This is most likely in tests, were we quickly log users in and out. |
|
201 // The most likely scenario is a user logged out, so reflect that. |
|
202 // Bug 995134 calls for better errors so we could retry if we were |
|
203 // sure this was the failure reason. |
|
204 doUpdate(null); |
|
205 }); |
|
206 }, |
|
207 |
|
208 onMenuPanelCommand: function (event) { |
|
209 let button = event.originalTarget; |
|
210 |
|
211 if (button.hasAttribute("signedin")) { |
|
212 this.openPreferences(); |
|
213 } else if (button.hasAttribute("failed")) { |
|
214 this.openSignInAgainPage(); |
|
215 } else { |
|
216 this.openAccountsPage(); |
|
217 } |
|
218 |
|
219 PanelUI.hide(); |
|
220 }, |
|
221 |
|
222 openPreferences: function () { |
|
223 openPreferences("paneSync"); |
|
224 }, |
|
225 |
|
226 openAccountsPage: function () { |
|
227 switchToTabHavingURI("about:accounts", true); |
|
228 }, |
|
229 |
|
230 openSignInAgainPage: function () { |
|
231 switchToTabHavingURI("about:accounts?action=reauth", true); |
|
232 } |
|
233 }; |