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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/metro/base/content/browser-ui.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1398 @@
     1.4 +// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +"use strict";
     1.9 +
    1.10 +Cu.import("resource://gre/modules/devtools/dbg-server.jsm")
    1.11 +Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
    1.12 +
    1.13 +/**
    1.14 + * Constants
    1.15 + */
    1.16 +
    1.17 +// Devtools Messages
    1.18 +const debugServerStateChanged = "devtools.debugger.remote-enabled";
    1.19 +const debugServerPortChanged = "devtools.debugger.remote-port";
    1.20 +
    1.21 +// delay when showing the tab bar briefly after a new foreground tab opens
    1.22 +const kForegroundTabAnimationDelay = 1000;
    1.23 +// delay when showing the tab bar after opening a new background tab opens
    1.24 +const kBackgroundTabAnimationDelay = 3000;
    1.25 +// delay before closing tab bar after closing or selecting a tab
    1.26 +const kChangeTabAnimationDelay = 500;
    1.27 +
    1.28 +/**
    1.29 + * Cache of commonly used elements.
    1.30 + */
    1.31 +
    1.32 +let Elements = {};
    1.33 +[
    1.34 +  ["contentShowing",     "bcast_contentShowing"],
    1.35 +  ["urlbarState",        "bcast_urlbarState"],
    1.36 +  ["loadingState",       "bcast_loadingState"],
    1.37 +  ["windowState",        "bcast_windowState"],
    1.38 +  ["chromeState",        "bcast_chromeState"],
    1.39 +  ["mainKeyset",         "mainKeyset"],
    1.40 +  ["stack",              "stack"],
    1.41 +  ["tabList",            "tabs"],
    1.42 +  ["tabs",               "tabs-container"],
    1.43 +  ["controls",           "browser-controls"],
    1.44 +  ["panelUI",            "panel-container"],
    1.45 +  ["tray",               "tray"],
    1.46 +  ["toolbar",            "toolbar"],
    1.47 +  ["browsers",           "browsers"],
    1.48 +  ["navbar",             "navbar"],
    1.49 +  ["autocomplete",       "urlbar-autocomplete"],
    1.50 +  ["contextappbar",      "contextappbar"],
    1.51 +  ["findbar",            "findbar"],
    1.52 +  ["contentViewport",    "content-viewport"],
    1.53 +  ["progress",           "progress-control"],
    1.54 +  ["progressContainer",  "progress-container"],
    1.55 +  ["feedbackLabel",  "feedback-label"],
    1.56 +].forEach(function (aElementGlobal) {
    1.57 +  let [name, id] = aElementGlobal;
    1.58 +  XPCOMUtils.defineLazyGetter(Elements, name, function() {
    1.59 +    return document.getElementById(id);
    1.60 +  });
    1.61 +});
    1.62 +
    1.63 +/**
    1.64 + * Cache of commonly used string bundles.
    1.65 + */
    1.66 +
    1.67 +var Strings = {};
    1.68 +[
    1.69 +  ["browser",    "chrome://browser/locale/browser.properties"],
    1.70 +  ["brand",      "chrome://branding/locale/brand.properties"]
    1.71 +].forEach(function (aStringBundle) {
    1.72 +  let [name, bundle] = aStringBundle;
    1.73 +  XPCOMUtils.defineLazyGetter(Strings, name, function() {
    1.74 +    return Services.strings.createBundle(bundle);
    1.75 +  });
    1.76 +});
    1.77 +
    1.78 +var BrowserUI = {
    1.79 +  get _edit() { return document.getElementById("urlbar-edit"); },
    1.80 +  get _back() { return document.getElementById("cmd_back"); },
    1.81 +  get _forward() { return document.getElementById("cmd_forward"); },
    1.82 +
    1.83 +  lastKnownGoodURL: "", // used when the user wants to escape unfinished url entry
    1.84 +  ready: false, // used for tests to determine when delayed initialization is done
    1.85 +
    1.86 +  init: function() {
    1.87 +    // start the debugger now so we can use it on the startup code as well
    1.88 +    if (Services.prefs.getBoolPref(debugServerStateChanged)) {
    1.89 +      this.runDebugServer();
    1.90 +    }
    1.91 +    Services.prefs.addObserver(debugServerStateChanged, this, false);
    1.92 +    Services.prefs.addObserver(debugServerPortChanged, this, false);
    1.93 +    Services.prefs.addObserver("app.crashreporter.autosubmit", this, false);
    1.94 +    Services.prefs.addObserver("metro.private_browsing.enabled", this, false);
    1.95 +    this.updatePrivateBrowsingUI();
    1.96 +
    1.97 +    Services.obs.addObserver(this, "handle-xul-text-link", false);
    1.98 +
    1.99 +    // listen content messages
   1.100 +    messageManager.addMessageListener("DOMTitleChanged", this);
   1.101 +    messageManager.addMessageListener("DOMWillOpenModalDialog", this);
   1.102 +    messageManager.addMessageListener("DOMWindowClose", this);
   1.103 +
   1.104 +    messageManager.addMessageListener("Browser:OpenURI", this);
   1.105 +    messageManager.addMessageListener("Browser:SaveAs:Return", this);
   1.106 +    messageManager.addMessageListener("Content:StateChange", this);
   1.107 +
   1.108 +    // listening escape to dismiss dialog on VK_ESCAPE
   1.109 +    window.addEventListener("keypress", this, true);
   1.110 +
   1.111 +    window.addEventListener("MozPrecisePointer", this, true);
   1.112 +    window.addEventListener("MozImprecisePointer", this, true);
   1.113 +
   1.114 +    window.addEventListener("AppCommand", this, true);
   1.115 +
   1.116 +    Services.prefs.addObserver("browser.cache.disk_cache_ssl", this, false);
   1.117 +
   1.118 +    // Init core UI modules
   1.119 +    ContextUI.init();
   1.120 +    PanelUI.init();
   1.121 +    FlyoutPanelsUI.init();
   1.122 +    PageThumbs.init();
   1.123 +    NewTabUtils.init();
   1.124 +    SettingsCharm.init();
   1.125 +    NavButtonSlider.init();
   1.126 +    SelectionHelperUI.init();
   1.127 +#ifdef NIGHTLY_BUILD
   1.128 +    ShumwayUtils.init();
   1.129 +#endif
   1.130 +
   1.131 +    // We can delay some initialization until after startup.  We wait until
   1.132 +    // the first page is shown, then dispatch a UIReadyDelayed event.
   1.133 +    messageManager.addMessageListener("pageshow", function onPageShow() {
   1.134 +      if (getBrowser().currentURI.spec == "about:blank")
   1.135 +        return;
   1.136 +
   1.137 +      messageManager.removeMessageListener("pageshow", onPageShow);
   1.138 +
   1.139 +      setTimeout(function() {
   1.140 +        let event = document.createEvent("Events");
   1.141 +        event.initEvent("UIReadyDelayed", true, false);
   1.142 +        window.dispatchEvent(event);
   1.143 +        BrowserUI.ready = true;
   1.144 +      }, 0);
   1.145 +    });
   1.146 +
   1.147 +    // Only load IndexedDB.js when we actually need it. A general fix will happen in bug 647079.
   1.148 +    messageManager.addMessageListener("IndexedDB:Prompt", function(aMessage) {
   1.149 +      return IndexedDB.receiveMessage(aMessage);
   1.150 +    });
   1.151 +
   1.152 +    // hook up telemetry ping for UI data
   1.153 +    try {
   1.154 +      UITelemetry.addSimpleMeasureFunction("metro-ui",
   1.155 +                                           BrowserUI._getMeasures.bind(BrowserUI));
   1.156 +    } catch (ex) {
   1.157 +      // swallow exception that occurs if metro-appbar measure is already set up
   1.158 +      dump("Failed to addSimpleMeasureFunction in browser-ui: " + ex.message + "\n");
   1.159 +    }
   1.160 +
   1.161 +    // Delay the panel UI and Sync initialization
   1.162 +    window.addEventListener("UIReadyDelayed", function delayedInit(aEvent) {
   1.163 +      Util.dumpLn("* delay load started...");
   1.164 +      window.removeEventListener("UIReadyDelayed",  delayedInit, false);
   1.165 +
   1.166 +      // Login Manager and Form History initialization
   1.167 +      Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
   1.168 +      messageManager.addMessageListener("Browser:MozApplicationManifest", OfflineApps);
   1.169 +
   1.170 +      try {
   1.171 +        MetroDownloadsView.init();
   1.172 +        DialogUI.init();
   1.173 +        FormHelperUI.init();
   1.174 +        FindHelperUI.init();
   1.175 +#ifdef NIGHTLY_BUILD
   1.176 +        PdfJs.init();
   1.177 +#endif
   1.178 +      } catch(ex) {
   1.179 +        Util.dumpLn("Exception in delay load module:", ex.message);
   1.180 +      }
   1.181 +
   1.182 +      BrowserUI._initFirstRunContent();
   1.183 +
   1.184 +      // check for left over crash reports and submit them if found.
   1.185 +      BrowserUI.startupCrashCheck();
   1.186 +
   1.187 +      Util.dumpLn("* delay load complete.");
   1.188 +    }, false);
   1.189 +
   1.190 +#ifndef MOZ_OFFICIAL_BRANDING
   1.191 +    setTimeout(function() {
   1.192 +      let startup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup).getStartupInfo();
   1.193 +      for (let name in startup) {
   1.194 +        if (name != "process")
   1.195 +          Services.console.logStringMessage("[timing] " + name + ": " + (startup[name] - startup.process) + "ms");
   1.196 +      }
   1.197 +    }, 3000);
   1.198 +#endif
   1.199 +  },
   1.200 +
   1.201 +  uninit: function() {
   1.202 +    messageManager.removeMessageListener("DOMTitleChanged", this);
   1.203 +    messageManager.removeMessageListener("DOMWillOpenModalDialog", this);
   1.204 +    messageManager.removeMessageListener("DOMWindowClose", this);
   1.205 +
   1.206 +    messageManager.removeMessageListener("Browser:OpenURI", this);
   1.207 +    messageManager.removeMessageListener("Browser:SaveAs:Return", this);
   1.208 +    messageManager.removeMessageListener("Content:StateChange", this);
   1.209 +
   1.210 +    messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps);
   1.211 +
   1.212 +    Services.prefs.removeObserver(debugServerStateChanged, this);
   1.213 +    Services.prefs.removeObserver(debugServerPortChanged, this);
   1.214 +    Services.prefs.removeObserver("app.crashreporter.autosubmit", this);
   1.215 +    Services.prefs.removeObserver("metro.private_browsing.enabled", this);
   1.216 +
   1.217 +    Services.obs.removeObserver(this, "handle-xul-text-link");
   1.218 +
   1.219 +    PanelUI.uninit();
   1.220 +    FlyoutPanelsUI.uninit();
   1.221 +    MetroDownloadsView.uninit();
   1.222 +    SettingsCharm.uninit();
   1.223 +    PageThumbs.uninit();
   1.224 +    if (WindowsPrefSync) {
   1.225 +      WindowsPrefSync.uninit();
   1.226 +    }
   1.227 +    this.stopDebugServer();
   1.228 +  },
   1.229 +
   1.230 +  /************************************
   1.231 +   * Devtools Debugger
   1.232 +   */
   1.233 +  runDebugServer: function runDebugServer(aPort) {
   1.234 +    let port = aPort || Services.prefs.getIntPref(debugServerPortChanged);
   1.235 +    if (!DebuggerServer.initialized) {
   1.236 +      DebuggerServer.init();
   1.237 +      DebuggerServer.addBrowserActors();
   1.238 +      DebuggerServer.addActors('chrome://browser/content/dbg-metro-actors.js');
   1.239 +    }
   1.240 +    DebuggerServer.openListener(port);
   1.241 +  },
   1.242 +
   1.243 +  stopDebugServer: function stopDebugServer() {
   1.244 +    if (DebuggerServer.initialized) {
   1.245 +      DebuggerServer.destroy();
   1.246 +    }
   1.247 +  },
   1.248 +
   1.249 +  // If the server is not on, port changes have nothing to effect. The new value
   1.250 +  //    will be picked up if the server is started.
   1.251 +  // To be consistent with desktop fx, if the port is changed while the server
   1.252 +  //    is running, restart server.
   1.253 +  changeDebugPort:function changeDebugPort(aPort) {
   1.254 +    if (DebuggerServer.initialized) {
   1.255 +      this.stopDebugServer();
   1.256 +      this.runDebugServer(aPort);
   1.257 +    }
   1.258 +  },
   1.259 +
   1.260 +  /*********************************
   1.261 +   * Content visibility
   1.262 +   */
   1.263 +
   1.264 +  get isContentShowing() {
   1.265 +    return Elements.contentShowing.getAttribute("disabled") != true;
   1.266 +  },
   1.267 +
   1.268 +  showContent: function showContent(aURI) {
   1.269 +    ContextUI.dismissTabs();
   1.270 +    ContextUI.dismissContextAppbar();
   1.271 +    FlyoutPanelsUI.hide();
   1.272 +    PanelUI.hide();
   1.273 +  },
   1.274 +
   1.275 +  /*********************************
   1.276 +   * Crash reporting
   1.277 +   */
   1.278 +
   1.279 +  get CrashSubmit() {
   1.280 +    delete this.CrashSubmit;
   1.281 +    Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
   1.282 +    return this.CrashSubmit;
   1.283 +  },
   1.284 +
   1.285 +  get lastCrashID() {
   1.286 +    return Cc["@mozilla.org/xre/runtime;1"].getService(Ci.nsIXULRuntime).lastRunCrashID;
   1.287 +  },
   1.288 +
   1.289 +  startupCrashCheck: function startupCrashCheck() {
   1.290 +#ifdef MOZ_CRASHREPORTER
   1.291 +    if (!CrashReporter.enabled) {
   1.292 +      return;
   1.293 +    }
   1.294 +
   1.295 +    // Ensure that CrashReporter state matches pref
   1.296 +    CrashReporter.submitReports = Services.prefs.getBoolPref("app.crashreporter.autosubmit");
   1.297 +
   1.298 +    BrowserUI.submitLastCrashReportOrShowPrompt();
   1.299 +#endif
   1.300 +  },
   1.301 +
   1.302 +
   1.303 +  /*********************************
   1.304 +   * Navigation
   1.305 +   */
   1.306 +
   1.307 +  // BrowserUI update bit flags
   1.308 +  NO_STARTUI_VISIBILITY:  1, // don't change the start ui visibility
   1.309 +
   1.310 +  /*
   1.311 +   * Updates the overall state of startui visibility and the toolbar, but not
   1.312 +   * the URL bar.
   1.313 +   */
   1.314 +  update: function(aFlags) {
   1.315 +    let flags = aFlags || 0;
   1.316 +    if (!(flags & this.NO_STARTUI_VISIBILITY)) {
   1.317 +      let uri = this.getDisplayURI(Browser.selectedBrowser);
   1.318 +      this.updateStartURIAttributes(uri);
   1.319 +    }
   1.320 +    this._updateButtons();
   1.321 +    this._updateToolbar();
   1.322 +  },
   1.323 +
   1.324 +  /* Updates the URL bar. */
   1.325 +  updateURI: function(aOptions) {
   1.326 +    let uri = this.getDisplayURI(Browser.selectedBrowser);
   1.327 +    let cleanURI = Util.isURLEmpty(uri) ? "" : uri;
   1.328 +    this._edit.value = cleanURI;
   1.329 +  },
   1.330 +
   1.331 +  get isStartTabVisible() {
   1.332 +    return this.isStartURI();
   1.333 +  },
   1.334 +
   1.335 +  isStartURI: function isStartURI(aURI) {
   1.336 +    aURI = aURI || Browser.selectedBrowser.currentURI.spec;
   1.337 +    return aURI.startsWith(kStartURI) || aURI == "about:start" || aURI == "about:home";
   1.338 +  },
   1.339 +
   1.340 +  updateStartURIAttributes: function (aURI) {
   1.341 +    let wasStart = Elements.windowState.hasAttribute("startpage");
   1.342 +    aURI = aURI || Browser.selectedBrowser.currentURI.spec;
   1.343 +    if (this.isStartURI(aURI)) {
   1.344 +      ContextUI.displayNavbar();
   1.345 +      Elements.windowState.setAttribute("startpage", "true");
   1.346 +    } else if (aURI != "about:blank") { // about:blank is loaded briefly for new tabs; ignore it
   1.347 +      Elements.windowState.removeAttribute("startpage");
   1.348 +    }
   1.349 +
   1.350 +    let isStart = Elements.windowState.hasAttribute("startpage");
   1.351 +    if (wasStart != isStart) {
   1.352 +      let event = document.createEvent("Events");
   1.353 +      event.initEvent("StartUIChange", true, true);
   1.354 +      Browser.selectedBrowser.dispatchEvent(event);
   1.355 +    }
   1.356 +  },
   1.357 +
   1.358 +  getDisplayURI: function(browser) {
   1.359 +    let uri = browser.currentURI;
   1.360 +    let spec = uri.spec;
   1.361 +
   1.362 +    try {
   1.363 +      spec = gURIFixup.createExposableURI(uri).spec;
   1.364 +    } catch (ex) {}
   1.365 +
   1.366 +    try {
   1.367 +      let charset = browser.characterSet;
   1.368 +      let textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"].
   1.369 +                         getService(Ci.nsITextToSubURI);
   1.370 +      spec = textToSubURI.unEscapeNonAsciiURI(charset, spec);
   1.371 +    } catch (ex) {}
   1.372 +
   1.373 +    return spec;
   1.374 +  },
   1.375 +
   1.376 +  goToURI: function(aURI) {
   1.377 +    aURI = aURI || this._edit.value;
   1.378 +    if (!aURI)
   1.379 +      return;
   1.380 +
   1.381 +    this._edit.value = aURI;
   1.382 +
   1.383 +    // Make sure we're online before attempting to load
   1.384 +    Util.forceOnline();
   1.385 +
   1.386 +    BrowserUI.showContent(aURI);
   1.387 +    Browser.selectedBrowser.focus();
   1.388 +
   1.389 +    Task.spawn(function() {
   1.390 +      let postData = {};
   1.391 +      let webNav = Ci.nsIWebNavigation;
   1.392 +      let flags = webNav.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP |
   1.393 +                  webNav.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
   1.394 +      aURI = yield Browser.getShortcutOrURI(aURI, postData);
   1.395 +      Browser.loadURI(aURI, { flags: flags, postData: postData });
   1.396 +
   1.397 +      // Delay doing the fixup so the raw URI is passed to loadURIWithFlags
   1.398 +      // and the proper third-party fixup can be done
   1.399 +      let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
   1.400 +                       Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS;
   1.401 +      let uri = gURIFixup.createFixupURI(aURI, fixupFlags);
   1.402 +      gHistSvc.markPageAsTyped(uri);
   1.403 +
   1.404 +      BrowserUI._titleChanged(Browser.selectedBrowser);
   1.405 +    });
   1.406 +  },
   1.407 +
   1.408 +  doOpenSearch: function doOpenSearch(aName) {
   1.409 +    // save the current value of the urlbar
   1.410 +    let searchValue = this._edit.value;
   1.411 +    let engine = Services.search.getEngineByName(aName);
   1.412 +    let submission = engine.getSubmission(searchValue, null);
   1.413 +
   1.414 +    this._edit.value = submission.uri.spec;
   1.415 +
   1.416 +    // Make sure we're online before attempting to load
   1.417 +    Util.forceOnline();
   1.418 +
   1.419 +    BrowserUI.showContent();
   1.420 +    Browser.selectedBrowser.focus();
   1.421 +
   1.422 +    Task.spawn(function () {
   1.423 +      Browser.loadURI(submission.uri.spec, { postData: submission.postData });
   1.424 +
   1.425 +      // loadURI may open a new tab, so get the selectedBrowser afterward.
   1.426 +      Browser.selectedBrowser.userTypedValue = submission.uri.spec;
   1.427 +      BrowserUI._titleChanged(Browser.selectedBrowser);
   1.428 +    });
   1.429 +  },
   1.430 +
   1.431 +  /*********************************
   1.432 +   * Tab management
   1.433 +   */
   1.434 +
   1.435 +  /**
   1.436 +   * Open a new tab in the foreground in response to a user action.
   1.437 +   * See Browser.addTab for more documentation.
   1.438 +   */
   1.439 +  addAndShowTab: function (aURI, aOwner, aParams) {
   1.440 +    ContextUI.peekTabs(kForegroundTabAnimationDelay);
   1.441 +    return Browser.addTab(aURI || kStartURI, true, aOwner, aParams);
   1.442 +  },
   1.443 +
   1.444 +  addAndShowPrivateTab: function (aURI, aOwner) {
   1.445 +    return this.addAndShowTab(aURI, aOwner, { private: true });
   1.446 +  },
   1.447 +
   1.448 +  get isPrivateBrowsingEnabled() {
   1.449 +    return Services.prefs.getBoolPref("metro.private_browsing.enabled");
   1.450 +  },
   1.451 +
   1.452 +  updatePrivateBrowsingUI: function () {
   1.453 +    let command = document.getElementById("cmd_newPrivateTab");
   1.454 +    if (this.isPrivateBrowsingEnabled) {
   1.455 +      command.removeAttribute("disabled");
   1.456 +    } else {
   1.457 +      command.setAttribute("disabled", "true");
   1.458 +    }
   1.459 +  },
   1.460 +
   1.461 +  /**
   1.462 +   * Open a new tab in response to clicking a link in an existing tab.
   1.463 +   * See Browser.addTab for more documentation.
   1.464 +   */
   1.465 +  openLinkInNewTab: function (aURI, aBringFront, aOwner) {
   1.466 +    ContextUI.peekTabs(aBringFront ? kForegroundTabAnimationDelay
   1.467 +                                   : kBackgroundTabAnimationDelay);
   1.468 +    let params = null;
   1.469 +    if (aOwner) {
   1.470 +      params = {
   1.471 +        referrerURI: aOwner.browser.documentURI,
   1.472 +        charset: aOwner.browser.characterSet,
   1.473 +      };
   1.474 +    }
   1.475 +    let tab = Browser.addTab(aURI, aBringFront, aOwner, params);
   1.476 +    Elements.tabList.strip.ensureElementIsVisible(tab.chromeTab);
   1.477 +    return tab;
   1.478 +  },
   1.479 +
   1.480 +  setOnTabAnimationEnd: function setOnTabAnimationEnd(aCallback) {
   1.481 +    Elements.tabs.addEventListener("animationend", function onAnimationEnd() {
   1.482 +      Elements.tabs.removeEventListener("animationend", onAnimationEnd);
   1.483 +      aCallback();
   1.484 +    });
   1.485 +  },
   1.486 +
   1.487 +  closeTab: function closeTab(aTab) {
   1.488 +    // If no tab is passed in, assume the current tab
   1.489 +    let tab = aTab || Browser.selectedTab;
   1.490 +    Browser.closeTab(tab);
   1.491 +  },
   1.492 +
   1.493 +  animateClosingTab: function animateClosingTab(tabToClose) {
   1.494 +    tabToClose.chromeTab.setAttribute("closing", "true");
   1.495 +
   1.496 +    let wasCollapsed = !ContextUI.tabbarVisible;
   1.497 +    if (wasCollapsed) {
   1.498 +      ContextUI.displayTabs();
   1.499 +    }
   1.500 +
   1.501 +    this.setOnTabAnimationEnd(function() {
   1.502 +      Browser.closeTab(tabToClose, { forceClose: true } );
   1.503 +      if (wasCollapsed)
   1.504 +        ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay);
   1.505 +    });
   1.506 +  },
   1.507 +
   1.508 +  /**
   1.509 +    * Re-open a closed tab.
   1.510 +    * @param aIndex
   1.511 +    *        The index of the tab (via nsSessionStore.getClosedTabData)
   1.512 +    * @returns a reference to the reopened tab.
   1.513 +    */
   1.514 +  undoCloseTab: function undoCloseTab(aIndex) {
   1.515 +    var tab = null;
   1.516 +    aIndex = aIndex || 0;
   1.517 +    var ss = Cc["@mozilla.org/browser/sessionstore;1"].
   1.518 +                getService(Ci.nsISessionStore);
   1.519 +    if (ss.getClosedTabCount(window) > (aIndex)) {
   1.520 +      tab = ss.undoCloseTab(window, aIndex);
   1.521 +    }
   1.522 +    return tab;
   1.523 +  },
   1.524 +
   1.525 +  // Useful for when we've received an event to close a particular DOM window.
   1.526 +  // Since we don't have windows, we want to close the corresponding tab.
   1.527 +  closeTabForBrowser: function closeTabForBrowser(aBrowser) {
   1.528 +    // Find the relevant tab, and close it.
   1.529 +    let browsers = Browser.browsers;
   1.530 +    for (let i = 0; i < browsers.length; i++) {
   1.531 +      if (browsers[i] == aBrowser) {
   1.532 +        Browser.closeTab(Browser.getTabAtIndex(i));
   1.533 +        return { preventDefault: true };
   1.534 +      }
   1.535 +    }
   1.536 +
   1.537 +    return {};
   1.538 +  },
   1.539 +
   1.540 +  selectTab: function selectTab(aTab) {
   1.541 +    Browser.selectedTab = aTab;
   1.542 +  },
   1.543 +
   1.544 +  selectTabAndDismiss: function selectTabAndDismiss(aTab) {
   1.545 +    this.selectTab(aTab);
   1.546 +    ContextUI.dismissTabsWithDelay(kChangeTabAnimationDelay);
   1.547 +  },
   1.548 +
   1.549 +  selectTabAtIndex: function selectTabAtIndex(aIndex) {
   1.550 +    // count backwards for aIndex < 0
   1.551 +    if (aIndex < 0)
   1.552 +      aIndex += Browser._tabs.length;
   1.553 +
   1.554 +    if (aIndex >= 0 && aIndex < Browser._tabs.length)
   1.555 +      Browser.selectedTab = Browser._tabs[aIndex];
   1.556 +  },
   1.557 +
   1.558 +  selectNextTab: function selectNextTab() {
   1.559 +    if (Browser._tabs.length == 1 || !Browser.selectedTab) {
   1.560 +     return;
   1.561 +    }
   1.562 +
   1.563 +    let tabIndex = Browser._tabs.indexOf(Browser.selectedTab) + 1;
   1.564 +    if (tabIndex >= Browser._tabs.length) {
   1.565 +      tabIndex = 0;
   1.566 +    }
   1.567 +
   1.568 +    Browser.selectedTab = Browser._tabs[tabIndex];
   1.569 +  },
   1.570 +
   1.571 +  selectPreviousTab: function selectPreviousTab() {
   1.572 +    if (Browser._tabs.length == 1 || !Browser.selectedTab) {
   1.573 +      return;
   1.574 +    }
   1.575 +
   1.576 +    let tabIndex = Browser._tabs.indexOf(Browser.selectedTab) - 1;
   1.577 +    if (tabIndex < 0) {
   1.578 +      tabIndex = Browser._tabs.length - 1;
   1.579 +    }
   1.580 +
   1.581 +    Browser.selectedTab = Browser._tabs[tabIndex];
   1.582 +  },
   1.583 +
   1.584 +  // Used for when we're about to open a modal dialog,
   1.585 +  // and want to ensure the opening tab is in front.
   1.586 +  selectTabForBrowser: function selectTabForBrowser(aBrowser) {
   1.587 +    for (let i = 0; i < Browser.tabs.length; i++) {
   1.588 +      if (Browser._tabs[i].browser == aBrowser) {
   1.589 +        Browser.selectedTab = Browser.tabs[i];
   1.590 +        break;
   1.591 +      }
   1.592 +    }
   1.593 +  },
   1.594 +
   1.595 +  updateUIFocus: function _updateUIFocus() {
   1.596 +    if (Elements.contentShowing.getAttribute("disabled") == "true" && Browser.selectedBrowser)
   1.597 +      Browser.selectedBrowser.messageManager.sendAsyncMessage("Browser:Blur", { });
   1.598 +  },
   1.599 +
   1.600 +  blurFocusedElement: function blurFocusedElement() {
   1.601 +    let focusedElement = document.commandDispatcher.focusedElement;
   1.602 +    if (focusedElement)
   1.603 +      focusedElement.blur();
   1.604 +  },
   1.605 +
   1.606 +  blurNavBar: function blurNavBar() {
   1.607 +    if (this._edit.focused) {
   1.608 +      this._edit.blur();
   1.609 +
   1.610 +      // Advanced notice to CAO, so we can shuffle the nav bar in advance
   1.611 +      // of the keyboard transition.
   1.612 +      ContentAreaObserver.navBarWillBlur();
   1.613 +
   1.614 +      return true;
   1.615 +    }
   1.616 +    return false;
   1.617 +  },
   1.618 +
   1.619 +  observe: function BrowserUI_observe(aSubject, aTopic, aData) {
   1.620 +    switch (aTopic) {
   1.621 +      case "handle-xul-text-link":
   1.622 +        let handled = aSubject.QueryInterface(Ci.nsISupportsPRBool);
   1.623 +        if (!handled.data) {
   1.624 +          this.addAndShowTab(aData, Browser.selectedTab);
   1.625 +          handled.data = true;
   1.626 +        }
   1.627 +        break;
   1.628 +      case "nsPref:changed":
   1.629 +        switch (aData) {
   1.630 +          case "browser.cache.disk_cache_ssl":
   1.631 +            this._sslDiskCacheEnabled = Services.prefs.getBoolPref(aData);
   1.632 +            break;
   1.633 +          case debugServerStateChanged:
   1.634 +            if (Services.prefs.getBoolPref(aData)) {
   1.635 +              this.runDebugServer();
   1.636 +            } else {
   1.637 +              this.stopDebugServer();
   1.638 +            }
   1.639 +            break;
   1.640 +          case debugServerPortChanged:
   1.641 +            this.changeDebugPort(Services.prefs.getIntPref(aData));
   1.642 +            break;
   1.643 +          case "app.crashreporter.autosubmit":
   1.644 +#ifdef MOZ_CRASHREPORTER
   1.645 +            CrashReporter.submitReports = Services.prefs.getBoolPref(aData);
   1.646 +
   1.647 +            // The user explicitly set the autosubmit option, so there is no
   1.648 +            // need to prompt them about crash reporting in the future
   1.649 +            Services.prefs.setBoolPref("app.crashreporter.prompted", true);
   1.650 +
   1.651 +            BrowserUI.submitLastCrashReportOrShowPrompt;
   1.652 +#endif
   1.653 +            break;
   1.654 +          case "metro.private_browsing.enabled":
   1.655 +            this.updatePrivateBrowsingUI();
   1.656 +            break;
   1.657 +        }
   1.658 +        break;
   1.659 +    }
   1.660 +  },
   1.661 +
   1.662 +  submitLastCrashReportOrShowPrompt: function() {
   1.663 +#ifdef MOZ_CRASHREPORTER
   1.664 +    let lastCrashID = this.lastCrashID;
   1.665 +    if (lastCrashID && lastCrashID.length) {
   1.666 +      if (Services.prefs.getBoolPref("app.crashreporter.autosubmit")) {
   1.667 +        Util.dumpLn("Submitting last crash id:", lastCrashID);
   1.668 +        let params = {};
   1.669 +        if (!Services.prefs.getBoolPref("app.crashreporter.submitURLs")) {
   1.670 +          params['extraExtraKeyVals'] = { URL: '' };
   1.671 +        }
   1.672 +        try {
   1.673 +          this.CrashSubmit.submit(lastCrashID, params);
   1.674 +        } catch (ex) {
   1.675 +          Util.dumpLn(ex);
   1.676 +        }
   1.677 +      } else if (!Services.prefs.getBoolPref("app.crashreporter.prompted")) {
   1.678 +        BrowserUI.addAndShowTab("about:crashprompt", null);
   1.679 +      }
   1.680 +    }
   1.681 +#endif
   1.682 +  },
   1.683 +
   1.684 +
   1.685 +
   1.686 +  /*********************************
   1.687 +   * Internal utils
   1.688 +   */
   1.689 +
   1.690 +  _titleChanged: function(aBrowser) {
   1.691 +    let url = this.getDisplayURI(aBrowser);
   1.692 +
   1.693 +    let tabCaption;
   1.694 +    if (aBrowser.contentTitle) {
   1.695 +      tabCaption = aBrowser.contentTitle;
   1.696 +    } else if (!Util.isURLEmpty(aBrowser.userTypedValue)) {
   1.697 +      tabCaption = aBrowser.userTypedValue;
   1.698 +    } else if (!Util.isURLEmpty(url)) {
   1.699 +      tabCaption = url;
   1.700 +    } else {
   1.701 +      tabCaption = Util.getEmptyURLTabTitle();
   1.702 +    }
   1.703 +
   1.704 +    let tab = Browser.getTabForBrowser(aBrowser);
   1.705 +    if (tab)
   1.706 +      tab.chromeTab.updateTitle(tabCaption);
   1.707 +  },
   1.708 +
   1.709 +  _updateButtons: function _updateButtons() {
   1.710 +    let browser = Browser.selectedBrowser;
   1.711 +    if (!browser) {
   1.712 +      return;
   1.713 +    }
   1.714 +    if (browser.canGoBack) {
   1.715 +      this._back.removeAttribute("disabled");
   1.716 +    } else {
   1.717 +      this._back.setAttribute("disabled", true);
   1.718 +    }
   1.719 +    if (browser.canGoForward) {
   1.720 +      this._forward.removeAttribute("disabled");
   1.721 +    } else {
   1.722 +      this._forward.setAttribute("disabled", true);
   1.723 +    }
   1.724 +  },
   1.725 +
   1.726 +  _updateToolbar: function _updateToolbar() {
   1.727 +    if (Browser.selectedTab.isLoading()) {
   1.728 +      Elements.loadingState.setAttribute("loading", true);
   1.729 +    } else {
   1.730 +      Elements.loadingState.removeAttribute("loading");
   1.731 +    }
   1.732 +  },
   1.733 +
   1.734 +  _closeOrQuit: function _closeOrQuit() {
   1.735 +    // Close active dialog, if we have one. If not then close the application.
   1.736 +    if (!BrowserUI.isContentShowing()) {
   1.737 +      BrowserUI.showContent();
   1.738 +    } else {
   1.739 +      // Check to see if we should really close the window
   1.740 +      if (Browser.closing()) {
   1.741 +        window.close();
   1.742 +        let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
   1.743 +        appStartup.quit(Ci.nsIAppStartup.eForceQuit);
   1.744 +      }
   1.745 +    }
   1.746 +  },
   1.747 +
   1.748 +  _onPreciseInput: function _onPreciseInput() {
   1.749 +    document.getElementById("bcast_preciseInput").setAttribute("input", "precise");
   1.750 +    let uri = Util.makeURI("chrome://browser/content/cursor.css");
   1.751 +    if (StyleSheetSvc.sheetRegistered(uri, Ci.nsIStyleSheetService.AGENT_SHEET)) {
   1.752 +      StyleSheetSvc.unregisterSheet(uri,
   1.753 +                                    Ci.nsIStyleSheetService.AGENT_SHEET);
   1.754 +    }
   1.755 +  },
   1.756 +
   1.757 +  _onImpreciseInput: function _onImpreciseInput() {
   1.758 +    document.getElementById("bcast_preciseInput").setAttribute("input", "imprecise");
   1.759 +    let uri = Util.makeURI("chrome://browser/content/cursor.css");
   1.760 +    if (!StyleSheetSvc.sheetRegistered(uri, Ci.nsIStyleSheetService.AGENT_SHEET)) {
   1.761 +      StyleSheetSvc.loadAndRegisterSheet(uri,
   1.762 +                                         Ci.nsIStyleSheetService.AGENT_SHEET);
   1.763 +    }
   1.764 +  },
   1.765 +
   1.766 +  _getMeasures: function() {
   1.767 +    let dimensions = {
   1.768 +      "window-width": ContentAreaObserver.width,
   1.769 +      "window-height": ContentAreaObserver.height
   1.770 +    };
   1.771 +    return dimensions;
   1.772 +  },
   1.773 +
   1.774 +  /*********************************
   1.775 +   * Event handling
   1.776 +   */
   1.777 +
   1.778 +  handleEvent: function handleEvent(aEvent) {
   1.779 +    var target = aEvent.target;
   1.780 +    switch (aEvent.type) {
   1.781 +      // Window events
   1.782 +      case "keypress":
   1.783 +        if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE)
   1.784 +          this.handleEscape(aEvent);
   1.785 +        break;
   1.786 +      case "MozPrecisePointer":
   1.787 +        this._onPreciseInput();
   1.788 +        break;
   1.789 +      case "MozImprecisePointer":
   1.790 +        this._onImpreciseInput();
   1.791 +        break;
   1.792 +      case "AppCommand":
   1.793 +        this.handleAppCommandEvent(aEvent);
   1.794 +        break;
   1.795 +    }
   1.796 +  },
   1.797 +
   1.798 +  // Checks if various different parts of the UI is visible and closes
   1.799 +  // them one at a time.
   1.800 +  handleEscape: function (aEvent) {
   1.801 +    aEvent.stopPropagation();
   1.802 +    aEvent.preventDefault();
   1.803 +
   1.804 +    if (this._edit.popupOpen) {
   1.805 +      this._edit.endEditing(true);
   1.806 +      return;
   1.807 +    }
   1.808 +
   1.809 +    // Check open popups
   1.810 +    if (DialogUI._popup) {
   1.811 +      DialogUI._hidePopup();
   1.812 +      return;
   1.813 +    }
   1.814 +
   1.815 +    // Check open panel
   1.816 +    if (PanelUI.isVisible) {
   1.817 +      PanelUI.hide();
   1.818 +      return;
   1.819 +    }
   1.820 +
   1.821 +    // Check content helper
   1.822 +    if (FindHelperUI.isActive) {
   1.823 +      FindHelperUI.hide();
   1.824 +      return;
   1.825 +    }
   1.826 +
   1.827 +    if (Browser.selectedTab.isLoading()) {
   1.828 +      Browser.selectedBrowser.stop();
   1.829 +      return;
   1.830 +    }
   1.831 +
   1.832 +    if (ContextUI.dismiss()) {
   1.833 +      return;
   1.834 +    }
   1.835 +  },
   1.836 +
   1.837 +  handleBackspace: function handleBackspace() {
   1.838 +    switch (Services.prefs.getIntPref("browser.backspace_action")) {
   1.839 +      case 0:
   1.840 +        CommandUpdater.doCommand("cmd_back");
   1.841 +        break;
   1.842 +      case 1:
   1.843 +        CommandUpdater.doCommand("cmd_scrollPageUp");
   1.844 +        break;
   1.845 +    }
   1.846 +  },
   1.847 +
   1.848 +  handleShiftBackspace: function handleShiftBackspace() {
   1.849 +    switch (Services.prefs.getIntPref("browser.backspace_action")) {
   1.850 +      case 0:
   1.851 +        CommandUpdater.doCommand("cmd_forward");
   1.852 +        break;
   1.853 +      case 1:
   1.854 +        CommandUpdater.doCommand("cmd_scrollPageDown");
   1.855 +        break;
   1.856 +    }
   1.857 +  },
   1.858 +
   1.859 +  openFile: function() {
   1.860 +    try {
   1.861 +      const nsIFilePicker = Ci.nsIFilePicker;
   1.862 +      let fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
   1.863 +      let self = this;
   1.864 +      let fpCallback = function fpCallback_done(aResult) {
   1.865 +        if (aResult == nsIFilePicker.returnOK) {
   1.866 +          self.goToURI(fp.fileURL.spec);
   1.867 +        }
   1.868 +      };
   1.869 +
   1.870 +      let windowTitle = Strings.browser.GetStringFromName("browserForOpenLocation");
   1.871 +      fp.init(window, windowTitle, nsIFilePicker.modeOpen);
   1.872 +      fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText |
   1.873 +                       nsIFilePicker.filterImages | nsIFilePicker.filterXML |
   1.874 +                       nsIFilePicker.filterHTML);
   1.875 +      fp.open(fpCallback);
   1.876 +    } catch (ex) {
   1.877 +      dump ('BrowserUI openFile exception: ' + ex + '\n');
   1.878 +    }
   1.879 +  },
   1.880 +
   1.881 +  savePage: function() {
   1.882 +    Browser.savePage();
   1.883 +  },
   1.884 +
   1.885 +  receiveMessage: function receiveMessage(aMessage) {
   1.886 +    let browser = aMessage.target;
   1.887 +    let json = aMessage.json;
   1.888 +    switch (aMessage.name) {
   1.889 +      case "DOMTitleChanged":
   1.890 +        this._titleChanged(browser);
   1.891 +        break;
   1.892 +      case "DOMWillOpenModalDialog":
   1.893 +        this.selectTabForBrowser(browser);
   1.894 +        break;
   1.895 +      case "DOMWindowClose":
   1.896 +        return this.closeTabForBrowser(browser);
   1.897 +        break;
   1.898 +      // XXX this and content's sender are a little warped
   1.899 +      case "Browser:OpenURI":
   1.900 +        let referrerURI = null;
   1.901 +        if (json.referrer)
   1.902 +          referrerURI = Services.io.newURI(json.referrer, null, null);
   1.903 +        this.goToURI(json.uri);
   1.904 +        break;
   1.905 +      case "Content:StateChange": {
   1.906 +        let tab = Browser.selectedTab;
   1.907 +        if (this.shouldCaptureThumbnails(tab)) {
   1.908 +          PageThumbs.captureAndStore(tab.browser);
   1.909 +          let currPage = tab.browser.currentURI.spec;
   1.910 +          Services.obs.notifyObservers(null, "Metro:RefreshTopsiteThumbnail", currPage);
   1.911 +        }
   1.912 +        break;
   1.913 +      }
   1.914 +    }
   1.915 +
   1.916 +    return {};
   1.917 +  },
   1.918 +
   1.919 +  shouldCaptureThumbnails: function shouldCaptureThumbnails(aTab) {
   1.920 +    // Capture only if it's the currently selected tab.
   1.921 +    if (aTab != Browser.selectedTab) {
   1.922 +      return false;
   1.923 +    }
   1.924 +    // Skip private tabs
   1.925 +    if (aTab.isPrivate) {
   1.926 +      return false;
   1.927 +    }
   1.928 +    // FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as
   1.929 +    //       that currently regresses Talos SVG tests.
   1.930 +    let browser = aTab.browser;
   1.931 +    let doc = browser.contentDocument;
   1.932 +    if (doc instanceof SVGDocument || doc instanceof XMLDocument) {
   1.933 +      return false;
   1.934 +    }
   1.935 +
   1.936 +    // Don't capture pages in snapped mode, this produces 2/3 black
   1.937 +    // thumbs or stretched out ones
   1.938 +    //   Ci.nsIWinMetroUtils.snapped is inaccessible on
   1.939 +    //   desktop/nonwindows systems
   1.940 +    if(Elements.windowState.getAttribute("viewstate") == "snapped") {
   1.941 +      return false;
   1.942 +    }
   1.943 +    // There's no point in taking screenshot of loading pages.
   1.944 +    if (browser.docShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE) {
   1.945 +      return false;
   1.946 +    }
   1.947 +
   1.948 +    // Don't take screenshots of about: pages.
   1.949 +    if (browser.currentURI.schemeIs("about")) {
   1.950 +      return false;
   1.951 +    }
   1.952 +
   1.953 +    // No valid document channel. We shouldn't take a screenshot.
   1.954 +    let channel = browser.docShell.currentDocumentChannel;
   1.955 +    if (!channel) {
   1.956 +      return false;
   1.957 +    }
   1.958 +
   1.959 +    // Don't take screenshots of internally redirecting about: pages.
   1.960 +    // This includes error pages.
   1.961 +    let uri = channel.originalURI;
   1.962 +    if (uri.schemeIs("about")) {
   1.963 +      return false;
   1.964 +    }
   1.965 +
   1.966 +    // http checks
   1.967 +    let httpChannel;
   1.968 +    try {
   1.969 +      httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
   1.970 +    } catch (e) { /* Not an HTTP channel. */ }
   1.971 +
   1.972 +    if (httpChannel) {
   1.973 +      // Continue only if we have a 2xx status code.
   1.974 +      try {
   1.975 +        if (Math.floor(httpChannel.responseStatus / 100) != 2) {
   1.976 +          return false;
   1.977 +        }
   1.978 +      } catch (e) {
   1.979 +        // Can't get response information from the httpChannel
   1.980 +        // because mResponseHead is not available.
   1.981 +        return false;
   1.982 +      }
   1.983 +
   1.984 +      // Cache-Control: no-store.
   1.985 +      if (httpChannel.isNoStoreResponse()) {
   1.986 +        return false;
   1.987 +      }
   1.988 +
   1.989 +      // Don't capture HTTPS pages unless the user enabled it.
   1.990 +      if (uri.schemeIs("https") && !this.sslDiskCacheEnabled) {
   1.991 +        return false;
   1.992 +      }
   1.993 +    }
   1.994 +
   1.995 +    return true;
   1.996 +  },
   1.997 +
   1.998 +  _sslDiskCacheEnabled: null,
   1.999 +
  1.1000 +  get sslDiskCacheEnabled() {
  1.1001 +    if (this._sslDiskCacheEnabled === null) {
  1.1002 +      this._sslDiskCacheEnabled = Services.prefs.getBoolPref("browser.cache.disk_cache_ssl");
  1.1003 +    }
  1.1004 +    return this._sslDiskCacheEnabled;
  1.1005 +  },
  1.1006 +
  1.1007 +  supportsCommand : function(cmd) {
  1.1008 +    var isSupported = false;
  1.1009 +    switch (cmd) {
  1.1010 +      case "cmd_back":
  1.1011 +      case "cmd_forward":
  1.1012 +      case "cmd_reload":
  1.1013 +      case "cmd_forceReload":
  1.1014 +      case "cmd_stop":
  1.1015 +      case "cmd_go":
  1.1016 +      case "cmd_home":
  1.1017 +      case "cmd_openLocation":
  1.1018 +      case "cmd_addBookmark":
  1.1019 +      case "cmd_bookmarks":
  1.1020 +      case "cmd_history":
  1.1021 +      case "cmd_remoteTabs":
  1.1022 +      case "cmd_quit":
  1.1023 +      case "cmd_close":
  1.1024 +      case "cmd_newTab":
  1.1025 +      case "cmd_newTabKey":
  1.1026 +      case "cmd_closeTab":
  1.1027 +      case "cmd_undoCloseTab":
  1.1028 +      case "cmd_actions":
  1.1029 +      case "cmd_panel":
  1.1030 +      case "cmd_reportingCrashesSubmitURLs":
  1.1031 +      case "cmd_flyout_back":
  1.1032 +      case "cmd_sanitize":
  1.1033 +      case "cmd_volumeLeft":
  1.1034 +      case "cmd_volumeRight":
  1.1035 +      case "cmd_openFile":
  1.1036 +      case "cmd_savePage":
  1.1037 +        isSupported = true;
  1.1038 +        break;
  1.1039 +      default:
  1.1040 +        isSupported = false;
  1.1041 +        break;
  1.1042 +    }
  1.1043 +    return isSupported;
  1.1044 +  },
  1.1045 +
  1.1046 +  isCommandEnabled : function(cmd) {
  1.1047 +    let elem = document.getElementById(cmd);
  1.1048 +    if (elem && elem.getAttribute("disabled") == "true")
  1.1049 +      return false;
  1.1050 +    return true;
  1.1051 +  },
  1.1052 +
  1.1053 +  doCommand : function(cmd) {
  1.1054 +    if (!this.isCommandEnabled(cmd))
  1.1055 +      return;
  1.1056 +    let browser = getBrowser();
  1.1057 +    switch (cmd) {
  1.1058 +      case "cmd_back":
  1.1059 +        browser.goBack();
  1.1060 +        break;
  1.1061 +      case "cmd_forward":
  1.1062 +        browser.goForward();
  1.1063 +        break;
  1.1064 +      case "cmd_reload":
  1.1065 +        browser.reload();
  1.1066 +        break;
  1.1067 +      case "cmd_forceReload":
  1.1068 +      {
  1.1069 +        // Simulate a new page
  1.1070 +        browser.lastLocation = null;
  1.1071 +
  1.1072 +        const reloadFlags = Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY |
  1.1073 +                            Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE;
  1.1074 +        browser.reloadWithFlags(reloadFlags);
  1.1075 +        break;
  1.1076 +      }
  1.1077 +      case "cmd_stop":
  1.1078 +        browser.stop();
  1.1079 +        break;
  1.1080 +      case "cmd_go":
  1.1081 +        this.goToURI();
  1.1082 +        break;
  1.1083 +      case "cmd_home":
  1.1084 +        this.goToURI(Browser.getHomePage());
  1.1085 +        break;
  1.1086 +      case "cmd_openLocation":
  1.1087 +        ContextUI.displayNavbar();
  1.1088 +        this._edit.beginEditing(true);
  1.1089 +        this._edit.select();
  1.1090 +        break;
  1.1091 +      case "cmd_addBookmark":
  1.1092 +        ContextUI.displayNavbar();
  1.1093 +        Appbar.onStarButton(true);
  1.1094 +        break;
  1.1095 +      case "cmd_bookmarks":
  1.1096 +        PanelUI.show("bookmarks-container");
  1.1097 +        break;
  1.1098 +      case "cmd_history":
  1.1099 +        PanelUI.show("history-container");
  1.1100 +        break;
  1.1101 +      case "cmd_remoteTabs":
  1.1102 +#ifdef MOZ_SERVICES_SYNC
  1.1103 +        if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) {
  1.1104 +          FlyoutPanelsUI.show('SyncFlyoutPanel');
  1.1105 +        } else {
  1.1106 +          PanelUI.show("remotetabs-container");
  1.1107 +        }
  1.1108 +#endif
  1.1109 +        break;
  1.1110 +      case "cmd_quit":
  1.1111 +        // Only close one window
  1.1112 +        this._closeOrQuit();
  1.1113 +        break;
  1.1114 +      case "cmd_close":
  1.1115 +        this._closeOrQuit();
  1.1116 +        break;
  1.1117 +      case "cmd_newTab":
  1.1118 +        this.addAndShowTab();
  1.1119 +        break;
  1.1120 +      case "cmd_newTabKey":
  1.1121 +        this.addAndShowTab();
  1.1122 +        // Make sure navbar is displayed before setting focus on url bar. Bug 907244
  1.1123 +        ContextUI.displayNavbar();
  1.1124 +        this._edit.beginEditing(false);
  1.1125 +        break;
  1.1126 +      case "cmd_closeTab":
  1.1127 +        this.closeTab();
  1.1128 +        break;
  1.1129 +      case "cmd_undoCloseTab":
  1.1130 +        this.undoCloseTab();
  1.1131 +        break;
  1.1132 +      case "cmd_sanitize":
  1.1133 +        this.confirmSanitizeDialog();
  1.1134 +        break;
  1.1135 +      case "cmd_flyout_back":
  1.1136 +        FlyoutPanelsUI.onBackButton();
  1.1137 +        break;
  1.1138 +      case "cmd_reportingCrashesSubmitURLs":
  1.1139 +        let urlCheckbox = document.getElementById("prefs-reporting-submitURLs");
  1.1140 +        Services.prefs.setBoolPref('app.crashreporter.submitURLs', urlCheckbox.checked);
  1.1141 +        break;
  1.1142 +      case "cmd_panel":
  1.1143 +        PanelUI.toggle();
  1.1144 +        break;
  1.1145 +      case "cmd_openFile":
  1.1146 +        this.openFile();
  1.1147 +        break;
  1.1148 +      case "cmd_savePage":
  1.1149 +        this.savePage();
  1.1150 +        break;
  1.1151 +    }
  1.1152 +  },
  1.1153 +
  1.1154 +  handleAppCommandEvent: function (aEvent) {
  1.1155 +    switch (aEvent.command) {
  1.1156 +      case "Back":
  1.1157 +        this.doCommand("cmd_back");
  1.1158 +        break;
  1.1159 +      case "Forward":
  1.1160 +        this.doCommand("cmd_forward");
  1.1161 +        break;
  1.1162 +      case "Reload":
  1.1163 +        this.doCommand("cmd_reload");
  1.1164 +        break;
  1.1165 +      case "Stop":
  1.1166 +        this.doCommand("cmd_stop");
  1.1167 +        break;
  1.1168 +      case "Home":
  1.1169 +        this.doCommand("cmd_home");
  1.1170 +        break;
  1.1171 +      case "New":
  1.1172 +        this.doCommand("cmd_newTab");
  1.1173 +        break;
  1.1174 +      case "Close":
  1.1175 +        this.doCommand("cmd_closeTab");
  1.1176 +        break;
  1.1177 +      case "Find":
  1.1178 +        FindHelperUI.show();
  1.1179 +        break;
  1.1180 +      case "Open":
  1.1181 +        this.doCommand("cmd_openFile");
  1.1182 +        break;
  1.1183 +      case "Save":
  1.1184 +        this.doCommand("cmd_savePage");
  1.1185 +        break;
  1.1186 +      case "Search":
  1.1187 +        this.doCommand("cmd_openLocation");
  1.1188 +        break;
  1.1189 +      default:
  1.1190 +        return;
  1.1191 +    }
  1.1192 +    aEvent.stopPropagation();
  1.1193 +    aEvent.preventDefault();
  1.1194 +  },
  1.1195 +
  1.1196 +  confirmSanitizeDialog: function () {
  1.1197 +    let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
  1.1198 +    let title = bundle.GetStringFromName("clearPrivateData.title2");
  1.1199 +    let message = bundle.GetStringFromName("clearPrivateData.message3");
  1.1200 +    let clearbutton = bundle.GetStringFromName("clearPrivateData.clearButton");
  1.1201 +
  1.1202 +    let prefsClearButton = document.getElementById("prefs-clear-data");
  1.1203 +    prefsClearButton.disabled = true;
  1.1204 +
  1.1205 +    let buttonPressed = Services.prompt.confirmEx(
  1.1206 +                          null,
  1.1207 +                          title,
  1.1208 +                          message,
  1.1209 +                          Ci.nsIPrompt.BUTTON_POS_0 * Ci.nsIPrompt.BUTTON_TITLE_IS_STRING +
  1.1210 +                          Ci.nsIPrompt.BUTTON_POS_1 * Ci.nsIPrompt.BUTTON_TITLE_CANCEL,
  1.1211 +                          clearbutton,
  1.1212 +                          null,
  1.1213 +                          null,
  1.1214 +                          null,
  1.1215 +                          { value: false });
  1.1216 +
  1.1217 +    // Clicking 'Clear' will call onSanitize().
  1.1218 +    if (buttonPressed === 0) {
  1.1219 +      SanitizeUI.onSanitize();
  1.1220 +    }
  1.1221 +
  1.1222 +    prefsClearButton.disabled = false;
  1.1223 +  },
  1.1224 +
  1.1225 +  _initFirstRunContent: function () {
  1.1226 +    let dismissed = Services.prefs.getBoolPref("browser.firstrun-content.dismissed");
  1.1227 +    let firstRunCount = Services.prefs.getIntPref("browser.firstrun.count");
  1.1228 +
  1.1229 +    if (!dismissed && firstRunCount > 0) {
  1.1230 +      document.loadOverlay("chrome://browser/content/FirstRunContentOverlay.xul", null);
  1.1231 +    }
  1.1232 +  },
  1.1233 +
  1.1234 +  firstRunContentDismiss: function() {
  1.1235 +    let firstRunElements = Elements.stack.querySelectorAll(".firstrun-content");
  1.1236 +    for (let node of firstRunElements) {
  1.1237 +      node.parentNode.removeChild(node);
  1.1238 +    }
  1.1239 +
  1.1240 +    Services.prefs.setBoolPref("browser.firstrun-content.dismissed", true);
  1.1241 +  },
  1.1242 +};
  1.1243 +
  1.1244 +var PanelUI = {
  1.1245 +  get _panels() { return document.getElementById("panel-items"); },
  1.1246 +
  1.1247 +  get isVisible() {
  1.1248 +    return !Elements.panelUI.hidden;
  1.1249 +  },
  1.1250 +
  1.1251 +  views: {
  1.1252 +    "console-container": "ConsolePanelView",
  1.1253 +  },
  1.1254 +
  1.1255 +  init: function() {
  1.1256 +    // Perform core init soon
  1.1257 +    setTimeout(function () {
  1.1258 +      for each (let viewName in this.views) {
  1.1259 +        let view = window[viewName];
  1.1260 +        if (view.init)
  1.1261 +          view.init();
  1.1262 +      }
  1.1263 +    }.bind(this), 0);
  1.1264 +
  1.1265 +    // Lazily run other initialization tasks when the views are shown
  1.1266 +    this._panels.addEventListener("ToolPanelShown", function(aEvent) {
  1.1267 +      let viewName = this.views[this._panels.selectedPanel.id];
  1.1268 +      let view = window[viewName];
  1.1269 +      if (view.show)
  1.1270 +        view.show();
  1.1271 +    }.bind(this), true);
  1.1272 +  },
  1.1273 +
  1.1274 +  uninit: function() {
  1.1275 +    for each (let viewName in this.views) {
  1.1276 +      let view = window[viewName];
  1.1277 +      if (view.uninit)
  1.1278 +        view.uninit();
  1.1279 +    }
  1.1280 +  },
  1.1281 +
  1.1282 +  switchPane: function switchPane(aPanelId) {
  1.1283 +    BrowserUI.blurFocusedElement();
  1.1284 +
  1.1285 +    let panel = aPanelId ? document.getElementById(aPanelId) : this._panels.selectedPanel;
  1.1286 +    let oldPanel = this._panels.selectedPanel;
  1.1287 +
  1.1288 +    if (oldPanel != panel) {
  1.1289 +      this._panels.selectedPanel = panel;
  1.1290 +
  1.1291 +      this._fire("ToolPanelHidden", oldPanel);
  1.1292 +    }
  1.1293 +
  1.1294 +    this._fire("ToolPanelShown", panel);
  1.1295 +  },
  1.1296 +
  1.1297 +  isPaneVisible: function isPaneVisible(aPanelId) {
  1.1298 +    return this.isVisible && this._panels.selectedPanel.id == aPanelId;
  1.1299 +  },
  1.1300 +
  1.1301 +  show: function show(aPanelId) {
  1.1302 +    Elements.panelUI.hidden = false;
  1.1303 +    Elements.contentShowing.setAttribute("disabled", "true");
  1.1304 +
  1.1305 +    this.switchPane(aPanelId);
  1.1306 +  },
  1.1307 +
  1.1308 +  hide: function hide() {
  1.1309 +    if (!this.isVisible)
  1.1310 +      return;
  1.1311 +
  1.1312 +    Elements.panelUI.hidden = true;
  1.1313 +    Elements.contentShowing.removeAttribute("disabled");
  1.1314 +    BrowserUI.blurFocusedElement();
  1.1315 +
  1.1316 +    this._fire("ToolPanelHidden", this._panels);
  1.1317 +  },
  1.1318 +
  1.1319 +  toggle: function toggle() {
  1.1320 +    if (this.isVisible) {
  1.1321 +      this.hide();
  1.1322 +    } else {
  1.1323 +      this.show();
  1.1324 +    }
  1.1325 +  },
  1.1326 +
  1.1327 +  _fire: function _fire(aName, anElement) {
  1.1328 +    let event = document.createEvent("Events");
  1.1329 +    event.initEvent(aName, true, true);
  1.1330 +    anElement.dispatchEvent(event);
  1.1331 +  }
  1.1332 +};
  1.1333 +
  1.1334 +var DialogUI = {
  1.1335 +  _popup: null,
  1.1336 +
  1.1337 +  init: function() {
  1.1338 +    window.addEventListener("mousedown", this, true);
  1.1339 +  },
  1.1340 +
  1.1341 +  /*******************************************
  1.1342 +   * Popups
  1.1343 +   */
  1.1344 +
  1.1345 +  pushPopup: function pushPopup(aPanel, aElements, aParent) {
  1.1346 +    this._hidePopup();
  1.1347 +    this._popup =  { "panel": aPanel,
  1.1348 +                     "elements": (aElements instanceof Array) ? aElements : [aElements] };
  1.1349 +    this._dispatchPopupChanged(true, aPanel);
  1.1350 +  },
  1.1351 +
  1.1352 +  popPopup: function popPopup(aPanel) {
  1.1353 +    if (!this._popup || aPanel != this._popup.panel)
  1.1354 +      return;
  1.1355 +    this._popup = null;
  1.1356 +    this._dispatchPopupChanged(false, aPanel);
  1.1357 +  },
  1.1358 +
  1.1359 +  _hidePopup: function _hidePopup() {
  1.1360 +    if (!this._popup)
  1.1361 +      return;
  1.1362 +    let panel = this._popup.panel;
  1.1363 +    if (panel.hide)
  1.1364 +      panel.hide();
  1.1365 +  },
  1.1366 +
  1.1367 +  /*******************************************
  1.1368 +   * Events
  1.1369 +   */
  1.1370 +
  1.1371 +  handleEvent: function (aEvent) {
  1.1372 +    switch (aEvent.type) {
  1.1373 +      case "mousedown":
  1.1374 +        if (!this._isEventInsidePopup(aEvent))
  1.1375 +          this._hidePopup();
  1.1376 +        break;
  1.1377 +      default:
  1.1378 +        break;
  1.1379 +    }
  1.1380 +  },
  1.1381 +
  1.1382 +  _dispatchPopupChanged: function _dispatchPopupChanged(aVisible, aElement) {
  1.1383 +    let event = document.createEvent("UIEvents");
  1.1384 +    event.initUIEvent("PopupChanged", true, true, window, aVisible);
  1.1385 +    aElement.dispatchEvent(event);
  1.1386 +  },
  1.1387 +
  1.1388 +  _isEventInsidePopup: function _isEventInsidePopup(aEvent) {
  1.1389 +    if (!this._popup)
  1.1390 +      return false;
  1.1391 +    let elements = this._popup.elements;
  1.1392 +    let targetNode = aEvent.target;
  1.1393 +    while (targetNode && elements.indexOf(targetNode) == -1) {
  1.1394 +      if (targetNode instanceof Element && targetNode.hasAttribute("for"))
  1.1395 +        targetNode = document.getElementById(targetNode.getAttribute("for"));
  1.1396 +      else
  1.1397 +        targetNode = targetNode.parentNode;
  1.1398 +    }
  1.1399 +    return targetNode ? true : false;
  1.1400 +  }
  1.1401 +};

mercurial