PageRenderTime 77ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 2ms

/browser/base/content/browser.js

http://github.com/zpao/v8monkey
JavaScript | 9169 lines | 6631 code | 1252 blank | 1286 comment | 1363 complexity | e72746e497ea254805b14fd1dcfe9bfe MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, AGPL-1.0, LGPL-2.1, BSD-3-Clause, GPL-2.0, JSON, Apache-2.0, 0BSD

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

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