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