PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 2ms

/browser/base/content/browser.js

https://bitbucket.org/MeeGoAdmin/mozilla-central/
JavaScript | 8709 lines | 6273 code | 1198 blank | 1238 comment | 1302 complexity | 41fa898ee7e534e7a4216d876f5859bf MD5 | raw file
Possible License(s): AGPL-1.0, MIT, BSD-3-Clause, Apache-2.0, LGPL-2.1, 0BSD, LGPL-3.0, MPL-2.0-no-copyleft-exception, GPL-2.0, JSON

Large files files are truncated, but you can click here to view the full file

  1. # -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2. # ***** BEGIN LICENSE BLOCK *****
  3. # Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4. #
  5. # The contents of this file are subject to the Mozilla Public License Version
  6. # 1.1 (the "License"); you may not use this file except in compliance with
  7. # the License. You may obtain a copy of the License at
  8. # http://www.mozilla.org/MPL/
  9. #
  10. # Software distributed under the License is distributed on an "AS IS" basis,
  11. # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. # for the specific language governing rights and limitations under the
  13. # License.
  14. #
  15. # The Original Code is mozilla.org code.
  16. #
  17. # The Initial Developer of the Original Code is
  18. # Netscape Communications Corporation.
  19. # Portions created by the Initial Developer are Copyright (C) 1998
  20. # the Initial Developer. All Rights Reserved.
  21. #
  22. # Contributor(s):
  23. # Blake Ross <blake@cs.stanford.edu>
  24. # David Hyatt <hyatt@mozilla.org>
  25. # Peter Annema <disttsc@bart.nl>
  26. # Dean Tessman <dean_tessman@hotmail.com>
  27. # Kevin Puetz <puetzk@iastate.edu>
  28. # Ben Goodger <ben@netscape.com>
  29. # Pierre Chanial <chanial@noos.fr>
  30. # Jason Eager <jce2@po.cwru.edu>
  31. # Joe Hewitt <hewitt@netscape.com>
  32. # Alec Flett <alecf@netscape.com>
  33. # Asaf Romano <mozilla.mano@sent.com>
  34. # Jason Barnabe <jason_barnabe@fastmail.fm>
  35. # Peter Parente <parente@cs.unc.edu>
  36. # Giorgio Maone <g.maone@informaction.com>
  37. # Tom Germeau <tom.germeau@epigoon.com>
  38. # Jesse Ruderman <jruderman@gmail.com>
  39. # Joe Hughes <joe@retrovirus.com>
  40. # Pamela Greene <pamg.bugs@gmail.com>
  41. # Michael Ventnor <m.ventnor@gmail.com>
  42. # Simon Bünzli <zeniko@gmail.com>
  43. # Johnathan Nightingale <johnath@mozilla.com>
  44. # Ehsan Akhgari <ehsan.akhgari@gmail.com>
  45. # Dão Gottwald <dao@mozilla.com>
  46. # Thomas K. Dyas <tdyas@zecador.org>
  47. # Edward Lee <edward.lee@engineering.uiuc.edu>
  48. # Paul OShannessy <paul@oshannessy.com>
  49. # Nils Maier <maierman@web.de>
  50. # Rob Arnold <robarnold@cmu.edu>
  51. # Dietrich Ayala <dietrich@mozilla.com>
  52. # Gavin Sharp <gavin@gavinsharp.com>
  53. # Justin Dolske <dolske@mozilla.com>
  54. # Rob Campbell <rcampbell@mozilla.com>
  55. # David Dahl <ddahl@mozilla.com>
  56. # Patrick Walton <pcwalton@mozilla.com>
  57. # Mihai Sucan <mihai.sucan@gmail.com>
  58. #
  59. # Alternatively, the contents of this file may be used under the terms of
  60. # either the GNU General Public License Version 2 or later (the "GPL"), or
  61. # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  62. # in which case the provisions of the GPL or the LGPL are applicable instead
  63. # of those above. If you wish to allow use of your version of this file only
  64. # under the terms of either the GPL or the LGPL, and not to allow others to
  65. # use your version of this file under the terms of the MPL, indicate your
  66. # decision by deleting the provisions above and replace them with the notice
  67. # and other provisions required by the GPL or the LGPL. If you do not delete
  68. # the provisions above, a recipient may use your version of this file under
  69. # the terms of any one of the MPL, the GPL or the LGPL.
  70. #
  71. # ***** END LICENSE BLOCK *****
  72. let Ci = Components.interfaces;
  73. let Cu = Components.utils;
  74. Cu.import("resource://gre/modules/XPCOMUtils.jsm");
  75. const nsIWebNavigation = Ci.nsIWebNavigation;
  76. var gCharsetMenu = null;
  77. var gLastBrowserCharset = null;
  78. var gPrevCharset = null;
  79. var gProxyFavIcon = null;
  80. var gLastValidURLStr = "";
  81. var gInPrintPreviewMode = false;
  82. var gDownloadMgr = null;
  83. var gContextMenu = null; // nsContextMenu instance
  84. var gDelayedStartupTimeoutId;
  85. var gStartupRan = false;
  86. #ifndef XP_MACOSX
  87. var gEditUIVisible = true;
  88. #endif
  89. [
  90. ["gBrowser", "content"],
  91. ["gNavToolbox", "navigator-toolbox"],
  92. ["gURLBar", "urlbar"],
  93. ["gNavigatorBundle", "bundle_browser"]
  94. ].forEach(function (elementGlobal) {
  95. var [name, id] = elementGlobal;
  96. window.__defineGetter__(name, function () {
  97. var element = document.getElementById(id);
  98. if (!element)
  99. return null;
  100. delete window[name];
  101. return window[name] = element;
  102. });
  103. window.__defineSetter__(name, function (val) {
  104. delete window[name];
  105. return window[name] = val;
  106. });
  107. });
  108. // Smart getter for the findbar. If you don't wish to force the creation of
  109. // the findbar, check gFindBarInitialized first.
  110. var gFindBarInitialized = false;
  111. XPCOMUtils.defineLazyGetter(window, "gFindBar", function() {
  112. let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  113. let findbar = document.createElementNS(XULNS, "findbar");
  114. findbar.id = "FindToolbar";
  115. let browserBottomBox = document.getElementById("browser-bottombox");
  116. browserBottomBox.insertBefore(findbar, browserBottomBox.firstChild);
  117. // Force a style flush to ensure that our binding is attached.
  118. findbar.clientTop;
  119. findbar.browser = gBrowser;
  120. window.gFindBarInitialized = true;
  121. return findbar;
  122. });
  123. __defineGetter__("gPrefService", function() {
  124. delete this.gPrefService;
  125. return this.gPrefService = Services.prefs;
  126. });
  127. __defineGetter__("AddonManager", function() {
  128. Cu.import("resource://gre/modules/AddonManager.jsm");
  129. return this.AddonManager;
  130. });
  131. __defineSetter__("AddonManager", function (val) {
  132. delete this.AddonManager;
  133. return this.AddonManager = val;
  134. });
  135. __defineGetter__("PluralForm", function() {
  136. Cu.import("resource://gre/modules/PluralForm.jsm");
  137. return this.PluralForm;
  138. });
  139. __defineSetter__("PluralForm", function (val) {
  140. delete this.PluralForm;
  141. return this.PluralForm = val;
  142. });
  143. #ifdef MOZ_SERVICES_SYNC
  144. XPCOMUtils.defineLazyGetter(this, "Weave", function() {
  145. let tmp = {};
  146. Cu.import("resource://services-sync/main.js", tmp);
  147. return tmp.Weave;
  148. });
  149. #endif
  150. XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
  151. let tmp = {};
  152. Cu.import("resource://gre/modules/PopupNotifications.jsm", tmp);
  153. try {
  154. return new tmp.PopupNotifications(gBrowser,
  155. document.getElementById("notification-popup"),
  156. document.getElementById("notification-popup-box"));
  157. } catch (ex) {
  158. Cu.reportError(ex);
  159. }
  160. });
  161. let gInitialPages = [
  162. "about:blank",
  163. "about:privatebrowsing",
  164. "about:sessionrestore"
  165. ];
  166. #include browser-fullZoom.js
  167. #include inspector.js
  168. #include browser-places.js
  169. #include browser-tabPreviews.js
  170. #include browser-tabview.js
  171. #ifdef MOZ_SERVICES_SYNC
  172. #include browser-syncui.js
  173. #endif
  174. XPCOMUtils.defineLazyGetter(this, "Win7Features", function () {
  175. #ifdef XP_WIN
  176. const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
  177. if (WINTASKBAR_CONTRACTID in Cc &&
  178. Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar).available) {
  179. let temp = {};
  180. Cu.import("resource://gre/modules/WindowsPreviewPerTab.jsm", temp);
  181. let AeroPeek = temp.AeroPeek;
  182. return {
  183. onOpenWindow: function () {
  184. AeroPeek.onOpenWindow(window);
  185. },
  186. onCloseWindow: function () {
  187. AeroPeek.onCloseWindow(window);
  188. }
  189. };
  190. }
  191. #endif
  192. return null;
  193. });
  194. #ifdef MOZ_CRASHREPORTER
  195. XPCOMUtils.defineLazyServiceGetter(this, "gCrashReporter",
  196. "@mozilla.org/xre/app-info;1",
  197. "nsICrashReporter");
  198. #endif
  199. XPCOMUtils.defineLazyGetter(this, "PageMenu", function() {
  200. let tmp = {};
  201. Cu.import("resource://gre/modules/PageMenu.jsm", tmp);
  202. return new tmp.PageMenu();
  203. });
  204. /**
  205. * We can avoid adding multiple load event listeners and save some time by adding
  206. * one listener that calls all real handlers.
  207. */
  208. function pageShowEventHandlers(event) {
  209. // Filter out events that are not about the document load we are interested in
  210. if (event.originalTarget == content.document) {
  211. charsetLoadListener(event);
  212. XULBrowserWindow.asyncUpdateUI();
  213. }
  214. }
  215. function UpdateBackForwardCommands(aWebNavigation) {
  216. var backBroadcaster = document.getElementById("Browser:Back");
  217. var forwardBroadcaster = document.getElementById("Browser:Forward");
  218. // Avoid setting attributes on broadcasters if the value hasn't changed!
  219. // Remember, guys, setting attributes on elements is expensive! They
  220. // get inherited into anonymous content, broadcast to other widgets, etc.!
  221. // Don't do it if the value hasn't changed! - dwh
  222. var backDisabled = backBroadcaster.hasAttribute("disabled");
  223. var forwardDisabled = forwardBroadcaster.hasAttribute("disabled");
  224. if (backDisabled == aWebNavigation.canGoBack) {
  225. if (backDisabled)
  226. backBroadcaster.removeAttribute("disabled");
  227. else
  228. backBroadcaster.setAttribute("disabled", true);
  229. }
  230. if (forwardDisabled == aWebNavigation.canGoForward) {
  231. if (forwardDisabled)
  232. forwardBroadcaster.removeAttribute("disabled");
  233. else
  234. forwardBroadcaster.setAttribute("disabled", true);
  235. }
  236. }
  237. /**
  238. * Click-and-Hold implementation for the Back and Forward buttons
  239. * XXXmano: should this live in toolbarbutton.xml?
  240. */
  241. function SetClickAndHoldHandlers() {
  242. var timer;
  243. function openMenu(aButton) {
  244. cancelHold(aButton);
  245. aButton.firstChild.hidden = false;
  246. aButton.open = true;
  247. }
  248. function mousedownHandler(aEvent) {
  249. if (aEvent.button != 0 ||
  250. aEvent.currentTarget.open ||
  251. aEvent.currentTarget.disabled)
  252. return;
  253. // Prevent the menupopup from opening immediately
  254. aEvent.currentTarget.firstChild.hidden = true;
  255. aEvent.currentTarget.addEventListener("mouseout", mouseoutHandler, false);
  256. aEvent.currentTarget.addEventListener("mouseup", mouseupHandler, false);
  257. timer = setTimeout(openMenu, 500, aEvent.currentTarget);
  258. }
  259. function mouseoutHandler(aEvent) {
  260. let buttonRect = aEvent.currentTarget.getBoundingClientRect();
  261. if (aEvent.clientX >= buttonRect.left &&
  262. aEvent.clientX <= buttonRect.right &&
  263. aEvent.clientY >= buttonRect.bottom)
  264. openMenu(aEvent.currentTarget);
  265. else
  266. cancelHold(aEvent.currentTarget);
  267. }
  268. function mouseupHandler(aEvent) {
  269. cancelHold(aEvent.currentTarget);
  270. }
  271. function cancelHold(aButton) {
  272. clearTimeout(timer);
  273. aButton.removeEventListener("mouseout", mouseoutHandler, false);
  274. aButton.removeEventListener("mouseup", mouseupHandler, false);
  275. }
  276. function clickHandler(aEvent) {
  277. if (aEvent.button == 0 &&
  278. aEvent.target == aEvent.currentTarget &&
  279. !aEvent.currentTarget.open &&
  280. !aEvent.currentTarget.disabled) {
  281. let cmdEvent = document.createEvent("xulcommandevent");
  282. cmdEvent.initCommandEvent("command", true, true, window, 0,
  283. aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
  284. aEvent.metaKey, null);
  285. aEvent.currentTarget.dispatchEvent(cmdEvent);
  286. }
  287. }
  288. function _addClickAndHoldListenersOnElement(aElm) {
  289. aElm.addEventListener("mousedown", mousedownHandler, true);
  290. aElm.addEventListener("click", clickHandler, true);
  291. }
  292. // Bug 414797: Clone unified-back-forward-button's context menu into both the
  293. // back and the forward buttons.
  294. var unifiedButton = document.getElementById("unified-back-forward-button");
  295. if (unifiedButton && !unifiedButton._clickHandlersAttached) {
  296. unifiedButton._clickHandlersAttached = true;
  297. let popup = document.getElementById("backForwardMenu").cloneNode(true);
  298. popup.removeAttribute("id");
  299. // Prevent the context attribute on unified-back-forward-button from being
  300. // inherited.
  301. popup.setAttribute("context", "");
  302. let backButton = document.getElementById("back-button");
  303. backButton.setAttribute("type", "menu");
  304. backButton.appendChild(popup);
  305. _addClickAndHoldListenersOnElement(backButton);
  306. let forwardButton = document.getElementById("forward-button");
  307. popup = popup.cloneNode(true);
  308. forwardButton.setAttribute("type", "menu");
  309. forwardButton.appendChild(popup);
  310. _addClickAndHoldListenersOnElement(forwardButton);
  311. }
  312. }
  313. const gSessionHistoryObserver = {
  314. observe: function(subject, topic, data)
  315. {
  316. if (topic != "browser:purge-session-history")
  317. return;
  318. var backCommand = document.getElementById("Browser:Back");
  319. backCommand.setAttribute("disabled", "true");
  320. var fwdCommand = document.getElementById("Browser:Forward");
  321. fwdCommand.setAttribute("disabled", "true");
  322. // Hide session restore button on about:home
  323. window.messageManager.sendAsyncMessage("Browser:HideSessionRestoreButton");
  324. if (gURLBar) {
  325. // Clear undo history of the URL bar
  326. gURLBar.editor.transactionManager.clear()
  327. }
  328. }
  329. };
  330. /**
  331. * Given a starting docshell and a URI to look up, find the docshell the URI
  332. * is loaded in.
  333. * @param aDocument
  334. * A document to find instead of using just a URI - this is more specific.
  335. * @param aDocShell
  336. * The doc shell to start at
  337. * @param aSoughtURI
  338. * The URI that we're looking for
  339. * @returns The doc shell that the sought URI is loaded in. Can be in
  340. * subframes.
  341. */
  342. function findChildShell(aDocument, aDocShell, aSoughtURI) {
  343. aDocShell.QueryInterface(Components.interfaces.nsIWebNavigation);
  344. aDocShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  345. var doc = aDocShell.getInterface(Components.interfaces.nsIDOMDocument);
  346. if ((aDocument && doc == aDocument) ||
  347. (aSoughtURI && aSoughtURI.spec == aDocShell.currentURI.spec))
  348. return aDocShell;
  349. var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeNode);
  350. for (var i = 0; i < node.childCount; ++i) {
  351. var docShell = node.getChildAt(i);
  352. docShell = findChildShell(aDocument, docShell, aSoughtURI);
  353. if (docShell)
  354. return docShell;
  355. }
  356. return null;
  357. }
  358. var gPopupBlockerObserver = {
  359. _reportButton: null,
  360. onReportButtonClick: function (aEvent)
  361. {
  362. if (aEvent.button != 0 || aEvent.target != this._reportButton)
  363. return;
  364. document.getElementById("blockedPopupOptions")
  365. .openPopup(this._reportButton, "after_end", 0, 2, false, false, aEvent);
  366. },
  367. handleEvent: function (aEvent)
  368. {
  369. if (aEvent.originalTarget != gBrowser.selectedBrowser)
  370. return;
  371. if (!this._reportButton && gURLBar)
  372. this._reportButton = document.getElementById("page-report-button");
  373. if (!gBrowser.pageReport) {
  374. // Hide the icon in the location bar (if the location bar exists)
  375. if (gURLBar)
  376. this._reportButton.hidden = true;
  377. return;
  378. }
  379. if (gURLBar)
  380. this._reportButton.hidden = false;
  381. // Only show the notification again if we've not already shown it. Since
  382. // notifications are per-browser, we don't need to worry about re-adding
  383. // it.
  384. if (!gBrowser.pageReport.reported) {
  385. if (gPrefService.getBoolPref("privacy.popups.showBrowserMessage")) {
  386. var brandBundle = document.getElementById("bundle_brand");
  387. var brandShortName = brandBundle.getString("brandShortName");
  388. var message;
  389. var popupCount = gBrowser.pageReport.length;
  390. #ifdef XP_WIN
  391. var popupButtonText = gNavigatorBundle.getString("popupWarningButton");
  392. var popupButtonAccesskey = gNavigatorBundle.getString("popupWarningButton.accesskey");
  393. #else
  394. var popupButtonText = gNavigatorBundle.getString("popupWarningButtonUnix");
  395. var popupButtonAccesskey = gNavigatorBundle.getString("popupWarningButtonUnix.accesskey");
  396. #endif
  397. if (popupCount > 1)
  398. message = gNavigatorBundle.getFormattedString("popupWarningMultiple", [brandShortName, popupCount]);
  399. else
  400. message = gNavigatorBundle.getFormattedString("popupWarning", [brandShortName]);
  401. var notificationBox = gBrowser.getNotificationBox();
  402. var notification = notificationBox.getNotificationWithValue("popup-blocked");
  403. if (notification) {
  404. notification.label = message;
  405. }
  406. else {
  407. var buttons = [{
  408. label: popupButtonText,
  409. accessKey: popupButtonAccesskey,
  410. popup: "blockedPopupOptions",
  411. callback: null
  412. }];
  413. const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
  414. notificationBox.appendNotification(message, "popup-blocked",
  415. "chrome://browser/skin/Info.png",
  416. priority, buttons);
  417. }
  418. }
  419. // Record the fact that we've reported this blocked popup, so we don't
  420. // show it again.
  421. gBrowser.pageReport.reported = true;
  422. }
  423. },
  424. toggleAllowPopupsForSite: function (aEvent)
  425. {
  426. var pm = Services.perms;
  427. var shouldBlock = aEvent.target.getAttribute("block") == "true";
  428. var perm = shouldBlock ? pm.DENY_ACTION : pm.ALLOW_ACTION;
  429. pm.add(gBrowser.currentURI, "popup", perm);
  430. gBrowser.getNotificationBox().removeCurrentNotification();
  431. },
  432. fillPopupList: function (aEvent)
  433. {
  434. // XXXben - rather than using |currentURI| here, which breaks down on multi-framed sites
  435. // we should really walk the pageReport and create a list of "allow for <host>"
  436. // menuitems for the common subset of hosts present in the report, this will
  437. // make us frame-safe.
  438. //
  439. // XXXjst - Note that when this is fixed to work with multi-framed sites,
  440. // also back out the fix for bug 343772 where
  441. // nsGlobalWindow::CheckOpenAllow() was changed to also
  442. // check if the top window's location is whitelisted.
  443. var uri = gBrowser.currentURI;
  444. var blockedPopupAllowSite = document.getElementById("blockedPopupAllowSite");
  445. try {
  446. blockedPopupAllowSite.removeAttribute("hidden");
  447. var pm = Services.perms;
  448. if (pm.testPermission(uri, "popup") == pm.ALLOW_ACTION) {
  449. // Offer an item to block popups for this site, if a whitelist entry exists
  450. // already for it.
  451. let blockString = gNavigatorBundle.getFormattedString("popupBlock", [uri.host]);
  452. blockedPopupAllowSite.setAttribute("label", blockString);
  453. blockedPopupAllowSite.setAttribute("block", "true");
  454. }
  455. else {
  456. // Offer an item to allow popups for this site
  457. let allowString = gNavigatorBundle.getFormattedString("popupAllow", [uri.host]);
  458. blockedPopupAllowSite.setAttribute("label", allowString);
  459. blockedPopupAllowSite.removeAttribute("block");
  460. }
  461. }
  462. catch (e) {
  463. blockedPopupAllowSite.setAttribute("hidden", "true");
  464. }
  465. if (gPrivateBrowsingUI.privateBrowsingEnabled)
  466. blockedPopupAllowSite.setAttribute("disabled", "true");
  467. else
  468. blockedPopupAllowSite.removeAttribute("disabled");
  469. var foundUsablePopupURI = false;
  470. var pageReport = gBrowser.pageReport;
  471. if (pageReport) {
  472. for (var i = 0; i < pageReport.length; ++i) {
  473. // popupWindowURI will be null if the file picker popup is blocked.
  474. // xxxdz this should make the option say "Show file picker" and do it (Bug 590306)
  475. if (!pageReport[i].popupWindowURI)
  476. continue;
  477. var popupURIspec = pageReport[i].popupWindowURI.spec;
  478. // Sometimes the popup URI that we get back from the pageReport
  479. // isn't useful (for instance, netscape.com's popup URI ends up
  480. // being "http://www.netscape.com", which isn't really the URI of
  481. // the popup they're trying to show). This isn't going to be
  482. // useful to the user, so we won't create a menu item for it.
  483. if (popupURIspec == "" || popupURIspec == "about:blank" ||
  484. popupURIspec == uri.spec)
  485. continue;
  486. // Because of the short-circuit above, we may end up in a situation
  487. // in which we don't have any usable popup addresses to show in
  488. // the menu, and therefore we shouldn't show the separator. However,
  489. // since we got past the short-circuit, we must've found at least
  490. // one usable popup URI and thus we'll turn on the separator later.
  491. foundUsablePopupURI = true;
  492. var menuitem = document.createElement("menuitem");
  493. var label = gNavigatorBundle.getFormattedString("popupShowPopupPrefix",
  494. [popupURIspec]);
  495. menuitem.setAttribute("label", label);
  496. menuitem.setAttribute("popupWindowURI", popupURIspec);
  497. menuitem.setAttribute("popupWindowFeatures", pageReport[i].popupWindowFeatures);
  498. menuitem.setAttribute("popupWindowName", pageReport[i].popupWindowName);
  499. menuitem.setAttribute("oncommand", "gPopupBlockerObserver.showBlockedPopup(event);");
  500. menuitem.requestingWindow = pageReport[i].requestingWindow;
  501. menuitem.requestingDocument = pageReport[i].requestingDocument;
  502. aEvent.target.appendChild(menuitem);
  503. }
  504. }
  505. // Show or hide the separator, depending on whether we added any
  506. // showable popup addresses to the menu.
  507. var blockedPopupsSeparator =
  508. document.getElementById("blockedPopupsSeparator");
  509. if (foundUsablePopupURI)
  510. blockedPopupsSeparator.removeAttribute("hidden");
  511. else
  512. blockedPopupsSeparator.setAttribute("hidden", true);
  513. var blockedPopupDontShowMessage = document.getElementById("blockedPopupDontShowMessage");
  514. var showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage");
  515. blockedPopupDontShowMessage.setAttribute("checked", !showMessage);
  516. if (aEvent.target.anchorNode.id == "page-report-button") {
  517. aEvent.target.anchorNode.setAttribute("open", "true");
  518. blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromLocationbar"));
  519. } else
  520. blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromMessage"));
  521. },
  522. onPopupHiding: function (aEvent) {
  523. if (aEvent.target.anchorNode.id == "page-report-button")
  524. aEvent.target.anchorNode.removeAttribute("open");
  525. let item = aEvent.target.lastChild;
  526. while (item && item.getAttribute("observes") != "blockedPopupsSeparator") {
  527. let next = item.previousSibling;
  528. item.parentNode.removeChild(item);
  529. item = next;
  530. }
  531. },
  532. showBlockedPopup: function (aEvent)
  533. {
  534. var target = aEvent.target;
  535. var popupWindowURI = target.getAttribute("popupWindowURI");
  536. var features = target.getAttribute("popupWindowFeatures");
  537. var name = target.getAttribute("popupWindowName");
  538. var dwi = target.requestingWindow;
  539. // If we have a requesting window and the requesting document is
  540. // still the current document, open the popup.
  541. if (dwi && dwi.document == target.requestingDocument) {
  542. dwi.open(popupWindowURI, name, features);
  543. }
  544. },
  545. editPopupSettings: function ()
  546. {
  547. var host = "";
  548. try {
  549. host = gBrowser.currentURI.host;
  550. }
  551. catch (e) { }
  552. var bundlePreferences = document.getElementById("bundle_preferences");
  553. var params = { blockVisible : false,
  554. sessionVisible : false,
  555. allowVisible : true,
  556. prefilledHost : host,
  557. permissionType : "popup",
  558. windowTitle : bundlePreferences.getString("popuppermissionstitle"),
  559. introText : bundlePreferences.getString("popuppermissionstext") };
  560. var existingWindow = Services.wm.getMostRecentWindow("Browser:Permissions");
  561. if (existingWindow) {
  562. existingWindow.initWithParams(params);
  563. existingWindow.focus();
  564. }
  565. else
  566. window.openDialog("chrome://browser/content/preferences/permissions.xul",
  567. "_blank", "resizable,dialog=no,centerscreen", params);
  568. },
  569. dontShowMessage: function ()
  570. {
  571. var showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage");
  572. gPrefService.setBoolPref("privacy.popups.showBrowserMessage", !showMessage);
  573. gBrowser.getNotificationBox().removeCurrentNotification();
  574. }
  575. };
  576. const gXPInstallObserver = {
  577. _findChildShell: function (aDocShell, aSoughtShell)
  578. {
  579. if (aDocShell == aSoughtShell)
  580. return aDocShell;
  581. var node = aDocShell.QueryInterface(Components.interfaces.nsIDocShellTreeNode);
  582. for (var i = 0; i < node.childCount; ++i) {
  583. var docShell = node.getChildAt(i);
  584. docShell = this._findChildShell(docShell, aSoughtShell);
  585. if (docShell == aSoughtShell)
  586. return docShell;
  587. }
  588. return null;
  589. },
  590. _getBrowser: function (aDocShell)
  591. {
  592. for (var i = 0; i < gBrowser.browsers.length; ++i) {
  593. var browser = gBrowser.getBrowserAtIndex(i);
  594. if (this._findChildShell(browser.docShell, aDocShell))
  595. return browser;
  596. }
  597. return null;
  598. },
  599. observe: function (aSubject, aTopic, aData)
  600. {
  601. var brandBundle = document.getElementById("bundle_brand");
  602. var installInfo = aSubject.QueryInterface(Components.interfaces.amIWebInstallInfo);
  603. var win = installInfo.originatingWindow;
  604. var shell = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  605. .getInterface(Components.interfaces.nsIWebNavigation)
  606. .QueryInterface(Components.interfaces.nsIDocShell);
  607. var browser = this._getBrowser(shell);
  608. if (!browser)
  609. return;
  610. const anchorID = "addons-notification-icon";
  611. var messageString, action;
  612. var brandShortName = brandBundle.getString("brandShortName");
  613. var notificationID = aTopic;
  614. // Make notifications persist a minimum of 30 seconds
  615. var options = {
  616. timeout: Date.now() + 30000
  617. };
  618. switch (aTopic) {
  619. case "addon-install-disabled":
  620. notificationID = "xpinstall-disabled"
  621. if (gPrefService.prefIsLocked("xpinstall.enabled")) {
  622. messageString = gNavigatorBundle.getString("xpinstallDisabledMessageLocked");
  623. buttons = [];
  624. }
  625. else {
  626. messageString = gNavigatorBundle.getString("xpinstallDisabledMessage");
  627. action = {
  628. label: gNavigatorBundle.getString("xpinstallDisabledButton"),
  629. accessKey: gNavigatorBundle.getString("xpinstallDisabledButton.accesskey"),
  630. callback: function editPrefs() {
  631. gPrefService.setBoolPref("xpinstall.enabled", true);
  632. }
  633. };
  634. }
  635. PopupNotifications.show(browser, notificationID, messageString, anchorID,
  636. action, null, options);
  637. break;
  638. case "addon-install-blocked":
  639. messageString = gNavigatorBundle.getFormattedString("xpinstallPromptWarning",
  640. [brandShortName, installInfo.originatingURI.host]);
  641. action = {
  642. label: gNavigatorBundle.getString("xpinstallPromptAllowButton"),
  643. accessKey: gNavigatorBundle.getString("xpinstallPromptAllowButton.accesskey"),
  644. callback: function() {
  645. installInfo.install();
  646. }
  647. };
  648. PopupNotifications.show(browser, notificationID, messageString, anchorID,
  649. action, null, options);
  650. break;
  651. case "addon-install-started":
  652. function needsDownload(aInstall) {
  653. return aInstall.state != AddonManager.STATE_DOWNLOADED;
  654. }
  655. // If all installs have already been downloaded then there is no need to
  656. // show the download progress
  657. if (!installInfo.installs.some(needsDownload))
  658. return;
  659. notificationID = "addon-progress";
  660. messageString = gNavigatorBundle.getString("addonDownloading");
  661. messageString = PluralForm.get(installInfo.installs.length, messageString);
  662. options.installs = installInfo.installs;
  663. options.contentWindow = browser.contentWindow;
  664. options.sourceURI = browser.currentURI;
  665. options.eventCallback = function(aEvent) {
  666. if (aEvent != "removed")
  667. return;
  668. options.contentWindow = null;
  669. options.sourceURI = null;
  670. };
  671. PopupNotifications.show(browser, notificationID, messageString, anchorID,
  672. null, null, options);
  673. break;
  674. case "addon-install-failed":
  675. // TODO This isn't terribly ideal for the multiple failure case
  676. installInfo.installs.forEach(function(aInstall) {
  677. var host = (installInfo.originatingURI instanceof Ci.nsIStandardURL) &&
  678. installInfo.originatingURI.host;
  679. if (!host)
  680. host = (aInstall.sourceURI instanceof Ci.nsIStandardURL) &&
  681. aInstall.sourceURI.host;
  682. var error = (host || aInstall.error == 0) ? "addonError" : "addonLocalError";
  683. if (aInstall.error != 0)
  684. error += aInstall.error;
  685. else if (aInstall.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
  686. error += "Blocklisted";
  687. else
  688. error += "Incompatible";
  689. messageString = gNavigatorBundle.getString(error);
  690. messageString = messageString.replace("#1", aInstall.name);
  691. if (host)
  692. messageString = messageString.replace("#2", host);
  693. messageString = messageString.replace("#3", brandShortName);
  694. messageString = messageString.replace("#4", Services.appinfo.version);
  695. PopupNotifications.show(browser, notificationID, messageString, anchorID,
  696. action, null, options);
  697. });
  698. break;
  699. case "addon-install-complete":
  700. var needsRestart = installInfo.installs.some(function(i) {
  701. return i.addon.pendingOperations != AddonManager.PENDING_NONE;
  702. });
  703. if (needsRestart) {
  704. messageString = gNavigatorBundle.getString("addonsInstalledNeedsRestart");
  705. action = {
  706. label: gNavigatorBundle.getString("addonInstallRestartButton"),
  707. accessKey: gNavigatorBundle.getString("addonInstallRestartButton.accesskey"),
  708. callback: function() {
  709. Application.restart();
  710. }
  711. };
  712. }
  713. else {
  714. messageString = gNavigatorBundle.getString("addonsInstalled");
  715. action = {
  716. label: gNavigatorBundle.getString("addonInstallManage"),
  717. accessKey: gNavigatorBundle.getString("addonInstallManage.accesskey"),
  718. callback: function() {
  719. // Calculate the add-on type that is most popular in the list of
  720. // installs
  721. var types = {};
  722. var bestType = null;
  723. installInfo.installs.forEach(function(aInstall) {
  724. if (aInstall.type in types)
  725. types[aInstall.type]++;
  726. else
  727. types[aInstall.type] = 1;
  728. if (!bestType || types[aInstall.type] > types[bestType])
  729. bestType = aInstall.type;
  730. });
  731. BrowserOpenAddonsMgr("addons://list/" + bestType);
  732. }
  733. };
  734. }
  735. messageString = PluralForm.get(installInfo.installs.length, messageString);
  736. messageString = messageString.replace("#1", installInfo.installs[0].name);
  737. messageString = messageString.replace("#2", installInfo.installs.length);
  738. messageString = messageString.replace("#3", brandShortName);
  739. // Remove notificaion on dismissal, since it's possible to cancel the
  740. // install through the addons manager UI, making the "restart" prompt
  741. // irrelevant.
  742. options.removeOnDismissal = true;
  743. PopupNotifications.show(browser, notificationID, messageString, anchorID,
  744. action, null, options);
  745. break;
  746. }
  747. }
  748. };
  749. const gFormSubmitObserver = {
  750. QueryInterface : XPCOMUtils.generateQI([Ci.nsIFormSubmitObserver]),
  751. panel: null,
  752. init: function()
  753. {
  754. this.panel = document.getElementById('invalid-form-popup');
  755. },
  756. panelIsOpen: function()
  757. {
  758. return this.panel && this.panel.state != "hiding" &&
  759. this.panel.state != "closed";
  760. },
  761. notifyInvalidSubmit : function (aFormElement, aInvalidElements)
  762. {
  763. // We are going to handle invalid form submission attempt by focusing the
  764. // first invalid element and show the corresponding validation message in a
  765. // panel attached to the element.
  766. if (!aInvalidElements.length) {
  767. return;
  768. }
  769. // Don't show the popup if the current tab doesn't contain the invalid form.
  770. if (gBrowser.contentDocument !=
  771. aFormElement.ownerDocument.defaultView.top.document) {
  772. return;
  773. }
  774. let element = aInvalidElements.queryElementAt(0, Ci.nsISupports);
  775. if (!(element instanceof HTMLInputElement ||
  776. element instanceof HTMLTextAreaElement ||
  777. element instanceof HTMLSelectElement ||
  778. element instanceof HTMLButtonElement)) {
  779. return;
  780. }
  781. this.panel.firstChild.textContent = element.validationMessage;
  782. element.focus();
  783. // If the user interacts with the element and makes it valid or leaves it,
  784. // we want to remove the popup.
  785. // We could check for clicks but a click is already removing the popup.
  786. function blurHandler() {
  787. gFormSubmitObserver.panel.hidePopup();
  788. };
  789. function inputHandler(e) {
  790. if (e.originalTarget.validity.valid) {
  791. gFormSubmitObserver.panel.hidePopup();
  792. } else {
  793. // If the element is now invalid for a new reason, we should update the
  794. // error message.
  795. if (gFormSubmitObserver.panel.firstChild.textContent !=
  796. e.originalTarget.validationMessage) {
  797. gFormSubmitObserver.panel.firstChild.textContent =
  798. e.originalTarget.validationMessage;
  799. }
  800. }
  801. };
  802. element.addEventListener("input", inputHandler, false);
  803. element.addEventListener("blur", blurHandler, false);
  804. // One event to bring them all and in the darkness bind them.
  805. this.panel.addEventListener("popuphiding", function(aEvent) {
  806. aEvent.target.removeEventListener("popuphiding", arguments.callee, false);
  807. element.removeEventListener("input", inputHandler, false);
  808. element.removeEventListener("blur", blurHandler, false);
  809. }, false);
  810. this.panel.hidden = false;
  811. // We want to show the popup at the middle of checkbox and radio buttons
  812. // and where the content begin for the other elements.
  813. let offset = 0;
  814. let position = "";
  815. if (element.tagName == 'INPUT' &&
  816. (element.type == 'radio' || element.type == 'checkbox')) {
  817. position = "bottomcenter topleft";
  818. } else {
  819. let win = element.ownerDocument.defaultView;
  820. let style = win.getComputedStyle(element, null);
  821. let utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
  822. .getInterface(Components.interfaces.nsIDOMWindowUtils);
  823. if (style.direction == 'rtl') {
  824. offset = parseInt(style.paddingRight) + parseInt(style.borderRightWidth);
  825. } else {
  826. offset = parseInt(style.paddingLeft) + parseInt(style.borderLeftWidth);
  827. }
  828. offset = Math.round(offset * utils.screenPixelsPerCSSPixel);
  829. position = "after_start";
  830. }
  831. this.panel.openPopup(element, position, offset, 0);
  832. }
  833. };
  834. // Simple gestures support
  835. //
  836. // As per bug #412486, web content must not be allowed to receive any
  837. // simple gesture events. Multi-touch gesture APIs are in their
  838. // infancy and we do NOT want to be forced into supporting an API that
  839. // will probably have to change in the future. (The current Mac OS X
  840. // API is undocumented and was reverse-engineered.) Until support is
  841. // implemented in the event dispatcher to keep these events as
  842. // chrome-only, we must listen for the simple gesture events during
  843. // the capturing phase and call stopPropagation on every event.
  844. let gGestureSupport = {
  845. /**
  846. * Add or remove mouse gesture event listeners
  847. *
  848. * @param aAddListener
  849. * True to add/init listeners and false to remove/uninit
  850. */
  851. init: function GS_init(aAddListener) {
  852. const gestureEvents = ["SwipeGesture",
  853. "MagnifyGestureStart", "MagnifyGestureUpdate", "MagnifyGesture",
  854. "RotateGestureStart", "RotateGestureUpdate", "RotateGesture",
  855. "TapGesture", "PressTapGesture"];
  856. let addRemove = aAddListener ? window.addEventListener :
  857. window.removeEventListener;
  858. gestureEvents.forEach(function (event) addRemove("Moz" + event, this, true),
  859. this);
  860. },
  861. /**
  862. * Dispatch events based on the type of mouse gesture event. For now, make
  863. * sure to stop propagation of every gesture event so that web content cannot
  864. * receive gesture events.
  865. *
  866. * @param aEvent
  867. * The gesture event to handle
  868. */
  869. handleEvent: function GS_handleEvent(aEvent) {
  870. aEvent.stopPropagation();
  871. // Create a preference object with some defaults
  872. let def = function(aThreshold, aLatched)
  873. ({ threshold: aThreshold, latched: !!aLatched });
  874. switch (aEvent.type) {
  875. case "MozSwipeGesture":
  876. aEvent.preventDefault();
  877. return this.onSwipe(aEvent);
  878. case "MozMagnifyGestureStart":
  879. aEvent.preventDefault();
  880. #ifdef XP_WIN
  881. return this._setupGesture(aEvent, "pinch", def(25, 0), "out", "in");
  882. #else
  883. return this._setupGesture(aEvent, "pinch", def(150, 1), "out", "in");
  884. #endif
  885. case "MozRotateGestureStart":
  886. aEvent.preventDefault();
  887. return this._setupGesture(aEvent, "twist", def(25, 0), "right", "left");
  888. case "MozMagnifyGestureUpdate":
  889. case "MozRotateGestureUpdate":
  890. aEvent.preventDefault();
  891. return this._doUpdate(aEvent);
  892. case "MozTapGesture":
  893. aEvent.preventDefault();
  894. return this._doAction(aEvent, ["tap"]);
  895. case "MozPressTapGesture":
  896. // Fall through to default behavior
  897. return;
  898. }
  899. },
  900. /**
  901. * Called at the start of "pinch" and "twist" gestures to setup all of the
  902. * information needed to process the gesture
  903. *
  904. * @param aEvent
  905. * The continual motion start event to handle
  906. * @param aGesture
  907. * Name of the gesture to handle
  908. * @param aPref
  909. * Preference object with the names of preferences and defaults
  910. * @param aInc
  911. * Command to trigger for increasing motion (without gesture name)
  912. * @param aDec
  913. * Command to trigger for decreasing motion (without gesture name)
  914. */
  915. _setupGesture: function GS__setupGesture(aEvent, aGesture, aPref, aInc, aDec) {
  916. // Try to load user-set values from preferences
  917. for (let [pref, def] in Iterator(aPref))
  918. aPref[pref] = this._getPref(aGesture + "." + pref, def);
  919. // Keep track of the total deltas and latching behavior
  920. let offset = 0;
  921. let latchDir = aEvent.delta > 0 ? 1 : -1;
  922. let isLatched = false;
  923. // Create the update function here to capture closure state
  924. this._doUpdate = function GS__doUpdate(aEvent) {
  925. // Update the offset with new event data
  926. offset += aEvent.delta;
  927. // Check if the cumulative deltas exceed the threshold
  928. if (Math.abs(offset) > aPref["threshold"]) {
  929. // Trigger the action if we don't care about latching; otherwise, make
  930. // sure either we're not latched and going the same direction of the
  931. // initial motion; or we're latched and going the opposite way
  932. let sameDir = (latchDir ^ offset) >= 0;
  933. if (!aPref["latched"] || (isLatched ^ sameDir)) {
  934. this._doAction(aEvent, [aGesture, offset > 0 ? aInc : aDec]);
  935. // We must be getting latched or leaving it, so just toggle
  936. isLatched = !isLatched;
  937. }
  938. // Reset motion counter to prepare for more of the same gesture
  939. offset = 0;
  940. }
  941. };
  942. // The start event also contains deltas, so handle an update right away
  943. this._doUpdate(aEvent);
  944. },
  945. /**
  946. * Generator producing the powerset of the input array where the first result
  947. * is the complete set and the last result (before StopIteration) is empty.
  948. *
  949. * @param aArray
  950. * Source array containing any number of elements
  951. * @yield Array that is a subset of the input array from full set to empty
  952. */
  953. _power: function GS__power(aArray) {
  954. // Create a bitmask based on the length of the array
  955. let num = 1 << aArray.length;
  956. while (--num >= 0) {
  957. // Only select array elements where the current bit is set
  958. yield aArray.reduce(function (aPrev, aCurr, aIndex) {
  959. if (num & 1 << aIndex)
  960. aPrev.push(aCurr);
  961. return aPrev;
  962. }, []);
  963. }
  964. },
  965. /**
  966. * Determine what action to do for the gesture based on which keys are
  967. * pressed and which commands are set
  968. *
  969. * @param aEvent
  970. * The original gesture event to convert into a fake click event
  971. * @param aGesture
  972. * Array of gesture name parts (to be joined by periods)
  973. * @return Name of the command found for the event's keys and gesture. If no
  974. * command is found, no value is returned (undefined).
  975. */
  976. _doAction: function GS__doAction(aEvent, aGesture) {
  977. // Create an array of pressed keys in a fixed order so that a command for
  978. // "meta" is preferred over "ctrl" when both buttons are pressed (and a
  979. // command for both don't exist)
  980. let keyCombos = [];
  981. ["shift", "alt", "ctrl", "meta"].forEach(function (key) {
  982. if (aEvent[key + "Key"])
  983. keyCombos.push(key);
  984. });
  985. // Try each combination of key presses in decreasing order for commands
  986. for each (let subCombo in this._power(keyCombos)) {
  987. // Convert a gesture and pressed keys into the corresponding command
  988. // action where the preference has the gesture before "shift" before
  989. // "alt" before "ctrl" before "meta" all separated by periods
  990. let command;
  991. try {
  992. command = this._getPref(aGesture.concat(subCombo).join("."));
  993. } catch (e) {}
  994. if (!command)
  995. continue;
  996. let node = document.getElementById(command);
  997. if (node) {
  998. if (node.getAttribute("disabled") != "true") {
  999. let cmdEvent = document.createEvent("xulcommandevent");
  1000. cmdEvent.initCommandEvent("command", true, true, window, 0,
  1001. aEvent.ctrlKey, aEvent.altKey, aEvent.shiftKey,
  1002. aEvent.metaKey, null);
  1003. node.dispatchEvent(cmdEvent);
  1004. }
  1005. } else {
  1006. goDoCommand(command);
  1007. }
  1008. return command;
  1009. }
  1010. return null;
  1011. },
  1012. /**
  1013. * Convert continual motion events into an action if it exceeds a threshold
  1014. * in a given direction. This function will be set by _setupGesture to
  1015. * capture state that needs to be shared across multiple gesture updates.
  1016. *
  1017. * @param aEvent
  1018. * The continual motion update event to handle
  1019. */
  1020. _doUpdate: function(aEvent) {},
  1021. /**
  1022. * Convert the swipe gesture into a browser action based on the direction
  1023. *
  1024. * @param aEvent
  1025. * The swipe event to handle
  1026. */
  1027. onSwipe: function GS_onSwipe(aEvent) {
  1028. // Figure out which one (and only one) direction was triggered
  1029. ["UP", "RIGHT", "DOWN", "LEFT"].forEach(function (dir) {
  1030. if (aEvent.direction == aEvent["DIRECTION_" + dir])
  1031. return this._doAction(aEvent, ["swipe", dir.toLowerCase()]);
  1032. }, this);
  1033. },
  1034. /**
  1035. * Get a gesture preference or use a default if it doesn't exist
  1036. *
  1037. * @param aPref
  1038. * Name of the preference to load under the gesture branch
  1039. * @param aDef
  1040. * Default value if the preference doesn't exist
  1041. */
  1042. _getPref: function GS__getPref(aPref, aDef) {
  1043. // Preferences branch under which all gestures preferences are stored
  1044. const branch = "browser.gesture.";
  1045. try {
  1046. // Determine what type of data to load based on default value's type
  1047. let type = typeof aDef;
  1048. let getFunc = "get" + (type == "boolean" ? "Bool" :
  1049. type == "number" ? "Int" : "Char") + "Pref";
  1050. return gPrefService[getFunc](branch + aPref);
  1051. }
  1052. catch (e) {
  1053. return aDef;
  1054. }
  1055. },
  1056. };
  1057. function BrowserStartup() {
  1058. var uriToLoad = null;
  1059. // window.arguments[0]: URI to load (string), or an nsISupportsArray of
  1060. // nsISupportsStrings to load, or a xul:tab of
  1061. // a tabbrowser, which will be replaced by this
  1062. // window (for this case, all other arguments are
  1063. // ignored).
  1064. // [1]: character set (string)
  1065. // [2]: referrer (nsIURI)
  1066. // [3]: postData (nsIInputStream)
  1067. // [4]: allowThirdPartyFixup (bool)
  1068. if ("arguments" in window && window.arguments[0])
  1069. uriToLoad = window.arguments[0];
  1070. var isLoadingBlank = uriToLoad == "about:blank";
  1071. var mustLoadSidebar = false;
  1072. prepareForStartup();
  1073. if (uriToLoad && !isLoadingBlank) {
  1074. if (uriToLoad instanceof Ci.nsISupportsArray) {
  1075. let count = uriToLoad.Count();
  1076. let specs = [];
  1077. for (let i = 0; i < count; i++) {
  1078. let urisstring = uriToLoad.GetElementAt(i).QueryInterface(Ci.nsISupportsString);
  1079. specs.push(urisstring.data);
  1080. }
  1081. // This function throws for certain malformed URIs, so use exception handling
  1082. // so that we don't disrupt startup
  1083. try {
  1084. gBrowser.loadTabs(specs, false, true);
  1085. } catch (e) {}
  1086. }
  1087. else if (uriToLoad instanceof XULElement) {
  1088. // swap the given tab with the default about:blank tab and then close
  1089. // the original tab in the other window.
  1090. // Stop the about:blank load
  1091. gBrowser.stop();
  1092. // make sure it has a docshell
  1093. gBrowser.docShell;
  1094. gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, uriToLoad);
  1095. }
  1096. else if (window.arguments.length >= 3) {
  1097. loadURI(uriToLoad, window.arguments[2], window.arguments[3] || null,
  1098. window.arguments[4] || false);
  1099. content.focus();
  1100. }
  1101. // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
  1102. // Such callers expect that window.arguments[0] is handled as a single URI.
  1103. else
  1104. loadOneOrMoreURIs(uriToLoad);
  1105. }
  1106. if (window.opener && !window.opener.closed) {
  1107. let openerSidebarBox = window.opener.document.getElementById("sidebar-box");
  1108. // If the opener had a sidebar, open the same sidebar in our window.
  1109. // The opener can be the hidden window too, if we're coming from the state
  1110. // where no windows are open, and the hidden window has no sidebar box.
  1111. if (openerSidebarBox && !openerSidebarBox.hidden) {
  1112. let sidebarCmd = openerSidebarBox.getAttribute("sidebarcommand");
  1113. let sidebarCmdElem = document.getElementById(sidebarCmd);
  1114. // dynamically generated sidebars will fail this check.
  1115. if (sidebarCmdElem) {
  1116. let sidebarBox = document.getElementById("sidebar-box");
  1117. let sidebarTitle = document.getElementById("sidebar-title");
  1118. sidebarTitle.setAttribute(
  1119. "value", window.opener.document.getElementById("sidebar-title").getAttribute("value"));
  1120. sidebarBox.setAttribute("width", openerSidebarBox.boxObject.width);
  1121. sidebarBox.setAttribute("sidebarcommand", sidebarCmd);
  1122. // Note: we're setting 'src' on sidebarBox, which is a <vbox>, not on
  1123. // the <browser id="sidebar">. This lets us delay the actual load until
  1124. // delayedStartup().
  1125. sidebarBox.setAttribute(
  1126. "src", window.opener.document.getElementById("sidebar").getAttribute("src"));
  1127. mustLoadSidebar = true;
  1128. sidebarBox.hidden = false;
  1129. document.getElementById("sidebar-splitter").hidden = false;
  1130. sidebarCmdElem.setAttribute("checked", "true");
  1131. }
  1132. }
  1133. }
  1134. else {
  1135. let box = document.getElementById("sidebar-box");
  1136. if (box.hasAttribute("sidebarcommand")) {
  1137. let commandID = box.getAttribute("sidebarcommand");
  1138. if (commandID) {
  1139. let command = document.getElementById(commandID);
  1140. if (command) {
  1141. mustLoadSidebar = true;
  1142. box.hidden = false;
  1143. document.getElementById("sidebar-splitter").hidden = false;
  1144. command.setAttribute("checked", "true");
  1145. }
  1146. else {
  1147. // Remove the |sidebarcommand| attribute, because the element it
  1148. // refers to no longer exists, so we should assume this sidebar
  1149. // panel has been uninstalled. (249883)
  1150. box.removeAttribute("sidebarcommand");
  1151. }
  1152. }
  1153. }
  1154. }
  1155. // Certain kinds of automigration rely on this notification to complete their
  1156. // tasks BEFORE the browser window is shown.
  1157. Services.obs.notifyObservers(null, "browser-window-before-show", "");
  1158. // Set a sane starting width/height for all resolutions on new profiles.
  1159. if (!document.documentElement.hasAttribute("width")) {
  1160. let defaultWidth = 994;
  1161. let defaultHeight;
  1162. if (screen.availHeight <= 600) {
  1163. document.documentElement.setAttribute("sizemode", "maximized");
  1164. defaultWidth = 610;
  1165. defaultHeight = 450;
  1166. }
  1167. else {
  1168. // Create a narrower window for large or wide-aspect displays, to suggest
  1169. // side-by-side page view.
  1170. if (screen.availWidth >= 1600)
  1171. defaultWidth = (screen.availWidth / 2) - 20;
  1172. defaultHeight = screen.availHeight - 10;
  1173. #ifdef MOZ_WIDGET_GTK2
  1174. // On X, we're not currently able to account for the size of the window
  1175. // border. Use 28px as a guess (titlebar + bottom window border)
  1176. defaultHeight -= 28;
  1177. #endif
  1178. }
  1179. document.documentElement.setAttribute("width", defaultWidth);
  1180. document.documentElement.setAttribute("height", defaultHeight);
  1181. }
  1182. if (!gShowPageResizers)
  1183. document.getElementById("status-bar").setAttribute("hideresizer", "true");
  1184. if (!window.toolbar.visible) {
  1185. // adjust browser UI for popups
  1186. if (gURLBar) {
  1187. gURLBar.setAttribute("readonly", "true");
  1188. gURLBar.setAttribute("enablehistory", "false");
  1189. }
  1190. goSetCommandEnabled("Browser:OpenLocation", false);
  1191. goSetCommandEnabled("cmd_newNavigatorTab", false);
  1192. }
  1193. #ifdef MENUBAR_CAN_AUTOHIDE
  1194. updateAppButtonDisplay();
  1195. #endif
  1196. CombinedStopReload.init();
  1197. allTabs.readPref();
  1198. TabsOnTop.syncCommand();
  1199. BookmarksMenuButton.init();
  1200. TabsInTitlebar.init();
  1201. gPrivateBrowsingUI.init();
  1202. retrieveToolbarIconsizesFromTheme();
  1203. gDelayedStartupTimeoutId = setTimeout(delayedStartup, 0, isLoadingBlank, mustLoadSidebar);
  1204. gStartupRan

Large files files are truncated, but you can click here to view the full file