|
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 // Progress heartbeat timer duration (ms) |
|
6 const kHeartbeatDuration = 1000; |
|
7 // Start and end progress screen css margins as percentages |
|
8 const kProgressMarginStart = 30; |
|
9 const kProgressMarginEnd = 70; |
|
10 |
|
11 const WebProgress = { |
|
12 get _identityBox() { return document.getElementById("identity-box"); }, |
|
13 |
|
14 init: function init() { |
|
15 messageManager.addMessageListener("Content:StateChange", this); |
|
16 messageManager.addMessageListener("Content:LocationChange", this); |
|
17 messageManager.addMessageListener("Content:SecurityChange", this); |
|
18 |
|
19 Elements.progress.addEventListener("transitionend", this, true); |
|
20 Elements.tabList.addEventListener("TabSelect", this, true); |
|
21 |
|
22 let urlBar = document.getElementById("urlbar-edit"); |
|
23 urlBar.addEventListener("input", this, false); |
|
24 |
|
25 return this; |
|
26 }, |
|
27 |
|
28 receiveMessage: function receiveMessage(aMessage) { |
|
29 let json = aMessage.json; |
|
30 let tab = Browser.getTabForBrowser(aMessage.target); |
|
31 |
|
32 switch (aMessage.name) { |
|
33 case "Content:StateChange": { |
|
34 if (json.stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) { |
|
35 if (json.stateFlags & Ci.nsIWebProgressListener.STATE_START) |
|
36 this._windowStart(json, tab); |
|
37 else if (json.stateFlags & Ci.nsIWebProgressListener.STATE_STOP) |
|
38 this._windowStop(json, tab); |
|
39 } |
|
40 |
|
41 if (json.stateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) { |
|
42 if (json.stateFlags & Ci.nsIWebProgressListener.STATE_START) |
|
43 this._networkStart(json, tab); |
|
44 else if (json.stateFlags & Ci.nsIWebProgressListener.STATE_STOP) |
|
45 this._networkStop(json, tab); |
|
46 } |
|
47 |
|
48 this._progressStep(tab); |
|
49 break; |
|
50 } |
|
51 |
|
52 case "Content:LocationChange": { |
|
53 this._locationChange(json, tab); |
|
54 this._progressStep(tab); |
|
55 break; |
|
56 } |
|
57 |
|
58 case "Content:SecurityChange": { |
|
59 this._securityChange(json, tab); |
|
60 this._progressStep(tab); |
|
61 break; |
|
62 } |
|
63 } |
|
64 }, |
|
65 |
|
66 handleEvent: function handleEvent(aEvent) { |
|
67 switch (aEvent.type) { |
|
68 case "transitionend": |
|
69 this._progressTransEnd(aEvent); |
|
70 break; |
|
71 case "TabSelect": |
|
72 this._onTabSelect(aEvent); |
|
73 break; |
|
74 case "input": |
|
75 this._onUrlBarInput(aEvent); |
|
76 break; |
|
77 } |
|
78 }, |
|
79 |
|
80 _securityChange: function _securityChange(aJson, aTab) { |
|
81 let state = aJson.state; |
|
82 let nsIWebProgressListener = Ci.nsIWebProgressListener; |
|
83 |
|
84 if (state & nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL) { |
|
85 aTab._identityState = "verifiedIdentity"; |
|
86 } else if (state & nsIWebProgressListener.STATE_IS_SECURE) { |
|
87 aTab._identityState = "verifiedDomain"; |
|
88 } else { |
|
89 aTab._identityState = ""; |
|
90 } |
|
91 |
|
92 if (aTab == Browser.selectedTab) { |
|
93 this._identityBox.className = aTab._identityState; |
|
94 } |
|
95 }, |
|
96 |
|
97 _locationChange: function _locationChange(aJson, aTab) { |
|
98 let spec = aJson.location; |
|
99 let location = spec.split("#")[0]; // Ignore fragment identifier changes. |
|
100 |
|
101 if (aTab == Browser.selectedTab) { |
|
102 BrowserUI.updateURI(); |
|
103 BrowserUI.update(); |
|
104 BrowserUI.updateStartURIAttributes(aJson.location); |
|
105 } |
|
106 |
|
107 let locationHasChanged = (location != aTab.browser.lastLocation); |
|
108 if (locationHasChanged) { |
|
109 Browser.getNotificationBox(aTab.browser).removeTransientNotifications(); |
|
110 aTab.browser.lastLocation = location; |
|
111 aTab.browser.userTypedValue = ""; |
|
112 aTab.browser.appIcon = { href: null, size:-1 }; |
|
113 |
|
114 #ifdef MOZ_CRASHREPORTER |
|
115 if (CrashReporter.enabled) |
|
116 CrashReporter.annotateCrashReport("URL", spec); |
|
117 #endif |
|
118 } |
|
119 |
|
120 let event = document.createEvent("UIEvents"); |
|
121 event.initUIEvent("URLChanged", true, false, window, locationHasChanged); |
|
122 aTab.browser.dispatchEvent(event); |
|
123 }, |
|
124 |
|
125 _networkStart: function _networkStart(aJson, aTab) { |
|
126 aTab.startLoading(); |
|
127 |
|
128 if (aTab == Browser.selectedTab) { |
|
129 // NO_STARTUI_VISIBILITY since the current uri for the tab has not |
|
130 // been updated yet. If we're coming off of the start page, this |
|
131 // would briefly show StartUI until _locationChange is called. |
|
132 BrowserUI.update(BrowserUI.NO_STARTUI_VISIBILITY); |
|
133 } |
|
134 }, |
|
135 |
|
136 _networkStop: function _networkStop(aJson, aTab) { |
|
137 aTab.endLoading(); |
|
138 |
|
139 if (aTab == Browser.selectedTab) { |
|
140 BrowserUI.update(); |
|
141 } |
|
142 }, |
|
143 |
|
144 _windowStart: function _windowStart(aJson, aTab) { |
|
145 this._progressStart(aJson, aTab); |
|
146 }, |
|
147 |
|
148 _windowStop: function _windowStop(aJson, aTab) { |
|
149 this._progressStop(aJson, aTab); |
|
150 }, |
|
151 |
|
152 _progressStart: function _progressStart(aJson, aTab) { |
|
153 // We will get multiple calls from _windowStart, so |
|
154 // only process once. |
|
155 if (aTab._progressActive) |
|
156 return; |
|
157 |
|
158 aTab._progressActive = true; |
|
159 |
|
160 // 'Whoosh' in |
|
161 aTab._progressCount = kProgressMarginStart; |
|
162 this._showProgressBar(aTab); |
|
163 }, |
|
164 |
|
165 _showProgressBar: function (aTab) { |
|
166 // display the track |
|
167 if (aTab == Browser.selectedTab) { |
|
168 Elements.progressContainer.removeAttribute("collapsed"); |
|
169 Elements.progress.style.width = aTab._progressCount + "%"; |
|
170 Elements.progress.removeAttribute("fade"); |
|
171 } |
|
172 |
|
173 // Create a pulse timer to keep things moving even if we don't |
|
174 // collect any state changes. |
|
175 setTimeout(function() { |
|
176 WebProgress._progressStepTimer(aTab); |
|
177 }, kHeartbeatDuration, this); |
|
178 }, |
|
179 |
|
180 _stepProgressCount: function _stepProgressCount(aTab) { |
|
181 // Step toward the end margin in smaller slices as we get closer |
|
182 let left = kProgressMarginEnd - aTab._progressCount; |
|
183 let step = left * .05; |
|
184 aTab._progressCount += Math.ceil(step); |
|
185 |
|
186 // Don't go past the 'whoosh out' margin. |
|
187 if (aTab._progressCount > kProgressMarginEnd) { |
|
188 aTab._progressCount = kProgressMarginEnd; |
|
189 } |
|
190 }, |
|
191 |
|
192 _progressStep: function _progressStep(aTab) { |
|
193 if (!aTab._progressActive) |
|
194 return; |
|
195 this._stepProgressCount(aTab); |
|
196 if (aTab == Browser.selectedTab) { |
|
197 Elements.progress.style.width = aTab._progressCount + "%"; |
|
198 } |
|
199 }, |
|
200 |
|
201 _progressStepTimer: function _progressStepTimer(aTab) { |
|
202 if (!aTab._progressActive) |
|
203 return; |
|
204 this._progressStep(aTab); |
|
205 |
|
206 setTimeout(function() { |
|
207 WebProgress._progressStepTimer(aTab); |
|
208 }, kHeartbeatDuration, this); |
|
209 }, |
|
210 |
|
211 _progressStop: function _progressStop(aJson, aTab) { |
|
212 aTab._progressActive = false; |
|
213 // 'Whoosh out' and fade |
|
214 if (aTab == Browser.selectedTab) { |
|
215 Elements.progress.style.width = "100%"; |
|
216 Elements.progress.setAttribute("fade", true); |
|
217 } |
|
218 }, |
|
219 |
|
220 _progressTransEnd: function _progressTransEnd(aEvent) { |
|
221 if (!Elements.progress.hasAttribute("fade")) |
|
222 return; |
|
223 // Close out fade finished, reset |
|
224 if (aEvent.propertyName == "opacity") { |
|
225 Elements.progress.style.width = "0px"; |
|
226 Elements.progressContainer.setAttribute("collapsed", true); |
|
227 } |
|
228 }, |
|
229 |
|
230 _onTabSelect: function(aEvent) { |
|
231 let tab = Browser.getTabFromChrome(aEvent.originalTarget); |
|
232 this._identityBox.className = tab._identityState || ""; |
|
233 if (tab._progressActive) { |
|
234 this._showProgressBar(tab); |
|
235 } else { |
|
236 Elements.progress.setAttribute("fade", true); |
|
237 Elements.progressContainer.setAttribute("collapsed", true); |
|
238 } |
|
239 }, |
|
240 |
|
241 _onUrlBarInput: function(aEvent) { |
|
242 Browser.selectedTab._identityState = this._identityBox.className = ""; |
|
243 }, |
|
244 }; |