Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | "use strict"; |
michael@0 | 6 | |
michael@0 | 7 | Cu.import("resource://gre/modules/devtools/dbg-server.jsm") |
michael@0 | 8 | Cu.import("resource://gre/modules/WindowsPrefSync.jsm"); |
michael@0 | 9 | |
michael@0 | 10 | /** |
michael@0 | 11 | * Constants |
michael@0 | 12 | */ |
michael@0 | 13 | |
michael@0 | 14 | // Devtools Messages |
michael@0 | 15 | const debugServerStateChanged = "devtools.debugger.remote-enabled"; |
michael@0 | 16 | const debugServerPortChanged = "devtools.debugger.remote-port"; |
michael@0 | 17 | |
michael@0 | 18 | // delay when showing the tab bar briefly after a new foreground tab opens |
michael@0 | 19 | const kForegroundTabAnimationDelay = 1000; |
michael@0 | 20 | // delay when showing the tab bar after opening a new background tab opens |
michael@0 | 21 | const kBackgroundTabAnimationDelay = 3000; |
michael@0 | 22 | // delay before closing tab bar after closing or selecting a tab |
michael@0 | 23 | const kChangeTabAnimationDelay = 500; |
michael@0 | 24 | |
michael@0 | 25 | /** |
michael@0 | 26 | * Cache of commonly used elements. |
michael@0 | 27 | */ |
michael@0 | 28 | |
michael@0 | 29 | let Elements = {}; |
michael@0 | 30 | [ |
michael@0 | 31 | ["contentShowing", "bcast_contentShowing"], |
michael@0 | 32 | ["urlbarState", "bcast_urlbarState"], |
michael@0 | 33 | ["loadingState", "bcast_loadingState"], |
michael@0 | 34 | ["windowState", "bcast_windowState"], |
michael@0 | 35 | ["chromeState", "bcast_chromeState"], |
michael@0 | 36 | ["mainKeyset", "mainKeyset"], |
michael@0 | 37 | ["stack", "stack"], |
michael@0 | 38 | ["tabList", "tabs"], |
michael@0 | 39 | ["tabs", "tabs-container"], |
michael@0 | 40 | ["controls", "browser-controls"], |
michael@0 | 41 | ["panelUI", "panel-container"], |
michael@0 | 42 | ["tray", "tray"], |
michael@0 | 43 | ["toolbar", "toolbar"], |
michael@0 | 44 | ["browsers", "browsers"], |
michael@0 | 45 | ["navbar", "navbar"], |
michael@0 | 46 | ["autocomplete", "urlbar-autocomplete"], |
michael@0 | 47 | ["contextappbar", "contextappbar"], |
michael@0 | 48 | ["findbar", "findbar"], |
michael@0 | 49 | ["contentViewport", "content-viewport"], |
michael@0 | 50 | ["progress", "progress-control"], |
michael@0 | 51 | ["progressContainer", "progress-container"], |
michael@0 | 52 | ["feedbackLabel", "feedback-label"], |
michael@0 | 53 | ].forEach(function (aElementGlobal) { |
michael@0 | 54 | let [name, id] = aElementGlobal; |
michael@0 | 55 | XPCOMUtils.defineLazyGetter(Elements, name, function() { |
michael@0 | 56 | return document.getElementById(id); |
michael@0 | 57 | }); |
michael@0 | 58 | }); |
michael@0 | 59 | |
michael@0 | 60 | /** |
michael@0 | 61 | * Cache of commonly used string bundles. |
michael@0 | 62 | */ |
michael@0 | 63 | |
michael@0 | 64 | var Strings = {}; |
michael@0 | 65 | [ |
michael@0 | 66 | ["browser", "chrome://browser/locale/browser.properties"], |
michael@0 | 67 | ["brand", "chrome://branding/locale/brand.properties"] |
michael@0 | 68 | ].forEach(function (aStringBundle) { |
michael@0 | 69 | let [name, bundle] = aStringBundle; |
michael@0 | 70 | XPCOMUtils.defineLazyGetter(Strings, name, function() { |
michael@0 | 71 | return Services.strings.createBundle(bundle); |
michael@0 | 72 | }); |
michael@0 | 73 | }); |
michael@0 | 74 | |
michael@0 | 75 | var BrowserUI = { |
michael@0 | 76 | get _edit() { return document.getElementById("urlbar-edit"); }, |
michael@0 | 77 | get _back() { return document.getElementById("cmd_back"); }, |
michael@0 | 78 | get _forward() { return document.getElementById("cmd_forward"); }, |
michael@0 | 79 | |
michael@0 | 80 | lastKnownGoodURL: "", // used when the user wants to escape unfinished url entry |
michael@0 | 81 | ready: false, // used for tests to determine when delayed initialization is done |
michael@0 | 82 | |
michael@0 | 83 | init: function() { |
michael@0 | 84 | // start the debugger now so we can use it on the startup code as well |
michael@0 | 85 | if (Services.prefs.getBoolPref(debugServerStateChanged)) { |
michael@0 | 86 | this.runDebugServer(); |
michael@0 | 87 | } |
michael@0 | 88 | Services.prefs.addObserver(debugServerStateChanged, this, false); |
michael@0 | 89 | Services.prefs.addObserver(debugServerPortChanged, this, false); |
michael@0 | 90 | Services.prefs.addObserver("app.crashreporter.autosubmit", this, false); |
michael@0 | 91 | Services.prefs.addObserver("metro.private_browsing.enabled", this, false); |
michael@0 | 92 | this.updatePrivateBrowsingUI(); |
michael@0 | 93 | |
michael@0 | 94 | Services.obs.addObserver(this, "handle-xul-text-link", false); |
michael@0 | 95 | |
michael@0 | 96 | // listen content messages |
michael@0 | 97 | messageManager.addMessageListener("DOMTitleChanged", this); |
michael@0 | 98 | messageManager.addMessageListener("DOMWillOpenModalDialog", this); |
michael@0 | 99 | messageManager.addMessageListener("DOMWindowClose", this); |
michael@0 | 100 | |
michael@0 | 101 | messageManager.addMessageListener("Browser:OpenURI", this); |
michael@0 | 102 | messageManager.addMessageListener("Browser:SaveAs:Return", this); |
michael@0 | 103 | messageManager.addMessageListener("Content:StateChange", this); |
michael@0 | 104 | |
michael@0 | 105 | // listening escape to dismiss dialog on VK_ESCAPE |
michael@0 | 106 | window.addEventListener("keypress", this, true); |
michael@0 | 107 | |
michael@0 | 108 | window.addEventListener("MozPrecisePointer", this, true); |
michael@0 | 109 | window.addEventListener("MozImprecisePointer", this, true); |
michael@0 | 110 | |
michael@0 | 111 | window.addEventListener("AppCommand", this, true); |
michael@0 | 112 | |
michael@0 | 113 | Services.prefs.addObserver("browser.cache.disk_cache_ssl", this, false); |
michael@0 | 114 | |
michael@0 | 115 | // Init core UI modules |
michael@0 | 116 | ContextUI.init(); |
michael@0 | 117 | PanelUI.init(); |
michael@0 | 118 | FlyoutPanelsUI.init(); |
michael@0 | 119 | PageThumbs.init(); |
michael@0 | 120 | NewTabUtils.init(); |
michael@0 | 121 | SettingsCharm.init(); |
michael@0 | 122 | NavButtonSlider.init(); |
michael@0 | 123 | SelectionHelperUI.init(); |
michael@0 | 124 | #ifdef NIGHTLY_BUILD |
michael@0 | 125 | ShumwayUtils.init(); |
michael@0 | 126 | #endif |
michael@0 | 127 | |
michael@0 | 128 | // We can delay some initialization until after startup. We wait until |
michael@0 | 129 | // the first page is shown, then dispatch a UIReadyDelayed event. |
michael@0 | 130 | messageManager.addMessageListener("pageshow", function onPageShow() { |
michael@0 | 131 | if (getBrowser().currentURI.spec == "about:blank") |
michael@0 | 132 | return; |
michael@0 | 133 | |
michael@0 | 134 | messageManager.removeMessageListener("pageshow", onPageShow); |
michael@0 | 135 | |
michael@0 | 136 | setTimeout(function() { |
michael@0 | 137 | let event = document.createEvent("Events"); |
michael@0 | 138 | event.initEvent("UIReadyDelayed", true, false); |
michael@0 | 139 | window.dispatchEvent(event); |
michael@0 | 140 | BrowserUI.ready = true; |
michael@0 | 141 | }, 0); |
michael@0 | 142 | }); |
michael@0 | 143 | |
michael@0 | 144 | // Only load IndexedDB.js when we actually need it. A general fix will happen in bug 647079. |
michael@0 | 145 | messageManager.addMessageListener("IndexedDB:Prompt", function(aMessage) { |
michael@0 | 146 | return IndexedDB.receiveMessage(aMessage); |
michael@0 | 147 | }); |
michael@0 | 148 | |
michael@0 | 149 | // hook up telemetry ping for UI data |
michael@0 | 150 | try { |
michael@0 | 151 | UITelemetry.addSimpleMeasureFunction("metro-ui", |
michael@0 | 152 | BrowserUI._getMeasures.bind(BrowserUI)); |
michael@0 | 153 | } catch (ex) { |
michael@0 | 154 | // swallow exception that occurs if metro-appbar measure is already set up |
michael@0 | 155 | dump("Failed to addSimpleMeasureFunction in browser-ui: " + ex.message + "\n"); |
michael@0 | 156 | } |
michael@0 | 157 | |
michael@0 | 158 | // Delay the panel UI and Sync initialization |
michael@0 | 159 | window.addEventListener("UIReadyDelayed", function delayedInit(aEvent) { |
michael@0 | 160 | Util.dumpLn("* delay load started..."); |
michael@0 | 161 | window.removeEventListener("UIReadyDelayed", delayedInit, false); |
michael@0 | 162 | |
michael@0 | 163 | // Login Manager and Form History initialization |
michael@0 | 164 | Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); |
michael@0 | 165 | messageManager.addMessageListener("Browser:MozApplicationManifest", OfflineApps); |
michael@0 | 166 | |
michael@0 | 167 | try { |
michael@0 | 168 | MetroDownloadsView.init(); |
michael@0 | 169 | DialogUI.init(); |
michael@0 | 170 | FormHelperUI.init(); |
michael@0 | 171 | FindHelperUI.init(); |
michael@0 | 172 | #ifdef NIGHTLY_BUILD |
michael@0 | 173 | PdfJs.init(); |
michael@0 | 174 | #endif |
michael@0 | 175 | } catch(ex) { |
michael@0 | 176 | Util.dumpLn("Exception in delay load module:", ex.message); |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | BrowserUI._initFirstRunContent(); |
michael@0 | 180 | |
michael@0 | 181 | // check for left over crash reports and submit them if found. |
michael@0 | 182 | BrowserUI.startupCrashCheck(); |
michael@0 | 183 | |
michael@0 | 184 | Util.dumpLn("* delay load complete."); |
michael@0 | 185 | }, false); |
michael@0 | 186 | |
michael@0 | 187 | #ifndef MOZ_OFFICIAL_BRANDING |
michael@0 | 188 | setTimeout(function() { |
michael@0 | 189 | let startup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).getStartupInfo(); |
michael@0 | 190 | for (let name in startup) { |
michael@0 | 191 | if (name != "process") |
michael@0 | 192 | Services.console.logStringMessage("[timing] " + name + ": " + (startup[name] - startup.process) + "ms"); |
michael@0 | 193 | } |
michael@0 | 194 | }, 3000); |
michael@0 | 195 | #endif |
michael@0 | 196 | }, |
michael@0 | 197 | |
michael@0 | 198 | uninit: function() { |
michael@0 | 199 | messageManager.removeMessageListener("DOMTitleChanged", this); |
michael@0 | 200 | messageManager.removeMessageListener("DOMWillOpenModalDialog", this); |
michael@0 | 201 | messageManager.removeMessageListener("DOMWindowClose", this); |
michael@0 | 202 | |
michael@0 | 203 | messageManager.removeMessageListener("Browser:OpenURI", this); |
michael@0 | 204 | messageManager.removeMessageListener("Browser:SaveAs:Return", this); |
michael@0 | 205 | messageManager.removeMessageListener("Content:StateChange", this); |
michael@0 | 206 | |
michael@0 | 207 | messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps); |
michael@0 | 208 | |
michael@0 | 209 | Services.prefs.removeObserver(debugServerStateChanged, this); |
michael@0 | 210 | Services.prefs.removeObserver(debugServerPortChanged, this); |
michael@0 | 211 | Services.prefs.removeObserver("app.crashreporter.autosubmit", this); |
michael@0 | 212 | Services.prefs.removeObserver("metro.private_browsing.enabled", this); |
michael@0 | 213 | |
michael@0 | 214 | Services.obs.removeObserver(this, "handle-xul-text-link"); |
michael@0 | 215 | |
michael@0 | 216 | PanelUI.uninit(); |
michael@0 | 217 | FlyoutPanelsUI.uninit(); |
michael@0 | 218 | MetroDownloadsView.uninit(); |
michael@0 | 219 | SettingsCharm.uninit(); |
michael@0 | 220 | PageThumbs.uninit(); |
michael@0 | 221 | if (WindowsPrefSync) { |
michael@0 | 222 | WindowsPrefSync.uninit(); |
michael@0 | 223 | } |
michael@0 | 224 | this.stopDebugServer(); |
michael@0 | 225 | }, |
michael@0 | 226 | |
michael@0 | 227 | /************************************ |
michael@0 | 228 | * Devtools Debugger |
michael@0 | 229 | */ |
michael@0 | 230 | runDebugServer: function runDebugServer(aPort) { |
michael@0 | 231 | let port = aPort || Services.prefs.getIntPref(debugServerPortChanged); |
michael@0 | 232 | if (!DebuggerServer.initialized) { |
michael@0 | 233 | DebuggerServer.init(); |
michael@0 | 234 | DebuggerServer.addBrowserActors(); |
michael@0 | 235 | DebuggerServer.addActors('chrome://browser/content/dbg-metro-actors.js'); |
michael@0 | 236 | } |
michael@0 | 237 | DebuggerServer.openListener(port); |
michael@0 | 238 | }, |
michael@0 | 239 | |
michael@0 | 240 | stopDebugServer: function stopDebugServer() { |
michael@0 | 241 | if (DebuggerServer.initialized) { |
michael@0 | 242 | DebuggerServer.destroy(); |
michael@0 | 243 | } |
michael@0 | 244 | }, |
michael@0 | 245 | |
michael@0 | 246 | // If the server is not on, port changes have nothing to effect. The new value |
michael@0 | 247 | // will be picked up if the server is started. |
michael@0 | 248 | // To be consistent with desktop fx, if the port is changed while the server |
michael@0 | 249 | // is running, restart server. |
michael@0 | 250 | changeDebugPort:function changeDebugPort(aPort) { |
michael@0 | 251 | if (DebuggerServer.initialized) { |
michael@0 | 252 | this.stopDebugServer(); |
michael@0 | 253 | this.runDebugServer(aPort); |
michael@0 | 254 | } |
michael@0 | 255 | }, |
michael@0 | 256 | |
michael@0 | 257 | /********************************* |
michael@0 | 258 | * Content visibility |
michael@0 | 259 | */ |
michael@0 | 260 | |
michael@0 | 261 | get isContentShowing() { |
michael@0 | 262 | return Elements.contentShowing.getAttribute("disabled") != true; |
michael@0 | 263 | }, |
michael@0 | 264 | |
michael@0 | 265 | showContent: function showContent(aURI) { |
michael@0 | 266 | ContextUI.dismissTabs(); |
michael@0 | 267 | ContextUI.dismissContextAppbar(); |
michael@0 | 268 | FlyoutPanelsUI.hide(); |
michael@0 | 269 | PanelUI.hide(); |
michael@0 | 270 | }, |
michael@0 | 271 | |
michael@0 | 272 | /********************************* |
michael@0 | 273 | * Crash reporting |
michael@0 | 274 | */ |
michael@0 | 275 | |
michael@0 | 276 | get CrashSubmit() { |
michael@0 | 277 | delete this.CrashSubmit; |
michael@0 | 278 | Cu.import("resource://gre/modules/CrashSubmit.jsm", this); |
michael@0 | 279 | return this.CrashSubmit; |
michael@0 | 280 | }, |
michael@0 | 281 | |
michael@0 | 282 | get lastCrashID() { |
michael@0 | 283 | return Cc["@mozilla.org/xre/runtime;1"].getService(Ci.nsIXULRuntime).lastRunCrashID; |
michael@0 | 284 | }, |
michael@0 | 285 | |
michael@0 | 286 | startupCrashCheck: function startupCrashCheck() { |
michael@0 | 287 | #ifdef MOZ_CRASHREPORTER |
michael@0 | 288 | if (!CrashReporter.enabled) { |
michael@0 | 289 | return; |
michael@0 | 290 | } |
michael@0 | 291 | |
michael@0 | 292 | // Ensure that CrashReporter state matches pref |
michael@0 | 293 | CrashReporter.submitReports = Services.prefs.getBoolPref("app.crashreporter.autosubmit"); |
michael@0 | 294 | |
michael@0 | 295 | BrowserUI.submitLastCrashReportOrShowPrompt(); |
michael@0 | 296 | #endif |
michael@0 | 297 | }, |
michael@0 | 298 | |
michael@0 | 299 | |
michael@0 | 300 | /********************************* |
michael@0 | 301 | * Navigation |
michael@0 | 302 | */ |
michael@0 | 303 | |
michael@0 | 304 | // BrowserUI update bit flags |
michael@0 | 305 | NO_STARTUI_VISIBILITY: 1, // don't change the start ui visibility |
michael@0 | 306 | |
michael@0 | 307 | /* |
michael@0 | 308 | * Updates the overall state of startui visibility and the toolbar, but not |
michael@0 | 309 | * the URL bar. |
michael@0 | 310 | */ |
michael@0 | 311 | update: function(aFlags) { |
michael@0 | 312 | let flags = aFlags || 0; |
michael@0 | 313 | if (!(flags & this.NO_STARTUI_VISIBILITY)) { |
michael@0 | 314 | let uri = this.getDisplayURI(Browser.selectedBrowser); |
michael@0 | 315 | this.updateStartURIAttributes(uri); |
michael@0 | 316 | } |
michael@0 | 317 | this._updateButtons(); |
michael@0 | 318 | this._updateToolbar(); |
michael@0 | 319 | }, |
michael@0 | 320 | |
michael@0 | 321 | /* Updates the URL bar. */ |
michael@0 | 322 | updateURI: function(aOptions) { |
michael@0 | 323 | let uri = this.getDisplayURI(Browser.selectedBrowser); |
michael@0 | 324 | let cleanURI = Util.isURLEmpty(uri) ? "" : uri; |
michael@0 | 325 | this._edit.value = cleanURI; |
michael@0 | 326 | }, |
michael@0 | 327 | |
michael@0 | 328 | get isStartTabVisible() { |
michael@0 | 329 | return this.isStartURI(); |
michael@0 | 330 | }, |
michael@0 | 331 | |
michael@0 | 332 | isStartURI: function isStartURI(aURI) { |
michael@0 | 333 | aURI = aURI || Browser.selectedBrowser.currentURI.spec; |
michael@0 | 334 | return aURI.startsWith(kStartURI) || aURI == "about:start" || aURI == "about:home"; |
michael@0 | 335 | }, |
michael@0 | 336 | |
michael@0 | 337 | updateStartURIAttributes: function (aURI) { |
michael@0 | 338 | let wasStart = Elements.windowState.hasAttribute("startpage"); |
michael@0 | 339 | aURI = aURI || Browser.selectedBrowser.currentURI.spec; |
michael@0 | 340 | if (this.isStartURI(aURI)) { |
michael@0 | 341 | ContextUI.displayNavbar(); |
michael@0 | 342 | Elements.windowState.setAttribute("startpage", "true"); |
michael@0 | 343 | } else if (aURI != "about:blank") { // about:blank is loaded briefly for new tabs; ignore it |
michael@0 | 344 | Elements.windowState.removeAttribute("startpage"); |
michael@0 | 345 | } |
michael@0 | 346 | |
michael@0 | 347 | let isStart = Elements.windowState.hasAttribute("startpage"); |
michael@0 | 348 | if (wasStart != isStart) { |
michael@0 | 349 | let event = document.createEvent("Events"); |
michael@0 | 350 | event.initEvent("StartUIChange", true, true); |
michael@0 | 351 | Browser.selectedBrowser.dispatchEvent(event); |
michael@0 | 352 | } |
michael@0 | 353 | }, |
michael@0 | 354 | |
michael@0 | 355 | getDisplayURI: function(browser) { |
michael@0 | 356 | let uri = browser.currentURI; |
michael@0 | 357 | let spec = uri.spec; |
michael@0 | 358 | |
michael@0 | 359 | try { |
michael@0 | 360 | spec = gURIFixup.createExposableURI(uri).spec; |
michael@0 | 361 | } catch (ex) {} |
michael@0 | 362 | |
michael@0 | 363 | try { |
michael@0 | 364 | let charset = browser.characterSet; |
michael@0 | 365 | let textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"]. |
michael@0 | 366 | getService(Ci.nsITextToSubURI); |
michael@0 | 367 | spec = textToSubURI.unEscapeNonAsciiURI(charset, spec); |
michael@0 | 368 | } catch (ex) {} |
michael@0 | 369 | |
michael@0 | 370 | return spec; |
michael@0 | 371 | }, |
michael@0 | 372 | |
michael@0 | 373 | goToURI: function(aURI) { |
michael@0 | 374 | aURI = aURI || this._edit.value; |
michael@0 | 375 | if (!aURI) |
michael@0 | 376 | return; |
michael@0 | 377 | |
michael@0 | 378 | this._edit.value = aURI; |
michael@0 | 379 | |
michael@0 | 380 | // Make sure we're online before attempting to load |
michael@0 | 381 | Util.forceOnline(); |
michael@0 | 382 | |
michael@0 | 383 | BrowserUI.showContent(aURI); |
michael@0 | 384 | Browser.selectedBrowser.focus(); |
michael@0 | 385 | |
michael@0 | 386 | Task.spawn(function() { |
michael@0 | 387 | let postData = {}; |
michael@0 | 388 | let webNav = Ci.nsIWebNavigation; |
michael@0 | 389 | let flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP | |
michael@0 | 390 | webNav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS; |
michael@0 | 391 | aURI = yield Browser.getShortcutOrURI(aURI, postData); |
michael@0 | 392 | Browser.loadURI(aURI, { flags: flags, postData: postData }); |
michael@0 | 393 | |
michael@0 | 394 | // Delay doing the fixup so the raw URI is passed to loadURIWithFlags |
michael@0 | 395 | // and the proper third-party fixup can be done |
michael@0 | 396 | let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP | |
michael@0 | 397 | Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS; |
michael@0 | 398 | let uri = gURIFixup.createFixupURI(aURI, fixupFlags); |
michael@0 | 399 | gHistSvc.markPageAsTyped(uri); |
michael@0 | 400 | |
michael@0 | 401 | BrowserUI._titleChanged(Browser.selectedBrowser); |
michael@0 | 402 | }); |
michael@0 | 403 | }, |
michael@0 | 404 | |
michael@0 | 405 | doOpenSearch: function doOpenSearch(aName) { |
michael@0 | 406 | // save the current value of the urlbar |
michael@0 | 407 | let searchValue = this._edit.value; |
michael@0 | 408 | let engine = Services.search.getEngineByName(aName); |
michael@0 | 409 | let submission = engine.getSubmission(searchValue, null); |
michael@0 | 410 | |
michael@0 | 411 | this._edit.value = submission.uri.spec; |
michael@0 | 412 | |
michael@0 | 413 | // Make sure we're online before attempting to load |
michael@0 | 414 | Util.forceOnline(); |
michael@0 | 415 | |
michael@0 | 416 | BrowserUI.showContent(); |
michael@0 | 417 | Browser.selectedBrowser.focus(); |
michael@0 | 418 | |
michael@0 | 419 | Task.spawn(function () { |
michael@0 | 420 | Browser.loadURI(submission.uri.spec, { postData: submission.postData }); |
michael@0 | 421 | |
michael@0 | 422 | // loadURI may open a new tab, so get the selectedBrowser afterward. |
michael@0 | 423 | Browser.selectedBrowser.userTypedValue = submission.uri.spec; |
michael@0 | 424 | BrowserUI._titleChanged(Browser.selectedBrowser); |
michael@0 | 425 | }); |
michael@0 | 426 | }, |
michael@0 | 427 | |
michael@0 | 428 | /********************************* |
michael@0 | 429 | * Tab management |
michael@0 | 430 | */ |
michael@0 | 431 | |
michael@0 | 432 | /** |
michael@0 | 433 | * Open a new tab in the foreground in response to a user action. |
michael@0 | 434 | * See Browser.addTab for more documentation. |
michael@0 | 435 | */ |
michael@0 | 436 | addAndShowTab: function (aURI, aOwner, aParams) { |
michael@0 | 437 | ContextUI.peekTabs(kForegroundTabAnimationDelay); |
michael@0 | 438 | return Browser.addTab(aURI || kStartURI, true, aOwner, aParams); |
michael@0 | 439 | }, |
michael@0 | 440 | |
michael@0 | 441 | addAndShowPrivateTab: function (aURI, aOwner) { |
michael@0 | 442 | return this.addAndShowTab(aURI, aOwner, { private: true }); |
michael@0 | 443 | }, |
michael@0 | 444 | |
michael@0 | 445 | get isPrivateBrowsingEnabled() { |
michael@0 | 446 | return Services.prefs.getBoolPref("metro.private_browsing.enabled"); |
michael@0 | 447 | }, |
michael@0 | 448 | |
michael@0 | 449 | updatePrivateBrowsingUI: function () { |
michael@0 | 450 | let command = document.getElementById("cmd_newPrivateTab"); |
michael@0 | 451 | if (this.isPrivateBrowsingEnabled) { |
michael@0 | 452 | command.removeAttribute("disabled"); |
michael@0 | 453 | } else { |
michael@0 | 454 | command.setAttribute("disabled", "true"); |
michael@0 | 455 | } |
michael@0 | 456 | }, |
michael@0 | 457 | |
michael@0 | 458 | /** |
michael@0 | 459 | * Open a new tab in response to clicking a link in an existing tab. |
michael@0 | 460 | * See Browser.addTab for more documentation. |
michael@0 | 461 | */ |
michael@0 | 462 | openLinkInNewTab: function (aURI, aBringFront, aOwner) { |
michael@0 | 463 | ContextUI.peekTabs(aBringFront ? kForegroundTabAnimationDelay |
michael@0 | 464 | : kBackgroundTabAnimationDelay); |
michael@0 | 465 | let params = null; |
michael@0 | 466 | if (aOwner) { |
michael@0 | 467 | params = { |
michael@0 | 468 | referrerURI: aOwner.browser.documentURI, |
michael@0 | 469 | charset: aOwner.browser.characterSet, |
michael@0 | 470 | }; |
michael@0 | 471 | } |
michael@0 | 472 | let tab = Browser.addTab(aURI, aBringFront, aOwner, params); |
michael@0 | 473 | Elements.tabList.strip.ensureElementIsVisible(tab.chromeTab); |
michael@0 | 474 | return tab; |
michael@0 | 475 | }, |
michael@0 | 476 | |
michael@0 | 477 | setOnTabAnimationEnd: function setOnTabAnimationEnd(aCallback) { |
michael@0 | 478 | Elements.tabs.addEventListener("animationend", function onAnimationEnd() { |
michael@0 | 479 | Elements.tabs.removeEventListener("animationend", onAnimationEnd); |
michael@0 | 480 | aCallback(); |
michael@0 | 481 | }); |
michael@0 | 482 | }, |
michael@0 | 483 | |
michael@0 | 484 | closeTab: function closeTab(aTab) { |
michael@0 | 485 | // If no tab is passed in, assume the current tab |
michael@0 | 486 | let tab = aTab || Browser.selectedTab; |
michael@0 | 487 | Browser.closeTab(tab); |
michael@0 | 488 | }, |
michael@0 | 489 | |
michael@0 | 490 | animateClosingTab: function animateClosingTab(tabToClose) { |
michael@0 | 491 | tabToClose.chromeTab.setAttribute("closing", "true"); |
michael@0 | 492 | |
michael@0 | 493 | let wasCollapsed = !ContextUI.tabbarVisible; |
michael@0 | 494 | if (wasCollapsed) { |
michael@0 | 495 | ContextUI.displayTabs(); |
michael@0 | 496 | } |
michael@0 | 497 | |
michael@0 | 498 | this.setOnTabAnimationEnd(function() { |
michael@0 | 499 | Browser.closeTab(tabToClose, { forceClose: true } ); |
michael@0 | 500 | if (wasCollapsed) |
michael@0 | 501 | ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay); |
michael@0 | 502 | }); |
michael@0 | 503 | }, |
michael@0 | 504 | |
michael@0 | 505 | /** |
michael@0 | 506 | * Re-open a closed tab. |
michael@0 | 507 | * @param aIndex |
michael@0 | 508 | * The index of the tab (via nsSessionStore.getClosedTabData) |
michael@0 | 509 | * @returns a reference to the reopened tab. |
michael@0 | 510 | */ |
michael@0 | 511 | undoCloseTab: function undoCloseTab(aIndex) { |
michael@0 | 512 | var tab = null; |
michael@0 | 513 | aIndex = aIndex || 0; |
michael@0 | 514 | var ss = Cc["@mozilla.org/browser/sessionstore;1"]. |
michael@0 | 515 | getService(Ci.nsISessionStore); |
michael@0 | 516 | if (ss.getClosedTabCount(window) > (aIndex)) { |
michael@0 | 517 | tab = ss.undoCloseTab(window, aIndex); |
michael@0 | 518 | } |
michael@0 | 519 | return tab; |
michael@0 | 520 | }, |
michael@0 | 521 | |
michael@0 | 522 | // Useful for when we've received an event to close a particular DOM window. |
michael@0 | 523 | // Since we don't have windows, we want to close the corresponding tab. |
michael@0 | 524 | closeTabForBrowser: function closeTabForBrowser(aBrowser) { |
michael@0 | 525 | // Find the relevant tab, and close it. |
michael@0 | 526 | let browsers = Browser.browsers; |
michael@0 | 527 | for (let i = 0; i < browsers.length; i++) { |
michael@0 | 528 | if (browsers[i] == aBrowser) { |
michael@0 | 529 | Browser.closeTab(Browser.getTabAtIndex(i)); |
michael@0 | 530 | return { preventDefault: true }; |
michael@0 | 531 | } |
michael@0 | 532 | } |
michael@0 | 533 | |
michael@0 | 534 | return {}; |
michael@0 | 535 | }, |
michael@0 | 536 | |
michael@0 | 537 | selectTab: function selectTab(aTab) { |
michael@0 | 538 | Browser.selectedTab = aTab; |
michael@0 | 539 | }, |
michael@0 | 540 | |
michael@0 | 541 | selectTabAndDismiss: function selectTabAndDismiss(aTab) { |
michael@0 | 542 | this.selectTab(aTab); |
michael@0 | 543 | ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay); |
michael@0 | 544 | }, |
michael@0 | 545 | |
michael@0 | 546 | selectTabAtIndex: function selectTabAtIndex(aIndex) { |
michael@0 | 547 | // count backwards for aIndex < 0 |
michael@0 | 548 | if (aIndex < 0) |
michael@0 | 549 | aIndex += Browser._tabs.length; |
michael@0 | 550 | |
michael@0 | 551 | if (aIndex >= 0 && aIndex < Browser._tabs.length) |
michael@0 | 552 | Browser.selectedTab = Browser._tabs[aIndex]; |
michael@0 | 553 | }, |
michael@0 | 554 | |
michael@0 | 555 | selectNextTab: function selectNextTab() { |
michael@0 | 556 | if (Browser._tabs.length == 1 || !Browser.selectedTab) { |
michael@0 | 557 | return; |
michael@0 | 558 | } |
michael@0 | 559 | |
michael@0 | 560 | let tabIndex = Browser._tabs.indexOf(Browser.selectedTab) + 1; |
michael@0 | 561 | if (tabIndex >= Browser._tabs.length) { |
michael@0 | 562 | tabIndex = 0; |
michael@0 | 563 | } |
michael@0 | 564 | |
michael@0 | 565 | Browser.selectedTab = Browser._tabs[tabIndex]; |
michael@0 | 566 | }, |
michael@0 | 567 | |
michael@0 | 568 | selectPreviousTab: function selectPreviousTab() { |
michael@0 | 569 | if (Browser._tabs.length == 1 || !Browser.selectedTab) { |
michael@0 | 570 | return; |
michael@0 | 571 | } |
michael@0 | 572 | |
michael@0 | 573 | let tabIndex = Browser._tabs.indexOf(Browser.selectedTab) - 1; |
michael@0 | 574 | if (tabIndex < 0) { |
michael@0 | 575 | tabIndex = Browser._tabs.length - 1; |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | Browser.selectedTab = Browser._tabs[tabIndex]; |
michael@0 | 579 | }, |
michael@0 | 580 | |
michael@0 | 581 | // Used for when we're about to open a modal dialog, |
michael@0 | 582 | // and want to ensure the opening tab is in front. |
michael@0 | 583 | selectTabForBrowser: function selectTabForBrowser(aBrowser) { |
michael@0 | 584 | for (let i = 0; i < Browser.tabs.length; i++) { |
michael@0 | 585 | if (Browser._tabs[i].browser == aBrowser) { |
michael@0 | 586 | Browser.selectedTab = Browser.tabs[i]; |
michael@0 | 587 | break; |
michael@0 | 588 | } |
michael@0 | 589 | } |
michael@0 | 590 | }, |
michael@0 | 591 | |
michael@0 | 592 | updateUIFocus: function _updateUIFocus() { |
michael@0 | 593 | if (Elements.contentShowing.getAttribute("disabled") == "true" && Browser.selectedBrowser) |
michael@0 | 594 | Browser.selectedBrowser.messageManager.sendAsyncMessage("Browser:Blur", { }); |
michael@0 | 595 | }, |
michael@0 | 596 | |
michael@0 | 597 | blurFocusedElement: function blurFocusedElement() { |
michael@0 | 598 | let focusedElement = document.commandDispatcher.focusedElement; |
michael@0 | 599 | if (focusedElement) |
michael@0 | 600 | focusedElement.blur(); |
michael@0 | 601 | }, |
michael@0 | 602 | |
michael@0 | 603 | blurNavBar: function blurNavBar() { |
michael@0 | 604 | if (this._edit.focused) { |
michael@0 | 605 | this._edit.blur(); |
michael@0 | 606 | |
michael@0 | 607 | // Advanced notice to CAO, so we can shuffle the nav bar in advance |
michael@0 | 608 | // of the keyboard transition. |
michael@0 | 609 | ContentAreaObserver.navBarWillBlur(); |
michael@0 | 610 | |
michael@0 | 611 | return true; |
michael@0 | 612 | } |
michael@0 | 613 | return false; |
michael@0 | 614 | }, |
michael@0 | 615 | |
michael@0 | 616 | observe: function BrowserUI_observe(aSubject, aTopic, aData) { |
michael@0 | 617 | switch (aTopic) { |
michael@0 | 618 | case "handle-xul-text-link": |
michael@0 | 619 | let handled = aSubject.QueryInterface(Ci.nsISupportsPRBool); |
michael@0 | 620 | if (!handled.data) { |
michael@0 | 621 | this.addAndShowTab(aData, Browser.selectedTab); |
michael@0 | 622 | handled.data = true; |
michael@0 | 623 | } |
michael@0 | 624 | break; |
michael@0 | 625 | case "nsPref:changed": |
michael@0 | 626 | switch (aData) { |
michael@0 | 627 | case "browser.cache.disk_cache_ssl": |
michael@0 | 628 | this._sslDiskCacheEnabled = Services.prefs.getBoolPref(aData); |
michael@0 | 629 | break; |
michael@0 | 630 | case debugServerStateChanged: |
michael@0 | 631 | if (Services.prefs.getBoolPref(aData)) { |
michael@0 | 632 | this.runDebugServer(); |
michael@0 | 633 | } else { |
michael@0 | 634 | this.stopDebugServer(); |
michael@0 | 635 | } |
michael@0 | 636 | break; |
michael@0 | 637 | case debugServerPortChanged: |
michael@0 | 638 | this.changeDebugPort(Services.prefs.getIntPref(aData)); |
michael@0 | 639 | break; |
michael@0 | 640 | case "app.crashreporter.autosubmit": |
michael@0 | 641 | #ifdef MOZ_CRASHREPORTER |
michael@0 | 642 | CrashReporter.submitReports = Services.prefs.getBoolPref(aData); |
michael@0 | 643 | |
michael@0 | 644 | // The user explicitly set the autosubmit option, so there is no |
michael@0 | 645 | // need to prompt them about crash reporting in the future |
michael@0 | 646 | Services.prefs.setBoolPref("app.crashreporter.prompted", true); |
michael@0 | 647 | |
michael@0 | 648 | BrowserUI.submitLastCrashReportOrShowPrompt; |
michael@0 | 649 | #endif |
michael@0 | 650 | break; |
michael@0 | 651 | case "metro.private_browsing.enabled": |
michael@0 | 652 | this.updatePrivateBrowsingUI(); |
michael@0 | 653 | break; |
michael@0 | 654 | } |
michael@0 | 655 | break; |
michael@0 | 656 | } |
michael@0 | 657 | }, |
michael@0 | 658 | |
michael@0 | 659 | submitLastCrashReportOrShowPrompt: function() { |
michael@0 | 660 | #ifdef MOZ_CRASHREPORTER |
michael@0 | 661 | let lastCrashID = this.lastCrashID; |
michael@0 | 662 | if (lastCrashID && lastCrashID.length) { |
michael@0 | 663 | if (Services.prefs.getBoolPref("app.crashreporter.autosubmit")) { |
michael@0 | 664 | Util.dumpLn("Submitting last crash id:", lastCrashID); |
michael@0 | 665 | let params = {}; |
michael@0 | 666 | if (!Services.prefs.getBoolPref("app.crashreporter.submitURLs")) { |
michael@0 | 667 | params['extraExtraKeyVals'] = { URL: '' }; |
michael@0 | 668 | } |
michael@0 | 669 | try { |
michael@0 | 670 | this.CrashSubmit.submit(lastCrashID, params); |
michael@0 | 671 | } catch (ex) { |
michael@0 | 672 | Util.dumpLn(ex); |
michael@0 | 673 | } |
michael@0 | 674 | } else if (!Services.prefs.getBoolPref("app.crashreporter.prompted")) { |
michael@0 | 675 | BrowserUI.addAndShowTab("about:crashprompt", null); |
michael@0 | 676 | } |
michael@0 | 677 | } |
michael@0 | 678 | #endif |
michael@0 | 679 | }, |
michael@0 | 680 | |
michael@0 | 681 | |
michael@0 | 682 | |
michael@0 | 683 | /********************************* |
michael@0 | 684 | * Internal utils |
michael@0 | 685 | */ |
michael@0 | 686 | |
michael@0 | 687 | _titleChanged: function(aBrowser) { |
michael@0 | 688 | let url = this.getDisplayURI(aBrowser); |
michael@0 | 689 | |
michael@0 | 690 | let tabCaption; |
michael@0 | 691 | if (aBrowser.contentTitle) { |
michael@0 | 692 | tabCaption = aBrowser.contentTitle; |
michael@0 | 693 | } else if (!Util.isURLEmpty(aBrowser.userTypedValue)) { |
michael@0 | 694 | tabCaption = aBrowser.userTypedValue; |
michael@0 | 695 | } else if (!Util.isURLEmpty(url)) { |
michael@0 | 696 | tabCaption = url; |
michael@0 | 697 | } else { |
michael@0 | 698 | tabCaption = Util.getEmptyURLTabTitle(); |
michael@0 | 699 | } |
michael@0 | 700 | |
michael@0 | 701 | let tab = Browser.getTabForBrowser(aBrowser); |
michael@0 | 702 | if (tab) |
michael@0 | 703 | tab.chromeTab.updateTitle(tabCaption); |
michael@0 | 704 | }, |
michael@0 | 705 | |
michael@0 | 706 | _updateButtons: function _updateButtons() { |
michael@0 | 707 | let browser = Browser.selectedBrowser; |
michael@0 | 708 | if (!browser) { |
michael@0 | 709 | return; |
michael@0 | 710 | } |
michael@0 | 711 | if (browser.canGoBack) { |
michael@0 | 712 | this._back.removeAttribute("disabled"); |
michael@0 | 713 | } else { |
michael@0 | 714 | this._back.setAttribute("disabled", true); |
michael@0 | 715 | } |
michael@0 | 716 | if (browser.canGoForward) { |
michael@0 | 717 | this._forward.removeAttribute("disabled"); |
michael@0 | 718 | } else { |
michael@0 | 719 | this._forward.setAttribute("disabled", true); |
michael@0 | 720 | } |
michael@0 | 721 | }, |
michael@0 | 722 | |
michael@0 | 723 | _updateToolbar: function _updateToolbar() { |
michael@0 | 724 | if (Browser.selectedTab.isLoading()) { |
michael@0 | 725 | Elements.loadingState.setAttribute("loading", true); |
michael@0 | 726 | } else { |
michael@0 | 727 | Elements.loadingState.removeAttribute("loading"); |
michael@0 | 728 | } |
michael@0 | 729 | }, |
michael@0 | 730 | |
michael@0 | 731 | _closeOrQuit: function _closeOrQuit() { |
michael@0 | 732 | // Close active dialog, if we have one. If not then close the application. |
michael@0 | 733 | if (!BrowserUI.isContentShowing()) { |
michael@0 | 734 | BrowserUI.showContent(); |
michael@0 | 735 | } else { |
michael@0 | 736 | // Check to see if we should really close the window |
michael@0 | 737 | if (Browser.closing()) { |
michael@0 | 738 | window.close(); |
michael@0 | 739 | let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup); |
michael@0 | 740 | appStartup.quit(Ci.nsIAppStartup.eForceQuit); |
michael@0 | 741 | } |
michael@0 | 742 | } |
michael@0 | 743 | }, |
michael@0 | 744 | |
michael@0 | 745 | _onPreciseInput: function _onPreciseInput() { |
michael@0 | 746 | document.getElementById("bcast_preciseInput").setAttribute("input", "precise"); |
michael@0 | 747 | let uri = Util.makeURI("chrome://browser/content/cursor.css"); |
michael@0 | 748 | if (StyleSheetSvc.sheetRegistered(uri, Ci.nsIStyleSheetService.AGENT_SHEET)) { |
michael@0 | 749 | StyleSheetSvc.unregisterSheet(uri, |
michael@0 | 750 | Ci.nsIStyleSheetService.AGENT_SHEET); |
michael@0 | 751 | } |
michael@0 | 752 | }, |
michael@0 | 753 | |
michael@0 | 754 | _onImpreciseInput: function _onImpreciseInput() { |
michael@0 | 755 | document.getElementById("bcast_preciseInput").setAttribute("input", "imprecise"); |
michael@0 | 756 | let uri = Util.makeURI("chrome://browser/content/cursor.css"); |
michael@0 | 757 | if (!StyleSheetSvc.sheetRegistered(uri, Ci.nsIStyleSheetService.AGENT_SHEET)) { |
michael@0 | 758 | StyleSheetSvc.loadAndRegisterSheet(uri, |
michael@0 | 759 | Ci.nsIStyleSheetService.AGENT_SHEET); |
michael@0 | 760 | } |
michael@0 | 761 | }, |
michael@0 | 762 | |
michael@0 | 763 | _getMeasures: function() { |
michael@0 | 764 | let dimensions = { |
michael@0 | 765 | "window-width": ContentAreaObserver.width, |
michael@0 | 766 | "window-height": ContentAreaObserver.height |
michael@0 | 767 | }; |
michael@0 | 768 | return dimensions; |
michael@0 | 769 | }, |
michael@0 | 770 | |
michael@0 | 771 | /********************************* |
michael@0 | 772 | * Event handling |
michael@0 | 773 | */ |
michael@0 | 774 | |
michael@0 | 775 | handleEvent: function handleEvent(aEvent) { |
michael@0 | 776 | var target = aEvent.target; |
michael@0 | 777 | switch (aEvent.type) { |
michael@0 | 778 | // Window events |
michael@0 | 779 | case "keypress": |
michael@0 | 780 | if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) |
michael@0 | 781 | this.handleEscape(aEvent); |
michael@0 | 782 | break; |
michael@0 | 783 | case "MozPrecisePointer": |
michael@0 | 784 | this._onPreciseInput(); |
michael@0 | 785 | break; |
michael@0 | 786 | case "MozImprecisePointer": |
michael@0 | 787 | this._onImpreciseInput(); |
michael@0 | 788 | break; |
michael@0 | 789 | case "AppCommand": |
michael@0 | 790 | this.handleAppCommandEvent(aEvent); |
michael@0 | 791 | break; |
michael@0 | 792 | } |
michael@0 | 793 | }, |
michael@0 | 794 | |
michael@0 | 795 | // Checks if various different parts of the UI is visible and closes |
michael@0 | 796 | // them one at a time. |
michael@0 | 797 | handleEscape: function (aEvent) { |
michael@0 | 798 | aEvent.stopPropagation(); |
michael@0 | 799 | aEvent.preventDefault(); |
michael@0 | 800 | |
michael@0 | 801 | if (this._edit.popupOpen) { |
michael@0 | 802 | this._edit.endEditing(true); |
michael@0 | 803 | return; |
michael@0 | 804 | } |
michael@0 | 805 | |
michael@0 | 806 | // Check open popups |
michael@0 | 807 | if (DialogUI._popup) { |
michael@0 | 808 | DialogUI._hidePopup(); |
michael@0 | 809 | return; |
michael@0 | 810 | } |
michael@0 | 811 | |
michael@0 | 812 | // Check open panel |
michael@0 | 813 | if (PanelUI.isVisible) { |
michael@0 | 814 | PanelUI.hide(); |
michael@0 | 815 | return; |
michael@0 | 816 | } |
michael@0 | 817 | |
michael@0 | 818 | // Check content helper |
michael@0 | 819 | if (FindHelperUI.isActive) { |
michael@0 | 820 | FindHelperUI.hide(); |
michael@0 | 821 | return; |
michael@0 | 822 | } |
michael@0 | 823 | |
michael@0 | 824 | if (Browser.selectedTab.isLoading()) { |
michael@0 | 825 | Browser.selectedBrowser.stop(); |
michael@0 | 826 | return; |
michael@0 | 827 | } |
michael@0 | 828 | |
michael@0 | 829 | if (ContextUI.dismiss()) { |
michael@0 | 830 | return; |
michael@0 | 831 | } |
michael@0 | 832 | }, |
michael@0 | 833 | |
michael@0 | 834 | handleBackspace: function handleBackspace() { |
michael@0 | 835 | switch (Services.prefs.getIntPref("browser.backspace_action")) { |
michael@0 | 836 | case 0: |
michael@0 | 837 | CommandUpdater.doCommand("cmd_back"); |
michael@0 | 838 | break; |
michael@0 | 839 | case 1: |
michael@0 | 840 | CommandUpdater.doCommand("cmd_scrollPageUp"); |
michael@0 | 841 | break; |
michael@0 | 842 | } |
michael@0 | 843 | }, |
michael@0 | 844 | |
michael@0 | 845 | handleShiftBackspace: function handleShiftBackspace() { |
michael@0 | 846 | switch (Services.prefs.getIntPref("browser.backspace_action")) { |
michael@0 | 847 | case 0: |
michael@0 | 848 | CommandUpdater.doCommand("cmd_forward"); |
michael@0 | 849 | break; |
michael@0 | 850 | case 1: |
michael@0 | 851 | CommandUpdater.doCommand("cmd_scrollPageDown"); |
michael@0 | 852 | break; |
michael@0 | 853 | } |
michael@0 | 854 | }, |
michael@0 | 855 | |
michael@0 | 856 | openFile: function() { |
michael@0 | 857 | try { |
michael@0 | 858 | const nsIFilePicker = Ci.nsIFilePicker; |
michael@0 | 859 | let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); |
michael@0 | 860 | let self = this; |
michael@0 | 861 | let fpCallback = function fpCallback_done(aResult) { |
michael@0 | 862 | if (aResult == nsIFilePicker.returnOK) { |
michael@0 | 863 | self.goToURI(fp.fileURL.spec); |
michael@0 | 864 | } |
michael@0 | 865 | }; |
michael@0 | 866 | |
michael@0 | 867 | let windowTitle = Strings.browser.GetStringFromName("browserForOpenLocation"); |
michael@0 | 868 | fp.init(window, windowTitle, nsIFilePicker.modeOpen); |
michael@0 | 869 | fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText | |
michael@0 | 870 | nsIFilePicker.filterImages | nsIFilePicker.filterXML | |
michael@0 | 871 | nsIFilePicker.filterHTML); |
michael@0 | 872 | fp.open(fpCallback); |
michael@0 | 873 | } catch (ex) { |
michael@0 | 874 | dump ('BrowserUI openFile exception: ' + ex + '\n'); |
michael@0 | 875 | } |
michael@0 | 876 | }, |
michael@0 | 877 | |
michael@0 | 878 | savePage: function() { |
michael@0 | 879 | Browser.savePage(); |
michael@0 | 880 | }, |
michael@0 | 881 | |
michael@0 | 882 | receiveMessage: function receiveMessage(aMessage) { |
michael@0 | 883 | let browser = aMessage.target; |
michael@0 | 884 | let json = aMessage.json; |
michael@0 | 885 | switch (aMessage.name) { |
michael@0 | 886 | case "DOMTitleChanged": |
michael@0 | 887 | this._titleChanged(browser); |
michael@0 | 888 | break; |
michael@0 | 889 | case "DOMWillOpenModalDialog": |
michael@0 | 890 | this.selectTabForBrowser(browser); |
michael@0 | 891 | break; |
michael@0 | 892 | case "DOMWindowClose": |
michael@0 | 893 | return this.closeTabForBrowser(browser); |
michael@0 | 894 | break; |
michael@0 | 895 | // XXX this and content's sender are a little warped |
michael@0 | 896 | case "Browser:OpenURI": |
michael@0 | 897 | let referrerURI = null; |
michael@0 | 898 | if (json.referrer) |
michael@0 | 899 | referrerURI = Services.io.newURI(json.referrer, null, null); |
michael@0 | 900 | this.goToURI(json.uri); |
michael@0 | 901 | break; |
michael@0 | 902 | case "Content:StateChange": { |
michael@0 | 903 | let tab = Browser.selectedTab; |
michael@0 | 904 | if (this.shouldCaptureThumbnails(tab)) { |
michael@0 | 905 | PageThumbs.captureAndStore(tab.browser); |
michael@0 | 906 | let currPage = tab.browser.currentURI.spec; |
michael@0 | 907 | Services.obs.notifyObservers(null, "Metro:RefreshTopsiteThumbnail", currPage); |
michael@0 | 908 | } |
michael@0 | 909 | break; |
michael@0 | 910 | } |
michael@0 | 911 | } |
michael@0 | 912 | |
michael@0 | 913 | return {}; |
michael@0 | 914 | }, |
michael@0 | 915 | |
michael@0 | 916 | shouldCaptureThumbnails: function shouldCaptureThumbnails(aTab) { |
michael@0 | 917 | // Capture only if it's the currently selected tab. |
michael@0 | 918 | if (aTab != Browser.selectedTab) { |
michael@0 | 919 | return false; |
michael@0 | 920 | } |
michael@0 | 921 | // Skip private tabs |
michael@0 | 922 | if (aTab.isPrivate) { |
michael@0 | 923 | return false; |
michael@0 | 924 | } |
michael@0 | 925 | // FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as |
michael@0 | 926 | // that currently regresses Talos SVG tests. |
michael@0 | 927 | let browser = aTab.browser; |
michael@0 | 928 | let doc = browser.contentDocument; |
michael@0 | 929 | if (doc instanceof SVGDocument || doc instanceof XMLDocument) { |
michael@0 | 930 | return false; |
michael@0 | 931 | } |
michael@0 | 932 | |
michael@0 | 933 | // Don't capture pages in snapped mode, this produces 2/3 black |
michael@0 | 934 | // thumbs or stretched out ones |
michael@0 | 935 | // Ci.nsIWinMetroUtils.snapped is inaccessible on |
michael@0 | 936 | // desktop/nonwindows systems |
michael@0 | 937 | if(Elements.windowState.getAttribute("viewstate") == "snapped") { |
michael@0 | 938 | return false; |
michael@0 | 939 | } |
michael@0 | 940 | // There's no point in taking screenshot of loading pages. |
michael@0 | 941 | if (browser.docShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE) { |
michael@0 | 942 | return false; |
michael@0 | 943 | } |
michael@0 | 944 | |
michael@0 | 945 | // Don't take screenshots of about: pages. |
michael@0 | 946 | if (browser.currentURI.schemeIs("about")) { |
michael@0 | 947 | return false; |
michael@0 | 948 | } |
michael@0 | 949 | |
michael@0 | 950 | // No valid document channel. We shouldn't take a screenshot. |
michael@0 | 951 | let channel = browser.docShell.currentDocumentChannel; |
michael@0 | 952 | if (!channel) { |
michael@0 | 953 | return false; |
michael@0 | 954 | } |
michael@0 | 955 | |
michael@0 | 956 | // Don't take screenshots of internally redirecting about: pages. |
michael@0 | 957 | // This includes error pages. |
michael@0 | 958 | let uri = channel.originalURI; |
michael@0 | 959 | if (uri.schemeIs("about")) { |
michael@0 | 960 | return false; |
michael@0 | 961 | } |
michael@0 | 962 | |
michael@0 | 963 | // http checks |
michael@0 | 964 | let httpChannel; |
michael@0 | 965 | try { |
michael@0 | 966 | httpChannel = channel.QueryInterface(Ci.nsIHttpChannel); |
michael@0 | 967 | } catch (e) { /* Not an HTTP channel. */ } |
michael@0 | 968 | |
michael@0 | 969 | if (httpChannel) { |
michael@0 | 970 | // Continue only if we have a 2xx status code. |
michael@0 | 971 | try { |
michael@0 | 972 | if (Math.floor(httpChannel.responseStatus / 100) != 2) { |
michael@0 | 973 | return false; |
michael@0 | 974 | } |
michael@0 | 975 | } catch (e) { |
michael@0 | 976 | // Can't get response information from the httpChannel |
michael@0 | 977 | // because mResponseHead is not available. |
michael@0 | 978 | return false; |
michael@0 | 979 | } |
michael@0 | 980 | |
michael@0 | 981 | // Cache-Control: no-store. |
michael@0 | 982 | if (httpChannel.isNoStoreResponse()) { |
michael@0 | 983 | return false; |
michael@0 | 984 | } |
michael@0 | 985 | |
michael@0 | 986 | // Don't capture HTTPS pages unless the user enabled it. |
michael@0 | 987 | if (uri.schemeIs("https") && !this.sslDiskCacheEnabled) { |
michael@0 | 988 | return false; |
michael@0 | 989 | } |
michael@0 | 990 | } |
michael@0 | 991 | |
michael@0 | 992 | return true; |
michael@0 | 993 | }, |
michael@0 | 994 | |
michael@0 | 995 | _sslDiskCacheEnabled: null, |
michael@0 | 996 | |
michael@0 | 997 | get sslDiskCacheEnabled() { |
michael@0 | 998 | if (this._sslDiskCacheEnabled === null) { |
michael@0 | 999 | this._sslDiskCacheEnabled = Services.prefs.getBoolPref("browser.cache.disk_cache_ssl"); |
michael@0 | 1000 | } |
michael@0 | 1001 | return this._sslDiskCacheEnabled; |
michael@0 | 1002 | }, |
michael@0 | 1003 | |
michael@0 | 1004 | supportsCommand : function(cmd) { |
michael@0 | 1005 | var isSupported = false; |
michael@0 | 1006 | switch (cmd) { |
michael@0 | 1007 | case "cmd_back": |
michael@0 | 1008 | case "cmd_forward": |
michael@0 | 1009 | case "cmd_reload": |
michael@0 | 1010 | case "cmd_forceReload": |
michael@0 | 1011 | case "cmd_stop": |
michael@0 | 1012 | case "cmd_go": |
michael@0 | 1013 | case "cmd_home": |
michael@0 | 1014 | case "cmd_openLocation": |
michael@0 | 1015 | case "cmd_addBookmark": |
michael@0 | 1016 | case "cmd_bookmarks": |
michael@0 | 1017 | case "cmd_history": |
michael@0 | 1018 | case "cmd_remoteTabs": |
michael@0 | 1019 | case "cmd_quit": |
michael@0 | 1020 | case "cmd_close": |
michael@0 | 1021 | case "cmd_newTab": |
michael@0 | 1022 | case "cmd_newTabKey": |
michael@0 | 1023 | case "cmd_closeTab": |
michael@0 | 1024 | case "cmd_undoCloseTab": |
michael@0 | 1025 | case "cmd_actions": |
michael@0 | 1026 | case "cmd_panel": |
michael@0 | 1027 | case "cmd_reportingCrashesSubmitURLs": |
michael@0 | 1028 | case "cmd_flyout_back": |
michael@0 | 1029 | case "cmd_sanitize": |
michael@0 | 1030 | case "cmd_volumeLeft": |
michael@0 | 1031 | case "cmd_volumeRight": |
michael@0 | 1032 | case "cmd_openFile": |
michael@0 | 1033 | case "cmd_savePage": |
michael@0 | 1034 | isSupported = true; |
michael@0 | 1035 | break; |
michael@0 | 1036 | default: |
michael@0 | 1037 | isSupported = false; |
michael@0 | 1038 | break; |
michael@0 | 1039 | } |
michael@0 | 1040 | return isSupported; |
michael@0 | 1041 | }, |
michael@0 | 1042 | |
michael@0 | 1043 | isCommandEnabled : function(cmd) { |
michael@0 | 1044 | let elem = document.getElementById(cmd); |
michael@0 | 1045 | if (elem && elem.getAttribute("disabled") == "true") |
michael@0 | 1046 | return false; |
michael@0 | 1047 | return true; |
michael@0 | 1048 | }, |
michael@0 | 1049 | |
michael@0 | 1050 | doCommand : function(cmd) { |
michael@0 | 1051 | if (!this.isCommandEnabled(cmd)) |
michael@0 | 1052 | return; |
michael@0 | 1053 | let browser = getBrowser(); |
michael@0 | 1054 | switch (cmd) { |
michael@0 | 1055 | case "cmd_back": |
michael@0 | 1056 | browser.goBack(); |
michael@0 | 1057 | break; |
michael@0 | 1058 | case "cmd_forward": |
michael@0 | 1059 | browser.goForward(); |
michael@0 | 1060 | break; |
michael@0 | 1061 | case "cmd_reload": |
michael@0 | 1062 | browser.reload(); |
michael@0 | 1063 | break; |
michael@0 | 1064 | case "cmd_forceReload": |
michael@0 | 1065 | { |
michael@0 | 1066 | // Simulate a new page |
michael@0 | 1067 | browser.lastLocation = null; |
michael@0 | 1068 | |
michael@0 | 1069 | const reloadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | |
michael@0 | 1070 | Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; |
michael@0 | 1071 | browser.reloadWithFlags(reloadFlags); |
michael@0 | 1072 | break; |
michael@0 | 1073 | } |
michael@0 | 1074 | case "cmd_stop": |
michael@0 | 1075 | browser.stop(); |
michael@0 | 1076 | break; |
michael@0 | 1077 | case "cmd_go": |
michael@0 | 1078 | this.goToURI(); |
michael@0 | 1079 | break; |
michael@0 | 1080 | case "cmd_home": |
michael@0 | 1081 | this.goToURI(Browser.getHomePage()); |
michael@0 | 1082 | break; |
michael@0 | 1083 | case "cmd_openLocation": |
michael@0 | 1084 | ContextUI.displayNavbar(); |
michael@0 | 1085 | this._edit.beginEditing(true); |
michael@0 | 1086 | this._edit.select(); |
michael@0 | 1087 | break; |
michael@0 | 1088 | case "cmd_addBookmark": |
michael@0 | 1089 | ContextUI.displayNavbar(); |
michael@0 | 1090 | Appbar.onStarButton(true); |
michael@0 | 1091 | break; |
michael@0 | 1092 | case "cmd_bookmarks": |
michael@0 | 1093 | PanelUI.show("bookmarks-container"); |
michael@0 | 1094 | break; |
michael@0 | 1095 | case "cmd_history": |
michael@0 | 1096 | PanelUI.show("history-container"); |
michael@0 | 1097 | break; |
michael@0 | 1098 | case "cmd_remoteTabs": |
michael@0 | 1099 | #ifdef MOZ_SERVICES_SYNC |
michael@0 | 1100 | if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) { |
michael@0 | 1101 | FlyoutPanelsUI.show('SyncFlyoutPanel'); |
michael@0 | 1102 | } else { |
michael@0 | 1103 | PanelUI.show("remotetabs-container"); |
michael@0 | 1104 | } |
michael@0 | 1105 | #endif |
michael@0 | 1106 | break; |
michael@0 | 1107 | case "cmd_quit": |
michael@0 | 1108 | // Only close one window |
michael@0 | 1109 | this._closeOrQuit(); |
michael@0 | 1110 | break; |
michael@0 | 1111 | case "cmd_close": |
michael@0 | 1112 | this._closeOrQuit(); |
michael@0 | 1113 | break; |
michael@0 | 1114 | case "cmd_newTab": |
michael@0 | 1115 | this.addAndShowTab(); |
michael@0 | 1116 | break; |
michael@0 | 1117 | case "cmd_newTabKey": |
michael@0 | 1118 | this.addAndShowTab(); |
michael@0 | 1119 | // Make sure navbar is displayed before setting focus on url bar. Bug 907244 |
michael@0 | 1120 | ContextUI.displayNavbar(); |
michael@0 | 1121 | this._edit.beginEditing(false); |
michael@0 | 1122 | break; |
michael@0 | 1123 | case "cmd_closeTab": |
michael@0 | 1124 | this.closeTab(); |
michael@0 | 1125 | break; |
michael@0 | 1126 | case "cmd_undoCloseTab": |
michael@0 | 1127 | this.undoCloseTab(); |
michael@0 | 1128 | break; |
michael@0 | 1129 | case "cmd_sanitize": |
michael@0 | 1130 | this.confirmSanitizeDialog(); |
michael@0 | 1131 | break; |
michael@0 | 1132 | case "cmd_flyout_back": |
michael@0 | 1133 | FlyoutPanelsUI.onBackButton(); |
michael@0 | 1134 | break; |
michael@0 | 1135 | case "cmd_reportingCrashesSubmitURLs": |
michael@0 | 1136 | let urlCheckbox = document.getElementById("prefs-reporting-submitURLs"); |
michael@0 | 1137 | Services.prefs.setBoolPref('app.crashreporter.submitURLs', urlCheckbox.checked); |
michael@0 | 1138 | break; |
michael@0 | 1139 | case "cmd_panel": |
michael@0 | 1140 | PanelUI.toggle(); |
michael@0 | 1141 | break; |
michael@0 | 1142 | case "cmd_openFile": |
michael@0 | 1143 | this.openFile(); |
michael@0 | 1144 | break; |
michael@0 | 1145 | case "cmd_savePage": |
michael@0 | 1146 | this.savePage(); |
michael@0 | 1147 | break; |
michael@0 | 1148 | } |
michael@0 | 1149 | }, |
michael@0 | 1150 | |
michael@0 | 1151 | handleAppCommandEvent: function (aEvent) { |
michael@0 | 1152 | switch (aEvent.command) { |
michael@0 | 1153 | case "Back": |
michael@0 | 1154 | this.doCommand("cmd_back"); |
michael@0 | 1155 | break; |
michael@0 | 1156 | case "Forward": |
michael@0 | 1157 | this.doCommand("cmd_forward"); |
michael@0 | 1158 | break; |
michael@0 | 1159 | case "Reload": |
michael@0 | 1160 | this.doCommand("cmd_reload"); |
michael@0 | 1161 | break; |
michael@0 | 1162 | case "Stop": |
michael@0 | 1163 | this.doCommand("cmd_stop"); |
michael@0 | 1164 | break; |
michael@0 | 1165 | case "Home": |
michael@0 | 1166 | this.doCommand("cmd_home"); |
michael@0 | 1167 | break; |
michael@0 | 1168 | case "New": |
michael@0 | 1169 | this.doCommand("cmd_newTab"); |
michael@0 | 1170 | break; |
michael@0 | 1171 | case "Close": |
michael@0 | 1172 | this.doCommand("cmd_closeTab"); |
michael@0 | 1173 | break; |
michael@0 | 1174 | case "Find": |
michael@0 | 1175 | FindHelperUI.show(); |
michael@0 | 1176 | break; |
michael@0 | 1177 | case "Open": |
michael@0 | 1178 | this.doCommand("cmd_openFile"); |
michael@0 | 1179 | break; |
michael@0 | 1180 | case "Save": |
michael@0 | 1181 | this.doCommand("cmd_savePage"); |
michael@0 | 1182 | break; |
michael@0 | 1183 | case "Search": |
michael@0 | 1184 | this.doCommand("cmd_openLocation"); |
michael@0 | 1185 | break; |
michael@0 | 1186 | default: |
michael@0 | 1187 | return; |
michael@0 | 1188 | } |
michael@0 | 1189 | aEvent.stopPropagation(); |
michael@0 | 1190 | aEvent.preventDefault(); |
michael@0 | 1191 | }, |
michael@0 | 1192 | |
michael@0 | 1193 | confirmSanitizeDialog: function () { |
michael@0 | 1194 | let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); |
michael@0 | 1195 | let title = bundle.GetStringFromName("clearPrivateData.title2"); |
michael@0 | 1196 | let message = bundle.GetStringFromName("clearPrivateData.message3"); |
michael@0 | 1197 | let clearbutton = bundle.GetStringFromName("clearPrivateData.clearButton"); |
michael@0 | 1198 | |
michael@0 | 1199 | let prefsClearButton = document.getElementById("prefs-clear-data"); |
michael@0 | 1200 | prefsClearButton.disabled = true; |
michael@0 | 1201 | |
michael@0 | 1202 | let buttonPressed = Services.prompt.confirmEx( |
michael@0 | 1203 | null, |
michael@0 | 1204 | title, |
michael@0 | 1205 | message, |
michael@0 | 1206 | Ci.nsIPrompt.BUTTON_POS_0 * Ci.nsIPrompt.BUTTON_TITLE_IS_STRING + |
michael@0 | 1207 | Ci.nsIPrompt.BUTTON_POS_1 * Ci.nsIPrompt.BUTTON_TITLE_CANCEL, |
michael@0 | 1208 | clearbutton, |
michael@0 | 1209 | null, |
michael@0 | 1210 | null, |
michael@0 | 1211 | null, |
michael@0 | 1212 | { value: false }); |
michael@0 | 1213 | |
michael@0 | 1214 | // Clicking 'Clear' will call onSanitize(). |
michael@0 | 1215 | if (buttonPressed === 0) { |
michael@0 | 1216 | SanitizeUI.onSanitize(); |
michael@0 | 1217 | } |
michael@0 | 1218 | |
michael@0 | 1219 | prefsClearButton.disabled = false; |
michael@0 | 1220 | }, |
michael@0 | 1221 | |
michael@0 | 1222 | _initFirstRunContent: function () { |
michael@0 | 1223 | let dismissed = Services.prefs.getBoolPref("browser.firstrun-content.dismissed"); |
michael@0 | 1224 | let firstRunCount = Services.prefs.getIntPref("browser.firstrun.count"); |
michael@0 | 1225 | |
michael@0 | 1226 | if (!dismissed && firstRunCount > 0) { |
michael@0 | 1227 | document.loadOverlay("chrome://browser/content/FirstRunContentOverlay.xul", null); |
michael@0 | 1228 | } |
michael@0 | 1229 | }, |
michael@0 | 1230 | |
michael@0 | 1231 | firstRunContentDismiss: function() { |
michael@0 | 1232 | let firstRunElements = Elements.stack.querySelectorAll(".firstrun-content"); |
michael@0 | 1233 | for (let node of firstRunElements) { |
michael@0 | 1234 | node.parentNode.removeChild(node); |
michael@0 | 1235 | } |
michael@0 | 1236 | |
michael@0 | 1237 | Services.prefs.setBoolPref("browser.firstrun-content.dismissed", true); |
michael@0 | 1238 | }, |
michael@0 | 1239 | }; |
michael@0 | 1240 | |
michael@0 | 1241 | var PanelUI = { |
michael@0 | 1242 | get _panels() { return document.getElementById("panel-items"); }, |
michael@0 | 1243 | |
michael@0 | 1244 | get isVisible() { |
michael@0 | 1245 | return !Elements.panelUI.hidden; |
michael@0 | 1246 | }, |
michael@0 | 1247 | |
michael@0 | 1248 | views: { |
michael@0 | 1249 | "console-container": "ConsolePanelView", |
michael@0 | 1250 | }, |
michael@0 | 1251 | |
michael@0 | 1252 | init: function() { |
michael@0 | 1253 | // Perform core init soon |
michael@0 | 1254 | setTimeout(function () { |
michael@0 | 1255 | for each (let viewName in this.views) { |
michael@0 | 1256 | let view = window[viewName]; |
michael@0 | 1257 | if (view.init) |
michael@0 | 1258 | view.init(); |
michael@0 | 1259 | } |
michael@0 | 1260 | }.bind(this), 0); |
michael@0 | 1261 | |
michael@0 | 1262 | // Lazily run other initialization tasks when the views are shown |
michael@0 | 1263 | this._panels.addEventListener("ToolPanelShown", function(aEvent) { |
michael@0 | 1264 | let viewName = this.views[this._panels.selectedPanel.id]; |
michael@0 | 1265 | let view = window[viewName]; |
michael@0 | 1266 | if (view.show) |
michael@0 | 1267 | view.show(); |
michael@0 | 1268 | }.bind(this), true); |
michael@0 | 1269 | }, |
michael@0 | 1270 | |
michael@0 | 1271 | uninit: function() { |
michael@0 | 1272 | for each (let viewName in this.views) { |
michael@0 | 1273 | let view = window[viewName]; |
michael@0 | 1274 | if (view.uninit) |
michael@0 | 1275 | view.uninit(); |
michael@0 | 1276 | } |
michael@0 | 1277 | }, |
michael@0 | 1278 | |
michael@0 | 1279 | switchPane: function switchPane(aPanelId) { |
michael@0 | 1280 | BrowserUI.blurFocusedElement(); |
michael@0 | 1281 | |
michael@0 | 1282 | let panel = aPanelId ? document.getElementById(aPanelId) : this._panels.selectedPanel; |
michael@0 | 1283 | let oldPanel = this._panels.selectedPanel; |
michael@0 | 1284 | |
michael@0 | 1285 | if (oldPanel != panel) { |
michael@0 | 1286 | this._panels.selectedPanel = panel; |
michael@0 | 1287 | |
michael@0 | 1288 | this._fire("ToolPanelHidden", oldPanel); |
michael@0 | 1289 | } |
michael@0 | 1290 | |
michael@0 | 1291 | this._fire("ToolPanelShown", panel); |
michael@0 | 1292 | }, |
michael@0 | 1293 | |
michael@0 | 1294 | isPaneVisible: function isPaneVisible(aPanelId) { |
michael@0 | 1295 | return this.isVisible && this._panels.selectedPanel.id == aPanelId; |
michael@0 | 1296 | }, |
michael@0 | 1297 | |
michael@0 | 1298 | show: function show(aPanelId) { |
michael@0 | 1299 | Elements.panelUI.hidden = false; |
michael@0 | 1300 | Elements.contentShowing.setAttribute("disabled", "true"); |
michael@0 | 1301 | |
michael@0 | 1302 | this.switchPane(aPanelId); |
michael@0 | 1303 | }, |
michael@0 | 1304 | |
michael@0 | 1305 | hide: function hide() { |
michael@0 | 1306 | if (!this.isVisible) |
michael@0 | 1307 | return; |
michael@0 | 1308 | |
michael@0 | 1309 | Elements.panelUI.hidden = true; |
michael@0 | 1310 | Elements.contentShowing.removeAttribute("disabled"); |
michael@0 | 1311 | BrowserUI.blurFocusedElement(); |
michael@0 | 1312 | |
michael@0 | 1313 | this._fire("ToolPanelHidden", this._panels); |
michael@0 | 1314 | }, |
michael@0 | 1315 | |
michael@0 | 1316 | toggle: function toggle() { |
michael@0 | 1317 | if (this.isVisible) { |
michael@0 | 1318 | this.hide(); |
michael@0 | 1319 | } else { |
michael@0 | 1320 | this.show(); |
michael@0 | 1321 | } |
michael@0 | 1322 | }, |
michael@0 | 1323 | |
michael@0 | 1324 | _fire: function _fire(aName, anElement) { |
michael@0 | 1325 | let event = document.createEvent("Events"); |
michael@0 | 1326 | event.initEvent(aName, true, true); |
michael@0 | 1327 | anElement.dispatchEvent(event); |
michael@0 | 1328 | } |
michael@0 | 1329 | }; |
michael@0 | 1330 | |
michael@0 | 1331 | var DialogUI = { |
michael@0 | 1332 | _popup: null, |
michael@0 | 1333 | |
michael@0 | 1334 | init: function() { |
michael@0 | 1335 | window.addEventListener("mousedown", this, true); |
michael@0 | 1336 | }, |
michael@0 | 1337 | |
michael@0 | 1338 | /******************************************* |
michael@0 | 1339 | * Popups |
michael@0 | 1340 | */ |
michael@0 | 1341 | |
michael@0 | 1342 | pushPopup: function pushPopup(aPanel, aElements, aParent) { |
michael@0 | 1343 | this._hidePopup(); |
michael@0 | 1344 | this._popup = { "panel": aPanel, |
michael@0 | 1345 | "elements": (aElements instanceof Array) ? aElements : [aElements] }; |
michael@0 | 1346 | this._dispatchPopupChanged(true, aPanel); |
michael@0 | 1347 | }, |
michael@0 | 1348 | |
michael@0 | 1349 | popPopup: function popPopup(aPanel) { |
michael@0 | 1350 | if (!this._popup || aPanel != this._popup.panel) |
michael@0 | 1351 | return; |
michael@0 | 1352 | this._popup = null; |
michael@0 | 1353 | this._dispatchPopupChanged(false, aPanel); |
michael@0 | 1354 | }, |
michael@0 | 1355 | |
michael@0 | 1356 | _hidePopup: function _hidePopup() { |
michael@0 | 1357 | if (!this._popup) |
michael@0 | 1358 | return; |
michael@0 | 1359 | let panel = this._popup.panel; |
michael@0 | 1360 | if (panel.hide) |
michael@0 | 1361 | panel.hide(); |
michael@0 | 1362 | }, |
michael@0 | 1363 | |
michael@0 | 1364 | /******************************************* |
michael@0 | 1365 | * Events |
michael@0 | 1366 | */ |
michael@0 | 1367 | |
michael@0 | 1368 | handleEvent: function (aEvent) { |
michael@0 | 1369 | switch (aEvent.type) { |
michael@0 | 1370 | case "mousedown": |
michael@0 | 1371 | if (!this._isEventInsidePopup(aEvent)) |
michael@0 | 1372 | this._hidePopup(); |
michael@0 | 1373 | break; |
michael@0 | 1374 | default: |
michael@0 | 1375 | break; |
michael@0 | 1376 | } |
michael@0 | 1377 | }, |
michael@0 | 1378 | |
michael@0 | 1379 | _dispatchPopupChanged: function _dispatchPopupChanged(aVisible, aElement) { |
michael@0 | 1380 | let event = document.createEvent("UIEvents"); |
michael@0 | 1381 | event.initUIEvent("PopupChanged", true, true, window, aVisible); |
michael@0 | 1382 | aElement.dispatchEvent(event); |
michael@0 | 1383 | }, |
michael@0 | 1384 | |
michael@0 | 1385 | _isEventInsidePopup: function _isEventInsidePopup(aEvent) { |
michael@0 | 1386 | if (!this._popup) |
michael@0 | 1387 | return false; |
michael@0 | 1388 | let elements = this._popup.elements; |
michael@0 | 1389 | let targetNode = aEvent.target; |
michael@0 | 1390 | while (targetNode && elements.indexOf(targetNode) == -1) { |
michael@0 | 1391 | if (targetNode instanceof Element && targetNode.hasAttribute("for")) |
michael@0 | 1392 | targetNode = document.getElementById(targetNode.getAttribute("for")); |
michael@0 | 1393 | else |
michael@0 | 1394 | targetNode = targetNode.parentNode; |
michael@0 | 1395 | } |
michael@0 | 1396 | return targetNode ? true : false; |
michael@0 | 1397 | } |
michael@0 | 1398 | }; |