browser/metro/base/content/browser-ui.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

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 };

mercurial